summaryrefslogtreecommitdiff
path: root/cc
diff options
context:
space:
mode:
authorBen Murdoch <benm@google.com>2013-07-31 11:42:55 +0100
committerBen Murdoch <benm@google.com>2013-07-31 11:42:55 +0100
commitfb250657ef40d7500f20882d5c9909c1013367d3 (patch)
treee7885d8f55b77d8ec4430fa4ec78add75c7270d8 /cc
parent8b098b9dd9d1242c3db3032622b35d8469d47ac4 (diff)
downloadchromium_org-fb250657ef40d7500f20882d5c9909c1013367d3.tar.gz
Merge from Chromium at DEPS revision r214456
This commit was generated by merge_to_master.py. Change-Id: If3f38c7966c2034e96c669968f72ea1e57f41964
Diffstat (limited to 'cc')
-rw-r--r--cc/layers/layer_impl.cc3
-rw-r--r--cc/output/context_provider.h9
-rw-r--r--cc/output/gl_renderer.cc36
-rw-r--r--cc/output/gl_renderer.h8
-rw-r--r--cc/output/gl_renderer_unittest.cc32
-rw-r--r--cc/output/output_surface.cc4
-rw-r--r--cc/output/output_surface.h3
-rw-r--r--cc/output/output_surface_client.h1
-rw-r--r--cc/output/renderer.h1
-rw-r--r--cc/output/renderer_pixeltest.cc129
-rw-r--r--cc/output/software_renderer.cc1
-rw-r--r--cc/output/software_renderer_unittest.cc1
-rw-r--r--cc/test/fake_context_provider.cc42
-rw-r--r--cc/test/fake_context_provider.h19
-rw-r--r--cc/test/fake_output_surface.h7
-rw-r--r--cc/test/fake_output_surface_client.h1
-rw-r--r--cc/test/pixel_test.cc13
-rw-r--r--cc/test/pixel_test.h1
-rw-r--r--cc/trees/layer_tree_host_impl.cc43
-rw-r--r--cc/trees/layer_tree_host_impl.h5
-rw-r--r--cc/trees/layer_tree_host_impl_unittest.cc328
-rw-r--r--cc/trees/layer_tree_impl.cc10
22 files changed, 552 insertions, 145 deletions
diff --git a/cc/layers/layer_impl.cc b/cc/layers/layer_impl.cc
index 008c68969b..f99c36786d 100644
--- a/cc/layers/layer_impl.cc
+++ b/cc/layers/layer_impl.cc
@@ -108,10 +108,11 @@ void LayerImpl::PassCopyRequests(ScopedPtrVector<CopyOutputRequest>* requests) {
if (requests->empty())
return;
+ bool was_empty = copy_requests_.empty();
copy_requests_.insert_and_take(copy_requests_.end(), *requests);
requests->clear();
- if (layer_tree_impl()->IsActiveTree())
+ if (was_empty && layer_tree_impl()->IsActiveTree())
layer_tree_impl()->AddLayerWithCopyOutputRequest(this);
NoteLayerPropertyChangedForSubtree();
}
diff --git a/cc/output/context_provider.h b/cc/output/context_provider.h
index 3b489c7104..13b7df5948 100644
--- a/cc/output/context_provider.h
+++ b/cc/output/context_provider.h
@@ -5,6 +5,7 @@
#ifndef CC_OUTPUT_CONTEXT_PROVIDER_H_
#define CC_OUTPUT_CONTEXT_PROVIDER_H_
+#include "base/callback.h"
#include "base/memory/ref_counted.h"
class GrContext;
@@ -32,6 +33,14 @@ class ContextProvider : public base::RefCountedThreadSafe<ContextProvider> {
// the context inside the provider is no longer valid.
virtual bool DestroyedOnMainThread() = 0;
+ // Sets a callback to be called when the context is lost. This should be
+ // called from the same thread that the context is bound to. To avoid races,
+ // it should be called before BindToCurrentThread(), or VerifyContexts()
+ // should be called after setting the callback.
+ typedef base::Closure LostContextCallback;
+ virtual void SetLostContextCallback(
+ const LostContextCallback& lost_context_callback) = 0;
+
protected:
friend class base::RefCountedThreadSafe<ContextProvider>;
virtual ~ContextProvider() {}
diff --git a/cc/output/gl_renderer.cc b/cc/output/gl_renderer.cc
index 60a0b92431..a6d61f6cfd 100644
--- a/cc/output/gl_renderer.cc
+++ b/cc/output/gl_renderer.cc
@@ -157,6 +157,8 @@ GLRenderer::GLRenderer(RendererClient* client,
is_using_bind_uniform_(false),
visible_(true),
is_scissor_enabled_(false),
+ stencil_shadow_(false),
+ blend_shadow_(false),
highp_threshold_min_(highp_threshold_min),
highp_threshold_cache_(0),
offscreen_context_labelled_(false),
@@ -295,6 +297,14 @@ void GLRenderer::ViewportChanged() {
}
void GLRenderer::ClearFramebuffer(DrawingFrame* frame) {
+ // It's unsafe to clear when we have a stencil test because glClear ignores
+ // stencil.
+ if (client_->ExternalStencilTestEnabled() &&
+ frame->current_render_pass == frame->root_render_pass) {
+ DCHECK(!frame->current_render_pass->has_transparent_background);
+ return;
+ }
+
// 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)
@@ -310,8 +320,10 @@ void GLRenderer::ClearFramebuffer(DrawingFrame* frame) {
GLbitfield clear_bits = GL_COLOR_BUFFER_BIT;
// Only the Skia GPU backend uses the stencil buffer. No need to clear it
// otherwise.
- if (CanUseSkiaGPUBackend())
+ if (always_clear || CanUseSkiaGPUBackend()) {
+ GLC(context_, context_->clearStencil(0));
clear_bits |= GL_STENCIL_BUFFER_BIT;
+ }
context_->clear(clear_bits);
}
}
@@ -1973,6 +1985,17 @@ void GLRenderer::SetShaderOpacity(float opacity, int alpha_location) {
GLC(context_, context_->uniform1f(alpha_location, opacity));
}
+void GLRenderer::SetStencilEnabled(bool enabled) {
+ if (enabled == stencil_shadow_)
+ return;
+
+ if (enabled)
+ GLC(context_, context_->enable(GL_STENCIL_TEST));
+ else
+ GLC(context_, context_->disable(GL_STENCIL_TEST));
+ stencil_shadow_ = enabled;
+}
+
void GLRenderer::SetBlendEnabled(bool enabled) {
if (enabled == blend_shadow_)
return;
@@ -2470,6 +2493,13 @@ bool GLRenderer::UseScopedTexture(DrawingFrame* frame,
void GLRenderer::BindFramebufferToOutputSurface(DrawingFrame* frame) {
current_framebuffer_lock_.reset();
output_surface_->BindFramebuffer();
+
+ if (client_->ExternalStencilTestEnabled()) {
+ SetStencilEnabled(true);
+ GLC(context_, context_->stencilFunc(GL_EQUAL, 1, 1));
+ } else {
+ SetStencilEnabled(false);
+ }
}
bool GLRenderer::BindFramebufferToTexture(DrawingFrame* frame,
@@ -2479,6 +2509,7 @@ bool GLRenderer::BindFramebufferToTexture(DrawingFrame* frame,
current_framebuffer_lock_.reset();
+ SetStencilEnabled(false);
GLC(context_,
context_->bindFramebuffer(GL_FRAMEBUFFER, offscreen_framebuffer_id_));
current_framebuffer_lock_ =
@@ -3079,10 +3110,11 @@ void GLRenderer::ReinitializeGLState() {
// Bind the common vertex attributes used for drawing all the layers.
shared_geometry_->PrepareForDraw();
- GLC(context_, context_->disable(GL_STENCIL_TEST));
GLC(context_, context_->disable(GL_DEPTH_TEST));
GLC(context_, context_->disable(GL_CULL_FACE));
GLC(context_, context_->colorMask(true, true, true, true));
+ GLC(context_, context_->disable(GL_STENCIL_TEST));
+ stencil_shadow_ = false;
GLC(context_, context_->enable(GL_BLEND));
blend_shadow_ = true;
GLC(context_, context_->blendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA));
diff --git a/cc/output/gl_renderer.h b/cc/output/gl_renderer.h
index 3e06537239..b1a3643b2b 100644
--- a/cc/output/gl_renderer.h
+++ b/cc/output/gl_renderer.h
@@ -101,6 +101,11 @@ class CC_EXPORT GLRenderer : public DirectRenderer {
gfx::Rect device_rect);
void ReleaseRenderPassTextures();
+ void SetStencilEnabled(bool enabled);
+ bool stencil_enabled() const { return stencil_shadow_; }
+ void SetBlendEnabled(bool enabled);
+ bool blend_enabled() const { return blend_shadow_; }
+
virtual void BindFramebufferToOutputSurface(DrawingFrame* frame) OVERRIDE;
virtual bool BindFramebufferToTexture(DrawingFrame* frame,
const ScopedResource* resource,
@@ -161,8 +166,6 @@ class CC_EXPORT GLRenderer : public DirectRenderer {
const gfx::Transform& draw_transform,
const gfx::RectF& quad_rect,
int matrix_location);
- void SetBlendEnabled(bool enabled);
- bool blend_enabled() const { return blend_shadow_; }
void SetUseProgram(unsigned program);
void CopyTextureToFramebuffer(const DrawingFrame* frame,
@@ -438,6 +441,7 @@ class CC_EXPORT GLRenderer : public DirectRenderer {
bool is_using_bind_uniform_;
bool visible_;
bool is_scissor_enabled_;
+ bool stencil_shadow_;
bool blend_shadow_;
unsigned program_shadow_;
TexturedQuadDrawCache draw_cache_;
diff --git a/cc/output/gl_renderer_unittest.cc b/cc/output/gl_renderer_unittest.cc
index dd4e5f33c7..e4213d6584 100644
--- a/cc/output/gl_renderer_unittest.cc
+++ b/cc/output/gl_renderer_unittest.cc
@@ -144,7 +144,8 @@ class FakeRendererClient : public RendererClient {
set_full_root_layer_damage_count_(0),
root_layer_(LayerImpl::Create(host_impl_.active_tree(), 1)),
viewport_size_(gfx::Size(1, 1)),
- scale_factor_(1.f) {
+ scale_factor_(1.f),
+ external_stencil_test_enabled_(false) {
root_layer_->CreateRenderSurface();
RenderPass::Id render_pass_id =
root_layer_->render_surface()->RenderPassId();
@@ -177,6 +178,13 @@ class FakeRendererClient : public RendererClient {
virtual bool AllowPartialSwap() const OVERRIDE {
return true;
}
+ virtual bool ExternalStencilTestEnabled() const OVERRIDE {
+ return external_stencil_test_enabled_;
+ }
+
+ void EnableExternalStencilTest() {
+ external_stencil_test_enabled_ = true;
+ }
// Methods added for test.
int set_full_root_layer_damage_count() const {
@@ -201,6 +209,7 @@ class FakeRendererClient : public RendererClient {
RenderPassList render_passes_in_draw_order_;
gfx::Size viewport_size_;
float scale_factor_;
+ bool external_stencil_test_enabled_;
};
class FakeRendererGL : public GLRenderer {
@@ -218,6 +227,7 @@ class FakeRendererGL : public GLRenderer {
using GLRenderer::DoDrawQuad;
using GLRenderer::BeginDrawingFrame;
using GLRenderer::FinishDrawingQuadList;
+ using GLRenderer::stencil_enabled;
};
class GLRendererTest : public testing::Test {
@@ -465,6 +475,16 @@ TEST_F(GLRendererTest, FramebufferDiscardedAfterReadbackWhenNotVisible) {
EXPECT_EQ(2, mock_client_.set_full_root_layer_damage_count());
}
+TEST_F(GLRendererTest, ExternalStencil) {
+ EXPECT_FALSE(renderer_.stencil_enabled());
+
+ mock_client_.EnableExternalStencilTest();
+ mock_client_.root_render_pass()->has_transparent_background = false;
+
+ renderer_.DrawFrame(mock_client_.render_passes_in_draw_order());
+ EXPECT_TRUE(renderer_.stencil_enabled());
+}
+
class ForbidSynchronousCallContext : public TestWebGraphicsContext3D {
public:
ForbidSynchronousCallContext() {}
@@ -948,14 +968,20 @@ TEST(GLRendererTest2, ShouldClearRootRenderPass) {
AddRenderPassQuad(root_pass, child_pass);
+#ifdef NDEBUG
+ GLint clear_bits = GL_COLOR_BUFFER_BIT;
+#else
+ GLint clear_bits = GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT;
+#endif
+
// First render pass is not the root one, clearing should happen.
- EXPECT_CALL(*mock_context, clear(GL_COLOR_BUFFER_BIT)).Times(AtLeast(1));
+ EXPECT_CALL(*mock_context, clear(clear_bits)).Times(AtLeast(1));
Expectation first_render_pass =
EXPECT_CALL(*mock_context, drawElements(_, _, _, _)).Times(1);
// The second render pass is the root one, clearing should be prevented.
- EXPECT_CALL(*mock_context, clear(GL_COLOR_BUFFER_BIT)).Times(0)
+ EXPECT_CALL(*mock_context, clear(clear_bits)).Times(0)
.After(first_render_pass);
EXPECT_CALL(*mock_context, drawElements(_, _, _, _)).Times(AnyNumber())
diff --git a/cc/output/output_surface.cc b/cc/output/output_surface.cc
index 201f67cb63..ce2e477013 100644
--- a/cc/output/output_surface.cc
+++ b/cc/output/output_surface.cc
@@ -273,6 +273,10 @@ void OutputSurface::DidLoseOutputSurface() {
client_->DidLoseOutputSurface();
}
+void OutputSurface::SetExternalStencilTest(bool enabled) {
+ client_->SetExternalStencilTest(enabled);
+}
+
void OutputSurface::SetExternalDrawConstraints(const gfx::Transform& transform,
gfx::Rect viewport) {
client_->SetExternalDrawConstraints(transform, viewport);
diff --git a/cc/output/output_surface.h b/cc/output/output_surface.h
index 4489c10774..86d4dc81dd 100644
--- a/cc/output/output_surface.h
+++ b/cc/output/output_surface.h
@@ -60,10 +60,12 @@ class CC_EXPORT OutputSurface : public FrameRateControllerClient {
: delegated_rendering(false),
max_frames_pending(0),
deferred_gl_initialization(false),
+ draw_and_swap_full_viewport_every_frame(false),
adjust_deadline_for_parent(true) {}
bool delegated_rendering;
int max_frames_pending;
bool deferred_gl_initialization;
+ bool draw_and_swap_full_viewport_every_frame;
// This doesn't handle the <webview> case, but once BeginFrame is
// supported natively, we shouldn't need adjust_deadline_for_parent.
bool adjust_deadline_for_parent;
@@ -167,6 +169,7 @@ class CC_EXPORT OutputSurface : public FrameRateControllerClient {
void DidSwapBuffers();
void OnSwapBuffersComplete(const CompositorFrameAck* ack);
void DidLoseOutputSurface();
+ void SetExternalStencilTest(bool enabled);
void SetExternalDrawConstraints(const gfx::Transform& transform,
gfx::Rect viewport);
diff --git a/cc/output/output_surface_client.h b/cc/output/output_surface_client.h
index e6f296b3df..b4e2820a01 100644
--- a/cc/output/output_surface_client.h
+++ b/cc/output/output_surface_client.h
@@ -34,6 +34,7 @@ class CC_EXPORT OutputSurfaceClient {
virtual void BeginFrame(const BeginFrameArgs& args) = 0;
virtual void OnSwapBuffersComplete(const CompositorFrameAck* ack) = 0;
virtual void DidLoseOutputSurface() = 0;
+ virtual void SetExternalStencilTest(bool enabled) = 0;
virtual void SetExternalDrawConstraints(const gfx::Transform& transform,
gfx::Rect viewport) = 0;
virtual void SetMemoryPolicy(const ManagedMemoryPolicy& policy,
diff --git a/cc/output/renderer.h b/cc/output/renderer.h
index 3a628ad1a5..a9a800b6a0 100644
--- a/cc/output/renderer.h
+++ b/cc/output/renderer.h
@@ -30,6 +30,7 @@ class CC_EXPORT RendererClient {
virtual bool ShouldClearRootRenderPass() const = 0;
virtual CompositorFrameMetadata MakeCompositorFrameMetadata() const = 0;
virtual bool AllowPartialSwap() const = 0;
+ virtual bool ExternalStencilTestEnabled() const = 0;
protected:
virtual ~RendererClient() {}
diff --git a/cc/output/renderer_pixeltest.cc b/cc/output/renderer_pixeltest.cc
index ed1df7ad19..9508aa2916 100644
--- a/cc/output/renderer_pixeltest.cc
+++ b/cc/output/renderer_pixeltest.cc
@@ -1000,6 +1000,135 @@ TEST_F(GLRendererPixelTestWithBackgroundFilter, InvertFilter) {
ExactPixelComparator(true)));
}
+class ExternalStencilPixelTest : public GLRendererPixelTest {
+ protected:
+ void ClearBackgroundToGreen() {
+ WebKit::WebGraphicsContext3D* context3d = output_surface_->context3d();
+ output_surface_->EnsureBackbuffer();
+ output_surface_->Reshape(device_viewport_size_, 1);
+ context3d->clearColor(0.f, 1.f, 0.f, 1.f);
+ context3d->clear(GL_COLOR_BUFFER_BIT);
+ }
+
+ void PopulateStencilBuffer() {
+ // Set two quadrants of the stencil buffer to 1.
+ WebKit::WebGraphicsContext3D* context3d = output_surface_->context3d();
+ ASSERT_TRUE(context3d->getContextAttributes().stencil);
+ output_surface_->EnsureBackbuffer();
+ output_surface_->Reshape(device_viewport_size_, 1);
+ context3d->clearStencil(0);
+ context3d->clear(GL_STENCIL_BUFFER_BIT);
+ context3d->enable(GL_SCISSOR_TEST);
+ context3d->clearStencil(1);
+ context3d->scissor(0,
+ 0,
+ device_viewport_size_.width() / 2,
+ device_viewport_size_.height() / 2);
+ context3d->clear(GL_STENCIL_BUFFER_BIT);
+ context3d->scissor(device_viewport_size_.width() / 2,
+ device_viewport_size_.height() / 2,
+ device_viewport_size_.width(),
+ device_viewport_size_.height());
+ context3d->clear(GL_STENCIL_BUFFER_BIT);
+ }
+};
+
+TEST_F(ExternalStencilPixelTest, StencilTestEnabled) {
+ ClearBackgroundToGreen();
+ PopulateStencilBuffer();
+ this->EnableExternalStencilTest();
+
+ // Draw a blue quad that covers the entire device viewport. It should be
+ // clipped to the bottom left and top right corners by the external stencil.
+ gfx::Rect rect(this->device_viewport_size_);
+ RenderPass::Id id(1, 1);
+ scoped_ptr<RenderPass> pass = CreateTestRootRenderPass(id, rect);
+ scoped_ptr<SharedQuadState> blue_shared_state =
+ CreateTestSharedQuadState(gfx::Transform(), rect);
+ scoped_ptr<SolidColorDrawQuad> blue = SolidColorDrawQuad::Create();
+ blue->SetNew(blue_shared_state.get(), rect, SK_ColorBLUE, false);
+ pass->quad_list.push_back(blue.PassAs<DrawQuad>());
+ pass->has_transparent_background = false;
+ RenderPassList pass_list;
+ pass_list.push_back(pass.Pass());
+
+ EXPECT_TRUE(this->RunPixelTest(
+ &pass_list,
+ base::FilePath(FILE_PATH_LITERAL("four_blue_green_checkers.png")),
+ ExactPixelComparator(true)));
+}
+
+TEST_F(ExternalStencilPixelTest, StencilTestDisabled) {
+ PopulateStencilBuffer();
+
+ // Draw a green quad that covers the entire device viewport. The stencil
+ // buffer should be ignored.
+ gfx::Rect rect(this->device_viewport_size_);
+ RenderPass::Id id(1, 1);
+ scoped_ptr<RenderPass> pass = CreateTestRootRenderPass(id, rect);
+ scoped_ptr<SharedQuadState> green_shared_state =
+ CreateTestSharedQuadState(gfx::Transform(), rect);
+ scoped_ptr<SolidColorDrawQuad> green = SolidColorDrawQuad::Create();
+ green->SetNew(green_shared_state.get(), rect, SK_ColorGREEN, false);
+ pass->quad_list.push_back(green.PassAs<DrawQuad>());
+ RenderPassList pass_list;
+ pass_list.push_back(pass.Pass());
+
+ EXPECT_TRUE(this->RunPixelTest(
+ &pass_list,
+ base::FilePath(FILE_PATH_LITERAL("green.png")),
+ ExactPixelComparator(true)));
+}
+
+TEST_F(ExternalStencilPixelTest, RenderSurfacesIgnoreStencil) {
+ // The stencil test should apply only to the final render pass.
+ ClearBackgroundToGreen();
+ PopulateStencilBuffer();
+ this->EnableExternalStencilTest();
+
+ gfx::Rect viewport_rect(this->device_viewport_size_);
+
+ RenderPass::Id root_pass_id(1, 1);
+ scoped_ptr<RenderPass> root_pass =
+ CreateTestRootRenderPass(root_pass_id, viewport_rect);
+ root_pass->has_transparent_background = false;
+
+ RenderPass::Id child_pass_id(2, 2);
+ gfx::Rect pass_rect(this->device_viewport_size_);
+ gfx::Transform transform_to_root;
+ scoped_ptr<RenderPass> child_pass =
+ CreateTestRenderPass(child_pass_id, pass_rect, transform_to_root);
+
+ gfx::Transform content_to_target_transform;
+ scoped_ptr<SharedQuadState> shared_state =
+ CreateTestSharedQuadState(content_to_target_transform, viewport_rect);
+
+ scoped_ptr<SolidColorDrawQuad> blue = SolidColorDrawQuad::Create();
+ blue->SetNew(shared_state.get(),
+ gfx::Rect(0,
+ 0,
+ this->device_viewport_size_.width(),
+ this->device_viewport_size_.height()),
+ SK_ColorBLUE,
+ false);
+ child_pass->quad_list.push_back(blue.PassAs<DrawQuad>());
+
+ scoped_ptr<SharedQuadState> pass_shared_state =
+ CreateTestSharedQuadState(gfx::Transform(), pass_rect);
+ root_pass->quad_list.push_back(
+ CreateTestRenderPassDrawQuad(pass_shared_state.get(),
+ pass_rect,
+ child_pass_id));
+ RenderPassList pass_list;
+ pass_list.push_back(child_pass.Pass());
+ pass_list.push_back(root_pass.Pass());
+
+ EXPECT_TRUE(this->RunPixelTest(
+ &pass_list,
+ base::FilePath(FILE_PATH_LITERAL("four_blue_green_checkers.png")),
+ ExactPixelComparator(true)));
+}
+
// Software renderer does not support anti-aliased edges.
TEST_F(GLRendererPixelTest, AntiAliasing) {
gfx::Rect rect(this->device_viewport_size_);
diff --git a/cc/output/software_renderer.cc b/cc/output/software_renderer.cc
index 7eac62f64a..7735e3c8c1 100644
--- a/cc/output/software_renderer.cc
+++ b/cc/output/software_renderer.cc
@@ -134,6 +134,7 @@ void SoftwareRenderer::EnsureScissorTestDisabled() {
void SoftwareRenderer::Finish() {}
void SoftwareRenderer::BindFramebufferToOutputSurface(DrawingFrame* frame) {
+ DCHECK(!client_->ExternalStencilTestEnabled());
current_framebuffer_lock_.reset();
current_canvas_ = root_canvas_;
}
diff --git a/cc/output/software_renderer_unittest.cc b/cc/output/software_renderer_unittest.cc
index deaf2f992b..238d654ac1 100644
--- a/cc/output/software_renderer_unittest.cc
+++ b/cc/output/software_renderer_unittest.cc
@@ -72,6 +72,7 @@ class SoftwareRendererTest : public testing::Test, public RendererClient {
virtual bool AllowPartialSwap() const OVERRIDE {
return true;
}
+ virtual bool ExternalStencilTestEnabled() const OVERRIDE { return false; }
protected:
scoped_ptr<FakeOutputSurface> output_surface_;
diff --git a/cc/test/fake_context_provider.cc b/cc/test/fake_context_provider.cc
index e12f783174..d49fa8978e 100644
--- a/cc/test/fake_context_provider.cc
+++ b/cc/test/fake_context_provider.cc
@@ -9,29 +9,38 @@
namespace cc {
FakeContextProvider::FakeContextProvider()
- : destroyed_(false) {
+ : bound_(false),
+ destroyed_(false) {
+ DCHECK(main_thread_checker_.CalledOnValidThread());
+ context_thread_checker_.DetachFromThread();
}
-FakeContextProvider::FakeContextProvider(
- const CreateCallback& create_callback)
- : create_callback_(create_callback),
- bound_(false),
- destroyed_(false) {
+FakeContextProvider::~FakeContextProvider() {
+ DCHECK(main_thread_checker_.CalledOnValidThread() ||
+ context_thread_checker_.CalledOnValidThread());
}
-FakeContextProvider::~FakeContextProvider() {}
+bool FakeContextProvider::InitializeOnMainThread(
+ const CreateCallback& create_callback) {
+ DCHECK(main_thread_checker_.CalledOnValidThread());
-bool FakeContextProvider::InitializeOnMainThread() {
DCHECK(!context3d_);
-
- if (create_callback_.is_null())
+ if (create_callback.is_null())
context3d_ = TestWebGraphicsContext3D::Create().Pass();
else
- context3d_ = create_callback_.Run();
+ context3d_ = create_callback.Run();
return context3d_;
}
bool FakeContextProvider::BindToCurrentThread() {
+ DCHECK(context3d_);
+
+ // This is called on the thread the context will be used.
+ DCHECK(context_thread_checker_.CalledOnValidThread());
+
+ if (bound_)
+ return true;
+
bound_ = true;
if (!context3d_->makeContextCurrent()) {
base::AutoLock lock(destroyed_lock_);
@@ -44,12 +53,14 @@ bool FakeContextProvider::BindToCurrentThread() {
WebKit::WebGraphicsContext3D* FakeContextProvider::Context3d() {
DCHECK(context3d_);
DCHECK(bound_);
+ DCHECK(context_thread_checker_.CalledOnValidThread());
return context3d_.get();
}
class GrContext* FakeContextProvider::GrContext() {
DCHECK(context3d_);
DCHECK(bound_);
+ DCHECK(context_thread_checker_.CalledOnValidThread());
// TODO(danakj): Make a fake GrContext.
return NULL;
@@ -58,6 +69,7 @@ class GrContext* FakeContextProvider::GrContext() {
void FakeContextProvider::VerifyContexts() {
DCHECK(context3d_);
DCHECK(bound_);
+ DCHECK(context_thread_checker_.CalledOnValidThread());
if (context3d_->isContextLost()) {
base::AutoLock lock(destroyed_lock_);
@@ -66,8 +78,16 @@ void FakeContextProvider::VerifyContexts() {
}
bool FakeContextProvider::DestroyedOnMainThread() {
+ DCHECK(main_thread_checker_.CalledOnValidThread());
+
base::AutoLock lock(destroyed_lock_);
return destroyed_;
}
+void FakeContextProvider::SetLostContextCallback(
+ const LostContextCallback& cb) {
+ DCHECK(context_thread_checker_.CalledOnValidThread());
+ NOTIMPLEMENTED();
+}
+
} // namespace cc
diff --git a/cc/test/fake_context_provider.h b/cc/test/fake_context_provider.h
index 9ab1abd3d3..4a18e4a8b0 100644
--- a/cc/test/fake_context_provider.h
+++ b/cc/test/fake_context_provider.h
@@ -8,6 +8,7 @@
#include "base/callback.h"
#include "base/memory/scoped_ptr.h"
#include "base/synchronization/lock.h"
+#include "base/threading/thread_checker.h"
#include "cc/output/context_provider.h"
namespace cc {
@@ -19,17 +20,13 @@ class FakeContextProvider : public cc::ContextProvider {
CreateCallback;
static scoped_refptr<FakeContextProvider> Create() {
- scoped_refptr<FakeContextProvider> provider = new FakeContextProvider();
- if (!provider->InitializeOnMainThread())
- return NULL;
- return provider;
+ return Create(CreateCallback());
}
static scoped_refptr<FakeContextProvider> Create(
const CreateCallback& create_callback) {
- scoped_refptr<FakeContextProvider> provider =
- new FakeContextProvider(create_callback);
- if (!provider->InitializeOnMainThread())
+ scoped_refptr<FakeContextProvider> provider = new FakeContextProvider;
+ if (!provider->InitializeOnMainThread(create_callback))
return NULL;
return provider;
}
@@ -39,18 +36,20 @@ class FakeContextProvider : public cc::ContextProvider {
virtual class GrContext* GrContext() OVERRIDE;
virtual void VerifyContexts() OVERRIDE;
virtual bool DestroyedOnMainThread() OVERRIDE;
+ virtual void SetLostContextCallback(const LostContextCallback& cb) OVERRIDE;
protected:
FakeContextProvider();
- explicit FakeContextProvider(const CreateCallback& create_callback);
virtual ~FakeContextProvider();
- bool InitializeOnMainThread();
+ bool InitializeOnMainThread(const CreateCallback& create_callback);
- CreateCallback create_callback_;
scoped_ptr<WebKit::WebGraphicsContext3D> context3d_;
bool bound_;
+ base::ThreadChecker main_thread_checker_;
+ base::ThreadChecker context_thread_checker_;
+
base::Lock destroyed_lock_;
bool destroyed_;
};
diff --git a/cc/test/fake_output_surface.h b/cc/test/fake_output_surface.h
index 18759ecb28..dfd4db5344 100644
--- a/cc/test/fake_output_surface.h
+++ b/cc/test/fake_output_surface.h
@@ -56,6 +56,7 @@ class FakeOutputSurface : public OutputSurface {
new FakeOutputSurface(software_device.Pass(), true));
}
+ // TODO(boliu): Use a general factory that takes Capabilities arg.
static scoped_ptr<FakeOutputSurface> CreateDeferredGL(
scoped_ptr<SoftwareOutputDevice> software_device) {
scoped_ptr<FakeOutputSurface> result(
@@ -64,6 +65,12 @@ class FakeOutputSurface : public OutputSurface {
return result.Pass();
}
+ static scoped_ptr<FakeOutputSurface> CreateAlwaysDrawAndSwap3d() {
+ scoped_ptr<FakeOutputSurface> result(Create3d());
+ result->capabilities_.draw_and_swap_full_viewport_every_frame = true;
+ return result.Pass();
+ }
+
CompositorFrame& last_sent_frame() { return last_sent_frame_; }
size_t num_sent_frames() { return num_sent_frames_; }
diff --git a/cc/test/fake_output_surface_client.h b/cc/test/fake_output_surface_client.h
index 830dcada9f..c8169d2c86 100644
--- a/cc/test/fake_output_surface_client.h
+++ b/cc/test/fake_output_surface_client.h
@@ -29,6 +29,7 @@ class FakeOutputSurfaceClient : public OutputSurfaceClient {
virtual void DidLoseOutputSurface() OVERRIDE;
virtual void SetExternalDrawConstraints(const gfx::Transform& transform,
gfx::Rect viewport) OVERRIDE {}
+ virtual void SetExternalStencilTest(bool enable) OVERRIDE {}
virtual void SetMemoryPolicy(
const ManagedMemoryPolicy& policy,
bool discard_backbuffer_when_not_visible) OVERRIDE;
diff --git a/cc/test/pixel_test.cc b/cc/test/pixel_test.cc
index 23a1a4fed8..5ec7a5c141 100644
--- a/cc/test/pixel_test.cc
+++ b/cc/test/pixel_test.cc
@@ -28,7 +28,7 @@ class PixelTest::PixelTestRendererClient
: public RendererClient, public OutputSurfaceClient {
public:
explicit PixelTestRendererClient(gfx::Rect device_viewport)
- : device_viewport_(device_viewport) {}
+ : device_viewport_(device_viewport), stencil_enabled_(false) {}
// RendererClient implementation.
virtual gfx::Rect DeviceViewport() const OVERRIDE {
@@ -50,6 +50,9 @@ class PixelTest::PixelTestRendererClient
virtual bool AllowPartialSwap() const OVERRIDE {
return true;
}
+ virtual bool ExternalStencilTestEnabled() const OVERRIDE {
+ return stencil_enabled_;
+ }
// OutputSurfaceClient implementation.
virtual bool DeferredInitialize(
@@ -65,12 +68,16 @@ class PixelTest::PixelTestRendererClient
gfx::Rect viewport) OVERRIDE {
device_viewport_ = viewport;
}
+ virtual void SetExternalStencilTest(bool enable) OVERRIDE {
+ stencil_enabled_ = enable;
+ }
virtual void SetMemoryPolicy(
const ManagedMemoryPolicy& policy, bool discard) OVERRIDE {}
virtual void SetTreeActivationCallback(const base::Closure&) OVERRIDE {}
private:
gfx::Rect device_viewport_;
+ bool stencil_enabled_;
LayerTreeSettings settings_;
};
@@ -175,6 +182,10 @@ void PixelTest::ForceExpandedViewport(gfx::Size surface_expansion,
}
}
+void PixelTest::EnableExternalStencilTest() {
+ fake_client_->SetExternalStencilTest(true);
+}
+
void PixelTest::SetUpSoftwareRenderer() {
CHECK(fake_client_);
diff --git a/cc/test/pixel_test.h b/cc/test/pixel_test.h
index 3c607ae2cc..1dd3e1a334 100644
--- a/cc/test/pixel_test.h
+++ b/cc/test/pixel_test.h
@@ -47,6 +47,7 @@ class PixelTest : public testing::Test {
void ForceExpandedViewport(gfx::Size surface_expansion,
gfx::Vector2d viewport_offset);
+ void EnableExternalStencilTest();
private:
void ReadbackResult(base::Closure quit_run_loop,
diff --git a/cc/trees/layer_tree_host_impl.cc b/cc/trees/layer_tree_host_impl.cc
index f97eea0f51..b263f2f417 100644
--- a/cc/trees/layer_tree_host_impl.cc
+++ b/cc/trees/layer_tree_host_impl.cc
@@ -194,6 +194,7 @@ LayerTreeHostImpl::LayerTreeHostImpl(
zero_budget_(false),
device_scale_factor_(1.f),
overdraw_bottom_height_(0.f),
+ external_stencil_test_enabled_(false),
animation_registrar_(AnimationRegistrar::Create()),
rendering_stats_instrumentation_(rendering_stats_instrumentation),
need_to_update_visible_tiles_before_draw_(false) {
@@ -257,17 +258,32 @@ void LayerTreeHostImpl::CommitComplete() {
client_->SendManagedMemoryStats();
}
-bool LayerTreeHostImpl::CanDraw() {
+bool LayerTreeHostImpl::CanDraw() const {
// Note: If you are changing this function or any other function that might
// affect the result of CanDraw, make sure to call
// client_->OnCanDrawStateChanged in the proper places and update the
// NotifyIfCanDrawChanged test.
+ if (!renderer_) {
+ TRACE_EVENT_INSTANT0("cc", "LayerTreeHostImpl::CanDraw no renderer",
+ TRACE_EVENT_SCOPE_THREAD);
+ return false;
+ }
+
+ // Must have an OutputSurface if |renderer_| is not NULL.
+ DCHECK(output_surface_);
+
+ // TODO(boliu): Make draws without root_layer work and move this below
+ // draw_and_swap_full_viewport_every_frame check. Tracked in crbug.com/264967.
if (!active_tree_->root_layer()) {
TRACE_EVENT_INSTANT0("cc", "LayerTreeHostImpl::CanDraw no root layer",
TRACE_EVENT_SCOPE_THREAD);
return false;
}
+
+ if (output_surface_->capabilities().draw_and_swap_full_viewport_every_frame)
+ return true;
+
if (device_viewport_size_.IsEmpty()) {
TRACE_EVENT_INSTANT0("cc", "LayerTreeHostImpl::CanDraw empty viewport",
TRACE_EVENT_SCOPE_THREAD);
@@ -279,11 +295,6 @@ bool LayerTreeHostImpl::CanDraw() {
TRACE_EVENT_SCOPE_THREAD);
return false;
}
- if (!renderer_) {
- TRACE_EVENT_INSTANT0("cc", "LayerTreeHostImpl::CanDraw no renderer",
- TRACE_EVENT_SCOPE_THREAD);
- return false;
- }
if (active_tree_->ContentsTexturesPurged()) {
TRACE_EVENT_INSTANT0(
"cc", "LayerTreeHostImpl::CanDraw contents textures purged",
@@ -568,6 +579,8 @@ bool LayerTreeHostImpl::CalculateRenderPasses(FrameData* frame) {
// A copy request should cause damage, so we should not have any copy
// requests in this case.
DCHECK_EQ(0u, active_tree_->LayersWithCopyOutputRequest().size());
+ DCHECK(!output_surface_->capabilities()
+ .draw_and_swap_full_viewport_every_frame);
return true;
}
@@ -730,7 +743,8 @@ bool LayerTreeHostImpl::CalculateRenderPasses(FrameData* frame) {
occlusion_tracker.LeaveLayer(it);
}
- if (have_copy_request)
+ if (have_copy_request ||
+ output_surface_->capabilities().draw_and_swap_full_viewport_every_frame)
draw_frame = true;
rendering_stats_instrumentation_->AddLayersDrawn(layers_drawn);
@@ -972,8 +986,11 @@ bool LayerTreeHostImpl::PrepareToDraw(FrameData* frame,
AddDamageNextUpdate(device_viewport_damage_rect);
}
- if (!CalculateRenderPasses(frame))
+ if (!CalculateRenderPasses(frame)) {
+ DCHECK(!output_surface_->capabilities()
+ .draw_and_swap_full_viewport_every_frame);
return false;
+ }
// If we return true, then we expect DrawLayers() to be called before this
// function is called again.
@@ -1117,6 +1134,10 @@ void LayerTreeHostImpl::SetExternalDrawConstraints(
external_viewport_ = viewport;
}
+void LayerTreeHostImpl::SetExternalStencilTest(bool enabled) {
+ external_stencil_test_enabled_ = enabled;
+}
+
void LayerTreeHostImpl::SetNeedsRedrawRect(gfx::Rect damage_rect) {
client_->SetNeedsRedrawRectOnImplThread(damage_rect);
}
@@ -1171,6 +1192,10 @@ bool LayerTreeHostImpl::AllowPartialSwap() const {
return !debug_state_.ShowHudRects();
}
+bool LayerTreeHostImpl::ExternalStencilTestEnabled() const {
+ return external_stencil_test_enabled_;
+}
+
static void LayerTreeHostImplDidBeginTracingCallback(LayerImpl* layer) {
layer->DidBeginTracing();
}
@@ -1182,6 +1207,8 @@ void LayerTreeHostImpl::DrawLayers(FrameData* frame,
if (frame->has_no_damage) {
TRACE_EVENT0("cc", "EarlyOut_NoDamage");
+ DCHECK(!output_surface_->capabilities()
+ .draw_and_swap_full_viewport_every_frame);
return;
}
diff --git a/cc/trees/layer_tree_host_impl.h b/cc/trees/layer_tree_host_impl.h
index 9a0f72fcc1..f4663ebcc5 100644
--- a/cc/trees/layer_tree_host_impl.h
+++ b/cc/trees/layer_tree_host_impl.h
@@ -189,6 +189,7 @@ class CC_EXPORT LayerTreeHostImpl
virtual bool ShouldClearRootRenderPass() const OVERRIDE;
virtual CompositorFrameMetadata MakeCompositorFrameMetadata() const OVERRIDE;
virtual bool AllowPartialSwap() const OVERRIDE;
+ virtual bool ExternalStencilTestEnabled() const OVERRIDE;
// TileManagerClient implementation.
virtual void NotifyReadyToActivate() OVERRIDE;
@@ -201,6 +202,7 @@ class CC_EXPORT LayerTreeHostImpl
virtual void BeginFrame(const BeginFrameArgs& args) OVERRIDE;
virtual void SetExternalDrawConstraints(const gfx::Transform& transform,
gfx::Rect viewport) OVERRIDE;
+ virtual void SetExternalStencilTest(bool enabled) OVERRIDE;
virtual void DidLoseOutputSurface() OVERRIDE;
virtual void OnSwapBuffersComplete(const CompositorFrameAck* ack) OVERRIDE;
virtual void SetMemoryPolicy(
@@ -213,7 +215,7 @@ class CC_EXPORT LayerTreeHostImpl
void OnCanDrawStateChangedForTree();
// Implementation
- bool CanDraw();
+ bool CanDraw() const;
OutputSurface* output_surface() const { return output_surface_.get(); }
std::string LayerTreeAsJson() const;
@@ -524,6 +526,7 @@ class CC_EXPORT LayerTreeHostImpl
// used for scrollable size.
gfx::Transform external_transform_;
gfx::Rect external_viewport_;
+ bool external_stencil_test_enabled_;
gfx::Rect viewport_damage_rect_;
diff --git a/cc/trees/layer_tree_host_impl_unittest.cc b/cc/trees/layer_tree_host_impl_unittest.cc
index 1fb6c380ed..f26fe7bd89 100644
--- a/cc/trees/layer_tree_host_impl_unittest.cc
+++ b/cc/trees/layer_tree_host_impl_unittest.cc
@@ -265,6 +265,72 @@ class LayerTreeHostImplTest : public testing::Test,
void pinch_zoom_pan_viewport_and_scroll_boundary_test(
float device_scale_factor);
+ void CheckNotifyCalledIfCanDrawChanged(bool always_draw) {
+ // Note: It is not possible to disable the renderer once it has been set,
+ // so we do not need to test that disabling the renderer notifies us
+ // that can_draw changed.
+ EXPECT_FALSE(host_impl_->CanDraw());
+ on_can_draw_state_changed_called_ = false;
+
+ // Set up the root layer, which allows us to draw.
+ SetupScrollAndContentsLayers(gfx::Size(100, 100));
+ EXPECT_TRUE(host_impl_->CanDraw());
+ EXPECT_TRUE(on_can_draw_state_changed_called_);
+ on_can_draw_state_changed_called_ = false;
+
+ // Toggle the root layer to make sure it toggles can_draw
+ host_impl_->active_tree()->SetRootLayer(scoped_ptr<LayerImpl>());
+ EXPECT_FALSE(host_impl_->CanDraw());
+ EXPECT_TRUE(on_can_draw_state_changed_called_);
+ on_can_draw_state_changed_called_ = false;
+
+ SetupScrollAndContentsLayers(gfx::Size(100, 100));
+ EXPECT_TRUE(host_impl_->CanDraw());
+ EXPECT_TRUE(on_can_draw_state_changed_called_);
+ on_can_draw_state_changed_called_ = false;
+
+ // Toggle the device viewport size to make sure it toggles can_draw.
+ host_impl_->SetViewportSize(gfx::Size());
+ if (always_draw) {
+ EXPECT_TRUE(host_impl_->CanDraw());
+ } else {
+ EXPECT_FALSE(host_impl_->CanDraw());
+ }
+ EXPECT_TRUE(on_can_draw_state_changed_called_);
+ on_can_draw_state_changed_called_ = false;
+
+ host_impl_->SetViewportSize(gfx::Size(100, 100));
+ EXPECT_TRUE(host_impl_->CanDraw());
+ EXPECT_TRUE(on_can_draw_state_changed_called_);
+ on_can_draw_state_changed_called_ = false;
+
+ // Toggle contents textures purged without causing any evictions,
+ // and make sure that it does not change can_draw.
+ set_reduce_memory_result(false);
+ host_impl_->SetMemoryPolicy(ManagedMemoryPolicy(
+ host_impl_->memory_allocation_limit_bytes() - 1), true);
+ EXPECT_TRUE(host_impl_->CanDraw());
+ EXPECT_FALSE(on_can_draw_state_changed_called_);
+ on_can_draw_state_changed_called_ = false;
+
+ // Toggle contents textures purged to make sure it toggles can_draw.
+ set_reduce_memory_result(true);
+ host_impl_->SetMemoryPolicy(ManagedMemoryPolicy(
+ host_impl_->memory_allocation_limit_bytes() - 1), true);
+ if (always_draw) {
+ EXPECT_TRUE(host_impl_->CanDraw());
+ } else {
+ EXPECT_FALSE(host_impl_->CanDraw());
+ }
+ EXPECT_TRUE(on_can_draw_state_changed_called_);
+ on_can_draw_state_changed_called_ = false;
+
+ host_impl_->active_tree()->ResetContentsTexturesPurged();
+ EXPECT_TRUE(host_impl_->CanDraw());
+ EXPECT_TRUE(on_can_draw_state_changed_called_);
+ on_can_draw_state_changed_called_ = false;
+ }
+
protected:
virtual scoped_ptr<OutputSurface> CreateOutputSurface() {
return CreateFakeOutputSurface();
@@ -294,69 +360,30 @@ class LayerTreeHostImplTest : public testing::Test,
int current_priority_cutoff_value_;
};
+TEST_F(LayerTreeHostImplTest, NotifyIfCanDrawChanged) {
+ bool always_draw = false;
+ CheckNotifyCalledIfCanDrawChanged(always_draw);
+}
+
+TEST_F(LayerTreeHostImplTest, CanDrawIncompleteFrames) {
+ LayerTreeSettings settings;
+ settings.impl_side_painting = true;
+ host_impl_ = LayerTreeHostImpl::Create(
+ settings, this, &proxy_, &stats_instrumentation_);
+ host_impl_->InitializeRenderer(
+ FakeOutputSurface::CreateAlwaysDrawAndSwap3d().PassAs<OutputSurface>());
+ host_impl_->SetViewportSize(gfx::Size(10, 10));
+
+ bool always_draw = true;
+ CheckNotifyCalledIfCanDrawChanged(always_draw);
+}
+
class TestWebGraphicsContext3DMakeCurrentFails
: public TestWebGraphicsContext3D {
public:
virtual bool makeContextCurrent() OVERRIDE { return false; }
};
-TEST_F(LayerTreeHostImplTest, NotifyIfCanDrawChanged) {
- // Note: It is not possible to disable the renderer once it has been set,
- // so we do not need to test that disabling the renderer notifies us
- // that can_draw changed.
- EXPECT_FALSE(host_impl_->CanDraw());
- on_can_draw_state_changed_called_ = false;
-
- SetupScrollAndContentsLayers(gfx::Size(100, 100));
- EXPECT_TRUE(host_impl_->CanDraw());
- EXPECT_TRUE(on_can_draw_state_changed_called_);
- on_can_draw_state_changed_called_ = false;
-
- // Toggle the root layer to make sure it toggles can_draw
- host_impl_->active_tree()->SetRootLayer(scoped_ptr<LayerImpl>());
- EXPECT_FALSE(host_impl_->CanDraw());
- EXPECT_TRUE(on_can_draw_state_changed_called_);
- on_can_draw_state_changed_called_ = false;
-
- SetupScrollAndContentsLayers(gfx::Size(100, 100));
- EXPECT_TRUE(host_impl_->CanDraw());
- EXPECT_TRUE(on_can_draw_state_changed_called_);
- on_can_draw_state_changed_called_ = false;
-
- // Toggle the device viewport size to make sure it toggles can_draw.
- host_impl_->SetViewportSize(gfx::Size());
- EXPECT_FALSE(host_impl_->CanDraw());
- EXPECT_TRUE(on_can_draw_state_changed_called_);
- on_can_draw_state_changed_called_ = false;
-
- host_impl_->SetViewportSize(gfx::Size(100, 100));
- EXPECT_TRUE(host_impl_->CanDraw());
- EXPECT_TRUE(on_can_draw_state_changed_called_);
- on_can_draw_state_changed_called_ = false;
-
- // Toggle contents textures purged without causing any evictions,
- // and make sure that it does not change can_draw.
- set_reduce_memory_result(false);
- host_impl_->SetMemoryPolicy(ManagedMemoryPolicy(
- host_impl_->memory_allocation_limit_bytes() - 1), true);
- EXPECT_TRUE(host_impl_->CanDraw());
- EXPECT_FALSE(on_can_draw_state_changed_called_);
- on_can_draw_state_changed_called_ = false;
-
- // Toggle contents textures purged to make sure it toggles can_draw.
- set_reduce_memory_result(true);
- host_impl_->SetMemoryPolicy(ManagedMemoryPolicy(
- host_impl_->memory_allocation_limit_bytes() - 1), true);
- EXPECT_FALSE(host_impl_->CanDraw());
- EXPECT_TRUE(on_can_draw_state_changed_called_);
- on_can_draw_state_changed_called_ = false;
-
- host_impl_->active_tree()->ResetContentsTexturesPurged();
- EXPECT_TRUE(host_impl_->CanDraw());
- EXPECT_TRUE(on_can_draw_state_changed_called_);
- on_can_draw_state_changed_called_ = false;
-}
-
TEST_F(LayerTreeHostImplTest, ScrollDeltaNoLayers) {
ASSERT_FALSE(host_impl_->active_tree()->root_layer());
@@ -2771,32 +2798,47 @@ TEST_F(LayerTreeHostImplTest, BlendingOffWhenDrawingOpaqueLayers) {
host_impl_->DidDrawAllLayers(frame);
}
-TEST_F(LayerTreeHostImplTest, ViewportCovered) {
- host_impl_->InitializeRenderer(CreateOutputSurface());
- host_impl_->active_tree()->set_background_color(SK_ColorGRAY);
-
- gfx::Size viewport_size(1000, 1000);
- host_impl_->SetViewportSize(viewport_size);
-
- host_impl_->active_tree()->SetRootLayer(
- LayerImpl::Create(host_impl_->active_tree(), 1));
- host_impl_->active_tree()->root_layer()->AddChild(
- BlendStateCheckLayer::Create(host_impl_->active_tree(),
- 2,
- host_impl_->resource_provider()));
- BlendStateCheckLayer* child = static_cast<BlendStateCheckLayer*>(
- host_impl_->active_tree()->root_layer()->children()[0]);
- child->SetExpectation(false, false);
- child->SetContentsOpaque(true);
-
- // No gutter rects
- {
- gfx::Rect layer_rect(0, 0, 1000, 1000);
- child->SetPosition(layer_rect.origin());
- child->SetBounds(layer_rect.size());
- child->SetContentBounds(layer_rect.size());
- child->SetQuadRect(gfx::Rect(layer_rect.size()));
- child->SetQuadVisibleRect(gfx::Rect(layer_rect.size()));
+class LayerTreeHostImplViewportCoveredTest : public LayerTreeHostImplTest {
+ public:
+ void CreateLayerTreeHostImpl(bool always_draw) {
+ LayerTreeSettings settings;
+ settings.minimum_occlusion_tracking_size = gfx::Size();
+ settings.impl_side_painting = true;
+ host_impl_ = LayerTreeHostImpl::Create(
+ settings, this, &proxy_, &stats_instrumentation_);
+ scoped_ptr<OutputSurface> output_surface;
+ if (always_draw) {
+ output_surface = FakeOutputSurface::CreateAlwaysDrawAndSwap3d()
+ .PassAs<OutputSurface>();
+ } else {
+ output_surface = CreateFakeOutputSurface();
+ }
+ host_impl_->InitializeRenderer(output_surface.Pass());
+ viewport_size_ = gfx::Size(1000, 1000);
+ }
+
+ void SetupActiveTreeLayers() {
+ host_impl_->active_tree()->set_background_color(SK_ColorGRAY);
+ host_impl_->active_tree()->SetRootLayer(
+ LayerImpl::Create(host_impl_->active_tree(), 1));
+ host_impl_->active_tree()->root_layer()->AddChild(
+ BlendStateCheckLayer::Create(host_impl_->active_tree(),
+ 2,
+ host_impl_->resource_provider()));
+ child_ = static_cast<BlendStateCheckLayer*>(
+ host_impl_->active_tree()->root_layer()->children()[0]);
+ child_->SetExpectation(false, false);
+ child_->SetContentsOpaque(true);
+ }
+
+ // Expect no gutter rects.
+ void TestLayerCoversFullViewport() {
+ gfx::Rect layer_rect(viewport_size_);
+ child_->SetPosition(layer_rect.origin());
+ child_->SetBounds(layer_rect.size());
+ child_->SetContentBounds(layer_rect.size());
+ child_->SetQuadRect(gfx::Rect(layer_rect.size()));
+ child_->SetQuadVisibleRect(gfx::Rect(layer_rect.size()));
LayerTreeHostImpl::FrameData frame;
EXPECT_TRUE(host_impl_->PrepareToDraw(&frame, gfx::Rect()));
@@ -2810,18 +2852,18 @@ TEST_F(LayerTreeHostImplTest, ViewportCovered) {
EXPECT_EQ(1u, frame.render_passes[0]->quad_list.size());
LayerTestCommon::VerifyQuadsExactlyCoverRect(
- frame.render_passes[0]->quad_list, gfx::Rect(viewport_size));
+ frame.render_passes[0]->quad_list, gfx::Rect(viewport_size_));
host_impl_->DidDrawAllLayers(frame);
}
- // Empty visible content area (fullscreen gutter rect)
- {
+ // Expect fullscreen gutter rect.
+ void TestEmptyLayer() {
gfx::Rect layer_rect(0, 0, 0, 0);
- child->SetPosition(layer_rect.origin());
- child->SetBounds(layer_rect.size());
- child->SetContentBounds(layer_rect.size());
- child->SetQuadRect(gfx::Rect(layer_rect.size()));
- child->SetQuadVisibleRect(gfx::Rect(layer_rect.size()));
+ child_->SetPosition(layer_rect.origin());
+ child_->SetBounds(layer_rect.size());
+ child_->SetContentBounds(layer_rect.size());
+ child_->SetQuadRect(gfx::Rect(layer_rect.size()));
+ child_->SetQuadVisibleRect(gfx::Rect(layer_rect.size()));
LayerTreeHostImpl::FrameData frame;
EXPECT_TRUE(host_impl_->PrepareToDraw(&frame, gfx::Rect()));
@@ -2835,18 +2877,18 @@ TEST_F(LayerTreeHostImplTest, ViewportCovered) {
EXPECT_EQ(1u, frame.render_passes[0]->quad_list.size());
LayerTestCommon::VerifyQuadsExactlyCoverRect(
- frame.render_passes[0]->quad_list, gfx::Rect(viewport_size));
+ frame.render_passes[0]->quad_list, gfx::Rect(viewport_size_));
host_impl_->DidDrawAllLayers(frame);
}
- // Content area in middle of clip rect (four surrounding gutter rects)
- {
+ // Expect four surrounding gutter rects.
+ void TestLayerInMiddleOfViewport() {
gfx::Rect layer_rect(500, 500, 200, 200);
- child->SetPosition(layer_rect.origin());
- child->SetBounds(layer_rect.size());
- child->SetContentBounds(layer_rect.size());
- child->SetQuadRect(gfx::Rect(layer_rect.size()));
- child->SetQuadVisibleRect(gfx::Rect(layer_rect.size()));
+ child_->SetPosition(layer_rect.origin());
+ child_->SetBounds(layer_rect.size());
+ child_->SetContentBounds(layer_rect.size());
+ child_->SetQuadRect(gfx::Rect(layer_rect.size()));
+ child_->SetQuadVisibleRect(gfx::Rect(layer_rect.size()));
LayerTreeHostImpl::FrameData frame;
EXPECT_TRUE(host_impl_->PrepareToDraw(&frame, gfx::Rect()));
@@ -2860,11 +2902,96 @@ TEST_F(LayerTreeHostImplTest, ViewportCovered) {
EXPECT_EQ(5u, frame.render_passes[0]->quad_list.size());
LayerTestCommon::VerifyQuadsExactlyCoverRect(
- frame.render_passes[0]->quad_list, gfx::Rect(viewport_size));
+ frame.render_passes[0]->quad_list, gfx::Rect(viewport_size_));
+ host_impl_->DidDrawAllLayers(frame);
+ }
+
+ // Expect no gutter rects.
+ void TestLayerIsLargerThanViewport() {
+ gfx::Rect layer_rect(viewport_size_.width() + 10,
+ viewport_size_.height() + 10);
+ child_->SetPosition(layer_rect.origin());
+ child_->SetBounds(layer_rect.size());
+ child_->SetContentBounds(layer_rect.size());
+ child_->SetQuadRect(gfx::Rect(layer_rect.size()));
+ child_->SetQuadVisibleRect(gfx::Rect(layer_rect.size()));
+
+ LayerTreeHostImpl::FrameData frame;
+ EXPECT_TRUE(host_impl_->PrepareToDraw(&frame, gfx::Rect()));
+ ASSERT_EQ(1u, frame.render_passes.size());
+
+ size_t num_gutter_quads = 0;
+ for (size_t i = 0; i < frame.render_passes[0]->quad_list.size(); ++i)
+ num_gutter_quads += (frame.render_passes[0]->quad_list[i]->material ==
+ DrawQuad::SOLID_COLOR) ? 1 : 0;
+ EXPECT_EQ(0u, num_gutter_quads);
+ EXPECT_EQ(1u, frame.render_passes[0]->quad_list.size());
+
host_impl_->DidDrawAllLayers(frame);
}
+
+ virtual void DidActivatePendingTree() OVERRIDE {
+ did_activate_pending_tree_ = true;
+ }
+
+ protected:
+ gfx::Size viewport_size_;
+ BlendStateCheckLayer* child_;
+ bool did_activate_pending_tree_;
+};
+
+TEST_F(LayerTreeHostImplViewportCoveredTest, ViewportCovered) {
+ bool always_draw = false;
+ CreateLayerTreeHostImpl(always_draw);
+
+ host_impl_->SetViewportSize(viewport_size_);
+ SetupActiveTreeLayers();
+ TestLayerCoversFullViewport();
+ TestEmptyLayer();
+ TestLayerInMiddleOfViewport();
+ TestLayerIsLargerThanViewport();
}
+TEST_F(LayerTreeHostImplViewportCoveredTest, ActiveTreeGrowViewportInvalid) {
+ bool always_draw = true;
+ CreateLayerTreeHostImpl(always_draw);
+
+ // Pending tree to force active_tree size invalid. Not used otherwise.
+ host_impl_->CreatePendingTree();
+ host_impl_->SetViewportSize(viewport_size_);
+ EXPECT_TRUE(host_impl_->active_tree()->ViewportSizeInvalid());
+
+ SetupActiveTreeLayers();
+ TestEmptyLayer();
+ TestLayerInMiddleOfViewport();
+ TestLayerIsLargerThanViewport();
+}
+
+TEST_F(LayerTreeHostImplViewportCoveredTest, ActiveTreeShrinkViewportInvalid) {
+ bool always_draw = true;
+ CreateLayerTreeHostImpl(always_draw);
+
+ // Set larger viewport and activate it to active tree.
+ host_impl_->CreatePendingTree();
+ gfx::Size larger_viewport(viewport_size_.width() + 100,
+ viewport_size_.height() + 100);
+ host_impl_->SetViewportSize(larger_viewport);
+ EXPECT_TRUE(host_impl_->active_tree()->ViewportSizeInvalid());
+ did_activate_pending_tree_ = false;
+ host_impl_->ActivatePendingTreeIfNeeded();
+ EXPECT_TRUE(did_activate_pending_tree_);
+ EXPECT_FALSE(host_impl_->active_tree()->ViewportSizeInvalid());
+
+ // Shrink pending tree viewport without activating.
+ host_impl_->CreatePendingTree();
+ host_impl_->SetViewportSize(viewport_size_);
+ EXPECT_TRUE(host_impl_->active_tree()->ViewportSizeInvalid());
+
+ SetupActiveTreeLayers();
+ TestEmptyLayer();
+ TestLayerInMiddleOfViewport();
+ TestLayerIsLargerThanViewport();
+}
class ReshapeTrackerContext: public TestWebGraphicsContext3D {
public:
@@ -4793,6 +4920,7 @@ class TestRenderer : public GLRenderer, public RendererClient {
virtual bool AllowPartialSwap() const OVERRIDE {
return true;
}
+ virtual bool ExternalStencilTestEnabled() const OVERRIDE { return false; }
protected:
TestRenderer(ResourceProvider* resource_provider,
diff --git a/cc/trees/layer_tree_impl.cc b/cc/trees/layer_tree_impl.cc
index c160d97bb9..8d1d04861e 100644
--- a/cc/trees/layer_tree_impl.cc
+++ b/cc/trees/layer_tree_impl.cc
@@ -584,10 +584,9 @@ void LayerTreeImpl::AddLayerWithCopyOutputRequest(LayerImpl* layer) {
// they are aborted if not serviced during draw.
DCHECK(IsActiveTree());
- if (std::find(layers_with_copy_output_request_.begin(),
- layers_with_copy_output_request_.end(),
- layer) != layers_with_copy_output_request_.end())
- return;
+ DCHECK(std::find(layers_with_copy_output_request_.begin(),
+ layers_with_copy_output_request_.end(),
+ layer) == layers_with_copy_output_request_.end());
layers_with_copy_output_request_.push_back(layer);
}
@@ -601,8 +600,7 @@ void LayerTreeImpl::RemoveLayerWithCopyOutputRequest(LayerImpl* layer) {
layers_with_copy_output_request_.end(),
layer);
DCHECK(it != layers_with_copy_output_request_.end());
- if (it != layers_with_copy_output_request_.end())
- layers_with_copy_output_request_.erase(it);
+ layers_with_copy_output_request_.erase(it);
}
const std::vector<LayerImpl*> LayerTreeImpl::LayersWithCopyOutputRequest()