summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--android_webview/native/DEPS1
-rw-r--r--android_webview/native/aw_contents.cc231
-rw-r--r--android_webview/native/aw_contents.h14
-rw-r--r--android_webview/native/webview_native.gyp1
-rw-r--r--android_webview/public/browser/draw_gl.h5
-rw-r--r--cc/cc_tests.gyp2
-rw-r--r--cc/delegated_renderer_layer_impl_unittest.cc35
-rw-r--r--cc/direct_renderer.cc3
-rw-r--r--cc/gl_renderer_pixeltest.cc1
-rw-r--r--cc/gl_renderer_unittest.cc67
-rw-r--r--cc/layer_tree_host_impl.cc5
-rw-r--r--cc/layer_tree_host_impl.h1
-rw-r--r--cc/layer_tree_host_impl_unittest.cc1
-rw-r--r--cc/layer_tree_settings.cc1
-rw-r--r--cc/layer_tree_settings.h1
-rw-r--r--cc/renderer.h7
-rw-r--r--cc/software_renderer_unittest.cc65
-rw-r--r--cc/test/render_pass_test_utils.cc61
-rw-r--r--cc/test/render_pass_test_utils.h44
-rw-r--r--content/browser/renderer_host/compositor_impl_android.cc13
-rw-r--r--content/browser/renderer_host/compositor_impl_android.h2
-rw-r--r--content/public/browser/android/compositor.h3
22 files changed, 501 insertions, 63 deletions
diff --git a/android_webview/native/DEPS b/android_webview/native/DEPS
index 04c6a9d..4f94198 100644
--- a/android_webview/native/DEPS
+++ b/android_webview/native/DEPS
@@ -2,4 +2,5 @@ include_rules = [
"+cc",
"+content/public/browser",
"+ui/gfx",
+ "+ui/gl",
]
diff --git a/android_webview/native/aw_contents.cc b/android_webview/native/aw_contents.cc
index 7cbcbc9..74edfa1 100644
--- a/android_webview/native/aw_contents.cc
+++ b/android_webview/native/aw_contents.cc
@@ -18,6 +18,7 @@
#include "base/android/jni_string.h"
#include "base/bind.h"
#include "base/callback.h"
+#include "base/debug/trace_event.h"
#include "base/message_loop.h"
#include "base/pickle.h"
#include "base/supports_user_data.h"
@@ -33,6 +34,18 @@
#include "jni/AwContents_jni.h"
#include "net/base/x509_certificate.h"
#include "ui/gfx/transform.h"
+#include "ui/gl/gl_bindings.h"
+
+// TODO(leandrogracia): remove when crbug.com/164140 is closed.
+// Borrowed from gl2ext.h. Cannot be included due to conflicts with
+// gl_bindings.h and the EGL library methods (eglGetCurrentContext).
+#ifndef GL_TEXTURE_EXTERNAL_OES
+#define GL_TEXTURE_EXTERNAL_OES 0x8D65
+#endif
+
+#ifndef GL_TEXTURE_BINDING_EXTERNAL_OES
+#define GL_TEXTURE_BINDING_EXTERNAL_OES 0x8D67
+#endif
using base::android::AttachCurrentThread;
using base::android::ConvertJavaStringToUTF16;
@@ -109,6 +122,7 @@ class NullCompositor : public content::Compositor {
virtual void DeleteTexture(WebKit::WebGLId texture_id) OVERRIDE {}
virtual void CopyTextureToBitmap(WebKit::WebGLId texture_id,
gfx::JavaBitmap& bitmap) OVERRIDE {}
+ virtual void SetHasTransparentBackground(bool flag) OVERRIDE {}
};
} // namespace
@@ -127,7 +141,8 @@ AwContents::AwContents(JNIEnv* env,
new AwWebContentsDelegate(env, web_contents_delegate)),
view_visible_(false),
compositor_visible_(false),
- is_composite_pending_(false) {
+ is_composite_pending_(false),
+ last_frame_context_(NULL) {
android_webview::AwBrowserDependencyFactory* dependency_factory =
android_webview::AwBrowserDependencyFactory::GetInstance();
@@ -137,6 +152,17 @@ AwContents::AwContents(JNIEnv* env,
SetWebContents(dependency_factory->CreateWebContents(private_browsing));
}
+void AwContents::ResetCompositor() {
+ if (UseCompositorDirectDraw()) {
+ compositor_.reset(content::Compositor::Create(this));
+ if (webview_layer_.get())
+ AttachWebViewLayer();
+ } else {
+ LOG(WARNING) << "Running on unsupported device: using null Compositor";
+ compositor_.reset(new NullCompositor);
+ }
+}
+
void AwContents::SetWebContents(content::WebContents* web_contents) {
web_contents_.reset(web_contents);
web_contents_->SetUserData(kAwContentsUserDataKey,
@@ -144,12 +170,7 @@ void AwContents::SetWebContents(content::WebContents* web_contents) {
web_contents_->SetDelegate(web_contents_delegate_.get());
render_view_host_ext_.reset(new AwRenderViewHostExt(web_contents_.get()));
- if (UseCompositorDirectDraw()) {
- compositor_.reset(content::Compositor::Create(this));
- } else {
- LOG(WARNING) << "Running on unsupported device: using null Compositor";
- compositor_.reset(new NullCompositor);
- }
+ ResetCompositor();
}
void AwContents::SetWebContents(JNIEnv* env, jobject obj, jint new_wc) {
@@ -164,24 +185,178 @@ AwContents::~AwContents() {
}
void AwContents::DrawGL(AwDrawGLInfo* draw_info) {
- // TODO(joth): Use the |draw_info| parameters.
- DLOG(INFO) << "Unimplemented AwContents::DrawGL params"
- << " clip_left=" << draw_info->clip_left
- << " clip_top=" << draw_info->clip_top
- << " clip_right=" << draw_info->clip_right
- << " clip_bottom=" << draw_info->clip_bottom;
- if (compositor_visible_ != view_visible_) {
- compositor_visible_ = view_visible_;
- compositor_->SetVisible(compositor_visible_);
- }
- if (!compositor_visible_ || draw_info->mode == AwDrawGLInfo::kModeProcess)
+ TRACE_EVENT0("AwContents", "AwContents::DrawGL");
+
+ if (!webview_layer_.get() || draw_info->mode == AwDrawGLInfo::kModeProcess)
return;
DCHECK_EQ(draw_info->mode, AwDrawGLInfo::kModeDraw);
+ SetCompositorVisibility(view_visible_);
+ if (!compositor_visible_)
+ return;
+
+ // TODO(leandrogracia): remove when crbug.com/164140 is closed.
+ // ---------------------------------------------------------------------------
+ GLint texture_external_oes_binding;
+ glGetIntegerv(GL_TEXTURE_BINDING_EXTERNAL_OES, &texture_external_oes_binding);
+
+ GLint vertex_array_buffer_binding;
+ glGetIntegerv(GL_ARRAY_BUFFER_BINDING, &vertex_array_buffer_binding);
+
+ GLint index_array_buffer_binding;
+ glGetIntegerv(GL_ELEMENT_ARRAY_BUFFER_BINDING, &index_array_buffer_binding);
+
+ GLint pack_alignment;
+ glGetIntegerv(GL_PACK_ALIGNMENT, &pack_alignment);
+
+ GLint unpack_alignment;
+ glGetIntegerv(GL_UNPACK_ALIGNMENT, &unpack_alignment);
+
+ struct {
+ GLint enabled;
+ GLint size;
+ GLint type;
+ GLint normalized;
+ GLint stride;
+ GLvoid* pointer;
+ } vertex_attrib[3];
+
+ for (size_t i = 0; i < ARRAYSIZE_UNSAFE(vertex_attrib); ++i) {
+ glGetVertexAttribiv(i, GL_VERTEX_ATTRIB_ARRAY_ENABLED,
+ &vertex_attrib[i].enabled);
+ glGetVertexAttribiv(i, GL_VERTEX_ATTRIB_ARRAY_SIZE,
+ &vertex_attrib[i].size);
+ glGetVertexAttribiv(i, GL_VERTEX_ATTRIB_ARRAY_TYPE,
+ &vertex_attrib[i].type);
+ glGetVertexAttribiv(i, GL_VERTEX_ATTRIB_ARRAY_NORMALIZED,
+ &vertex_attrib[i].normalized);
+ glGetVertexAttribiv(i, GL_VERTEX_ATTRIB_ARRAY_STRIDE,
+ &vertex_attrib[i].stride);
+ glGetVertexAttribPointerv(i, GL_VERTEX_ATTRIB_ARRAY_POINTER,
+ &vertex_attrib[i].pointer);
+ }
+
+ GLboolean depth_test;
+ glGetBooleanv(GL_DEPTH_TEST, &depth_test);
+
+ GLboolean cull_face;
+ glGetBooleanv(GL_CULL_FACE, &cull_face);
+
+ GLboolean color_mask[4];
+ glGetBooleanv(GL_COLOR_WRITEMASK, color_mask);
+
+ GLboolean blend_enabled;
+ glGetBooleanv(GL_BLEND, &blend_enabled);
+
+ GLint blend_src_rgb;
+ glGetIntegerv(GL_BLEND_SRC_RGB, &blend_src_rgb);
+
+ GLint blend_src_alpha;
+ glGetIntegerv(GL_BLEND_SRC_ALPHA, &blend_src_alpha);
+
+ GLint blend_dest_rgb;
+ glGetIntegerv(GL_BLEND_DST_RGB, &blend_dest_rgb);
+
+ GLint blend_dest_alpha;
+ glGetIntegerv(GL_BLEND_DST_ALPHA, &blend_dest_alpha);
+
+ GLint active_texture;
+ glGetIntegerv(GL_ACTIVE_TEXTURE, &active_texture);
+
+ GLint viewport[4];
+ glGetIntegerv(GL_VIEWPORT, viewport);
+
+ GLboolean scissor_test;
+ glGetBooleanv(GL_SCISSOR_TEST, &scissor_test);
+
+ GLint scissor_box[4];
+ glGetIntegerv(GL_SCISSOR_BOX, scissor_box);
+
+ GLint current_program;
+ glGetIntegerv(GL_CURRENT_PROGRAM, &current_program);
+ // ---------------------------------------------------------------------------
+
+ // We need to watch if the current Android context has changed and enforce
+ // a clean-up in the compositor.
+ EGLContext current_context = eglGetCurrentContext();
+ if (!current_context) {
+ LOG(WARNING) << "No current context attached. Skipping composite.";
+ return;
+ }
+
+ if (last_frame_context_ != current_context) {
+ if (last_frame_context_)
+ ResetCompositor();
+ last_frame_context_ = current_context;
+ }
+
+ compositor_->SetWindowBounds(gfx::Size(draw_info->width, draw_info->height));
+ compositor_->SetHasTransparentBackground(!draw_info->is_layer);
+
+ gfx::Transform transform;
+ transform.matrix().setColMajorf(draw_info->transform);
+ webview_layer_->setTransform(transform);
+
compositor_->Composite();
is_composite_pending_ = false;
+
+ // TODO(leandrogracia): remove when crbug.com/164140 is closed.
+ // ---------------------------------------------------------------------------
+ glBindTexture(GL_TEXTURE_EXTERNAL_OES, texture_external_oes_binding);
+ glBindBuffer(GL_ARRAY_BUFFER, vertex_array_buffer_binding);
+ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, index_array_buffer_binding);
+
+ glPixelStorei(GL_PACK_ALIGNMENT, pack_alignment);
+ glPixelStorei(GL_UNPACK_ALIGNMENT, unpack_alignment);
+
+ for (size_t i = 0; i < ARRAYSIZE_UNSAFE(vertex_attrib); ++i) {
+ glVertexAttribPointer(i, vertex_attrib[i].size,
+ vertex_attrib[i].type, vertex_attrib[i].normalized,
+ vertex_attrib[i].stride, vertex_attrib[i].pointer);
+
+ if (vertex_attrib[i].enabled)
+ glEnableVertexAttribArray(i);
+ else
+ glDisableVertexAttribArray(i);
+ }
+
+ if (depth_test)
+ glEnable(GL_DEPTH_TEST);
+ else
+ glDisable(GL_DEPTH_TEST);
+
+ if (cull_face)
+ glEnable(GL_CULL_FACE);
+ else
+ glDisable(GL_CULL_FACE);
+
+ glColorMask(color_mask[0], color_mask[1], color_mask[2],
+ color_mask[3]);
+
+ if (blend_enabled)
+ glEnable(GL_BLEND);
+ else
+ glDisable(GL_BLEND);
+
+ glBlendFuncSeparate(blend_src_rgb, blend_dest_rgb,
+ blend_src_alpha, blend_dest_alpha);
+
+ glActiveTexture(active_texture);
+
+ glViewport(viewport[0], viewport[1], viewport[2], viewport[3]);
+
+ if (scissor_test)
+ glEnable(GL_SCISSOR_TEST);
+ else
+ glDisable(GL_SCISSOR_TEST);
+
+ glScissor(scissor_box[0], scissor_box[1], scissor_box[2],
+ scissor_box[3]);
+
+ glUseProgram(current_program);
+ // ---------------------------------------------------------------------------
}
jint AwContents::GetWebContents(JNIEnv* env, jobject obj) {
@@ -192,7 +367,14 @@ void AwContents::DidInitializeContentViewCore(JNIEnv* env, jobject obj,
jint content_view_core) {
ContentViewCore* core = reinterpret_cast<ContentViewCore*>(content_view_core);
DCHECK(core == ContentViewCore::FromWebContents(web_contents_.get()));
- compositor_->SetRootLayer(core->GetLayer());
+ webview_layer_ = cc::Layer::create();
+ webview_layer_->addChild(core->GetLayer());
+ AttachWebViewLayer();
+}
+
+void AwContents::AttachWebViewLayer() {
+ DCHECK(webview_layer_.get());
+ compositor_->SetRootLayer(webview_layer_.get());
Invalidate();
}
@@ -403,7 +585,7 @@ void AwContents::OnFindResultReceived(int active_ordinal,
}
void AwContents::ScheduleComposite() {
- // TODO(joth): Call back out to framework attachFunctor (Java side) from here.
+ TRACE_EVENT0("AwContents", "AwContents::ScheduleComposite");
Invalidate();
}
@@ -421,6 +603,13 @@ void AwContents::Invalidate() {
Java_AwContents_invalidate(env, obj.obj());
}
+void AwContents::SetCompositorVisibility(bool visible) {
+ if (compositor_visible_ != visible) {
+ compositor_visible_ = visible;
+ compositor_->SetVisible(compositor_visible_);
+ }
+}
+
void AwContents::OnSwapBuffersCompleted() {
}
@@ -505,7 +694,7 @@ void AwContents::OnAttachedToWindow(JNIEnv* env, jobject obj, int w, int h) {
void AwContents::OnDetachedFromWindow(JNIEnv* env, jobject obj) {
view_visible_ = false;
- // TODO(joth): Request a DrawGL (kModeProcess) call, to tell the compositor.
+ SetCompositorVisibility(false);
}
base::android::ScopedJavaLocalRef<jbyteArray>
diff --git a/android_webview/native/aw_contents.h b/android_webview/native/aw_contents.h
index 6a542c9..410f5d5 100644
--- a/android_webview/native/aw_contents.h
+++ b/android_webview/native/aw_contents.h
@@ -16,6 +16,7 @@
#include "content/public/browser/android/compositor.h"
#include "content/public/browser/javascript_dialogs.h"
+typedef void* EGLContext;
class TabContents;
namespace cc {
@@ -121,18 +122,27 @@ class AwContents : public FindHelper::Listener,
private:
void Invalidate();
void SetWebContents(content::WebContents* web_contents);
+ void SetCompositorVisibility(bool visible);
+ void ResetCompositor();
+ void AttachWebViewLayer();
JavaObjectWeakGlobalRef java_ref_;
scoped_ptr<content::WebContents> web_contents_;
scoped_ptr<AwWebContentsDelegate> web_contents_delegate_;
scoped_ptr<AwRenderViewHostExt> render_view_host_ext_;
scoped_ptr<FindHelper> find_helper_;
+ scoped_ptr<content::WebContents> pending_contents_;
+
+ // Compositor-specific state.
scoped_ptr<content::Compositor> compositor_;
- // State to track if the view is visible, and if the compositor knows yet.
+ scoped_refptr<cc::Layer> webview_layer_;
bool view_visible_;
bool compositor_visible_;
bool is_composite_pending_;
- scoped_ptr<content::WebContents> pending_contents_;
+
+ // Used only for detecting Android View System context changes.
+ // Not to be used between draw calls.
+ EGLContext last_frame_context_;
DISALLOW_COPY_AND_ASSIGN(AwContents);
};
diff --git a/android_webview/native/webview_native.gyp b/android_webview/native/webview_native.gyp
index 865b870..a4b62f6 100644
--- a/android_webview/native/webview_native.gyp
+++ b/android_webview/native/webview_native.gyp
@@ -13,6 +13,7 @@
'../../base/base.gyp:base_static',
'../../content/content.gyp:web_contents_delegate_android',
'../../skia/skia.gyp:skia',
+ '../../ui/gl/gl.gyp:gl',
'android_webview_native_jni',
],
'include_dirs': [
diff --git a/android_webview/public/browser/draw_gl.h b/android_webview/public/browser/draw_gl.h
index 75a3a61..8bea559 100644
--- a/android_webview/public/browser/draw_gl.h
+++ b/android_webview/public/browser/draw_gl.h
@@ -38,7 +38,10 @@ struct AwDrawGLInfo {
kStatusMaskDone = 0x0,
kStatusMaskDraw = 0x1,
kStatusMaskInvoke = 0x2,
- } status_mask;
+ };
+
+ // Output: mask indicating the status after calling the functor.
+ unsigned int status_mask;
// Output: dirty region to redraw.
float dirty_left;
diff --git a/cc/cc_tests.gyp b/cc/cc_tests.gyp
index 1781533..58661a0 100644
--- a/cc/cc_tests.gyp
+++ b/cc/cc_tests.gyp
@@ -100,6 +100,8 @@
'test/pixel_test_output_surface.h',
'test/render_pass_test_common.cc',
'test/render_pass_test_common.h',
+ 'test/render_pass_test_utils.cc',
+ 'test/render_pass_test_utils.h',
'test/scheduler_test_common.cc',
'test/scheduler_test_common.h',
'test/tiled_layer_test_common.cc',
diff --git a/cc/delegated_renderer_layer_impl_unittest.cc b/cc/delegated_renderer_layer_impl_unittest.cc
index 9106831..68e47a9 100644
--- a/cc/delegated_renderer_layer_impl_unittest.cc
+++ b/cc/delegated_renderer_layer_impl_unittest.cc
@@ -20,6 +20,7 @@
#include "cc/test/geometry_test_utils.h"
#include "cc/test/mock_quad_culler.h"
#include "cc/test/render_pass_test_common.h"
+#include "cc/test/render_pass_test_utils.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/gfx/transform.h"
@@ -51,40 +52,6 @@ protected:
scoped_ptr<LayerTreeHostImpl> m_hostImpl;
};
-static TestRenderPass* addRenderPass(ScopedPtrVector<RenderPass>& passList, RenderPass::Id id, gfx::Rect outputRect, gfx::Transform rootTransform)
-{
- scoped_ptr<TestRenderPass> pass(TestRenderPass::Create());
- pass->SetNew(id, outputRect, outputRect, rootTransform);
- TestRenderPass* saved = pass.get();
- passList.append(pass.PassAs<RenderPass>());
- return saved;
-}
-
-static SolidColorDrawQuad* addQuad(TestRenderPass* pass, gfx::Rect rect, SkColor color)
-{
- MockQuadCuller quadSink(pass->quad_list, pass->shared_quad_state_list);
- AppendQuadsData data(pass->id);
- SharedQuadState* sharedState = quadSink.useSharedQuadState(SharedQuadState::Create());
- sharedState->SetAll(gfx::Transform(), rect, rect, rect, false, 1);
- scoped_ptr<SolidColorDrawQuad> quad = SolidColorDrawQuad::Create();
- quad->SetNew(sharedState, rect, color);
- SolidColorDrawQuad* quadPtr = quad.get();
- quadSink.append(quad.PassAs<DrawQuad>(), data);
- return quadPtr;
-}
-
-static void addRenderPassQuad(TestRenderPass* toPass, TestRenderPass* contributingPass)
-{
- MockQuadCuller quadSink(toPass->quad_list, toPass->shared_quad_state_list);
- AppendQuadsData data(toPass->id);
- gfx::Rect outputRect = contributingPass->output_rect;
- SharedQuadState* sharedState = quadSink.useSharedQuadState(SharedQuadState::Create());
- sharedState->SetAll(gfx::Transform(), outputRect, outputRect, outputRect, false, 1);
- scoped_ptr<RenderPassDrawQuad> quad = RenderPassDrawQuad::Create();
- quad->SetNew(sharedState, outputRect, contributingPass->id, false, 0, outputRect, gfx::RectF());
- quadSink.append(quad.PassAs<DrawQuad>(), data);
-}
-
class DelegatedRendererLayerImplTestSimple : public DelegatedRendererLayerImplTest {
public:
DelegatedRendererLayerImplTestSimple()
diff --git a/cc/direct_renderer.cc b/cc/direct_renderer.cc
index 1682e91..d5dc975 100644
--- a/cc/direct_renderer.cc
+++ b/cc/direct_renderer.cc
@@ -238,7 +238,8 @@ void DirectRenderer::drawRenderPass(DrawingFrame& frame, const RenderPass* rende
setScissorTestRect(moveScissorToWindowSpace(frame, renderPassScissor));
}
- clearFramebuffer(frame);
+ if (frame.currentRenderPass != frame.rootRenderPass || m_client->shouldClearRootRenderPass())
+ clearFramebuffer(frame);
const QuadList& quadList = renderPass->quad_list;
for (QuadList::constBackToFrontIterator it = quadList.backToFrontBegin(); it != quadList.backToFrontEnd(); ++it) {
diff --git a/cc/gl_renderer_pixeltest.cc b/cc/gl_renderer_pixeltest.cc
index ee2a015..6d35668 100644
--- a/cc/gl_renderer_pixeltest.cc
+++ b/cc/gl_renderer_pixeltest.cc
@@ -41,6 +41,7 @@ class FakeRendererClient : public RendererClient {
virtual void enforceManagedMemoryPolicy(
const ManagedMemoryPolicy&) OVERRIDE {}
virtual bool hasImplThread() const OVERRIDE { return false; }
+ virtual bool shouldClearRootRenderPass() const { return true; }
};
class GLRendererPixelTest : public testing::Test {
diff --git a/cc/gl_renderer_unittest.cc b/cc/gl_renderer_unittest.cc
index 8521627..5eee6ac 100644
--- a/cc/gl_renderer_unittest.cc
+++ b/cc/gl_renderer_unittest.cc
@@ -12,6 +12,7 @@
#include "cc/test/fake_output_surface.h"
#include "cc/test/fake_web_graphics_context_3d.h"
#include "cc/test/render_pass_test_common.h"
+#include "cc/test/render_pass_test_utils.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/khronos/GLES2/gl2.h"
@@ -22,6 +23,8 @@ using namespace WebKitTests;
using testing::_;
using testing::AnyNumber;
+using testing::AtLeast;
+using testing::Expectation;
using testing::InSequence;
using testing::Mock;
@@ -82,6 +85,7 @@ public:
virtual void setManagedMemoryPolicy(const ManagedMemoryPolicy& policy) OVERRIDE { m_memoryAllocationLimitBytes = policy.bytesLimitWhenVisible; }
virtual void enforceManagedMemoryPolicy(const ManagedMemoryPolicy& policy) OVERRIDE { if (m_lastCallWasSetVisibility) *m_lastCallWasSetVisibility = false; }
virtual bool hasImplThread() const OVERRIDE { return false; }
+ virtual bool shouldClearRootRenderPass() const OVERRIDE { return true; }
// Methods added for test.
int setFullRootLayerDamageCount() const { return m_setFullRootLayerDamageCount; }
@@ -578,5 +582,68 @@ TEST(GLRendererTest2, activeTextureState)
Mock::VerifyAndClearExpectations(context);
}
+class NoClearRootRenderPassFakeClient : public FakeRendererClient {
+public:
+ virtual bool shouldClearRootRenderPass() const { return false; }
+};
+
+class NoClearRootRenderPassMockContext : public FakeWebGraphicsContext3D {
+public:
+ MOCK_METHOD1(clear, void(WGC3Dbitfield mask));
+ MOCK_METHOD4(drawElements, void(WGC3Denum mode, WGC3Dsizei count, WGC3Denum type, WGC3Dintptr offset));
+};
+
+TEST(GLRendererTest2, shouldClearRootRenderPass)
+{
+ NoClearRootRenderPassFakeClient mockClient;
+ scoped_ptr<OutputSurface> outputSurface(FakeOutputSurface::Create3d(scoped_ptr<WebKit::WebGraphicsContext3D>(new NoClearRootRenderPassMockContext)));
+ NoClearRootRenderPassMockContext* mockContext = static_cast<NoClearRootRenderPassMockContext*>(outputSurface->Context3D());
+
+ scoped_ptr<ResourceProvider> resourceProvider(ResourceProvider::create(outputSurface.get()));
+ FakeRendererGL renderer(&mockClient, resourceProvider.get());
+ EXPECT_TRUE(renderer.initialize());
+
+ gfx::Rect viewportRect(mockClient.deviceViewportSize());
+ ScopedPtrVector<RenderPass> renderPasses;
+
+ RenderPass::Id rootPassId(1, 0);
+ TestRenderPass* rootPass = addRenderPass(renderPasses, rootPassId, viewportRect, gfx::Transform());
+ addQuad(rootPass, viewportRect, SK_ColorGREEN);
+
+ RenderPass::Id childPassId(2, 0);
+ TestRenderPass* childPass = addRenderPass(renderPasses, childPassId, viewportRect, gfx::Transform());
+ addQuad(childPass, viewportRect, SK_ColorBLUE);
+
+ addRenderPassQuad(rootPass, childPass);
+
+ mockClient.renderPassesInDrawOrder().clear();
+ mockClient.renderPassesInDrawOrder().push_back(childPass);
+ mockClient.renderPassesInDrawOrder().push_back(rootPass);
+ mockClient.renderPasses().set(rootPassId, renderPasses.take(0));
+ mockClient.renderPasses().set(childPassId, renderPasses.take(1));
+
+ // First render pass is not the root one, clearing should happen.
+ EXPECT_CALL(*mockContext, clear(GL_COLOR_BUFFER_BIT))
+ .Times(AtLeast(1));
+
+ Expectation firstRenderPass = EXPECT_CALL(*mockContext, drawElements(_, _, _, _))
+ .Times(1);
+
+ // The second render pass is the root one, clearing should be prevented.
+ EXPECT_CALL(*mockContext, clear(GL_COLOR_BUFFER_BIT))
+ .Times(0)
+ .After(firstRenderPass);
+
+ EXPECT_CALL(*mockContext, drawElements(_, _, _, _))
+ .Times(AnyNumber())
+ .After(firstRenderPass);
+
+ renderer.decideRenderPassAllocationsForFrame(mockClient.renderPassesInDrawOrder());
+ renderer.drawFrame(mockClient.renderPassesInDrawOrder(), mockClient.renderPasses());
+
+ // In multiple render passes all but the root pass should clear the framebuffer.
+ Mock::VerifyAndClearExpectations(&mockContext);
+}
+
} // namespace
} // namespace cc
diff --git a/cc/layer_tree_host_impl.cc b/cc/layer_tree_host_impl.cc
index 89ebdde..8ac47bc 100644
--- a/cc/layer_tree_host_impl.cc
+++ b/cc/layer_tree_host_impl.cc
@@ -829,6 +829,11 @@ void LayerTreeHostImpl::ScheduleCheckForCompletedSetPixels()
m_client->setNeedsRedrawOnImplThread();
}
+bool LayerTreeHostImpl::shouldClearRootRenderPass() const
+{
+ return m_settings.shouldClearRootRenderPass;
+}
+
void LayerTreeHostImpl::setManagedMemoryPolicy(const ManagedMemoryPolicy& policy)
{
if (m_managedMemoryPolicy == policy)
diff --git a/cc/layer_tree_host_impl.h b/cc/layer_tree_host_impl.h
index f591080..9943da2 100644
--- a/cc/layer_tree_host_impl.h
+++ b/cc/layer_tree_host_impl.h
@@ -170,6 +170,7 @@ public:
virtual void setManagedMemoryPolicy(const ManagedMemoryPolicy& policy) OVERRIDE;
virtual void enforceManagedMemoryPolicy(const ManagedMemoryPolicy& policy) OVERRIDE;
virtual bool hasImplThread() const OVERRIDE;
+ virtual bool shouldClearRootRenderPass() const OVERRIDE;
// TileManagerClient implementation.
virtual void ScheduleManageTiles() OVERRIDE;
diff --git a/cc/layer_tree_host_impl_unittest.cc b/cc/layer_tree_host_impl_unittest.cc
index a2846b5..8f52e9d 100644
--- a/cc/layer_tree_host_impl_unittest.cc
+++ b/cc/layer_tree_host_impl_unittest.cc
@@ -4228,6 +4228,7 @@ public:
virtual void setManagedMemoryPolicy(const ManagedMemoryPolicy& policy) OVERRIDE { }
virtual void enforceManagedMemoryPolicy(const ManagedMemoryPolicy& policy) OVERRIDE { }
virtual bool hasImplThread() const OVERRIDE { return false; }
+ virtual bool shouldClearRootRenderPass() const OVERRIDE { return true; }
protected:
TestRenderer(ResourceProvider* resourceProvider, Proxy* proxy) : GLRenderer(this, resourceProvider) { }
diff --git a/cc/layer_tree_settings.cc b/cc/layer_tree_settings.cc
index 27723fc..4ef2b7b 100644
--- a/cc/layer_tree_settings.cc
+++ b/cc/layer_tree_settings.cc
@@ -24,6 +24,7 @@ LayerTreeSettings::LayerTreeSettings()
, backgroundColorInsteadOfCheckerboard(false)
, showOverdrawInTracing(false)
, canUseLCDText(true)
+ , shouldClearRootRenderPass(true)
, refreshRate(0)
, maxPartialTextureUpdates(std::numeric_limits<size_t>::max())
, numRasterThreads(1)
diff --git a/cc/layer_tree_settings.h b/cc/layer_tree_settings.h
index e10e0d3..e5ca724 100644
--- a/cc/layer_tree_settings.h
+++ b/cc/layer_tree_settings.h
@@ -27,6 +27,7 @@ class CC_EXPORT LayerTreeSettings {
bool backgroundColorInsteadOfCheckerboard;
bool showOverdrawInTracing;
bool canUseLCDText;
+ bool shouldClearRootRenderPass;
double refreshRate;
size_t maxPartialTextureUpdates;
size_t numRasterThreads;
diff --git a/cc/renderer.h b/cc/renderer.h
index 87346aa..2adf7c0 100644
--- a/cc/renderer.h
+++ b/cc/renderer.h
@@ -26,6 +26,7 @@ public:
virtual void setManagedMemoryPolicy(const ManagedMemoryPolicy& policy) = 0;
virtual void enforceManagedMemoryPolicy(const ManagedMemoryPolicy& policy) = 0;
virtual bool hasImplThread() const = 0;
+ virtual bool shouldClearRootRenderPass() const = 0;
protected:
virtual ~RendererClient() { }
};
@@ -38,9 +39,9 @@ public:
const LayerTreeSettings& settings() const { return m_client->settings(); }
- gfx::Size viewportSize() { return m_client->deviceViewportSize(); }
- int viewportWidth() { return viewportSize().width(); }
- int viewportHeight() { return viewportSize().height(); }
+ gfx::Size viewportSize() const { return m_client->deviceViewportSize(); }
+ int viewportWidth() const { return viewportSize().width(); }
+ int viewportHeight() const { return viewportSize().height(); }
virtual void viewportChanged() { }
virtual void receiveCompositorFrameAck(const CompositorFrameAck&) { }
diff --git a/cc/software_renderer_unittest.cc b/cc/software_renderer_unittest.cc
index 529d9c7..f61a7e3 100644
--- a/cc/software_renderer_unittest.cc
+++ b/cc/software_renderer_unittest.cc
@@ -13,6 +13,7 @@
#include "cc/test/fake_software_output_device.h"
#include "cc/test/geometry_test_utils.h"
#include "cc/test/render_pass_test_common.h"
+#include "cc/test/render_pass_test_utils.h"
#include "cc/tile_draw_quad.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -25,6 +26,11 @@ namespace {
class SoftwareRendererTest : public testing::Test, public RendererClient {
public:
+ SoftwareRendererTest()
+ : m_shouldClearRootRenderPass(true)
+ {
+ }
+
void initializeRenderer() {
m_outputSurface = FakeOutputSurface::CreateSoftware(scoped_ptr<SoftwareOutputDevice>(new FakeSoftwareOutputDevice));
m_resourceProvider = ResourceProvider::create(m_outputSurface.get());
@@ -35,7 +41,8 @@ public:
FakeOutputSurface* outputSurface() const { return m_outputSurface.get(); }
ResourceProvider* resourceProvider() const { return m_resourceProvider.get(); }
SoftwareRenderer* renderer() const { return m_renderer.get(); }
- void setViewportSize(gfx::Size viewportSize) { m_viewportSize = viewportSize; }
+ void setViewportSize(const gfx::Size& viewportSize) { m_viewportSize = viewportSize; }
+ void setShouldClearRootRenderPass(bool clearRootRenderPass) { m_shouldClearRootRenderPass = clearRootRenderPass; }
// RendererClient implementation.
virtual const gfx::Size& deviceViewportSize() const OVERRIDE { return m_viewportSize; }
@@ -46,6 +53,7 @@ public:
virtual void setManagedMemoryPolicy(const ManagedMemoryPolicy& policy) OVERRIDE { };
virtual void enforceManagedMemoryPolicy(const ManagedMemoryPolicy& policy) OVERRIDE { };
virtual bool hasImplThread() const OVERRIDE { return false; }
+ virtual bool shouldClearRootRenderPass() const OVERRIDE { return m_shouldClearRootRenderPass; }
protected:
scoped_ptr<FakeOutputSurface> m_outputSurface;
@@ -53,6 +61,7 @@ protected:
scoped_ptr<SoftwareRenderer> m_renderer;
gfx::Size m_viewportSize;
LayerTreeSettings m_settings;
+ bool m_shouldClearRootRenderPass;
};
TEST_F(SoftwareRendererTest, solidColorQuad)
@@ -154,5 +163,59 @@ TEST_F(SoftwareRendererTest, tileQuad)
EXPECT_EQ(SK_ColorCYAN, pixels[outerPixels - outerSize.width() - 2]);
}
+TEST_F(SoftwareRendererTest, shouldClearRootRenderPass)
+{
+ gfx::Rect viewportRect(gfx::Size(100, 100));
+ size_t viewportPixels = viewportRect.width() * viewportRect.height();
+ setViewportSize(viewportRect.size());
+ setShouldClearRootRenderPass(false);
+ initializeRenderer();
+
+ RenderPassList list;
+ RenderPassIdHashMap hashmap;
+ ScopedPtrVector<RenderPass> renderPasses;
+ scoped_array<SkColor> pixels(new SkColor[viewportPixels]);
+
+ // Draw a fullscreen green quad in a first frame.
+ RenderPass::Id rootClearPassId(1, 0);
+ TestRenderPass* rootClearPass = addRenderPass(renderPasses, rootClearPassId, viewportRect, gfx::Transform());
+ addQuad(rootClearPass, viewportRect, SK_ColorGREEN);
+
+ list.push_back(rootClearPass);
+ hashmap.set(rootClearPassId, renderPasses.take(0));
+
+ renderer()->decideRenderPassAllocationsForFrame(list);
+ renderer()->drawFrame(list, hashmap);
+ renderer()->getFramebufferPixels(pixels.get(), viewportRect);
+
+ EXPECT_EQ(SK_ColorGREEN, pixels[0]);
+ EXPECT_EQ(SK_ColorGREEN, pixels[viewportPixels - 1]);
+
+ renderPasses.clear();
+ hashmap.clear();
+ list.clear();
+
+ // Draw a smaller magenta rect without filling the viewport in a separate frame.
+ gfx::Rect smallerRect(20, 20, 60, 60);
+
+ RenderPass::Id rootSmallerPassId(2, 0);
+ TestRenderPass* rootSmallerPass = addRenderPass(renderPasses, rootSmallerPassId, viewportRect, gfx::Transform());
+ addQuad(rootSmallerPass, smallerRect, SK_ColorMAGENTA);
+
+ list.push_back(rootSmallerPass);
+ hashmap.set(rootSmallerPassId, renderPasses.take(0));
+
+ renderer()->decideRenderPassAllocationsForFrame(list);
+ renderer()->drawFrame(list, hashmap);
+ renderer()->getFramebufferPixels(pixels.get(), viewportRect);
+
+ // If we didn't clear, the borders should still be green.
+ EXPECT_EQ(SK_ColorGREEN, pixels[0]);
+ EXPECT_EQ(SK_ColorGREEN, pixels[viewportPixels - 1]);
+
+ EXPECT_EQ(SK_ColorMAGENTA, pixels[smallerRect.y() * viewportRect.width() + smallerRect.x()]);
+ EXPECT_EQ(SK_ColorMAGENTA, pixels[(smallerRect.bottom() - 1) * viewportRect.width() + smallerRect.right() - 1]);
+}
+
} // namespace
} // namespace cc
diff --git a/cc/test/render_pass_test_utils.cc b/cc/test/render_pass_test_utils.cc
new file mode 100644
index 0000000..579bc1e
--- /dev/null
+++ b/cc/test/render_pass_test_utils.cc
@@ -0,0 +1,61 @@
+// Copyright 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "cc/test/render_pass_test_utils.h"
+
+#include "cc/append_quads_data.h"
+#include "cc/quad_sink.h"
+#include "cc/render_pass_draw_quad.h"
+#include "cc/shared_quad_state.h"
+#include "cc/solid_color_draw_quad.h"
+#include "cc/test/mock_quad_culler.h"
+#include "cc/test/render_pass_test_common.h"
+#include "ui/gfx/rect.h"
+
+using WebKitTests::TestRenderPass;
+
+namespace cc {
+
+TestRenderPass* addRenderPass(ScopedPtrVector<RenderPass>& passList,
+ RenderPass::Id id,
+ const gfx::Rect& outputRect,
+ const gfx::Transform& rootTransform) {
+ scoped_ptr<TestRenderPass> pass(TestRenderPass::Create());
+ pass->SetNew(id, outputRect, outputRect, rootTransform);
+ TestRenderPass* saved = pass.get();
+ passList.append(pass.PassAs<RenderPass>());
+ return saved;
+}
+
+SolidColorDrawQuad* addQuad(TestRenderPass* pass,
+ const gfx::Rect& rect,
+ SkColor color) {
+ MockQuadCuller quadSink(pass->quad_list, pass->shared_quad_state_list);
+ AppendQuadsData data(pass->id);
+ SharedQuadState* sharedState =
+ quadSink.useSharedQuadState(SharedQuadState::Create());
+ sharedState->SetAll(gfx::Transform(), rect, rect, rect, false, 1);
+ scoped_ptr<SolidColorDrawQuad> quad = SolidColorDrawQuad::Create();
+ quad->SetNew(sharedState, rect, color);
+ SolidColorDrawQuad* quadPtr = quad.get();
+ quadSink.append(quad.PassAs<DrawQuad>(), data);
+ return quadPtr;
+}
+
+void addRenderPassQuad(TestRenderPass* toPass,
+ TestRenderPass* contributingPass) {
+ MockQuadCuller quadSink(toPass->quad_list, toPass->shared_quad_state_list);
+ AppendQuadsData data(toPass->id);
+ gfx::Rect outputRect = contributingPass->output_rect;
+ SharedQuadState* sharedState =
+ quadSink.useSharedQuadState(SharedQuadState::Create());
+ sharedState->SetAll(gfx::Transform(), outputRect, outputRect, outputRect,
+ false, 1);
+ scoped_ptr<RenderPassDrawQuad> quad = RenderPassDrawQuad::Create();
+ quad->SetNew(sharedState, outputRect, contributingPass->id, false, 0,
+ outputRect, gfx::RectF());
+ quadSink.append(quad.PassAs<DrawQuad>(), data);
+}
+
+} // namespace cc
diff --git a/cc/test/render_pass_test_utils.h b/cc/test/render_pass_test_utils.h
new file mode 100644
index 0000000..c06fbd6
--- /dev/null
+++ b/cc/test/render_pass_test_utils.h
@@ -0,0 +1,44 @@
+// Copyright 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CC_TEST_RENDER_PASS_TEST_UTILS_H_
+#define CC_TEST_RENDER_PASS_TEST_UTILS_H_
+
+#include "cc/render_pass.h"
+#include "cc/scoped_ptr_vector.h"
+#include "third_party/skia/include/core/SkColor.h"
+
+namespace gfx {
+class Rect;
+class Transform;
+}
+
+namespace WebKitTests {
+class TestRenderPass;
+}
+
+namespace cc {
+
+class SolidColorDrawQuad;
+
+// Adds a new render pass with the provided properties to the given
+// render pass list.
+WebKitTests::TestRenderPass* addRenderPass(
+ ScopedPtrVector<RenderPass>& passList,
+ RenderPass::Id id,
+ const gfx::Rect& outputRect,
+ const gfx::Transform& rootTransform);
+
+// Adds a solid quad to a given render pass.
+SolidColorDrawQuad* addQuad(WebKitTests::TestRenderPass* pass,
+ const gfx::Rect& rect,
+ SkColor color);
+
+// Adds a render pass quad to an existing render pass.
+void addRenderPassQuad(WebKitTests::TestRenderPass* toPass,
+ WebKitTests::TestRenderPass* contributingPass);
+
+} // namespace cc
+
+#endif // CC_TEST_RENDER_PASS_TEST_UTILS_H_
diff --git a/content/browser/renderer_host/compositor_impl_android.cc b/content/browser/renderer_host/compositor_impl_android.cc
index 1d6bd2f..a4b9534 100644
--- a/content/browser/renderer_host/compositor_impl_android.cc
+++ b/content/browser/renderer_host/compositor_impl_android.cc
@@ -123,6 +123,7 @@ bool CompositorImpl::UsesDirectGL() {
CompositorImpl::CompositorImpl(Compositor::Client* client)
: root_layer_(cc::Layer::create()),
+ has_transparent_background_(false),
window_(NULL),
surface_id_(0),
client_(client),
@@ -172,6 +173,11 @@ void CompositorImpl::SetVisible(bool visible) {
cc::LayerTreeSettings settings;
settings.refreshRate = 60.0;
+ // Do not clear the framebuffer when rendering into external GL contexts
+ // like Android View System's.
+ if (UsesDirectGL())
+ settings.shouldClearRootRenderPass = false;
+
scoped_ptr<cc::Thread> impl_thread;
if (g_impl_thread)
impl_thread = cc::ThreadImpl::createForDifferentThread(
@@ -183,6 +189,7 @@ void CompositorImpl::SetVisible(bool visible) {
host_->setVisible(true);
host_->setSurfaceReady();
host_->setViewportSize(size_, size_);
+ host_->setHasTransparentBackground(has_transparent_background_);
}
}
@@ -196,6 +203,12 @@ void CompositorImpl::SetWindowBounds(const gfx::Size& size) {
root_layer_->setBounds(size);
}
+void CompositorImpl::SetHasTransparentBackground(bool flag) {
+ has_transparent_background_ = flag;
+ if (host_.get())
+ host_->setHasTransparentBackground(flag);
+}
+
bool CompositorImpl::CompositeAndReadback(void *pixels, const gfx::Rect& rect) {
if (host_.get())
return host_->compositeAndReadback(pixels, rect);
diff --git a/content/browser/renderer_host/compositor_impl_android.h b/content/browser/renderer_host/compositor_impl_android.h
index 1514fcf51..9ce37a4 100644
--- a/content/browser/renderer_host/compositor_impl_android.h
+++ b/content/browser/renderer_host/compositor_impl_android.h
@@ -48,6 +48,7 @@ class CONTENT_EXPORT CompositorImpl
virtual void SetWindowSurface(ANativeWindow* window) OVERRIDE;
virtual void SetVisible(bool visible) OVERRIDE;
virtual void SetWindowBounds(const gfx::Size& size) OVERRIDE;
+ virtual void SetHasTransparentBackground(bool flag) OVERRIDE;
virtual bool CompositeAndReadback(
void *pixels, const gfx::Rect& rect) OVERRIDE;
virtual void Composite() OVERRIDE;
@@ -89,6 +90,7 @@ class CONTENT_EXPORT CompositorImpl
scoped_ptr<cc::LayerTreeHost> host_;
gfx::Size size_;
+ bool has_transparent_background_;
ANativeWindow* window_;
int surface_id_;
diff --git a/content/public/browser/android/compositor.h b/content/public/browser/android/compositor.h
index bca7fe7..d0f98c2 100644
--- a/content/public/browser/android/compositor.h
+++ b/content/public/browser/android/compositor.h
@@ -71,6 +71,9 @@ class CONTENT_EXPORT Compositor {
// Set the output surface handle which the compositor renders into.
virtual void SetWindowSurface(ANativeWindow* window) = 0;
+ // Tells the view tree to assume a transparent background when rendering.
+ virtual void SetHasTransparentBackground(bool flag) = 0;
+
// Attempts to composite and read back the result into the provided buffer.
// The buffer must be at least window width * height * 4 (RGBA) bytes large.
// The buffer is not modified if false is returned.