summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorpiman@chromium.org <piman@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-09-20 07:15:33 +0000
committerpiman@chromium.org <piman@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-09-20 07:15:33 +0000
commit48c9fa72a0f011aece88b66d69e2fe93e05a2bda (patch)
tree3efbdfe1f1672442774b7840c76e1537fb7b7845
parent1b3fbdee193ecca5402f2232c01045440d5f50be (diff)
downloadchromium_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.h3
-rw-r--r--cc/output/direct_renderer.cc21
-rw-r--r--cc/output/direct_renderer.h5
-rw-r--r--cc/output/gl_renderer.cc30
-rw-r--r--cc/output/gl_renderer.h5
-rw-r--r--cc/output/gl_renderer_unittest.cc204
-rw-r--r--cc/output/software_renderer.cc6
-rw-r--r--cc/output/software_renderer.h5
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;