diff options
author | piman@chromium.org <piman@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-09-20 07:15:33 +0000 |
---|---|---|
committer | piman@chromium.org <piman@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-09-20 07:15:33 +0000 |
commit | 48c9fa72a0f011aece88b66d69e2fe93e05a2bda (patch) | |
tree | 3efbdfe1f1672442774b7840c76e1537fb7b7845 | |
parent | 1b3fbdee193ecca5402f2232c01045440d5f50be (diff) | |
download | chromium_src-48c9fa72a0f011aece88b66d69e2fe93e05a2bda.zip chromium_src-48c9fa72a0f011aece88b66d69e2fe93e05a2bda.tar.gz chromium_src-48c9fa72a0f011aece88b66d69e2fe93e05a2bda.tar.bz2 |
cc: Don't discard framebuffer when using partial swaps
BUG=294433
Review URL: https://chromiumcodereview.appspot.com/24239006
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@224318 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r-- | cc/debug/test_web_graphics_context_3d.h | 3 | ||||
-rw-r--r-- | cc/output/direct_renderer.cc | 21 | ||||
-rw-r--r-- | cc/output/direct_renderer.h | 5 | ||||
-rw-r--r-- | cc/output/gl_renderer.cc | 30 | ||||
-rw-r--r-- | cc/output/gl_renderer.h | 5 | ||||
-rw-r--r-- | cc/output/gl_renderer_unittest.cc | 204 | ||||
-rw-r--r-- | cc/output/software_renderer.cc | 6 | ||||
-rw-r--r-- | cc/output/software_renderer.h | 5 |
8 files changed, 239 insertions, 40 deletions
diff --git a/cc/debug/test_web_graphics_context_3d.h b/cc/debug/test_web_graphics_context_3d.h index 3cc7073..4db270c 100644 --- a/cc/debug/test_web_graphics_context_3d.h +++ b/cc/debug/test_web_graphics_context_3d.h @@ -190,6 +190,9 @@ class CC_EXPORT TestWebGraphicsContext3D : public FakeWebGraphicsContext3D { void set_have_post_sub_buffer(bool have) { test_capabilities_.post_sub_buffer = have; } + void set_have_discard_framebuffer(bool have) { + test_capabilities_.discard_framebuffer = have; + } // When this context is lost, all contexts in its share group are also lost. void add_share_group_context(WebKit::WebGraphicsContext3D* context3d) { diff --git a/cc/output/direct_renderer.cc b/cc/output/direct_renderer.cc index 51ac56a..aad41ed 100644 --- a/cc/output/direct_renderer.cc +++ b/cc/output/direct_renderer.cc @@ -333,19 +333,34 @@ void DirectRenderer::DrawRenderPass(DrawingFrame* frame, bool using_scissor_as_optimization = Capabilities().using_partial_swap && allow_partial_swap; gfx::RectF render_pass_scissor; + bool draw_rect_covers_full_surface = true; + if (frame->current_render_pass == frame->root_render_pass && + !client_->DeviceViewport().Contains( + gfx::Rect(output_surface_->SurfaceSize()))) + draw_rect_covers_full_surface = false; if (using_scissor_as_optimization) { render_pass_scissor = ComputeScissorRectForRenderPass(frame); SetScissorTestRectInDrawSpace(frame, render_pass_scissor); + if (!render_pass_scissor.Contains(frame->current_render_pass->output_rect)) + draw_rect_covers_full_surface = false; } if (frame->current_render_pass != frame->root_render_pass || settings_->should_clear_root_render_pass) { - if (NeedDeviceClip(frame)) + if (NeedDeviceClip(frame)) { SetScissorTestRect(DeviceClipRect(frame)); - else if (!using_scissor_as_optimization) + draw_rect_covers_full_surface = false; + } else if (!using_scissor_as_optimization) { EnsureScissorTestDisabled(); - ClearFramebuffer(frame); + } + + bool has_external_stencil_test = + output_surface_->HasExternalStencilTest() && + frame->current_render_pass == frame->root_render_pass; + + DiscardPixels(has_external_stencil_test, draw_rect_covers_full_surface); + ClearFramebuffer(frame, has_external_stencil_test); } const QuadList& quad_list = render_pass->quad_list; diff --git a/cc/output/direct_renderer.h b/cc/output/direct_renderer.h index efa34cf..e5ee83c 100644 --- a/cc/output/direct_renderer.h +++ b/cc/output/direct_renderer.h @@ -118,7 +118,10 @@ class CC_EXPORT DirectRenderer : public Renderer { gfx::Rect target_rect) = 0; virtual void SetDrawViewport(gfx::Rect window_space_viewport) = 0; virtual void SetScissorTestRect(gfx::Rect scissor_rect) = 0; - virtual void ClearFramebuffer(DrawingFrame* frame) = 0; + virtual void DiscardPixels(bool has_external_stencil_test, + bool draw_rect_covers_full_surface) = 0; + virtual void ClearFramebuffer(DrawingFrame* frame, + bool has_external_stencil_test) = 0; virtual void DoDrawQuad(DrawingFrame* frame, const DrawQuad* quad) = 0; virtual void BeginDrawingFrame(DrawingFrame* frame) = 0; virtual void FinishDrawingFrame(DrawingFrame* frame) = 0; diff --git a/cc/output/gl_renderer.cc b/cc/output/gl_renderer.cc index f365e36..f4b1e57 100644 --- a/cc/output/gl_renderer.cc +++ b/cc/output/gl_renderer.cc @@ -290,25 +290,29 @@ void GLRenderer::ViewportChanged() { ReinitializeGrCanvas(); } -void GLRenderer::ClearFramebuffer(DrawingFrame* frame) { +void GLRenderer::DiscardPixels(bool has_external_stencil_test, + bool draw_rect_covers_full_surface) { + if (has_external_stencil_test || !draw_rect_covers_full_surface || + !capabilities_.using_discard_framebuffer) + return; + bool using_default_framebuffer = + !current_framebuffer_lock_ && + output_surface_->capabilities().uses_default_gl_framebuffer; + GLenum attachments[] = {static_cast<GLenum>( + using_default_framebuffer ? GL_COLOR_EXT : GL_COLOR_ATTACHMENT0_EXT)}; + context_->discardFramebufferEXT( + GL_FRAMEBUFFER, arraysize(attachments), attachments); +} + +void GLRenderer::ClearFramebuffer(DrawingFrame* frame, + bool has_external_stencil_test) { // It's unsafe to clear when we have a stencil test because glClear ignores // stencil. - if (output_surface_->HasExternalStencilTest() && - frame->current_render_pass == frame->root_render_pass) { + if (has_external_stencil_test) { DCHECK(!frame->current_render_pass->has_transparent_background); return; } - if (capabilities_.using_discard_framebuffer) { - bool using_default_framebuffer = - !current_framebuffer_lock_ && - output_surface_->capabilities().uses_default_gl_framebuffer; - GLenum attachments[] = {static_cast<GLenum>( - using_default_framebuffer ? GL_COLOR_EXT : GL_COLOR_ATTACHMENT0_EXT)}; - context_->discardFramebufferEXT( - GL_FRAMEBUFFER, arraysize(attachments), attachments); - } - // On DEBUG builds, opaque render passes are cleared to blue to easily see // regions that were not drawn on the screen. if (frame->current_render_pass->has_transparent_background) diff --git a/cc/output/gl_renderer.h b/cc/output/gl_renderer.h index 13f65f2..bc47870 100644 --- a/cc/output/gl_renderer.h +++ b/cc/output/gl_renderer.h @@ -117,7 +117,10 @@ class CC_EXPORT GLRenderer : public DirectRenderer { gfx::Rect target_rect) OVERRIDE; virtual void SetDrawViewport(gfx::Rect window_space_viewport) OVERRIDE; virtual void SetScissorTestRect(gfx::Rect scissor_rect) OVERRIDE; - virtual void ClearFramebuffer(DrawingFrame* frame) OVERRIDE; + virtual void DiscardPixels(bool has_external_stencil_test, + bool draw_rect_covers_full_surface) OVERRIDE; + virtual void ClearFramebuffer(DrawingFrame* frame, + bool has_external_stencil_test) OVERRIDE; virtual void DoDrawQuad(DrawingFrame* frame, const class DrawQuad*) OVERRIDE; virtual void BeginDrawingFrame(DrawingFrame* frame) OVERRIDE; virtual void FinishDrawingFrame(DrawingFrame* frame) OVERRIDE; diff --git a/cc/output/gl_renderer_unittest.cc b/cc/output/gl_renderer_unittest.cc index 18d77e4445..836287f 100644 --- a/cc/output/gl_renderer_unittest.cc +++ b/cc/output/gl_renderer_unittest.cc @@ -143,7 +143,8 @@ class FakeRendererClient : public RendererClient { : host_impl_(&proxy_), set_full_root_layer_damage_count_(0), root_layer_(LayerImpl::Create(host_impl_.active_tree(), 1)), - viewport_size_(gfx::Size(1, 1)) { + viewport_(gfx::Rect(0, 0, 1, 1)), + clip_(gfx::Rect(0, 0, 1, 1)) { root_layer_->CreateRenderSurface(); RenderPass::Id render_pass_id = root_layer_->render_surface()->RenderPassId(); @@ -154,11 +155,8 @@ class FakeRendererClient : public RendererClient { } // RendererClient methods. - virtual gfx::Rect DeviceViewport() const OVERRIDE { - static gfx::Size fake_size(1, 1); - return gfx::Rect(fake_size); - } - virtual gfx::Rect DeviceClip() const OVERRIDE { return DeviceViewport(); } + virtual gfx::Rect DeviceViewport() const OVERRIDE { return viewport_; } + virtual gfx::Rect DeviceClip() const OVERRIDE { return clip_; } virtual void SetFullRootLayerDamage() OVERRIDE { set_full_root_layer_damage_count_++; } @@ -170,7 +168,8 @@ class FakeRendererClient : public RendererClient { int set_full_root_layer_damage_count() const { return set_full_root_layer_damage_count_; } - void set_viewport(gfx::Size viewport_size) { viewport_size_ = viewport_size; } + void set_viewport(gfx::Rect viewport) { viewport_ = viewport; } + void set_clip(gfx::Rect clip) { clip_ = clip; } RenderPass* root_render_pass() { return render_passes_in_draw_order_.back(); } RenderPassList* render_passes_in_draw_order() { @@ -183,7 +182,8 @@ class FakeRendererClient : public RendererClient { int set_full_root_layer_damage_count_; scoped_ptr<LayerImpl> root_layer_; RenderPassList render_passes_in_draw_order_; - gfx::Size viewport_size_; + gfx::Rect viewport_; + gfx::Rect clip_; }; class FakeRendererGL : public GLRenderer { @@ -1137,22 +1137,184 @@ TEST(GLRendererTest2, ScissorTestWhenClearing) { renderer_client.render_passes_in_draw_order(), NULL, 1.f, true); } +class DiscardCheckingContext : public TestWebGraphicsContext3D { + public: + DiscardCheckingContext() : discarded_(0) { + set_have_post_sub_buffer(true); + set_have_discard_framebuffer(true); + } + + virtual void discardFramebufferEXT(WGC3Denum target, + WGC3Dsizei numAttachments, + const WGC3Denum* attachments) { + ++discarded_; + } + + int discarded() const { return discarded_; } + void reset() { discarded_ = 0; } + + private: + int discarded_; +}; + class NonReshapableOutputSurface : public FakeOutputSurface { public: explicit NonReshapableOutputSurface( scoped_ptr<TestWebGraphicsContext3D> context3d) - : FakeOutputSurface( - TestContextProvider::Create(context3d.Pass()), - false) {} - virtual gfx::Size SurfaceSize() const OVERRIDE { return gfx::Size(500, 500); } + : FakeOutputSurface(TestContextProvider::Create(context3d.Pass()), + false) { + surface_size_ = gfx::Size(500, 500); + } + virtual void Reshape(gfx::Size size, float scale_factor) OVERRIDE {} + void set_fixed_size(gfx::Size size) { surface_size_ = size; } }; -class OffsetViewportRendererClient : public FakeRendererClient { - public: - virtual gfx::Rect DeviceViewport() const OVERRIDE { - return gfx::Rect(10, 10, 100, 100); +TEST(GLRendererTest2, NoDiscardOnPartialUpdates) { + scoped_ptr<DiscardCheckingContext> context_owned(new DiscardCheckingContext); + DiscardCheckingContext* context = context_owned.get(); + + FakeOutputSurfaceClient output_surface_client; + scoped_ptr<NonReshapableOutputSurface> output_surface( + new NonReshapableOutputSurface( + context_owned.PassAs<TestWebGraphicsContext3D>())); + CHECK(output_surface->BindToClient(&output_surface_client)); + output_surface->set_fixed_size(gfx::Size(100, 100)); + + scoped_ptr<ResourceProvider> resource_provider( + ResourceProvider::Create(output_surface.get(), 0, false)); + + LayerTreeSettings settings; + settings.partial_swap_enabled = true; + FakeRendererClient renderer_client; + renderer_client.set_viewport(gfx::Rect(0, 0, 100, 100)); + renderer_client.set_clip(gfx::Rect(0, 0, 100, 100)); + FakeRendererGL renderer(&renderer_client, + &settings, + output_surface.get(), + resource_provider.get()); + EXPECT_TRUE(renderer.Initialize()); + EXPECT_TRUE(renderer.Capabilities().using_partial_swap); + + gfx::Rect viewport_rect(renderer_client.DeviceViewport()); + ScopedPtrVector<RenderPass>& render_passes = + *renderer_client.render_passes_in_draw_order(); + render_passes.clear(); + + { + // Partial frame, should not discard. + RenderPass::Id root_pass_id(1, 0); + TestRenderPass* root_pass = AddRenderPass( + &render_passes, root_pass_id, viewport_rect, gfx::Transform()); + AddQuad(root_pass, viewport_rect, SK_ColorGREEN); + root_pass->damage_rect = gfx::RectF(2.f, 2.f, 3.f, 3.f); + + renderer.DecideRenderPassAllocationsForFrame( + *renderer_client.render_passes_in_draw_order()); + renderer.DrawFrame( + renderer_client.render_passes_in_draw_order(), NULL, 1.f, true); + EXPECT_EQ(0, context->discarded()); + context->reset(); } -}; + { + // Full frame, should discard. + RenderPass::Id root_pass_id(1, 0); + TestRenderPass* root_pass = AddRenderPass( + &render_passes, root_pass_id, viewport_rect, gfx::Transform()); + AddQuad(root_pass, viewport_rect, SK_ColorGREEN); + root_pass->damage_rect = gfx::RectF(root_pass->output_rect); + + renderer.DecideRenderPassAllocationsForFrame( + *renderer_client.render_passes_in_draw_order()); + renderer.DrawFrame( + renderer_client.render_passes_in_draw_order(), NULL, 1.f, true); + EXPECT_EQ(1, context->discarded()); + context->reset(); + } + { + // Partial frame, disallow partial swap, should discard. + RenderPass::Id root_pass_id(1, 0); + TestRenderPass* root_pass = AddRenderPass( + &render_passes, root_pass_id, viewport_rect, gfx::Transform()); + AddQuad(root_pass, viewport_rect, SK_ColorGREEN); + root_pass->damage_rect = gfx::RectF(2.f, 2.f, 3.f, 3.f); + + renderer.DecideRenderPassAllocationsForFrame( + *renderer_client.render_passes_in_draw_order()); + renderer.DrawFrame( + renderer_client.render_passes_in_draw_order(), NULL, 1.f, false); + EXPECT_EQ(1, context->discarded()); + context->reset(); + } + { + // Full frame, external scissor is set, should not discard. + output_surface->set_has_external_stencil_test(true); + RenderPass::Id root_pass_id(1, 0); + TestRenderPass* root_pass = AddRenderPass( + &render_passes, root_pass_id, viewport_rect, gfx::Transform()); + AddQuad(root_pass, viewport_rect, SK_ColorGREEN); + root_pass->damage_rect = gfx::RectF(root_pass->output_rect); + root_pass->has_transparent_background = false; + + renderer.DecideRenderPassAllocationsForFrame( + *renderer_client.render_passes_in_draw_order()); + renderer.DrawFrame( + renderer_client.render_passes_in_draw_order(), NULL, 1.f, true); + EXPECT_EQ(0, context->discarded()); + context->reset(); + output_surface->set_has_external_stencil_test(false); + } + { + // Full frame, clipped, should not discard. + renderer_client.set_clip(gfx::Rect(10, 10, 10, 10)); + RenderPass::Id root_pass_id(1, 0); + TestRenderPass* root_pass = AddRenderPass( + &render_passes, root_pass_id, viewport_rect, gfx::Transform()); + AddQuad(root_pass, viewport_rect, SK_ColorGREEN); + root_pass->damage_rect = gfx::RectF(root_pass->output_rect); + + renderer.DecideRenderPassAllocationsForFrame( + *renderer_client.render_passes_in_draw_order()); + renderer.DrawFrame( + renderer_client.render_passes_in_draw_order(), NULL, 1.f, true); + EXPECT_EQ(0, context->discarded()); + context->reset(); + } + { + // Full frame, doesn't cover the surface, should not discard. + renderer_client.set_viewport(gfx::Rect(10, 10, 10, 10)); + viewport_rect = renderer_client.DeviceViewport(); + RenderPass::Id root_pass_id(1, 0); + TestRenderPass* root_pass = AddRenderPass( + &render_passes, root_pass_id, viewport_rect, gfx::Transform()); + AddQuad(root_pass, viewport_rect, SK_ColorGREEN); + root_pass->damage_rect = gfx::RectF(root_pass->output_rect); + + renderer.DecideRenderPassAllocationsForFrame( + *renderer_client.render_passes_in_draw_order()); + renderer.DrawFrame( + renderer_client.render_passes_in_draw_order(), NULL, 1.f, true); + EXPECT_EQ(0, context->discarded()); + context->reset(); + } + { + // Full frame, doesn't cover the surface (no offset), should not discard. + renderer_client.set_viewport(gfx::Rect(0, 0, 50, 50)); + renderer_client.set_clip(gfx::Rect(0, 0, 100, 100)); + viewport_rect = renderer_client.DeviceViewport(); + RenderPass::Id root_pass_id(1, 0); + TestRenderPass* root_pass = AddRenderPass( + &render_passes, root_pass_id, viewport_rect, gfx::Transform()); + AddQuad(root_pass, viewport_rect, SK_ColorGREEN); + root_pass->damage_rect = gfx::RectF(root_pass->output_rect); + + renderer.DecideRenderPassAllocationsForFrame( + *renderer_client.render_passes_in_draw_order()); + renderer.DrawFrame( + renderer_client.render_passes_in_draw_order(), NULL, 1.f, true); + EXPECT_EQ(0, context->discarded()); + context->reset(); + } +} class FlippedScissorAndViewportContext : public TestWebGraphicsContext3D { public: @@ -1201,7 +1363,9 @@ TEST(GLRendererTest2, ScissorAndViewportWithinNonreshapableSurface) { ResourceProvider::Create(output_surface.get(), 0, false)); LayerTreeSettings settings; - OffsetViewportRendererClient renderer_client; + FakeRendererClient renderer_client; + renderer_client.set_viewport(gfx::Rect(10, 10, 100, 100)); + renderer_client.set_clip(gfx::Rect(10, 10, 100, 100)); FakeRendererGL renderer(&renderer_client, &settings, output_surface.get(), @@ -1606,7 +1770,7 @@ TEST_F(MockOutputSurfaceTest, DrawFrameAndResizeAndSwap) { EXPECT_CALL(output_surface_, SwapBuffers(_)).Times(1); renderer_->SwapBuffers(); - set_viewport(gfx::Size(2, 2)); + set_viewport(gfx::Rect(0, 0, 2, 2)); renderer_->ViewportChanged(); DrawFrame(2.f); @@ -1617,7 +1781,7 @@ TEST_F(MockOutputSurfaceTest, DrawFrameAndResizeAndSwap) { EXPECT_CALL(output_surface_, SwapBuffers(_)).Times(1); renderer_->SwapBuffers(); - set_viewport(gfx::Size(1, 1)); + set_viewport(gfx::Rect(0, 0, 1, 1)); renderer_->ViewportChanged(); DrawFrame(1.f); diff --git a/cc/output/software_renderer.cc b/cc/output/software_renderer.cc index 394d79a..fa8c178 100644 --- a/cc/output/software_renderer.cc +++ b/cc/output/software_renderer.cc @@ -182,7 +182,11 @@ void SoftwareRenderer::ClearCanvas(SkColor color) { current_canvas_->clear(color); } -void SoftwareRenderer::ClearFramebuffer(DrawingFrame* frame) { +void SoftwareRenderer::DiscardPixels(bool has_external_stencil_test, + bool draw_rect_covers_full_surface) {} + +void SoftwareRenderer::ClearFramebuffer(DrawingFrame* frame, + bool has_external_stencil_test) { if (frame->current_render_pass->has_transparent_background) { ClearCanvas(SkColorSetARGB(0, 0, 0, 0)); } else { diff --git a/cc/output/software_renderer.h b/cc/output/software_renderer.h index e534f80..5a8780e 100644 --- a/cc/output/software_renderer.h +++ b/cc/output/software_renderer.h @@ -57,7 +57,10 @@ class CC_EXPORT SoftwareRenderer : public DirectRenderer { gfx::Rect target_rect) OVERRIDE; virtual void SetDrawViewport(gfx::Rect window_space_viewport) OVERRIDE; virtual void SetScissorTestRect(gfx::Rect scissor_rect) OVERRIDE; - virtual void ClearFramebuffer(DrawingFrame* frame) OVERRIDE; + virtual void DiscardPixels(bool has_external_stencil_test, + bool draw_rect_covers_full_surface) OVERRIDE; + virtual void ClearFramebuffer(DrawingFrame* frame, + bool has_external_stencil_test) OVERRIDE; virtual void DoDrawQuad(DrawingFrame* frame, const DrawQuad* quad) OVERRIDE; virtual void BeginDrawingFrame(DrawingFrame* frame) OVERRIDE; virtual void FinishDrawingFrame(DrawingFrame* frame) OVERRIDE; |