diff options
author | tschmelcher@chromium.org <tschmelcher@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-03-21 17:06:47 +0000 |
---|---|---|
committer | tschmelcher@chromium.org <tschmelcher@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-03-21 17:06:47 +0000 |
commit | 470474b8d45ed2c30a09b99d3efcc528d47ea3dd (patch) | |
tree | d7f19b756fb88dcaa7948f98f9742f3d3f295623 /o3d | |
parent | 3531ce93cb1f24667da7209c11faf9ffe069d612 (diff) | |
download | chromium_src-470474b8d45ed2c30a09b99d3efcc528d47ea3dd.zip chromium_src-470474b8d45ed2c30a09b99d3efcc528d47ea3dd.tar.gz chromium_src-470474b8d45ed2c30a09b99d3efcc528d47ea3dd.tar.bz2 |
O2D: Enable clipping for the non-COMPOSITING_TO_IMAGE case (i.e., Linux and Windows).
TEST=loaded O2D on Lin & Win with COMPOSITING_TO_IMAGE both off and on and verified it worked and perf was improved; loaded O2D in Mac with COMPOSITING_TO_IMAGE off and verified that works too
BUG=none
Review URL: http://codereview.chromium.org/6714033
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@78895 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'o3d')
-rw-r--r-- | o3d/core/cross/cairo/renderer_cairo.cc | 158 | ||||
-rw-r--r-- | o3d/core/cross/cairo/renderer_cairo.h | 25 |
2 files changed, 100 insertions, 83 deletions
diff --git a/o3d/core/cross/cairo/renderer_cairo.cc b/o3d/core/cross/cairo/renderer_cairo.cc index 1de765f..dcc3e82 100644 --- a/o3d/core/cross/cairo/renderer_cairo.cc +++ b/o3d/core/cross/cairo/renderer_cairo.cc @@ -50,6 +50,17 @@ #include "core/cross/cairo/layer.h" #include "core/cross/cairo/texture_cairo.h" +#ifdef OS_MACOSX +// As of OS X 10.6.4, the Quartz 2D drawing API has hardware acceleration +// disabled by default, and if you force-enable it then it actually hurts +// performance instead of improving it (really, go google it). It also turns out +// that the performance of the software implementation in Pixman is about 12% +// faster than the OS X software implementation (measured as CPU usage per +// rendered frame), so we do all compositing with Pixman via an image surface +// and only use the OS to paint the final frame to the screen. +#define COMPOSITING_TO_IMAGE 1 +#endif + namespace o3d { // This is a factory function for creating 2D Renderer objects. @@ -70,9 +81,7 @@ RendererCairo::RendererCairo(ServiceLocator* service_locator) hwnd_(NULL), #endif display_surface_(NULL), -#ifdef COMPOSITING_TO_IMAGE - image_surface_(NULL), -#endif + offscreen_surface_(NULL), fullscreen_(false), size_dirty_(false) { // Don't need to do anything. @@ -90,9 +99,7 @@ RendererCairo* RendererCairo::CreateDefault(ServiceLocator* service_locator) { void RendererCairo::Destroy() { DLOG(INFO) << "To Destroy"; -#ifdef COMPOSITING_TO_IMAGE - DestroyImageSurface(); -#endif + DestroyOffscreenSurface(); #if defined(OS_LINUX) || defined(OS_WIN) DestroyDisplaySurface(); #endif @@ -138,31 +145,28 @@ static void RoundRegion(const Layer::Region& in_region, void RendererCairo::Paint() { #ifdef OS_MACOSX // On OSX we can't persist the display surface across Paint() calls because - // of issues in Safari with unbalanced CGContextSaveGState/RestoreGState calls - // causing crashes, so we have to create and destroy the surface for every - // frame. + // of issues with unbalanced CGContextSaveGState/RestoreGState calls, so we + // have to create and destroy the surface for every frame. CreateDisplaySurface(); #endif - if (!display_surface_) { - DLOG(INFO) << "No target surface, cannot paint"; +#if !defined(COMPOSITING_TO_IMAGE) && defined(OS_LINUX) + if (!offscreen_surface_) { + // Have to call this here because strangely it breaks rendering if we call + // it during InitCommon() on Linux. Possibly the X11 Window underlying the + // display_surface_ is not fully initialized until sometime after + // NPP_SetWindow(). + CreateOffscreenSurface(); + } +#endif + + if (!display_surface_ || !offscreen_surface_) { + DLOG(INFO) << "No target surface(s), cannot paint"; return; } // TODO(tschmelcher): Don't keep creating and destroying the drawing context. - cairo_t* cr = cairo_create( -#ifdef COMPOSITING_TO_IMAGE - image_surface_ -#else - display_surface_ -#endif - ); - -#ifndef COMPOSITING_TO_IMAGE - // Redirect drawing to an off-screen surface (holding only colour information, - // without an alpha channel). - cairo_push_group_with_content(cr, CAIRO_CONTENT_COLOR); -#endif + cairo_t* cr = cairo_create(offscreen_surface_); cairo_save(cr); @@ -170,11 +174,9 @@ void RendererCairo::Paint() { cairo_set_fill_rule(cr, CAIRO_FILL_RULE_WINDING); // If we have been resized then we must redraw everything, since the new - // surface will be uninitialized. + // offscreen surface will be uninitialized. if (size_dirty_) { -#ifdef COMPOSITING_TO_IMAGE AddDisplayRegion(cr); -#endif } // Build an initial clip region for all drawing operations that restricts @@ -220,35 +222,25 @@ void RendererCairo::Paint() { !layer->GetSavedShouldPaint())) { // If it is visible and the region, content, or visibility has changed // then the current region must be redrawn. -#ifdef COMPOSITING_TO_IMAGE AddRegion(cr, layer->outer_clip_region()); -#endif } if (layer->GetSavedShouldPaint() && (layer->region_dirty() || !layer->ShouldPaint())) { // If the region or visibility has changed and it was visible before then // the old region must be redrawn. -#ifdef COMPOSITING_TO_IMAGE AddRegion(cr, layer->GetSavedOuterClipRegion()); -#endif } } // Must also redraw the regions of any formerly visible layers. for (RegionList::const_iterator i = layer_ghost_list_.begin(); i != layer_ghost_list_.end(); ++i) { -#ifdef COMPOSITING_TO_IMAGE AddRegion(cr, *i); -#endif } // Clip everything outside the regions defined by the above. -#ifdef COMPOSITING_TO_IMAGE - // TODO(tschmelcher): Perform this clipping for the non-COMPOSITING_TO_IMAGE - // case too. cairo_clip(cr); -#endif // If any visible layer has had its z-value modified, re-sort the list to get // the right draw order. @@ -333,17 +325,16 @@ void RendererCairo::Paint() { cairo_restore(cr); -#ifdef COMPOSITING_TO_IMAGE - // Finish drawing to the image and set up a new context for painting the image - // to the screen. + // Finish drawing to the offscreen surface. cairo_destroy(cr); + + // Set up a new context for painting the offscreen surface to the screen. cr = cairo_create(display_surface_); - cairo_set_source_surface(cr, image_surface_, 0, 0); + cairo_set_source_surface(cr, offscreen_surface_, 0, 0); + // Painting to a Win32 window with the SOURCE operator interacts poorly with + // window resizing, so on Windows we use the default of OVER. +#ifndef OS_WIN cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE); -#else - // Finish off-screen drawing and make the off-screen surface the source for - // paints to the screen. - cairo_pop_group_to_source(cr); #endif // Paint to the screen. @@ -437,8 +428,8 @@ void RendererCairo::InitCommon() { #if defined(OS_LINUX) || defined(OS_WIN) CreateDisplaySurface(); #endif -#ifdef COMPOSITING_TO_IMAGE - CreateImageSurface(); +#if defined(COMPOSITING_TO_IMAGE) || !defined(OS_LINUX) + CreateOffscreenSurface(); #endif } @@ -471,7 +462,15 @@ void RendererCairo::CreateDisplaySurface() { HDC hdc = GetDC(hwnd_); display_surface_ = cairo_win32_surface_create(hdc); +#endif + + if (CAIRO_STATUS_SUCCESS != cairo_surface_status(display_surface_)) { + DLOG(ERROR) << "Failed to create display surface"; + DestroyDisplaySurface(); + return; + } +#ifdef OS_WIN // Check the surface to make sure it has the correct clip box. cairo_win32_surface_t* cairo_surface = reinterpret_cast<cairo_win32_surface_t*>(display_surface_); @@ -508,20 +507,44 @@ void RendererCairo::DestroyDisplaySurface() { } } -#ifdef COMPOSITING_TO_IMAGE -void RendererCairo::CreateImageSurface() { - image_surface_ = cairo_image_surface_create(CAIRO_FORMAT_RGB24, - display_width(), - display_height()); +void RendererCairo::CreateOffscreenSurface() { +#if defined(COMPOSITING_TO_IMAGE) + offscreen_surface_ = cairo_image_surface_create(CAIRO_FORMAT_RGB24, + display_width(), + display_height()); +#elif defined(OS_LINUX) || defined(OS_WIN) + if (!display_surface_) { + DLOG(INFO) << "No display surface, cannot create offscreen surface"; + return; + } + offscreen_surface_ = cairo_surface_create_similar(display_surface_, + CAIRO_CONTENT_COLOR, + display_width(), + display_height()); +#else // OS_MACOSX + // On OSX we can't use cairo_surface_create_similar() because display_surface_ + // is only valid during Paint(), so instead hard-code what a + // cairo_surface_create_similar() call would do. + // (Note that this code path is not actually taken right now because we use + // COMPOSITING_TO_IMAGE on OSX.) + offscreen_surface_ = cairo_quartz_surface_create(CAIRO_FORMAT_RGB24, + display_width(), + display_height()); +#endif + + if (CAIRO_STATUS_SUCCESS != cairo_surface_status(offscreen_surface_)) { + DLOG(ERROR) << "Failed to create offscreen surface"; + DestroyOffscreenSurface(); + return; + } } -void RendererCairo::DestroyImageSurface() { - if (image_surface_) { - cairo_surface_destroy(image_surface_); - image_surface_ = NULL; +void RendererCairo::DestroyOffscreenSurface() { + if (offscreen_surface_) { + cairo_surface_destroy(offscreen_surface_); + offscreen_surface_ = NULL; } } -#endif void RendererCairo::AddDisplayRegion(cairo_t* cr) { cairo_rectangle(cr, 0, 0, display_width(), display_height()); @@ -577,14 +600,17 @@ void RendererCairo::Resize(int width, int height) { SetClientSize(width, height); #if defined(OS_LINUX) - cairo_xlib_surface_set_size(display_surface_, width, height); + if (display_surface_) { + cairo_xlib_surface_set_size(display_surface_, width, height); + } #elif defined(OS_WIN) DestroyDisplaySurface(); CreateDisplaySurface(); #endif -#ifdef COMPOSITING_TO_IMAGE - DestroyImageSurface(); - CreateImageSurface(); + + DestroyOffscreenSurface(); +#if defined(COMPOSITING_TO_IMAGE) || !defined(OS_LINUX) + CreateOffscreenSurface(); #endif } @@ -665,7 +691,6 @@ void RendererCairo::SetViewportInPixels(int left, NOTIMPLEMENTED(); } -// TODO(fransiskusx): Need to implement it later. // Turns fullscreen display on. // Parameters: // display: a platform-specific display identifier @@ -686,6 +711,10 @@ bool RendererCairo::GoFullscreen(const DisplayWindow& display, SetClientSize(window_attributes.width, window_attributes.height); DestroyDisplaySurface(); CreateDisplaySurface(); + DestroyOffscreenSurface(); +#ifdef COMPOSITING_TO_IMAGE + CreateOffscreenSurface(); +#endif } #elif defined(OS_WIN) DEVMODE dev_mode; @@ -702,7 +731,6 @@ bool RendererCairo::GoFullscreen(const DisplayWindow& display, return fullscreen_; } -// TODO(fransiskusx): Need to implement it later. // Cancels fullscreen display. Restores rendering to windowed mode // with the given width and height. // Parameters: @@ -724,6 +752,10 @@ bool RendererCairo::CancelFullscreen(const DisplayWindow& display, SetClientSize(width, height); DestroyDisplaySurface(); CreateDisplaySurface(); + DestroyOffscreenSurface(); +#ifdef COMPOSITING_TO_IMAGE + CreateOffscreenSurface(); +#endif #elif defined(OS_WIN) if (hwnd_ == NULL) { // Not initialized. diff --git a/o3d/core/cross/cairo/renderer_cairo.h b/o3d/core/cross/cairo/renderer_cairo.h index 819b08b..2162990 100644 --- a/o3d/core/cross/cairo/renderer_cairo.h +++ b/o3d/core/cross/cairo/renderer_cairo.h @@ -43,17 +43,6 @@ #include "core/cross/renderer.h" #include "core/cross/cairo/layer.h" -#ifdef OS_MACOSX -// As of OS X 10.6.4, the Quartz 2D drawing API has hardware acceleration -// disabled by default, and if you force-enable it then it actually hurts -// performance instead of improving it (really, go google it). It also turns out -// that the performance of the software implementation in Pixman is about 12% -// faster than the OS X software implementation (measured as CPU usage per -// rendered frame), so we do all compositing with Pixman via an image surface -// and only use the OS to paint the final frame to the screen. -#define COMPOSITING_TO_IMAGE 1 -#endif - namespace o3d { namespace o2d { @@ -246,10 +235,8 @@ class RendererCairo : public Renderer { void CreateDisplaySurface(); void DestroyDisplaySurface(); -#ifdef COMPOSITING_TO_IMAGE - void CreateImageSurface(); - void DestroyImageSurface(); -#endif + void CreateOffscreenSurface(); + void DestroyOffscreenSurface(); void AddDisplayRegion(cairo_t* cr); void AddRegion(cairo_t* cr, const Layer::Region& region); @@ -267,11 +254,9 @@ class RendererCairo : public Renderer { // The OS-specific cairo surface for our display window. cairo_surface_t* display_surface_; -#ifdef COMPOSITING_TO_IMAGE - // An image surface for compositing the frame before drawing to the display - // surface. - cairo_surface_t* image_surface_; -#endif + // An offscreen surface for compositing the frame before drawing to the + // display surface. + cairo_surface_t* offscreen_surface_; // List of all layers. LayerList layer_list_; |