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 01:52]
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 8: Line 8:
 First a bit of background: First a bit of background:
  
-* All of GDK/WIN32 is using a Windows Drawing Context (DC).\\ +  * All of GDK/WIN32 is using a Windows Drawing Context (DC).\\ 
-* When a cairo-surface is used, GdkDrawables use ''cairo_win32_surface_create(HDC*)''.\\ +  * When a cairo-surface is used, GdkDrawables use ''cairo_win32_surface_create(HDC*)''.\\ 
-* That cairo-surface has the geometry of the GC (not the size of the GdkDrawable).\\ +  * That cairo-surface has the geometry of the DC (not the size of the GdkDrawable).\\ 
-* operations on the cairo-surface are flushed to the DC. Gdk does not use an extra copy step (cairo does that).+  * operations on the cairo-surface are flushed to the DC. Gdk does not use an extra copy step (cairo does that).
  
 ==== A: Cairo BitBlt ==== ==== A: Cairo BitBlt ====
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 GC 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 GC backed) and only synchronize the modified-areas to the GC 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 GC, 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.1414281121.txt.gz · Last modified: 26.10.2014 01:52 by rgareus