Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(320)

Unified Diff: cc/output/gl_renderer_unittest.cc

Issue 1531403002: Revert "Delete CC." (Closed) Base URL: https://github.com/domokit/mojo.git@master
Patch Set: Created 5 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « cc/output/gl_renderer_draw_cache.cc ('k') | cc/output/output_surface.h » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: cc/output/gl_renderer_unittest.cc
diff --git a/cc/output/gl_renderer_unittest.cc b/cc/output/gl_renderer_unittest.cc
new file mode 100644
index 0000000000000000000000000000000000000000..7e0f8e0f5c1a92a8c787a90898e843717475e7df
--- /dev/null
+++ b/cc/output/gl_renderer_unittest.cc
@@ -0,0 +1,2076 @@
+// 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/output/gl_renderer.h"
+
+#include <set>
+
+#include "cc/base/math_util.h"
+#include "cc/output/compositor_frame_metadata.h"
+#include "cc/resources/resource_provider.h"
+#include "cc/test/fake_impl_proxy.h"
+#include "cc/test/fake_layer_tree_host_impl.h"
+#include "cc/test/fake_output_surface.h"
+#include "cc/test/fake_output_surface_client.h"
+#include "cc/test/fake_renderer_client.h"
+#include "cc/test/pixel_test.h"
+#include "cc/test/render_pass_test_common.h"
+#include "cc/test/render_pass_test_utils.h"
+#include "cc/test/test_shared_bitmap_manager.h"
+#include "cc/test/test_web_graphics_context_3d.h"
+#include "gpu/GLES2/gl2extchromium.h"
+#include "gpu/command_buffer/client/context_support.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/skia/include/core/SkImageFilter.h"
+#include "third_party/skia/include/core/SkMatrix.h"
+#include "third_party/skia/include/effects/SkColorFilterImageFilter.h"
+#include "third_party/skia/include/effects/SkColorMatrixFilter.h"
+#include "ui/gfx/transform.h"
+
+using testing::_;
+using testing::AnyNumber;
+using testing::Args;
+using testing::AtLeast;
+using testing::ElementsAre;
+using testing::Expectation;
+using testing::InSequence;
+using testing::Mock;
+using testing::Return;
+using testing::StrictMock;
+
+namespace cc {
+
+class GLRendererTest : public testing::Test {
+ protected:
+ RenderPass* root_render_pass() { return render_passes_in_draw_order_.back(); }
+
+ RenderPassList render_passes_in_draw_order_;
+};
+
+#define EXPECT_PROGRAM_VALID(program_binding) \
+ do { \
+ EXPECT_TRUE((program_binding)->program()); \
+ EXPECT_TRUE((program_binding)->initialized()); \
+ } while (false)
+
+static inline SkXfermode::Mode BlendModeToSkXfermode(BlendMode blend_mode) {
+ switch (blend_mode) {
+ case BLEND_MODE_NONE:
+ case BLEND_MODE_NORMAL:
+ return SkXfermode::kSrcOver_Mode;
+ case BLEND_MODE_SCREEN:
+ return SkXfermode::kScreen_Mode;
+ case BLEND_MODE_OVERLAY:
+ return SkXfermode::kOverlay_Mode;
+ case BLEND_MODE_DARKEN:
+ return SkXfermode::kDarken_Mode;
+ case BLEND_MODE_LIGHTEN:
+ return SkXfermode::kLighten_Mode;
+ case BLEND_MODE_COLOR_DODGE:
+ return SkXfermode::kColorDodge_Mode;
+ case BLEND_MODE_COLOR_BURN:
+ return SkXfermode::kColorBurn_Mode;
+ case BLEND_MODE_HARD_LIGHT:
+ return SkXfermode::kHardLight_Mode;
+ case BLEND_MODE_SOFT_LIGHT:
+ return SkXfermode::kSoftLight_Mode;
+ case BLEND_MODE_DIFFERENCE:
+ return SkXfermode::kDifference_Mode;
+ case BLEND_MODE_EXCLUSION:
+ return SkXfermode::kExclusion_Mode;
+ case BLEND_MODE_MULTIPLY:
+ return SkXfermode::kMultiply_Mode;
+ case BLEND_MODE_HUE:
+ return SkXfermode::kHue_Mode;
+ case BLEND_MODE_SATURATION:
+ return SkXfermode::kSaturation_Mode;
+ case BLEND_MODE_COLOR:
+ return SkXfermode::kColor_Mode;
+ case BLEND_MODE_LUMINOSITY:
+ return SkXfermode::kLuminosity_Mode;
+ }
+ return SkXfermode::kSrcOver_Mode;
+}
+
+// Explicitly named to be a friend in GLRenderer for shader access.
+class GLRendererShaderPixelTest : public GLRendererPixelTest {
+ public:
+ void SetUp() override {
+ GLRendererPixelTest::SetUp();
+ ASSERT_FALSE(renderer()->IsContextLost());
+ }
+
+ void TearDown() override {
+ GLRendererPixelTest::TearDown();
+ ASSERT_FALSE(renderer()->IsContextLost());
+ }
+
+ void TestBasicShaders() {
+ EXPECT_PROGRAM_VALID(renderer()->GetTileCheckerboardProgram());
+ EXPECT_PROGRAM_VALID(renderer()->GetDebugBorderProgram());
+ EXPECT_PROGRAM_VALID(renderer()->GetSolidColorProgram());
+ EXPECT_PROGRAM_VALID(renderer()->GetSolidColorProgramAA());
+ }
+
+ void TestShadersWithPrecision(TexCoordPrecision precision) {
+ EXPECT_PROGRAM_VALID(renderer()->GetTextureProgram(precision));
+ EXPECT_PROGRAM_VALID(
+ renderer()->GetNonPremultipliedTextureProgram(precision));
+ EXPECT_PROGRAM_VALID(renderer()->GetTextureBackgroundProgram(precision));
+ EXPECT_PROGRAM_VALID(
+ renderer()->GetNonPremultipliedTextureBackgroundProgram(precision));
+ EXPECT_PROGRAM_VALID(renderer()->GetTextureIOSurfaceProgram(precision));
+ EXPECT_PROGRAM_VALID(renderer()->GetVideoYUVProgram(precision));
+ EXPECT_PROGRAM_VALID(renderer()->GetVideoYUVAProgram(precision));
+ if (renderer()->Capabilities().using_egl_image)
+ EXPECT_PROGRAM_VALID(renderer()->GetVideoStreamTextureProgram(precision));
+ else
+ EXPECT_FALSE(renderer()->GetVideoStreamTextureProgram(precision));
+ }
+
+ void TestShadersWithPrecisionAndBlend(TexCoordPrecision precision,
+ BlendMode blend_mode) {
+ EXPECT_PROGRAM_VALID(
+ renderer()->GetRenderPassProgram(precision, blend_mode));
+ EXPECT_PROGRAM_VALID(
+ renderer()->GetRenderPassProgramAA(precision, blend_mode));
+ }
+
+ void TestShadersWithPrecisionAndSampler(TexCoordPrecision precision,
+ SamplerType sampler) {
+ if (!renderer()->Capabilities().using_egl_image &&
+ sampler == SAMPLER_TYPE_EXTERNAL_OES) {
+ // This will likely be hit in tests due to usage of osmesa.
+ return;
+ }
+
+ EXPECT_PROGRAM_VALID(renderer()->GetTileProgram(precision, sampler));
+ EXPECT_PROGRAM_VALID(renderer()->GetTileProgramOpaque(precision, sampler));
+ EXPECT_PROGRAM_VALID(renderer()->GetTileProgramAA(precision, sampler));
+ EXPECT_PROGRAM_VALID(renderer()->GetTileProgramSwizzle(precision, sampler));
+ EXPECT_PROGRAM_VALID(
+ renderer()->GetTileProgramSwizzleOpaque(precision, sampler));
+ EXPECT_PROGRAM_VALID(
+ renderer()->GetTileProgramSwizzleAA(precision, sampler));
+ }
+
+ void TestShadersWithMasks(TexCoordPrecision precision,
+ SamplerType sampler,
+ BlendMode blend_mode,
+ bool mask_for_background) {
+ if (!renderer()->Capabilities().using_egl_image &&
+ sampler == SAMPLER_TYPE_EXTERNAL_OES) {
+ // This will likely be hit in tests due to usage of osmesa.
+ return;
+ }
+
+ EXPECT_PROGRAM_VALID(renderer()->GetRenderPassMaskProgram(
+ precision, sampler, blend_mode, mask_for_background));
+ EXPECT_PROGRAM_VALID(renderer()->GetRenderPassMaskProgramAA(
+ precision, sampler, blend_mode, mask_for_background));
+ EXPECT_PROGRAM_VALID(renderer()->GetRenderPassMaskColorMatrixProgramAA(
+ precision, sampler, blend_mode, mask_for_background));
+ EXPECT_PROGRAM_VALID(renderer()->GetRenderPassMaskColorMatrixProgram(
+ precision, sampler, blend_mode, mask_for_background));
+ }
+};
+
+namespace {
+
+#if !defined(OS_ANDROID) && !defined(OS_WIN)
+static const TexCoordPrecision kPrecisionList[] = {TEX_COORD_PRECISION_MEDIUM,
+ TEX_COORD_PRECISION_HIGH};
+
+static const BlendMode kBlendModeList[LAST_BLEND_MODE + 1] = {
+ BLEND_MODE_NONE,
+ BLEND_MODE_NORMAL,
+ BLEND_MODE_SCREEN,
+ BLEND_MODE_OVERLAY,
+ BLEND_MODE_DARKEN,
+ BLEND_MODE_LIGHTEN,
+ BLEND_MODE_COLOR_DODGE,
+ BLEND_MODE_COLOR_BURN,
+ BLEND_MODE_HARD_LIGHT,
+ BLEND_MODE_SOFT_LIGHT,
+ BLEND_MODE_DIFFERENCE,
+ BLEND_MODE_EXCLUSION,
+ BLEND_MODE_MULTIPLY,
+ BLEND_MODE_HUE,
+ BLEND_MODE_SATURATION,
+ BLEND_MODE_COLOR,
+ BLEND_MODE_LUMINOSITY,
+};
+
+static const SamplerType kSamplerList[] = {
+ SAMPLER_TYPE_2D,
+ SAMPLER_TYPE_2D_RECT,
+ SAMPLER_TYPE_EXTERNAL_OES,
+};
+
+TEST_F(GLRendererShaderPixelTest, BasicShadersCompile) {
+ TestBasicShaders();
+}
+
+class PrecisionShaderPixelTest
+ : public GLRendererShaderPixelTest,
+ public ::testing::WithParamInterface<TexCoordPrecision> {};
+
+TEST_P(PrecisionShaderPixelTest, ShadersCompile) {
+ TestShadersWithPrecision(GetParam());
+}
+
+INSTANTIATE_TEST_CASE_P(PrecisionShadersCompile,
+ PrecisionShaderPixelTest,
+ ::testing::ValuesIn(kPrecisionList));
+
+class PrecisionBlendShaderPixelTest
+ : public GLRendererShaderPixelTest,
+ public ::testing::WithParamInterface<
+ std::tr1::tuple<TexCoordPrecision, BlendMode>> {};
+
+TEST_P(PrecisionBlendShaderPixelTest, ShadersCompile) {
+ TestShadersWithPrecisionAndBlend(std::tr1::get<0>(GetParam()),
+ std::tr1::get<1>(GetParam()));
+}
+
+INSTANTIATE_TEST_CASE_P(
+ PrecisionBlendShadersCompile,
+ PrecisionBlendShaderPixelTest,
+ ::testing::Combine(::testing::ValuesIn(kPrecisionList),
+ ::testing::ValuesIn(kBlendModeList)));
+
+class PrecisionSamplerShaderPixelTest
+ : public GLRendererShaderPixelTest,
+ public ::testing::WithParamInterface<
+ std::tr1::tuple<TexCoordPrecision, SamplerType>> {};
+
+TEST_P(PrecisionSamplerShaderPixelTest, ShadersCompile) {
+ TestShadersWithPrecisionAndSampler(std::tr1::get<0>(GetParam()),
+ std::tr1::get<1>(GetParam()));
+}
+
+INSTANTIATE_TEST_CASE_P(PrecisionSamplerShadersCompile,
+ PrecisionSamplerShaderPixelTest,
+ ::testing::Combine(::testing::ValuesIn(kPrecisionList),
+ ::testing::ValuesIn(kSamplerList)));
+
+class MaskShaderPixelTest
+ : public GLRendererShaderPixelTest,
+ public ::testing::WithParamInterface<
+ std::tr1::tuple<TexCoordPrecision, SamplerType, BlendMode, bool>> {};
+
+TEST_P(MaskShaderPixelTest, ShadersCompile) {
+ TestShadersWithMasks(
+ std::tr1::get<0>(GetParam()), std::tr1::get<1>(GetParam()),
+ std::tr1::get<2>(GetParam()), std::tr1::get<3>(GetParam()));
+}
+
+INSTANTIATE_TEST_CASE_P(MaskShadersCompile,
+ MaskShaderPixelTest,
+ ::testing::Combine(::testing::ValuesIn(kPrecisionList),
+ ::testing::ValuesIn(kSamplerList),
+ ::testing::ValuesIn(kBlendModeList),
+ ::testing::Bool()));
+
+#endif
+
+class FakeRendererGL : public GLRenderer {
+ public:
+ FakeRendererGL(RendererClient* client,
+ const RendererSettings* settings,
+ OutputSurface* output_surface,
+ ResourceProvider* resource_provider)
+ : GLRenderer(client,
+ settings,
+ output_surface,
+ resource_provider,
+ NULL,
+ 0) {}
+
+ // GLRenderer methods.
+
+ // Changing visibility to public.
+ using GLRenderer::IsBackbufferDiscarded;
+ using GLRenderer::DoDrawQuad;
+ using GLRenderer::BeginDrawingFrame;
+ using GLRenderer::FinishDrawingQuadList;
+ using GLRenderer::stencil_enabled;
+};
+
+class GLRendererWithDefaultHarnessTest : public GLRendererTest {
+ protected:
+ GLRendererWithDefaultHarnessTest() {
+ output_surface_ =
+ FakeOutputSurface::Create3d(TestWebGraphicsContext3D::Create()).Pass();
+ CHECK(output_surface_->BindToClient(&output_surface_client_));
+
+ shared_bitmap_manager_.reset(new TestSharedBitmapManager());
+ resource_provider_ = ResourceProvider::Create(output_surface_.get(),
+ shared_bitmap_manager_.get(),
+ NULL,
+ NULL,
+ 0,
+ false,
+ 1).Pass();
+ renderer_ = make_scoped_ptr(new FakeRendererGL(&renderer_client_,
+ &settings_,
+ output_surface_.get(),
+ resource_provider_.get()));
+ }
+
+ void SwapBuffers() { renderer_->SwapBuffers(CompositorFrameMetadata()); }
+
+ RendererSettings settings_;
+ FakeOutputSurfaceClient output_surface_client_;
+ scoped_ptr<FakeOutputSurface> output_surface_;
+ FakeRendererClient renderer_client_;
+ scoped_ptr<SharedBitmapManager> shared_bitmap_manager_;
+ scoped_ptr<ResourceProvider> resource_provider_;
+ scoped_ptr<FakeRendererGL> renderer_;
+};
+
+// Closing the namespace here so that GLRendererShaderTest can take advantage
+// of the friend relationship with GLRenderer and all of the mock classes
+// declared above it.
+} // namespace
+
+class GLRendererShaderTest : public GLRendererTest {
+ protected:
+ GLRendererShaderTest() {
+ output_surface_ = FakeOutputSurface::Create3d().Pass();
+ CHECK(output_surface_->BindToClient(&output_surface_client_));
+
+ shared_bitmap_manager_.reset(new TestSharedBitmapManager());
+ resource_provider_ = ResourceProvider::Create(output_surface_.get(),
+ shared_bitmap_manager_.get(),
+ NULL,
+ NULL,
+ 0,
+ false,
+ 1).Pass();
+ renderer_.reset(new FakeRendererGL(&renderer_client_,
+ &settings_,
+ output_surface_.get(),
+ resource_provider_.get()));
+ }
+
+ void TestRenderPassProgram(TexCoordPrecision precision,
+ BlendMode blend_mode) {
+ EXPECT_PROGRAM_VALID(
+ &renderer_->render_pass_program_[precision][blend_mode]);
+ EXPECT_EQ(renderer_->render_pass_program_[precision][blend_mode].program(),
+ renderer_->program_shadow_);
+ }
+
+ void TestRenderPassColorMatrixProgram(TexCoordPrecision precision,
+ BlendMode blend_mode) {
+ EXPECT_PROGRAM_VALID(
+ &renderer_->render_pass_color_matrix_program_[precision][blend_mode]);
+ EXPECT_EQ(
+ renderer_->render_pass_color_matrix_program_[precision][blend_mode]
+ .program(),
+ renderer_->program_shadow_);
+ }
+
+ void TestRenderPassMaskProgram(TexCoordPrecision precision,
+ SamplerType sampler,
+ BlendMode blend_mode) {
+ EXPECT_PROGRAM_VALID(
+ &renderer_->render_pass_mask_program_[precision]
+ [sampler]
+ [blend_mode]
+ [NO_MASK]);
+ EXPECT_EQ(
+ renderer_->render_pass_mask_program_[precision]
+ [sampler]
+ [blend_mode]
+ [NO_MASK].program(),
+ renderer_->program_shadow_);
+ }
+
+ void TestRenderPassMaskColorMatrixProgram(TexCoordPrecision precision,
+ SamplerType sampler,
+ BlendMode blend_mode) {
+ EXPECT_PROGRAM_VALID(&renderer_->render_pass_mask_color_matrix_program_
+ [precision][sampler][blend_mode][NO_MASK]);
+ EXPECT_EQ(renderer_->render_pass_mask_color_matrix_program_
+ [precision][sampler][blend_mode][NO_MASK].program(),
+ renderer_->program_shadow_);
+ }
+
+ void TestRenderPassProgramAA(TexCoordPrecision precision,
+ BlendMode blend_mode) {
+ EXPECT_PROGRAM_VALID(
+ &renderer_->render_pass_program_aa_[precision][blend_mode]);
+ EXPECT_EQ(
+ renderer_->render_pass_program_aa_[precision][blend_mode].program(),
+ renderer_->program_shadow_);
+ }
+
+ void TestRenderPassColorMatrixProgramAA(TexCoordPrecision precision,
+ BlendMode blend_mode) {
+ EXPECT_PROGRAM_VALID(
+ &renderer_
+ ->render_pass_color_matrix_program_aa_[precision][blend_mode]);
+ EXPECT_EQ(
+ renderer_->render_pass_color_matrix_program_aa_[precision][blend_mode]
+ .program(),
+ renderer_->program_shadow_);
+ }
+
+ void TestRenderPassMaskProgramAA(TexCoordPrecision precision,
+ SamplerType sampler,
+ BlendMode blend_mode) {
+ EXPECT_PROGRAM_VALID(
+ &renderer_
+ ->render_pass_mask_program_aa_
+ [precision][sampler][blend_mode][NO_MASK]);
+ EXPECT_EQ(
+ renderer_->render_pass_mask_program_aa_[precision][sampler][blend_mode]
+ [NO_MASK].program(),
+ renderer_->program_shadow_);
+ }
+
+ void TestRenderPassMaskColorMatrixProgramAA(TexCoordPrecision precision,
+ SamplerType sampler,
+ BlendMode blend_mode) {
+ EXPECT_PROGRAM_VALID(&renderer_->render_pass_mask_color_matrix_program_aa_
+ [precision][sampler][blend_mode][NO_MASK]);
+ EXPECT_EQ(renderer_->render_pass_mask_color_matrix_program_aa_
+ [precision][sampler][blend_mode][NO_MASK].program(),
+ renderer_->program_shadow_);
+ }
+
+ void TestSolidColorProgramAA() {
+ EXPECT_PROGRAM_VALID(&renderer_->solid_color_program_aa_);
+ EXPECT_EQ(renderer_->solid_color_program_aa_.program(),
+ renderer_->program_shadow_);
+ }
+
+ RendererSettings settings_;
+ FakeOutputSurfaceClient output_surface_client_;
+ scoped_ptr<FakeOutputSurface> output_surface_;
+ FakeRendererClient renderer_client_;
+ scoped_ptr<SharedBitmapManager> shared_bitmap_manager_;
+ scoped_ptr<ResourceProvider> resource_provider_;
+ scoped_ptr<FakeRendererGL> renderer_;
+};
+
+namespace {
+
+// Test GLRenderer DiscardBackbuffer functionality:
+// Suggest discarding framebuffer when one exists and the renderer is not
+// visible.
+// Expected: it is discarded and damage tracker is reset.
+TEST_F(
+ GLRendererWithDefaultHarnessTest,
+ SuggestBackbufferNoShouldDiscardBackbufferAndDamageRootLayerIfNotVisible) {
+ renderer_->SetVisible(false);
+ EXPECT_EQ(1, renderer_client_.set_full_root_layer_damage_count());
+ EXPECT_TRUE(renderer_->IsBackbufferDiscarded());
+}
+
+// Test GLRenderer DiscardBackbuffer functionality:
+// Suggest discarding framebuffer when one exists and the renderer is visible.
+// Expected: the allocation is ignored.
+TEST_F(GLRendererWithDefaultHarnessTest,
+ SuggestBackbufferNoDoNothingWhenVisible) {
+ renderer_->SetVisible(true);
+ EXPECT_EQ(0, renderer_client_.set_full_root_layer_damage_count());
+ EXPECT_FALSE(renderer_->IsBackbufferDiscarded());
+}
+
+// Test GLRenderer DiscardBackbuffer functionality:
+// Suggest discarding framebuffer when one does not exist.
+// Expected: it does nothing.
+TEST_F(GLRendererWithDefaultHarnessTest,
+ SuggestBackbufferNoWhenItDoesntExistShouldDoNothing) {
+ renderer_->SetVisible(false);
+ EXPECT_EQ(1, renderer_client_.set_full_root_layer_damage_count());
+ EXPECT_TRUE(renderer_->IsBackbufferDiscarded());
+
+ EXPECT_EQ(1, renderer_client_.set_full_root_layer_damage_count());
+ EXPECT_TRUE(renderer_->IsBackbufferDiscarded());
+}
+
+// Test GLRenderer DiscardBackbuffer functionality:
+// Begin drawing a frame while a framebuffer is discarded.
+// Expected: will recreate framebuffer.
+TEST_F(GLRendererWithDefaultHarnessTest,
+ DiscardedBackbufferIsRecreatedForScopeDuration) {
+ gfx::Rect viewport_rect(1, 1);
+ renderer_->SetVisible(false);
+ EXPECT_TRUE(renderer_->IsBackbufferDiscarded());
+ EXPECT_EQ(1, renderer_client_.set_full_root_layer_damage_count());
+
+ AddRenderPass(&render_passes_in_draw_order_,
+ RenderPassId(1, 0),
+ viewport_rect,
+ gfx::Transform());
+
+ renderer_->SetVisible(true);
+ renderer_->DrawFrame(&render_passes_in_draw_order_,
+ 1.f,
+ viewport_rect,
+ viewport_rect,
+ false);
+ EXPECT_FALSE(renderer_->IsBackbufferDiscarded());
+
+ SwapBuffers();
+ EXPECT_EQ(1u, output_surface_->num_sent_frames());
+}
+
+TEST_F(GLRendererWithDefaultHarnessTest, ExternalStencil) {
+ gfx::Rect viewport_rect(1, 1);
+ EXPECT_FALSE(renderer_->stencil_enabled());
+
+ output_surface_->set_has_external_stencil_test(true);
+
+ TestRenderPass* root_pass = AddRenderPass(&render_passes_in_draw_order_,
+ RenderPassId(1, 0),
+ viewport_rect,
+ gfx::Transform());
+ root_pass->has_transparent_background = false;
+
+ renderer_->DrawFrame(&render_passes_in_draw_order_,
+ 1.f,
+ viewport_rect,
+ viewport_rect,
+ false);
+ EXPECT_TRUE(renderer_->stencil_enabled());
+}
+
+class ForbidSynchronousCallContext : public TestWebGraphicsContext3D {
+ public:
+ ForbidSynchronousCallContext() {}
+
+ void getAttachedShaders(GLuint program,
+ GLsizei max_count,
+ GLsizei* count,
+ GLuint* shaders) override {
+ ADD_FAILURE();
+ }
+ GLint getAttribLocation(GLuint program, const GLchar* name) override {
+ ADD_FAILURE();
+ return 0;
+ }
+ void getBooleanv(GLenum pname, GLboolean* value) override { ADD_FAILURE(); }
+ void getBufferParameteriv(GLenum target,
+ GLenum pname,
+ GLint* value) override {
+ ADD_FAILURE();
+ }
+ GLenum getError() override {
+ ADD_FAILURE();
+ return GL_NO_ERROR;
+ }
+ void getFloatv(GLenum pname, GLfloat* value) override { ADD_FAILURE(); }
+ void getFramebufferAttachmentParameteriv(GLenum target,
+ GLenum attachment,
+ GLenum pname,
+ GLint* value) override {
+ ADD_FAILURE();
+ }
+ void getIntegerv(GLenum pname, GLint* value) override {
+ if (pname == GL_MAX_TEXTURE_SIZE) {
+ // MAX_TEXTURE_SIZE is cached client side, so it's OK to query.
+ *value = 1024;
+ } else {
+ ADD_FAILURE();
+ }
+ }
+
+ // We allow querying the shader compilation and program link status in debug
+ // mode, but not release.
+ void getProgramiv(GLuint program, GLenum pname, GLint* value) override {
+#ifndef NDEBUG
+ *value = 1;
+#else
+ ADD_FAILURE();
+#endif
+ }
+
+ void getShaderiv(GLuint shader, GLenum pname, GLint* value) override {
+#ifndef NDEBUG
+ *value = 1;
+#else
+ ADD_FAILURE();
+#endif
+ }
+
+ void getRenderbufferParameteriv(GLenum target,
+ GLenum pname,
+ GLint* value) override {
+ ADD_FAILURE();
+ }
+
+ void getShaderPrecisionFormat(GLenum shadertype,
+ GLenum precisiontype,
+ GLint* range,
+ GLint* precision) override {
+ ADD_FAILURE();
+ }
+ void getTexParameterfv(GLenum target, GLenum pname, GLfloat* value) override {
+ ADD_FAILURE();
+ }
+ void getTexParameteriv(GLenum target, GLenum pname, GLint* value) override {
+ ADD_FAILURE();
+ }
+ void getUniformfv(GLuint program, GLint location, GLfloat* value) override {
+ ADD_FAILURE();
+ }
+ void getUniformiv(GLuint program, GLint location, GLint* value) override {
+ ADD_FAILURE();
+ }
+ GLint getUniformLocation(GLuint program, const GLchar* name) override {
+ ADD_FAILURE();
+ return 0;
+ }
+ void getVertexAttribfv(GLuint index, GLenum pname, GLfloat* value) override {
+ ADD_FAILURE();
+ }
+ void getVertexAttribiv(GLuint index, GLenum pname, GLint* value) override {
+ ADD_FAILURE();
+ }
+ GLsizeiptr getVertexAttribOffset(GLuint index, GLenum pname) override {
+ ADD_FAILURE();
+ return 0;
+ }
+};
+TEST_F(GLRendererTest, InitializationDoesNotMakeSynchronousCalls) {
+ FakeOutputSurfaceClient output_surface_client;
+ scoped_ptr<OutputSurface> output_surface(FakeOutputSurface::Create3d(
+ scoped_ptr<TestWebGraphicsContext3D>(new ForbidSynchronousCallContext)));
+ CHECK(output_surface->BindToClient(&output_surface_client));
+
+ scoped_ptr<SharedBitmapManager> shared_bitmap_manager(
+ new TestSharedBitmapManager());
+ scoped_ptr<ResourceProvider> resource_provider(
+ ResourceProvider::Create(output_surface.get(),
+ shared_bitmap_manager.get(),
+ NULL,
+ NULL,
+ 0,
+ false,
+ 1));
+
+ RendererSettings settings;
+ FakeRendererClient renderer_client;
+ FakeRendererGL renderer(&renderer_client,
+ &settings,
+ output_surface.get(),
+ resource_provider.get());
+}
+
+class LoseContextOnFirstGetContext : public TestWebGraphicsContext3D {
+ public:
+ LoseContextOnFirstGetContext() {}
+
+ void getProgramiv(GLuint program, GLenum pname, GLint* value) override {
+ context_lost_ = true;
+ *value = 0;
+ }
+
+ void getShaderiv(GLuint shader, GLenum pname, GLint* value) override {
+ context_lost_ = true;
+ *value = 0;
+ }
+};
+
+TEST_F(GLRendererTest, InitializationWithQuicklyLostContextDoesNotAssert) {
+ FakeOutputSurfaceClient output_surface_client;
+ scoped_ptr<OutputSurface> output_surface(FakeOutputSurface::Create3d(
+ scoped_ptr<TestWebGraphicsContext3D>(new LoseContextOnFirstGetContext)));
+ CHECK(output_surface->BindToClient(&output_surface_client));
+
+ scoped_ptr<SharedBitmapManager> shared_bitmap_manager(
+ new TestSharedBitmapManager());
+ scoped_ptr<ResourceProvider> resource_provider(
+ ResourceProvider::Create(output_surface.get(),
+ shared_bitmap_manager.get(),
+ NULL,
+ NULL,
+ 0,
+ false,
+ 1));
+
+ RendererSettings settings;
+ FakeRendererClient renderer_client;
+ FakeRendererGL renderer(&renderer_client,
+ &settings,
+ output_surface.get(),
+ resource_provider.get());
+}
+
+class ClearCountingContext : public TestWebGraphicsContext3D {
+ public:
+ ClearCountingContext() { test_capabilities_.gpu.discard_framebuffer = true; }
+
+ MOCK_METHOD3(discardFramebufferEXT,
+ void(GLenum target,
+ GLsizei numAttachments,
+ const GLenum* attachments));
+ MOCK_METHOD1(clear, void(GLbitfield mask));
+};
+
+TEST_F(GLRendererTest, OpaqueBackground) {
+ scoped_ptr<ClearCountingContext> context_owned(new ClearCountingContext);
+ ClearCountingContext* context = context_owned.get();
+
+ FakeOutputSurfaceClient output_surface_client;
+ scoped_ptr<OutputSurface> output_surface(
+ FakeOutputSurface::Create3d(context_owned.Pass()));
+ CHECK(output_surface->BindToClient(&output_surface_client));
+
+ scoped_ptr<SharedBitmapManager> shared_bitmap_manager(
+ new TestSharedBitmapManager());
+ scoped_ptr<ResourceProvider> resource_provider(
+ ResourceProvider::Create(output_surface.get(),
+ shared_bitmap_manager.get(),
+ NULL,
+ NULL,
+ 0,
+ false,
+ 1));
+
+ RendererSettings settings;
+ FakeRendererClient renderer_client;
+ FakeRendererGL renderer(&renderer_client,
+ &settings,
+ output_surface.get(),
+ resource_provider.get());
+
+ gfx::Rect viewport_rect(1, 1);
+ TestRenderPass* root_pass = AddRenderPass(&render_passes_in_draw_order_,
+ RenderPassId(1, 0),
+ viewport_rect,
+ gfx::Transform());
+ root_pass->has_transparent_background = false;
+
+ // On DEBUG builds, render passes with opaque background clear to blue to
+ // easily see regions that were not drawn on the screen.
+ EXPECT_CALL(*context, discardFramebufferEXT(GL_FRAMEBUFFER, _, _))
+ .With(Args<2, 1>(ElementsAre(GL_COLOR_EXT)))
+ .Times(1);
+#ifdef NDEBUG
+ EXPECT_CALL(*context, clear(_)).Times(0);
+#else
+ EXPECT_CALL(*context, clear(_)).Times(1);
+#endif
+ renderer.DrawFrame(&render_passes_in_draw_order_,
+ 1.f,
+ viewport_rect,
+ viewport_rect,
+ false);
+ Mock::VerifyAndClearExpectations(context);
+}
+
+TEST_F(GLRendererTest, TransparentBackground) {
+ scoped_ptr<ClearCountingContext> context_owned(new ClearCountingContext);
+ ClearCountingContext* context = context_owned.get();
+
+ FakeOutputSurfaceClient output_surface_client;
+ scoped_ptr<OutputSurface> output_surface(
+ FakeOutputSurface::Create3d(context_owned.Pass()));
+ CHECK(output_surface->BindToClient(&output_surface_client));
+
+ scoped_ptr<SharedBitmapManager> shared_bitmap_manager(
+ new TestSharedBitmapManager());
+ scoped_ptr<ResourceProvider> resource_provider(
+ ResourceProvider::Create(output_surface.get(),
+ shared_bitmap_manager.get(),
+ NULL,
+ NULL,
+ 0,
+ false,
+ 1));
+
+ RendererSettings settings;
+ FakeRendererClient renderer_client;
+ FakeRendererGL renderer(&renderer_client,
+ &settings,
+ output_surface.get(),
+ resource_provider.get());
+
+ gfx::Rect viewport_rect(1, 1);
+ TestRenderPass* root_pass = AddRenderPass(&render_passes_in_draw_order_,
+ RenderPassId(1, 0),
+ viewport_rect,
+ gfx::Transform());
+ root_pass->has_transparent_background = true;
+
+ EXPECT_CALL(*context, discardFramebufferEXT(GL_FRAMEBUFFER, 1, _)).Times(1);
+ EXPECT_CALL(*context, clear(_)).Times(1);
+ renderer.DrawFrame(&render_passes_in_draw_order_,
+ 1.f,
+ viewport_rect,
+ viewport_rect,
+ false);
+
+ Mock::VerifyAndClearExpectations(context);
+}
+
+TEST_F(GLRendererTest, OffscreenOutputSurface) {
+ scoped_ptr<ClearCountingContext> context_owned(new ClearCountingContext);
+ ClearCountingContext* context = context_owned.get();
+
+ FakeOutputSurfaceClient output_surface_client;
+ scoped_ptr<OutputSurface> output_surface(
+ FakeOutputSurface::CreateOffscreen(context_owned.Pass()));
+ CHECK(output_surface->BindToClient(&output_surface_client));
+
+ scoped_ptr<SharedBitmapManager> shared_bitmap_manager(
+ new TestSharedBitmapManager());
+ scoped_ptr<ResourceProvider> resource_provider(
+ ResourceProvider::Create(output_surface.get(),
+ shared_bitmap_manager.get(),
+ NULL,
+ NULL,
+ 0,
+ false,
+ 1));
+
+ RendererSettings settings;
+ FakeRendererClient renderer_client;
+ FakeRendererGL renderer(&renderer_client,
+ &settings,
+ output_surface.get(),
+ resource_provider.get());
+
+ gfx::Rect viewport_rect(1, 1);
+ AddRenderPass(&render_passes_in_draw_order_,
+ RenderPassId(1, 0),
+ viewport_rect,
+ gfx::Transform());
+
+ EXPECT_CALL(*context, discardFramebufferEXT(GL_FRAMEBUFFER, _, _))
+ .With(Args<2, 1>(ElementsAre(GL_COLOR_ATTACHMENT0)))
+ .Times(1);
+ EXPECT_CALL(*context, clear(_)).Times(AnyNumber());
+ renderer.DrawFrame(&render_passes_in_draw_order_,
+ 1.f,
+ viewport_rect,
+ viewport_rect,
+ false);
+ Mock::VerifyAndClearExpectations(context);
+}
+
+class VisibilityChangeIsLastCallTrackingContext
+ : public TestWebGraphicsContext3D {
+ public:
+ VisibilityChangeIsLastCallTrackingContext()
+ : last_call_was_set_visibility_(false) {}
+
+ // TestWebGraphicsContext3D methods.
+ void flush() override { last_call_was_set_visibility_ = false; }
+ void deleteTexture(GLuint) override { last_call_was_set_visibility_ = false; }
+ void deleteFramebuffer(GLuint) override {
+ last_call_was_set_visibility_ = false;
+ }
+ void deleteQueryEXT(GLuint) override {
+ last_call_was_set_visibility_ = false;
+ }
+ void deleteRenderbuffer(GLuint) override {
+ last_call_was_set_visibility_ = false;
+ }
+
+ // Methods added for test.
+ void set_last_call_was_visibility(bool visible) {
+ DCHECK(last_call_was_set_visibility_ == false);
+ last_call_was_set_visibility_ = true;
+ }
+ bool last_call_was_set_visibility() const {
+ return last_call_was_set_visibility_;
+ }
+
+ private:
+ bool last_call_was_set_visibility_;
+};
+
+TEST_F(GLRendererTest, VisibilityChangeIsLastCall) {
+ scoped_ptr<VisibilityChangeIsLastCallTrackingContext> context_owned(
+ new VisibilityChangeIsLastCallTrackingContext);
+ VisibilityChangeIsLastCallTrackingContext* context = context_owned.get();
+
+ scoped_refptr<TestContextProvider> provider =
+ TestContextProvider::Create(context_owned.Pass());
+
+ provider->support()->SetSurfaceVisibleCallback(base::Bind(
+ &VisibilityChangeIsLastCallTrackingContext::set_last_call_was_visibility,
+ base::Unretained(context)));
+
+ FakeOutputSurfaceClient output_surface_client;
+ scoped_ptr<OutputSurface> output_surface(
+ FakeOutputSurface::Create3d(provider));
+ CHECK(output_surface->BindToClient(&output_surface_client));
+
+ scoped_ptr<SharedBitmapManager> shared_bitmap_manager(
+ new TestSharedBitmapManager());
+ scoped_ptr<ResourceProvider> resource_provider(
+ ResourceProvider::Create(output_surface.get(),
+ shared_bitmap_manager.get(),
+ NULL,
+ NULL,
+ 0,
+ false,
+ 1));
+
+ RendererSettings settings;
+ FakeRendererClient renderer_client;
+ FakeRendererGL renderer(&renderer_client,
+ &settings,
+ output_surface.get(),
+ resource_provider.get());
+
+ gfx::Rect viewport_rect(1, 1);
+ AddRenderPass(&render_passes_in_draw_order_,
+ RenderPassId(1, 0),
+ viewport_rect,
+ gfx::Transform());
+
+ // Ensure that the call to SetSurfaceVisible is the last call issue to the
+ // GPU process, after glFlush is called, and after the RendererClient's
+ // SetManagedMemoryPolicy is called. Plumb this tracking between both the
+ // RenderClient and the Context by giving them both a pointer to a variable on
+ // the stack.
+ renderer.SetVisible(true);
+ renderer.DrawFrame(&render_passes_in_draw_order_,
+ 1.f,
+ viewport_rect,
+ viewport_rect,
+ false);
+ renderer.SetVisible(false);
+ EXPECT_TRUE(context->last_call_was_set_visibility());
+}
+
+class TextureStateTrackingContext : public TestWebGraphicsContext3D {
+ public:
+ TextureStateTrackingContext() : active_texture_(GL_INVALID_ENUM) {
+ test_capabilities_.gpu.egl_image_external = true;
+ }
+
+ MOCK_METHOD1(waitSyncPoint, void(unsigned sync_point));
+ MOCK_METHOD3(texParameteri, void(GLenum target, GLenum pname, GLint param));
+ MOCK_METHOD4(drawElements,
+ void(GLenum mode, GLsizei count, GLenum type, GLintptr offset));
+
+ virtual void activeTexture(GLenum texture) {
+ EXPECT_NE(texture, active_texture_);
+ active_texture_ = texture;
+ }
+
+ GLenum active_texture() const { return active_texture_; }
+
+ private:
+ GLenum active_texture_;
+};
+
+TEST_F(GLRendererTest, ActiveTextureState) {
+ scoped_ptr<TextureStateTrackingContext> context_owned(
+ new TextureStateTrackingContext);
+ TextureStateTrackingContext* context = context_owned.get();
+
+ FakeOutputSurfaceClient output_surface_client;
+ scoped_ptr<OutputSurface> output_surface(
+ FakeOutputSurface::Create3d(context_owned.Pass()));
+ CHECK(output_surface->BindToClient(&output_surface_client));
+
+ scoped_ptr<SharedBitmapManager> shared_bitmap_manager(
+ new TestSharedBitmapManager());
+ scoped_ptr<ResourceProvider> resource_provider(
+ ResourceProvider::Create(output_surface.get(),
+ shared_bitmap_manager.get(),
+ NULL,
+ NULL,
+ 0,
+ false,
+ 1));
+
+ RendererSettings settings;
+ FakeRendererClient renderer_client;
+ FakeRendererGL renderer(&renderer_client,
+ &settings,
+ output_surface.get(),
+ resource_provider.get());
+
+ // During initialization we are allowed to set any texture parameters.
+ EXPECT_CALL(*context, texParameteri(_, _, _)).Times(AnyNumber());
+
+ RenderPassId id(1, 1);
+ TestRenderPass* root_pass = AddRenderPass(
+ &render_passes_in_draw_order_, id, gfx::Rect(100, 100), gfx::Transform());
+ root_pass->AppendOneOfEveryQuadType(resource_provider.get(),
+ RenderPassId(2, 1));
+
+ renderer.DecideRenderPassAllocationsForFrame(render_passes_in_draw_order_);
+
+ // Set up expected texture filter state transitions that match the quads
+ // created in AppendOneOfEveryQuadType().
+ Mock::VerifyAndClearExpectations(context);
+ {
+ InSequence sequence;
+
+ // The sync points for all quads are waited on first. This sync point is
+ // for a texture quad drawn later in the frame.
+ EXPECT_CALL(*context,
+ waitSyncPoint(TestRenderPass::kSyncPointForMailboxTextureQuad))
+ .Times(1);
+
+ // yuv_quad is drawn with the default linear filter.
+ EXPECT_CALL(*context, drawElements(_, _, _, _));
+
+ // tile_quad is drawn with GL_NEAREST because it is not transformed or
+ // scaled.
+ EXPECT_CALL(
+ *context,
+ texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST));
+ EXPECT_CALL(
+ *context,
+ texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST));
+ EXPECT_CALL(*context, drawElements(_, _, _, _));
+
+ // transformed_tile_quad uses GL_LINEAR.
+ EXPECT_CALL(*context, drawElements(_, _, _, _));
+
+ // scaled_tile_quad also uses GL_LINEAR.
+ EXPECT_CALL(*context, drawElements(_, _, _, _));
+
+ // The remaining quads also use GL_LINEAR because nearest neighbor
+ // filtering is currently only used with tile quads.
+ EXPECT_CALL(*context, drawElements(_, _, _, _)).Times(7);
+ }
+
+ gfx::Rect viewport_rect(100, 100);
+ renderer.DrawFrame(&render_passes_in_draw_order_,
+ 1.f,
+ viewport_rect,
+ viewport_rect,
+ false);
+ Mock::VerifyAndClearExpectations(context);
+}
+
+class NoClearRootRenderPassMockContext : public TestWebGraphicsContext3D {
+ public:
+ MOCK_METHOD1(clear, void(GLbitfield mask));
+ MOCK_METHOD4(drawElements,
+ void(GLenum mode, GLsizei count, GLenum type, GLintptr offset));
+};
+
+TEST_F(GLRendererTest, ShouldClearRootRenderPass) {
+ scoped_ptr<NoClearRootRenderPassMockContext> mock_context_owned(
+ new NoClearRootRenderPassMockContext);
+ NoClearRootRenderPassMockContext* mock_context = mock_context_owned.get();
+
+ FakeOutputSurfaceClient output_surface_client;
+ scoped_ptr<OutputSurface> output_surface(
+ FakeOutputSurface::Create3d(mock_context_owned.Pass()));
+ CHECK(output_surface->BindToClient(&output_surface_client));
+
+ scoped_ptr<SharedBitmapManager> shared_bitmap_manager(
+ new TestSharedBitmapManager());
+ scoped_ptr<ResourceProvider> resource_provider(
+ ResourceProvider::Create(output_surface.get(),
+ shared_bitmap_manager.get(),
+ NULL,
+ NULL,
+ 0,
+ false,
+ 1));
+
+ RendererSettings settings;
+ settings.should_clear_root_render_pass = false;
+
+ FakeRendererClient renderer_client;
+ FakeRendererGL renderer(&renderer_client,
+ &settings,
+ output_surface.get(),
+ resource_provider.get());
+
+ gfx::Rect viewport_rect(10, 10);
+
+ RenderPassId root_pass_id(1, 0);
+ TestRenderPass* root_pass = AddRenderPass(&render_passes_in_draw_order_,
+ root_pass_id,
+ viewport_rect,
+ gfx::Transform());
+ AddQuad(root_pass, viewport_rect, SK_ColorGREEN);
+
+ RenderPassId child_pass_id(2, 0);
+ TestRenderPass* child_pass = AddRenderPass(&render_passes_in_draw_order_,
+ child_pass_id,
+ viewport_rect,
+ gfx::Transform());
+ AddQuad(child_pass, viewport_rect, SK_ColorBLUE);
+
+ 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(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(clear_bits)).Times(0).After(
+ first_render_pass);
+
+ EXPECT_CALL(*mock_context, drawElements(_, _, _, _)).Times(AnyNumber()).After(
+ first_render_pass);
+
+ renderer.DecideRenderPassAllocationsForFrame(render_passes_in_draw_order_);
+ renderer.DrawFrame(&render_passes_in_draw_order_,
+ 1.f,
+ viewport_rect,
+ viewport_rect,
+ false);
+
+ // In multiple render passes all but the root pass should clear the
+ // framebuffer.
+ Mock::VerifyAndClearExpectations(&mock_context);
+}
+
+class ScissorTestOnClearCheckingContext : public TestWebGraphicsContext3D {
+ public:
+ ScissorTestOnClearCheckingContext() : scissor_enabled_(false) {}
+
+ void clear(GLbitfield) override { EXPECT_FALSE(scissor_enabled_); }
+
+ void enable(GLenum cap) override {
+ if (cap == GL_SCISSOR_TEST)
+ scissor_enabled_ = true;
+ }
+
+ void disable(GLenum cap) override {
+ if (cap == GL_SCISSOR_TEST)
+ scissor_enabled_ = false;
+ }
+
+ private:
+ bool scissor_enabled_;
+};
+
+TEST_F(GLRendererTest, ScissorTestWhenClearing) {
+ scoped_ptr<ScissorTestOnClearCheckingContext> context_owned(
+ new ScissorTestOnClearCheckingContext);
+
+ FakeOutputSurfaceClient output_surface_client;
+ scoped_ptr<OutputSurface> output_surface(
+ FakeOutputSurface::Create3d(context_owned.Pass()));
+ CHECK(output_surface->BindToClient(&output_surface_client));
+
+ scoped_ptr<SharedBitmapManager> shared_bitmap_manager(
+ new TestSharedBitmapManager());
+ scoped_ptr<ResourceProvider> resource_provider(
+ ResourceProvider::Create(output_surface.get(),
+ shared_bitmap_manager.get(),
+ NULL,
+ NULL,
+ 0,
+ false,
+ 1));
+
+ RendererSettings settings;
+ FakeRendererClient renderer_client;
+ FakeRendererGL renderer(&renderer_client,
+ &settings,
+ output_surface.get(),
+ resource_provider.get());
+ EXPECT_FALSE(renderer.Capabilities().using_partial_swap);
+
+ gfx::Rect viewport_rect(1, 1);
+
+ gfx::Rect grand_child_rect(25, 25);
+ RenderPassId grand_child_pass_id(3, 0);
+ TestRenderPass* grand_child_pass =
+ AddRenderPass(&render_passes_in_draw_order_,
+ grand_child_pass_id,
+ grand_child_rect,
+ gfx::Transform());
+ AddClippedQuad(grand_child_pass, grand_child_rect, SK_ColorYELLOW);
+
+ gfx::Rect child_rect(50, 50);
+ RenderPassId child_pass_id(2, 0);
+ TestRenderPass* child_pass = AddRenderPass(&render_passes_in_draw_order_,
+ child_pass_id,
+ child_rect,
+ gfx::Transform());
+ AddQuad(child_pass, child_rect, SK_ColorBLUE);
+
+ RenderPassId root_pass_id(1, 0);
+ TestRenderPass* root_pass = AddRenderPass(&render_passes_in_draw_order_,
+ root_pass_id,
+ viewport_rect,
+ gfx::Transform());
+ AddQuad(root_pass, viewport_rect, SK_ColorGREEN);
+
+ AddRenderPassQuad(root_pass, child_pass);
+ AddRenderPassQuad(child_pass, grand_child_pass);
+
+ renderer.DecideRenderPassAllocationsForFrame(render_passes_in_draw_order_);
+ renderer.DrawFrame(&render_passes_in_draw_order_,
+ 1.f,
+ viewport_rect,
+ viewport_rect,
+ false);
+}
+
+class DiscardCheckingContext : public TestWebGraphicsContext3D {
+ public:
+ DiscardCheckingContext() : discarded_(0) {
+ set_have_post_sub_buffer(true);
+ set_have_discard_framebuffer(true);
+ }
+
+ void discardFramebufferEXT(GLenum target,
+ GLsizei numAttachments,
+ const GLenum* attachments) override {
+ ++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) {
+ surface_size_ = gfx::Size(500, 500);
+ }
+ void Reshape(const gfx::Size& size, float scale_factor) override {}
+ void set_fixed_size(const gfx::Size& size) { surface_size_ = size; }
+};
+
+TEST_F(GLRendererTest, 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.Pass()));
+ CHECK(output_surface->BindToClient(&output_surface_client));
+ output_surface->set_fixed_size(gfx::Size(100, 100));
+
+ scoped_ptr<SharedBitmapManager> shared_bitmap_manager(
+ new TestSharedBitmapManager());
+ scoped_ptr<ResourceProvider> resource_provider(
+ ResourceProvider::Create(output_surface.get(),
+ shared_bitmap_manager.get(),
+ NULL,
+ NULL,
+ 0,
+ false,
+ 1));
+
+ RendererSettings settings;
+ settings.partial_swap_enabled = true;
+ FakeRendererClient renderer_client;
+ FakeRendererGL renderer(&renderer_client,
+ &settings,
+ output_surface.get(),
+ resource_provider.get());
+ EXPECT_TRUE(renderer.Capabilities().using_partial_swap);
+
+ gfx::Rect viewport_rect(100, 100);
+ gfx::Rect clip_rect(100, 100);
+
+ {
+ // Partial frame, should not discard.
+ RenderPassId root_pass_id(1, 0);
+ TestRenderPass* root_pass = AddRenderPass(&render_passes_in_draw_order_,
+ root_pass_id,
+ viewport_rect,
+ gfx::Transform());
+ AddQuad(root_pass, viewport_rect, SK_ColorGREEN);
+ root_pass->damage_rect = gfx::Rect(2, 2, 3, 3);
+
+ renderer.DecideRenderPassAllocationsForFrame(render_passes_in_draw_order_);
+ renderer.DrawFrame(&render_passes_in_draw_order_,
+ 1.f,
+ viewport_rect,
+ clip_rect,
+ false);
+ EXPECT_EQ(0, context->discarded());
+ context->reset();
+ }
+ {
+ // Full frame, should discard.
+ RenderPassId root_pass_id(1, 0);
+ TestRenderPass* root_pass = AddRenderPass(&render_passes_in_draw_order_,
+ root_pass_id,
+ viewport_rect,
+ gfx::Transform());
+ AddQuad(root_pass, viewport_rect, SK_ColorGREEN);
+ root_pass->damage_rect = root_pass->output_rect;
+
+ renderer.DecideRenderPassAllocationsForFrame(render_passes_in_draw_order_);
+ renderer.DrawFrame(&render_passes_in_draw_order_,
+ 1.f,
+ viewport_rect,
+ clip_rect,
+ 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);
+ RenderPassId root_pass_id(1, 0);
+ TestRenderPass* root_pass = AddRenderPass(&render_passes_in_draw_order_,
+ root_pass_id,
+ viewport_rect,
+ gfx::Transform());
+ AddQuad(root_pass, viewport_rect, SK_ColorGREEN);
+ root_pass->damage_rect = root_pass->output_rect;
+ root_pass->has_transparent_background = false;
+
+ renderer.DecideRenderPassAllocationsForFrame(render_passes_in_draw_order_);
+ renderer.DrawFrame(&render_passes_in_draw_order_,
+ 1.f,
+ viewport_rect,
+ clip_rect,
+ false);
+ EXPECT_EQ(0, context->discarded());
+ context->reset();
+ output_surface->set_has_external_stencil_test(false);
+ }
+ {
+ // Full frame, clipped, should not discard.
+ clip_rect = gfx::Rect(10, 10, 10, 10);
+ RenderPassId root_pass_id(1, 0);
+ TestRenderPass* root_pass = AddRenderPass(&render_passes_in_draw_order_,
+ root_pass_id,
+ viewport_rect,
+ gfx::Transform());
+ AddQuad(root_pass, viewport_rect, SK_ColorGREEN);
+ root_pass->damage_rect = root_pass->output_rect;
+
+ renderer.DecideRenderPassAllocationsForFrame(render_passes_in_draw_order_);
+ renderer.DrawFrame(&render_passes_in_draw_order_,
+ 1.f,
+ viewport_rect,
+ clip_rect,
+ false);
+ EXPECT_EQ(0, context->discarded());
+ context->reset();
+ }
+ {
+ // Full frame, doesn't cover the surface, should not discard.
+ viewport_rect = gfx::Rect(10, 10, 10, 10);
+ RenderPassId root_pass_id(1, 0);
+ TestRenderPass* root_pass = AddRenderPass(&render_passes_in_draw_order_,
+ root_pass_id,
+ viewport_rect,
+ gfx::Transform());
+ AddQuad(root_pass, viewport_rect, SK_ColorGREEN);
+ root_pass->damage_rect = root_pass->output_rect;
+
+ renderer.DecideRenderPassAllocationsForFrame(render_passes_in_draw_order_);
+ renderer.DrawFrame(&render_passes_in_draw_order_,
+ 1.f,
+ viewport_rect,
+ clip_rect,
+ false);
+ EXPECT_EQ(0, context->discarded());
+ context->reset();
+ }
+ {
+ // Full frame, doesn't cover the surface (no offset), should not discard.
+ clip_rect = gfx::Rect(100, 100);
+ viewport_rect = gfx::Rect(50, 50);
+ RenderPassId root_pass_id(1, 0);
+ TestRenderPass* root_pass = AddRenderPass(&render_passes_in_draw_order_,
+ root_pass_id,
+ viewport_rect,
+ gfx::Transform());
+ AddQuad(root_pass, viewport_rect, SK_ColorGREEN);
+ root_pass->damage_rect = root_pass->output_rect;
+
+ renderer.DecideRenderPassAllocationsForFrame(render_passes_in_draw_order_);
+ renderer.DrawFrame(&render_passes_in_draw_order_,
+ 1.f,
+ viewport_rect,
+ clip_rect,
+ false);
+ EXPECT_EQ(0, context->discarded());
+ context->reset();
+ }
+}
+
+class FlippedScissorAndViewportContext : public TestWebGraphicsContext3D {
+ public:
+ MOCK_METHOD4(viewport, void(GLint x, GLint y, GLsizei width, GLsizei height));
+ MOCK_METHOD4(scissor, void(GLint x, GLint y, GLsizei width, GLsizei height));
+};
+
+TEST_F(GLRendererTest, ScissorAndViewportWithinNonreshapableSurface) {
+ // In Android WebView, the OutputSurface is unable to respect reshape() calls
+ // and maintains a fixed size. This test verifies that glViewport and
+ // glScissor's Y coordinate is flipped correctly in this environment, and that
+ // the glViewport can be at a nonzero origin within the surface.
+ scoped_ptr<FlippedScissorAndViewportContext> context_owned(
+ new FlippedScissorAndViewportContext);
+
+ // We expect exactly one call to viewport on this context and exactly two
+ // to scissor (one to scissor the clear, one to scissor the quad draw).
+ EXPECT_CALL(*context_owned, viewport(10, 390, 100, 100));
+ EXPECT_CALL(*context_owned, scissor(10, 390, 100, 100));
+ EXPECT_CALL(*context_owned, scissor(30, 450, 20, 20));
+
+ FakeOutputSurfaceClient output_surface_client;
+ scoped_ptr<OutputSurface> output_surface(
+ new NonReshapableOutputSurface(context_owned.Pass()));
+ CHECK(output_surface->BindToClient(&output_surface_client));
+
+ scoped_ptr<SharedBitmapManager> shared_bitmap_manager(
+ new TestSharedBitmapManager());
+ scoped_ptr<ResourceProvider> resource_provider(
+ ResourceProvider::Create(output_surface.get(),
+ shared_bitmap_manager.get(),
+ NULL,
+ NULL,
+ 0,
+ false,
+ 1));
+
+ RendererSettings settings;
+ FakeRendererClient renderer_client;
+ FakeRendererGL renderer(&renderer_client,
+ &settings,
+ output_surface.get(),
+ resource_provider.get());
+ EXPECT_FALSE(renderer.Capabilities().using_partial_swap);
+
+ gfx::Rect device_viewport_rect(10, 10, 100, 100);
+ gfx::Rect viewport_rect(device_viewport_rect.size());
+ gfx::Rect quad_rect = gfx::Rect(20, 20, 20, 20);
+
+ RenderPassId root_pass_id(1, 0);
+ TestRenderPass* root_pass = AddRenderPass(&render_passes_in_draw_order_,
+ root_pass_id,
+ viewport_rect,
+ gfx::Transform());
+ AddClippedQuad(root_pass, quad_rect, SK_ColorGREEN);
+
+ renderer.DecideRenderPassAllocationsForFrame(render_passes_in_draw_order_);
+ renderer.DrawFrame(&render_passes_in_draw_order_,
+ 1.f,
+ device_viewport_rect,
+ device_viewport_rect,
+ false);
+}
+
+TEST_F(GLRendererTest, DrawFramePreservesFramebuffer) {
+ // When using render-to-FBO to display the surface, all rendering is done
+ // to a non-zero FBO. Make sure that the framebuffer is always restored to
+ // the correct framebuffer during rendering, if changed.
+ // Note: there is one path that will set it to 0, but that is after the render
+ // has finished.
+ FakeOutputSurfaceClient output_surface_client;
+ scoped_ptr<FakeOutputSurface> output_surface(
+ FakeOutputSurface::Create3d(TestWebGraphicsContext3D::Create().Pass()));
+ CHECK(output_surface->BindToClient(&output_surface_client));
+
+ scoped_ptr<SharedBitmapManager> shared_bitmap_manager(
+ new TestSharedBitmapManager());
+ scoped_ptr<ResourceProvider> resource_provider(ResourceProvider::Create(
+ output_surface.get(), shared_bitmap_manager.get(), NULL, NULL, 0, false,
+ 1));
+
+ RendererSettings settings;
+ FakeRendererClient renderer_client;
+ FakeRendererGL renderer(&renderer_client, &settings, output_surface.get(),
+ resource_provider.get());
+ EXPECT_FALSE(renderer.Capabilities().using_partial_swap);
+
+ gfx::Rect device_viewport_rect(0, 0, 100, 100);
+ gfx::Rect viewport_rect(device_viewport_rect.size());
+ gfx::Rect quad_rect = gfx::Rect(20, 20, 20, 20);
+
+ RenderPassId root_pass_id(1, 0);
+ TestRenderPass* root_pass =
+ AddRenderPass(&render_passes_in_draw_order_, root_pass_id, viewport_rect,
+ gfx::Transform());
+ AddClippedQuad(root_pass, quad_rect, SK_ColorGREEN);
+
+ unsigned fbo;
+ gpu::gles2::GLES2Interface* gl =
+ output_surface->context_provider()->ContextGL();
+ gl->GenFramebuffers(1, &fbo);
+ output_surface->set_framebuffer(fbo);
+
+ renderer.DecideRenderPassAllocationsForFrame(render_passes_in_draw_order_);
+ renderer.DrawFrame(&render_passes_in_draw_order_, 1.f, device_viewport_rect,
+ device_viewport_rect, false);
+
+ int bound_fbo;
+ gl->GetIntegerv(GL_FRAMEBUFFER_BINDING, &bound_fbo);
+ EXPECT_EQ(static_cast<int>(fbo), bound_fbo);
+}
+
+TEST_F(GLRendererShaderTest, DrawRenderPassQuadShaderPermutations) {
+ gfx::Rect viewport_rect(1, 1);
+
+ gfx::Rect child_rect(50, 50);
+ RenderPassId child_pass_id(2, 0);
+ TestRenderPass* child_pass;
+
+ RenderPassId root_pass_id(1, 0);
+ TestRenderPass* root_pass;
+
+ ResourceProvider::ResourceId mask = resource_provider_->CreateResource(
+ gfx::Size(20, 12), GL_CLAMP_TO_EDGE,
+ ResourceProvider::TEXTURE_HINT_IMMUTABLE,
+ resource_provider_->best_texture_format());
+ resource_provider_->AllocateForTesting(mask);
+
+ SkScalar matrix[20];
+ float amount = 0.5f;
+ matrix[0] = 0.213f + 0.787f * amount;
+ matrix[1] = 0.715f - 0.715f * amount;
+ matrix[2] = 1.f - (matrix[0] + matrix[1]);
+ matrix[3] = matrix[4] = 0;
+ matrix[5] = 0.213f - 0.213f * amount;
+ matrix[6] = 0.715f + 0.285f * amount;
+ matrix[7] = 1.f - (matrix[5] + matrix[6]);
+ matrix[8] = matrix[9] = 0;
+ matrix[10] = 0.213f - 0.213f * amount;
+ matrix[11] = 0.715f - 0.715f * amount;
+ matrix[12] = 1.f - (matrix[10] + matrix[11]);
+ matrix[13] = matrix[14] = 0;
+ matrix[15] = matrix[16] = matrix[17] = matrix[19] = 0;
+ matrix[18] = 1;
+ skia::RefPtr<SkColorFilter> color_filter(
+ skia::AdoptRef(SkColorMatrixFilter::Create(matrix)));
+ skia::RefPtr<SkImageFilter> filter = skia::AdoptRef(
+ SkColorFilterImageFilter::Create(color_filter.get(), NULL));
+ FilterOperations filters;
+ filters.Append(FilterOperation::CreateReferenceFilter(filter));
+
+ gfx::Transform transform_causing_aa;
+ transform_causing_aa.Rotate(20.0);
+
+ for (int i = 0; i <= LAST_BLEND_MODE; ++i) {
+ BlendMode blend_mode = static_cast<BlendMode>(i);
+ SkXfermode::Mode xfer_mode = BlendModeToSkXfermode(blend_mode);
+ settings_.force_blending_with_shaders = (blend_mode != BLEND_MODE_NONE);
+ // RenderPassProgram
+ render_passes_in_draw_order_.clear();
+ child_pass = AddRenderPass(&render_passes_in_draw_order_,
+ child_pass_id,
+ child_rect,
+ gfx::Transform());
+
+ root_pass = AddRenderPass(&render_passes_in_draw_order_,
+ root_pass_id,
+ viewport_rect,
+ gfx::Transform());
+
+ AddRenderPassQuad(root_pass,
+ child_pass,
+ 0,
+ FilterOperations(),
+ gfx::Transform(),
+ xfer_mode);
+
+ renderer_->DecideRenderPassAllocationsForFrame(
+ render_passes_in_draw_order_);
+ renderer_->DrawFrame(&render_passes_in_draw_order_,
+ 1.f,
+ viewport_rect,
+ viewport_rect,
+ false);
+ TestRenderPassProgram(TEX_COORD_PRECISION_MEDIUM, blend_mode);
+
+ // RenderPassColorMatrixProgram
+ render_passes_in_draw_order_.clear();
+
+ child_pass = AddRenderPass(&render_passes_in_draw_order_,
+ child_pass_id,
+ child_rect,
+ transform_causing_aa);
+
+ root_pass = AddRenderPass(&render_passes_in_draw_order_,
+ root_pass_id,
+ viewport_rect,
+ gfx::Transform());
+
+ AddRenderPassQuad(
+ root_pass, child_pass, 0, filters, gfx::Transform(), xfer_mode);
+
+ renderer_->DecideRenderPassAllocationsForFrame(
+ render_passes_in_draw_order_);
+ renderer_->DrawFrame(&render_passes_in_draw_order_,
+ 1.f,
+ viewport_rect,
+ viewport_rect,
+ false);
+ TestRenderPassColorMatrixProgram(TEX_COORD_PRECISION_MEDIUM, blend_mode);
+
+ // RenderPassMaskProgram
+ render_passes_in_draw_order_.clear();
+
+ child_pass = AddRenderPass(&render_passes_in_draw_order_,
+ child_pass_id,
+ child_rect,
+ gfx::Transform());
+
+ root_pass = AddRenderPass(&render_passes_in_draw_order_,
+ root_pass_id,
+ viewport_rect,
+ gfx::Transform());
+
+ AddRenderPassQuad(root_pass,
+ child_pass,
+ mask,
+ FilterOperations(),
+ gfx::Transform(),
+ xfer_mode);
+
+ renderer_->DecideRenderPassAllocationsForFrame(
+ render_passes_in_draw_order_);
+ renderer_->DrawFrame(&render_passes_in_draw_order_,
+ 1.f,
+ viewport_rect,
+ viewport_rect,
+ false);
+ TestRenderPassMaskProgram(TEX_COORD_PRECISION_MEDIUM, SAMPLER_TYPE_2D,
+ blend_mode);
+
+ // RenderPassMaskColorMatrixProgram
+ render_passes_in_draw_order_.clear();
+
+ child_pass = AddRenderPass(&render_passes_in_draw_order_,
+ child_pass_id,
+ child_rect,
+ gfx::Transform());
+
+ root_pass = AddRenderPass(&render_passes_in_draw_order_,
+ root_pass_id,
+ viewport_rect,
+ gfx::Transform());
+
+ AddRenderPassQuad(
+ root_pass, child_pass, mask, filters, gfx::Transform(), xfer_mode);
+
+ renderer_->DecideRenderPassAllocationsForFrame(
+ render_passes_in_draw_order_);
+ renderer_->DrawFrame(&render_passes_in_draw_order_,
+ 1.f,
+ viewport_rect,
+ viewport_rect,
+ false);
+ TestRenderPassMaskColorMatrixProgram(TEX_COORD_PRECISION_MEDIUM,
+ SAMPLER_TYPE_2D, blend_mode);
+
+ // RenderPassProgramAA
+ render_passes_in_draw_order_.clear();
+
+ child_pass = AddRenderPass(&render_passes_in_draw_order_,
+ child_pass_id,
+ child_rect,
+ transform_causing_aa);
+
+ root_pass = AddRenderPass(&render_passes_in_draw_order_,
+ root_pass_id,
+ viewport_rect,
+ gfx::Transform());
+
+ AddRenderPassQuad(root_pass,
+ child_pass,
+ 0,
+ FilterOperations(),
+ transform_causing_aa,
+ xfer_mode);
+
+ renderer_->DecideRenderPassAllocationsForFrame(
+ render_passes_in_draw_order_);
+ renderer_->DrawFrame(&render_passes_in_draw_order_,
+ 1.f,
+ viewport_rect,
+ viewport_rect,
+ false);
+ TestRenderPassProgramAA(TEX_COORD_PRECISION_MEDIUM, blend_mode);
+
+ // RenderPassColorMatrixProgramAA
+ render_passes_in_draw_order_.clear();
+
+ child_pass = AddRenderPass(&render_passes_in_draw_order_,
+ child_pass_id,
+ child_rect,
+ transform_causing_aa);
+
+ root_pass = AddRenderPass(&render_passes_in_draw_order_,
+ root_pass_id,
+ viewport_rect,
+ gfx::Transform());
+
+ AddRenderPassQuad(
+ root_pass, child_pass, 0, filters, transform_causing_aa, xfer_mode);
+
+ renderer_->DecideRenderPassAllocationsForFrame(
+ render_passes_in_draw_order_);
+ renderer_->DrawFrame(&render_passes_in_draw_order_,
+ 1.f,
+ viewport_rect,
+ viewport_rect,
+ false);
+ TestRenderPassColorMatrixProgramAA(TEX_COORD_PRECISION_MEDIUM, blend_mode);
+
+ // RenderPassMaskProgramAA
+ render_passes_in_draw_order_.clear();
+
+ child_pass = AddRenderPass(&render_passes_in_draw_order_,
+ child_pass_id,
+ child_rect,
+ transform_causing_aa);
+
+ root_pass = AddRenderPass(&render_passes_in_draw_order_,
+ root_pass_id,
+ viewport_rect,
+ gfx::Transform());
+
+ AddRenderPassQuad(root_pass,
+ child_pass,
+ mask,
+ FilterOperations(),
+ transform_causing_aa,
+ xfer_mode);
+
+ renderer_->DecideRenderPassAllocationsForFrame(
+ render_passes_in_draw_order_);
+ renderer_->DrawFrame(&render_passes_in_draw_order_,
+ 1.f,
+ viewport_rect,
+ viewport_rect,
+ false);
+ TestRenderPassMaskProgramAA(TEX_COORD_PRECISION_MEDIUM, SAMPLER_TYPE_2D,
+ blend_mode);
+
+ // RenderPassMaskColorMatrixProgramAA
+ render_passes_in_draw_order_.clear();
+
+ child_pass = AddRenderPass(&render_passes_in_draw_order_,
+ child_pass_id,
+ child_rect,
+ transform_causing_aa);
+
+ root_pass = AddRenderPass(&render_passes_in_draw_order_,
+ root_pass_id,
+ viewport_rect,
+ transform_causing_aa);
+
+ AddRenderPassQuad(
+ root_pass, child_pass, mask, filters, transform_causing_aa, xfer_mode);
+
+ renderer_->DecideRenderPassAllocationsForFrame(
+ render_passes_in_draw_order_);
+ renderer_->DrawFrame(&render_passes_in_draw_order_,
+ 1.f,
+ viewport_rect,
+ viewport_rect,
+ false);
+ TestRenderPassMaskColorMatrixProgramAA(TEX_COORD_PRECISION_MEDIUM,
+ SAMPLER_TYPE_2D, blend_mode);
+ }
+}
+
+// At this time, the AA code path cannot be taken if the surface's rect would
+// project incorrectly by the given transform, because of w<0 clipping.
+TEST_F(GLRendererShaderTest, DrawRenderPassQuadSkipsAAForClippingTransform) {
+ gfx::Rect child_rect(50, 50);
+ RenderPassId child_pass_id(2, 0);
+ TestRenderPass* child_pass;
+
+ gfx::Rect viewport_rect(1, 1);
+ RenderPassId root_pass_id(1, 0);
+ TestRenderPass* root_pass;
+
+ gfx::Transform transform_preventing_aa;
+ transform_preventing_aa.ApplyPerspectiveDepth(40.0);
+ transform_preventing_aa.RotateAboutYAxis(-20.0);
+ transform_preventing_aa.Scale(30.0, 1.0);
+
+ // Verify that the test transform and test rect actually do cause the clipped
+ // flag to trigger. Otherwise we are not testing the intended scenario.
+ bool clipped = false;
+ MathUtil::MapQuad(transform_preventing_aa, gfx::QuadF(child_rect), &clipped);
+ ASSERT_TRUE(clipped);
+
+ child_pass = AddRenderPass(&render_passes_in_draw_order_,
+ child_pass_id,
+ child_rect,
+ transform_preventing_aa);
+
+ root_pass = AddRenderPass(&render_passes_in_draw_order_,
+ root_pass_id,
+ viewport_rect,
+ gfx::Transform());
+
+ AddRenderPassQuad(root_pass,
+ child_pass,
+ 0,
+ FilterOperations(),
+ transform_preventing_aa,
+ SkXfermode::kSrcOver_Mode);
+
+ renderer_->DecideRenderPassAllocationsForFrame(render_passes_in_draw_order_);
+ renderer_->DrawFrame(&render_passes_in_draw_order_,
+ 1.f,
+ viewport_rect,
+ viewport_rect,
+ false);
+
+ // If use_aa incorrectly ignores clipping, it will use the
+ // RenderPassProgramAA shader instead of the RenderPassProgram.
+ TestRenderPassProgram(TEX_COORD_PRECISION_MEDIUM, BLEND_MODE_NONE);
+}
+
+TEST_F(GLRendererShaderTest, DrawSolidColorShader) {
+ gfx::Rect viewport_rect(1, 1);
+ RenderPassId root_pass_id(1, 0);
+ TestRenderPass* root_pass;
+
+ gfx::Transform pixel_aligned_transform_causing_aa;
+ pixel_aligned_transform_causing_aa.Translate(25.5f, 25.5f);
+ pixel_aligned_transform_causing_aa.Scale(0.5f, 0.5f);
+
+ root_pass = AddRenderPass(&render_passes_in_draw_order_,
+ root_pass_id,
+ viewport_rect,
+ gfx::Transform());
+ AddTransformedQuad(root_pass,
+ viewport_rect,
+ SK_ColorYELLOW,
+ pixel_aligned_transform_causing_aa);
+
+ renderer_->DecideRenderPassAllocationsForFrame(render_passes_in_draw_order_);
+ renderer_->DrawFrame(&render_passes_in_draw_order_,
+ 1.f,
+ viewport_rect,
+ viewport_rect,
+ false);
+
+ TestSolidColorProgramAA();
+}
+
+class OutputSurfaceMockContext : public TestWebGraphicsContext3D {
+ public:
+ OutputSurfaceMockContext() { test_capabilities_.gpu.post_sub_buffer = true; }
+
+ // Specifically override methods even if they are unused (used in conjunction
+ // with StrictMock). We need to make sure that GLRenderer does not issue
+ // framebuffer-related GLuint calls directly. Instead these are supposed to go
+ // through the OutputSurface abstraction.
+ MOCK_METHOD2(bindFramebuffer, void(GLenum target, GLuint framebuffer));
+ MOCK_METHOD3(reshapeWithScaleFactor,
+ void(int width, int height, float scale_factor));
+ MOCK_METHOD4(drawElements,
+ void(GLenum mode, GLsizei count, GLenum type, GLintptr offset));
+};
+
+class MockOutputSurface : public OutputSurface {
+ public:
+ MockOutputSurface()
+ : OutputSurface(
+ TestContextProvider::Create(scoped_ptr<TestWebGraphicsContext3D>(
+ new StrictMock<OutputSurfaceMockContext>))) {
+ surface_size_ = gfx::Size(100, 100);
+ }
+ virtual ~MockOutputSurface() {}
+
+ MOCK_METHOD0(EnsureBackbuffer, void());
+ MOCK_METHOD0(DiscardBackbuffer, void());
+ MOCK_METHOD2(Reshape, void(const gfx::Size& size, float scale_factor));
+ MOCK_METHOD0(BindFramebuffer, void());
+ MOCK_METHOD1(SwapBuffers, void(CompositorFrame* frame));
+};
+
+class MockOutputSurfaceTest : public GLRendererTest {
+ protected:
+ virtual void SetUp() {
+ FakeOutputSurfaceClient output_surface_client_;
+ CHECK(output_surface_.BindToClient(&output_surface_client_));
+
+ shared_bitmap_manager_.reset(new TestSharedBitmapManager());
+ resource_provider_ = ResourceProvider::Create(&output_surface_,
+ shared_bitmap_manager_.get(),
+ NULL,
+ NULL,
+ 0,
+ false,
+ 1).Pass();
+
+ renderer_.reset(new FakeRendererGL(&renderer_client_,
+ &settings_,
+ &output_surface_,
+ resource_provider_.get()));
+ }
+
+ void SwapBuffers() { renderer_->SwapBuffers(CompositorFrameMetadata()); }
+
+ void DrawFrame(float device_scale_factor,
+ const gfx::Rect& device_viewport_rect) {
+ RenderPassId render_pass_id(1, 0);
+ TestRenderPass* render_pass = AddRenderPass(&render_passes_in_draw_order_,
+ render_pass_id,
+ device_viewport_rect,
+ gfx::Transform());
+ AddQuad(render_pass, device_viewport_rect, SK_ColorGREEN);
+
+ EXPECT_CALL(output_surface_, EnsureBackbuffer()).WillRepeatedly(Return());
+
+ EXPECT_CALL(output_surface_,
+ Reshape(device_viewport_rect.size(), device_scale_factor))
+ .Times(1);
+
+ EXPECT_CALL(output_surface_, BindFramebuffer()).Times(1);
+
+ EXPECT_CALL(*Context(), drawElements(_, _, _, _)).Times(1);
+
+ renderer_->DecideRenderPassAllocationsForFrame(
+ render_passes_in_draw_order_);
+ renderer_->DrawFrame(&render_passes_in_draw_order_,
+ device_scale_factor,
+ device_viewport_rect,
+ device_viewport_rect,
+ false);
+ }
+
+ OutputSurfaceMockContext* Context() {
+ return static_cast<OutputSurfaceMockContext*>(
+ static_cast<TestContextProvider*>(output_surface_.context_provider())
+ ->TestContext3d());
+ }
+
+ RendererSettings settings_;
+ FakeOutputSurfaceClient output_surface_client_;
+ StrictMock<MockOutputSurface> output_surface_;
+ scoped_ptr<SharedBitmapManager> shared_bitmap_manager_;
+ scoped_ptr<ResourceProvider> resource_provider_;
+ FakeRendererClient renderer_client_;
+ scoped_ptr<FakeRendererGL> renderer_;
+};
+
+TEST_F(MockOutputSurfaceTest, DrawFrameAndSwap) {
+ gfx::Rect device_viewport_rect(1, 1);
+ DrawFrame(1.f, device_viewport_rect);
+
+ EXPECT_CALL(output_surface_, SwapBuffers(_)).Times(1);
+ renderer_->SwapBuffers(CompositorFrameMetadata());
+}
+
+TEST_F(MockOutputSurfaceTest, DrawFrameAndResizeAndSwap) {
+ gfx::Rect device_viewport_rect(1, 1);
+
+ DrawFrame(1.f, device_viewport_rect);
+ EXPECT_CALL(output_surface_, SwapBuffers(_)).Times(1);
+ renderer_->SwapBuffers(CompositorFrameMetadata());
+
+ device_viewport_rect = gfx::Rect(2, 2);
+
+ DrawFrame(2.f, device_viewport_rect);
+ EXPECT_CALL(output_surface_, SwapBuffers(_)).Times(1);
+ renderer_->SwapBuffers(CompositorFrameMetadata());
+
+ DrawFrame(2.f, device_viewport_rect);
+ EXPECT_CALL(output_surface_, SwapBuffers(_)).Times(1);
+ renderer_->SwapBuffers(CompositorFrameMetadata());
+
+ device_viewport_rect = gfx::Rect(1, 1);
+
+ DrawFrame(1.f, device_viewport_rect);
+ EXPECT_CALL(output_surface_, SwapBuffers(_)).Times(1);
+ renderer_->SwapBuffers(CompositorFrameMetadata());
+}
+
+class GLRendererTestSyncPoint : public GLRendererPixelTest {
+ protected:
+ static void SyncPointCallback(int* callback_count) {
+ ++(*callback_count);
+ base::MessageLoop::current()->QuitWhenIdle();
+ }
+
+ static void OtherCallback(int* callback_count) {
+ ++(*callback_count);
+ base::MessageLoop::current()->QuitWhenIdle();
+ }
+};
+
+#if !defined(OS_ANDROID)
+TEST_F(GLRendererTestSyncPoint, SignalSyncPointOnLostContext) {
+ int sync_point_callback_count = 0;
+ int other_callback_count = 0;
+ gpu::gles2::GLES2Interface* gl =
+ output_surface_->context_provider()->ContextGL();
+ gpu::ContextSupport* context_support =
+ output_surface_->context_provider()->ContextSupport();
+
+ uint32 sync_point = gl->InsertSyncPointCHROMIUM();
+
+ gl->LoseContextCHROMIUM(GL_GUILTY_CONTEXT_RESET_ARB,
+ GL_INNOCENT_CONTEXT_RESET_ARB);
+
+ context_support->SignalSyncPoint(
+ sync_point, base::Bind(&SyncPointCallback, &sync_point_callback_count));
+ EXPECT_EQ(0, sync_point_callback_count);
+ EXPECT_EQ(0, other_callback_count);
+
+ // Make the sync point happen.
+ gl->Finish();
+ // Post a task after the sync point.
+ base::MessageLoop::current()->PostTask(
+ FROM_HERE, base::Bind(&OtherCallback, &other_callback_count));
+
+ base::MessageLoop::current()->Run();
+
+ // The sync point shouldn't have happened since the context was lost.
+ EXPECT_EQ(0, sync_point_callback_count);
+ EXPECT_EQ(1, other_callback_count);
+}
+
+TEST_F(GLRendererTestSyncPoint, SignalSyncPoint) {
+ int sync_point_callback_count = 0;
+ int other_callback_count = 0;
+
+ gpu::gles2::GLES2Interface* gl =
+ output_surface_->context_provider()->ContextGL();
+ gpu::ContextSupport* context_support =
+ output_surface_->context_provider()->ContextSupport();
+
+ uint32 sync_point = gl->InsertSyncPointCHROMIUM();
+
+ context_support->SignalSyncPoint(
+ sync_point, base::Bind(&SyncPointCallback, &sync_point_callback_count));
+ EXPECT_EQ(0, sync_point_callback_count);
+ EXPECT_EQ(0, other_callback_count);
+
+ // Make the sync point happen.
+ gl->Finish();
+ // Post a task after the sync point.
+ base::MessageLoop::current()->PostTask(
+ FROM_HERE, base::Bind(&OtherCallback, &other_callback_count));
+
+ base::MessageLoop::current()->Run();
+
+ // The sync point should have happened.
+ EXPECT_EQ(1, sync_point_callback_count);
+ EXPECT_EQ(1, other_callback_count);
+}
+#endif // OS_ANDROID
+
+} // namespace
+} // namespace cc
« no previous file with comments | « cc/output/gl_renderer_draw_cache.cc ('k') | cc/output/output_surface.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698