Differences

This shows you the differences between two versions of the page.

Link to this comparison view

wiki:ardour_windows_gdk_and_cairo [26.10.2014 04:12]
rgareus
wiki:ardour_windows_gdk_and_cairo [28.10.2014 15:24] (current)
81.57.94.90 [Ardour, Windows, Gdk/GTK and Cairo]
Line 1: Line 1:
 ====== Ardour, Windows, Gdk/GTK and Cairo ====== ====== Ardour, Windows, Gdk/GTK and Cairo ======
  
-Lab Notes. +Lab Notes.\\ 
-Analysis the //slowness// and high CPU-usage of the Ardour3 GUI on the windows platform.+Analysis the //slowness// and high CPU-usage of the [[http://ardour.org|Ardour3]] GUI on the Windows platform.
  
 ===== Findings ===== ===== Findings =====
Line 17: Line 17:
 When using a cairo-surface backed by Windows Drawing Context: When using a cairo-surface backed by Windows Drawing Context:
  
-  - The first cairo-operation on that surface which need an Alpha-Channel creates a fallback-surface (RGB32). This is done because windows DC does not properly support 32bit RGBA.+  - The first cairo-operation on that surface which need an Alpha-Channel creates a fallback-surface (ARGB32). This is done because windows DC does not properly support 32bit RGBA.
   - Then, cairo calls [[http://msdn.microsoft.com/en-us/library/windows/desktop/dd183370%28v=vs.85%29.aspx|BitBlt]] to copy the whole DC area to that new surface.   - Then, cairo calls [[http://msdn.microsoft.com/en-us/library/windows/desktop/dd183370%28v=vs.85%29.aspx|BitBlt]] to copy the whole DC area to that new surface.
   - Cairo continues to operate on the fallback surface.   - Cairo continues to operate on the fallback surface.
   - Eventually, Cairo ''BitBlt''s back only the changed parts when the surface is flushed or destroyed.   - Eventually, Cairo ''BitBlt''s back only the changed parts when the surface is flushed or destroyed.
-  - A surface_flush also invalidates and destroys the fallback-surface (next cairo operation on that surfacego back to ''[1]'').+  - A surface_flush also invalidates and destroys the fallback-surface (the next cairo operation on that surface go back to **1.**).
  
  
Line 31: Line 31:
 and more specifically, how Ardour uses GTK for its cairo canvas. and more specifically, how Ardour uses GTK for its cairo canvas.
  
-In a lot of cases in Ardour the BitBlt (2.) is not even needed. Ardour draws its own background. +In a lot of cases in Ardour the BitBlt (**2.**) is not even needed. Ardour Canvas Items draw their own background. 
-Everything that is ''BitBlt'' during step 2 above is overwritten. This is in particular true for the largest area (main canvas) of ardour.+All pixels that are ''BitBlt'' during step 2 above are overwritten. This is in particular true for the largest area (main canvas) of Ardour.
  
-In that case it would be helpful to have an API to tell cairo to skip the initial ''BitBlt'' -- or rather tell gdk to not use a win32 surface in the first place.+In that case it would be helpful to have an API to tell cairo to skip the initial ''BitBlt'' -- or rather tell Gdk to not use a win32 DC backed surface in the first place.
  
-For other cases it is however essential to initially copy the DC to the fallback surface in cases where there's composition (gtk-box background, ardour-cairo foreground with round-edges (alpha) or text).  In ardour's case that's mostly static things like buttonstoolbar  when the actual DC geometry is small.+In cases where there is composition, it is however essential to initially copy the DC to the fallback surface (e.g. gtk-box background, ardour-cairo foreground with round-edges (alpha) or text) in order to properly display 
 +edges or round corners. In ardour's case this is  only relevant for mostly static widgets like buttons or the toolbar when the actual DC geometry is small.
  
 Ideally Gdk should be changed to always use a cairo image/software-surface (never DC backed) and only synchronize the modified-areas to the DC as a last step (GdkWindow uses a cairo backing store already). Ideally Gdk should be changed to always use a cairo image/software-surface (never DC backed) and only synchronize the modified-areas to the DC as a last step (GdkWindow uses a cairo backing store already).
  
-The cairo/pixmap software implementation beats various HW acceleration methods for 2D drawing performance (also on other platforms) and the cairo image/software surface works reliably regardless of underlying hardware. 
  
 ===== Other Findings ===== ===== Other Findings =====
 +
 +While the above issue has been analyzed in detail, (code study, gdb and print'ing) the facts below
 +were established using //printf-debugging// for the most part.
  
 ==== B: Gdk Backing Store ==== ==== B: Gdk Backing Store ====
  
 Every GdkWindow has a backing store (gdkwindow.c): Every GdkWindow has a backing store (gdkwindow.c):
-'' 
-gdk_window_begin_paint_region()'' creates a new temporary cairo-surface (using GdkDrawable API), it is destroyed again in ''gdk_window_end_paint_region()''.  
  
-Some operations on the backing-store are RGB region-copies only (no alpha) and hence do not have the BitBlt problem, but when ardour is active the vast majority or expose-event do trigger the issue.+''gdk_window_begin_paint_region()'' creates a new temporary cairo-surface (using GdkDrawable API), it is destroyed again in ''gdk_window_end_paint_region()''.  
 + 
 +Some operations on the backing-store are RGB region-copies only (no alpha) and hence do not have the BitBlt problem, but when ardour is active the vast majority or expose-events do trigger the issue.
  
 -> BitBlt the complete window. zzzZZZ. -> BitBlt the complete window. zzzZZZ.
 +
 +(possible workaround: unset [[https://developer.gnome.org/gtk2/stable/GtkWidget.html#gtk-widget-set-double-buffered|double buffering]])
  
 ==== C: Gdk/Windows Drawing Context Size ==== ==== C: Gdk/Windows Drawing Context Size ====
  
-The windows DC size is a region-combine of all invalidated widgets for a given expose. e.g. When invalidating a 16x16 widget top-left and one bottom-right: the drawing-context and hence the fallback-surfaces needed to BitBlt is the complete window.+The windows ''DC'' geometry is a region-combine of all invalidated widgets for a given expose. e.g. When invalidating a 16x16 widget top-left and one bottom-right: the drawing-context and hence the fallback-surfaces needed to BitBlt is the complete window.
  
 ==== D: Compositing ==== ==== D: Compositing ====
  
-GdkDrawable background and pixmaps, etc are painted with DC, text is done with pango-cairo. There are often multiple surface-flushes for every GdkDrawable expose, each of which implies a ''BitBlt''. +GdkDrawable background and pixmaps, etc are painted with ''GC'', text is done with pango-cairo. There are often multiple surface-flushes for every GdkDrawable expose, each of which implies a ''BitBlt''.
  
 ==== E: Surface Allocation ==== ==== E: Surface Allocation ====
Line 83: Line 87:
  
 {{ :wiki:a3_no_bitblt.png?600 |}} {{ :wiki:a3_no_bitblt.png?600 |}}
 +
 +compare to the image on the left (with BitBlt).
 +
 +{{:wiki:a3_win_3386.png?100  }}
  
 Various hacks would be possible to address the issue. Various hacks would be possible to address the issue.
-However there's not a single simple point to easily work around this. +<del>However there's not a single simple point to easily work around this</del>
-Probably the easiest way to mitigate the performance hog is to provide a custom GdkDrawable implementation for the main canvas (which does not use a hardware backed surface).+Probably the easiest way to mitigate the performance hog is to provide a custom GdkDrawable implementation for the main canvas (which does not use a hardware backed surface) and keep using default GdkDrawable for all other widgets.  A similar solution would be to make the backing-store of GdkWindow persistent and access it directly. 
 + 
 +A quick hack has been prototyped. The cairo-surface user-data API is used to flag select cairo/win surfaces to not BitBlt (ardour's main canvas & meters): [[https://gist.github.com/x42/ef0b0f6e70d416b3af17|patch for ardour, libcairo]] ((In this case a dedicated user-data key - known to ardour and libcairo - is used to tunnel the information though gdk/gtk which remains unchanged.)).
  
-Still, while performance on Linux & OSX is OK, the expose strategy (see B -> F above) is abysmal and unsuitable for Ardour in general. It only works because CPUs are fast :)+Still, while performance on Linux & OSX is OKish, the expose and invalidation strategy (see B -> F above) is abysmal and unsuitable for Ardour in general. It only works because CPUs are fast :)
  
 The proper way forward: **get rid of GdkDrawable on _all_ platforms.** The proper way forward: **get rid of GdkDrawable on _all_ platforms.**
Line 96: Line 106:
 Use a single cairo [ARGB32] surface for the whole GUI and directly map its data to e.g an openGL texture. Use a single cairo [ARGB32] surface for the whole GUI and directly map its data to e.g an openGL texture.
  
-The ardour canvas already has its own event management and puGL can provide the rest. That'll still leave window-management, box (and table?) layout packingto be done, but those are manageable.+Cairo's ''...surface_mark_dirty()'', damage-reduction and surface-flushing algorithms are very efficient. 
 + 
 +The [[http://ardour.org/canvas.html|ardour canvas]] already has its own event management and [[http://drobilla.net/software/pugl/|puGL]] can provide the rest... That will still leave window-management, box (and table?) layout packing to be done, but those are manageable.
  
 The hard part will be tree-views, file-manager (and maybe menu), maybe some hybrid solution can be done for those cases (or code copy/paste of select GTK implementations sans Gdk). The hard part will be tree-views, file-manager (and maybe menu), maybe some hybrid solution can be done for those cases (or code copy/paste of select GTK implementations sans Gdk).
 +
 +The cairo/pixmap software-surface implementation beats various Hardware-accelerations for 2D drawing performance (on any platform with most graphics chipsets/drivers). And more importantly, the cairo image/software surface works reliably regardless of underlying hardware.
 +Until cairo 2D HW accelleration improves in a way useful to ardour ((Internally ardour uses a lot of cairo surfaces and patterns for waveform image cache, meter-gradients, button insets. They are currently not backed by a hardware.)), using a software image-surface for the complete top-level window will be most efficient.  
 +
 +===== Versions Used =====
 +
 +  * Ardour 3.5-3386-gec92524  (ardour-build-tools 11919e4, x86_64-w64-mingw32-gcc (GCC) 4.9.1)
 +  * glib-2.42.0
 +  * cairo-1.14.0  +  [[https://gist.github.com/x42/c875f8910c9186c013fb|BitBlt debug diff]]
 +  * gtk+-2.24.24 , gtkmm-2.24.4
 +
 
wiki/ardour_windows_gdk_and_cairo.1414293151.txt.gz · Last modified: 26.10.2014 04:12 by rgareus