1 // Copyright 2012 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #include "cc/output/gl_renderer.h" 6 7 #include <set> 8 9 #include "cc/base/math_util.h" 10 #include "cc/output/compositor_frame_metadata.h" 11 #include "cc/resources/prioritized_resource_manager.h" 12 #include "cc/resources/resource_provider.h" 13 #include "cc/resources/sync_point_helper.h" 14 #include "cc/test/fake_impl_proxy.h" 15 #include "cc/test/fake_layer_tree_host_impl.h" 16 #include "cc/test/fake_output_surface.h" 17 #include "cc/test/mock_quad_culler.h" 18 #include "cc/test/pixel_test.h" 19 #include "cc/test/render_pass_test_common.h" 20 #include "cc/test/render_pass_test_utils.h" 21 #include "cc/test/test_web_graphics_context_3d.h" 22 #include "gpu/GLES2/gl2extchromium.h" 23 #include "testing/gmock/include/gmock/gmock.h" 24 #include "testing/gtest/include/gtest/gtest.h" 25 #include "third_party/khronos/GLES2/gl2.h" 26 #include "third_party/skia/include/core/SkImageFilter.h" 27 #include "third_party/skia/include/core/SkMatrix.h" 28 #include "third_party/skia/include/effects/SkColorFilterImageFilter.h" 29 #include "third_party/skia/include/effects/SkColorMatrixFilter.h" 30 #include "ui/gfx/transform.h" 31 32 using testing::_; 33 using testing::AnyNumber; 34 using testing::AtLeast; 35 using testing::Expectation; 36 using testing::InSequence; 37 using testing::Mock; 38 using testing::Return; 39 using testing::StrictMock; 40 using WebKit::WebGLId; 41 using WebKit::WebString; 42 using WebKit::WGC3Dbitfield; 43 using WebKit::WGC3Dboolean; 44 using WebKit::WGC3Dchar; 45 using WebKit::WGC3Denum; 46 using WebKit::WGC3Dfloat; 47 using WebKit::WGC3Dint; 48 using WebKit::WGC3Dintptr; 49 using WebKit::WGC3Dsizei; 50 using WebKit::WGC3Dsizeiptr; 51 using WebKit::WGC3Duint; 52 53 namespace cc { 54 55 #define EXPECT_PROGRAM_VALID(program_binding) \ 56 do { \ 57 EXPECT_TRUE(program_binding->program()); \ 58 EXPECT_TRUE(program_binding->initialized()); \ 59 } while (false) 60 61 // Explicitly named to be a friend in GLRenderer for shader access. 62 class GLRendererShaderPixelTest : public GLRendererPixelTest { 63 public: 64 void TestShaders() { 65 ASSERT_FALSE(renderer()->IsContextLost()); 66 EXPECT_PROGRAM_VALID(renderer()->GetTileCheckerboardProgram()); 67 EXPECT_PROGRAM_VALID(renderer()->GetDebugBorderProgram()); 68 EXPECT_PROGRAM_VALID(renderer()->GetSolidColorProgram()); 69 EXPECT_PROGRAM_VALID(renderer()->GetSolidColorProgramAA()); 70 TestShadersWithTexCoordPrecision(TexCoordPrecisionMedium); 71 TestShadersWithTexCoordPrecision(TexCoordPrecisionHigh); 72 ASSERT_FALSE(renderer()->IsContextLost()); 73 } 74 75 void TestShadersWithTexCoordPrecision(TexCoordPrecision precision) { 76 EXPECT_PROGRAM_VALID(renderer()->GetTileProgram(precision)); 77 EXPECT_PROGRAM_VALID(renderer()->GetTileProgramOpaque(precision)); 78 EXPECT_PROGRAM_VALID(renderer()->GetTileProgramAA(precision)); 79 EXPECT_PROGRAM_VALID(renderer()->GetTileProgramSwizzle(precision)); 80 EXPECT_PROGRAM_VALID(renderer()->GetTileProgramSwizzleOpaque(precision)); 81 EXPECT_PROGRAM_VALID(renderer()->GetTileProgramSwizzleAA(precision)); 82 EXPECT_PROGRAM_VALID(renderer()->GetRenderPassProgram(precision)); 83 EXPECT_PROGRAM_VALID(renderer()->GetRenderPassProgramAA(precision)); 84 EXPECT_PROGRAM_VALID(renderer()->GetRenderPassMaskProgram(precision)); 85 EXPECT_PROGRAM_VALID(renderer()->GetRenderPassMaskProgramAA(precision)); 86 EXPECT_PROGRAM_VALID( 87 renderer()->GetRenderPassColorMatrixProgram(precision)); 88 EXPECT_PROGRAM_VALID( 89 renderer()->GetRenderPassMaskColorMatrixProgramAA(precision)); 90 EXPECT_PROGRAM_VALID( 91 renderer()->GetRenderPassColorMatrixProgramAA(precision)); 92 EXPECT_PROGRAM_VALID( 93 renderer()->GetRenderPassMaskColorMatrixProgram(precision)); 94 EXPECT_PROGRAM_VALID(renderer()->GetTextureProgram(precision)); 95 EXPECT_PROGRAM_VALID( 96 renderer()->GetNonPremultipliedTextureProgram(precision)); 97 EXPECT_PROGRAM_VALID(renderer()->GetTextureBackgroundProgram(precision)); 98 EXPECT_PROGRAM_VALID( 99 renderer()->GetNonPremultipliedTextureBackgroundProgram(precision)); 100 EXPECT_PROGRAM_VALID(renderer()->GetTextureIOSurfaceProgram(precision)); 101 EXPECT_PROGRAM_VALID(renderer()->GetVideoYUVProgram(precision)); 102 EXPECT_PROGRAM_VALID(renderer()->GetVideoYUVAProgram(precision)); 103 // This is unlikely to be ever true in tests due to usage of osmesa. 104 if (renderer()->Capabilities().using_egl_image) 105 EXPECT_PROGRAM_VALID(renderer()->GetVideoStreamTextureProgram(precision)); 106 else 107 EXPECT_FALSE(renderer()->GetVideoStreamTextureProgram(precision)); 108 } 109 }; 110 111 namespace { 112 113 #if !defined(OS_ANDROID) 114 TEST_F(GLRendererShaderPixelTest, AllShadersCompile) { TestShaders(); } 115 #endif 116 117 class FrameCountingContext : public TestWebGraphicsContext3D { 118 public: 119 FrameCountingContext() : frame_(0) {} 120 121 // WebGraphicsContext3D methods. 122 123 // This method would normally do a glSwapBuffers under the hood. 124 virtual void prepareTexture() { frame_++; } 125 virtual WebString getString(WebKit::WGC3Denum name) { 126 if (name == GL_EXTENSIONS) 127 return WebString( 128 "GL_CHROMIUM_set_visibility GL_CHROMIUM_gpu_memory_manager " 129 "GL_CHROMIUM_discard_backbuffer"); 130 return WebString(); 131 } 132 133 // Methods added for test. 134 int frame_count() { return frame_; } 135 136 private: 137 int frame_; 138 }; 139 140 class FakeRendererClient : public RendererClient { 141 public: 142 FakeRendererClient() 143 : host_impl_(&proxy_), 144 set_full_root_layer_damage_count_(0), 145 root_layer_(LayerImpl::Create(host_impl_.active_tree(), 1)), 146 viewport_size_(gfx::Size(1, 1)), 147 scale_factor_(1.f), 148 external_stencil_test_enabled_(false) { 149 root_layer_->CreateRenderSurface(); 150 RenderPass::Id render_pass_id = 151 root_layer_->render_surface()->RenderPassId(); 152 scoped_ptr<RenderPass> root_render_pass = RenderPass::Create(); 153 root_render_pass->SetNew( 154 render_pass_id, gfx::Rect(), gfx::Rect(), gfx::Transform()); 155 render_passes_in_draw_order_.push_back(root_render_pass.Pass()); 156 } 157 158 // RendererClient methods. 159 virtual gfx::Rect DeviceViewport() const OVERRIDE { 160 static gfx::Size fake_size(1, 1); 161 return gfx::Rect(fake_size); 162 } 163 virtual float DeviceScaleFactor() const OVERRIDE { 164 return scale_factor_; 165 } 166 virtual const LayerTreeSettings& Settings() const OVERRIDE { 167 static LayerTreeSettings fake_settings; 168 return fake_settings; 169 } 170 virtual void SetFullRootLayerDamage() OVERRIDE { 171 set_full_root_layer_damage_count_++; 172 } 173 virtual bool HasImplThread() const OVERRIDE { return false; } 174 virtual bool ShouldClearRootRenderPass() const OVERRIDE { return true; } 175 virtual CompositorFrameMetadata MakeCompositorFrameMetadata() const OVERRIDE { 176 return CompositorFrameMetadata(); 177 } 178 virtual bool AllowPartialSwap() const OVERRIDE { 179 return true; 180 } 181 virtual bool ExternalStencilTestEnabled() const OVERRIDE { 182 return external_stencil_test_enabled_; 183 } 184 185 void EnableExternalStencilTest() { 186 external_stencil_test_enabled_ = true; 187 } 188 189 // Methods added for test. 190 int set_full_root_layer_damage_count() const { 191 return set_full_root_layer_damage_count_; 192 } 193 void set_viewport_and_scale( 194 gfx::Size viewport_size, float scale_factor) { 195 viewport_size_ = viewport_size; 196 scale_factor_ = scale_factor; 197 } 198 199 RenderPass* root_render_pass() { return render_passes_in_draw_order_.back(); } 200 RenderPassList* render_passes_in_draw_order() { 201 return &render_passes_in_draw_order_; 202 } 203 204 private: 205 FakeImplProxy proxy_; 206 FakeLayerTreeHostImpl host_impl_; 207 int set_full_root_layer_damage_count_; 208 scoped_ptr<LayerImpl> root_layer_; 209 RenderPassList render_passes_in_draw_order_; 210 gfx::Size viewport_size_; 211 float scale_factor_; 212 bool external_stencil_test_enabled_; 213 }; 214 215 class FakeRendererGL : public GLRenderer { 216 public: 217 FakeRendererGL(RendererClient* client, 218 OutputSurface* output_surface, 219 ResourceProvider* resource_provider) 220 : GLRenderer(client, output_surface, resource_provider, 0) {} 221 222 // GLRenderer methods. 223 224 // Changing visibility to public. 225 using GLRenderer::Initialize; 226 using GLRenderer::IsBackbufferDiscarded; 227 using GLRenderer::DoDrawQuad; 228 using GLRenderer::BeginDrawingFrame; 229 using GLRenderer::FinishDrawingQuadList; 230 using GLRenderer::stencil_enabled; 231 }; 232 233 class GLRendererTest : public testing::Test { 234 protected: 235 GLRendererTest() 236 : output_surface_(FakeOutputSurface::Create3d( 237 scoped_ptr<WebKit::WebGraphicsContext3D>( 238 new FrameCountingContext()))), 239 resource_provider_(ResourceProvider::Create(output_surface_.get(), 0)), 240 renderer_(&mock_client_, 241 output_surface_.get(), 242 resource_provider_.get()) {} 243 244 virtual void SetUp() { renderer_.Initialize(); } 245 246 void SwapBuffers() { renderer_.SwapBuffers(); } 247 248 FrameCountingContext* Context() { 249 return static_cast<FrameCountingContext*>(output_surface_->context3d()); 250 } 251 252 scoped_ptr<OutputSurface> output_surface_; 253 FakeRendererClient mock_client_; 254 scoped_ptr<ResourceProvider> resource_provider_; 255 FakeRendererGL renderer_; 256 }; 257 258 // Closing the namespace here so that GLRendererShaderTest can take advantage 259 // of the friend relationship with GLRenderer and all of the mock classes 260 // declared above it. 261 } // namespace 262 263 264 // Gives unique shader ids and unique program ids for tests that need them. 265 class ShaderCreatorMockGraphicsContext : public TestWebGraphicsContext3D { 266 public: 267 ShaderCreatorMockGraphicsContext() 268 : next_program_id_number_(10000), 269 next_shader_id_number_(1) {} 270 271 bool hasShader(WebGLId shader) { 272 return shader_set_.find(shader) != shader_set_.end(); 273 } 274 275 bool hasProgram(WebGLId program) { 276 return program_set_.find(program) != program_set_.end(); 277 } 278 279 virtual WebGLId createProgram() { 280 unsigned program = next_program_id_number_; 281 program_set_.insert(program); 282 next_program_id_number_++; 283 return program; 284 } 285 286 virtual void deleteProgram(WebGLId program) { 287 ASSERT_TRUE(hasProgram(program)); 288 program_set_.erase(program); 289 } 290 291 virtual void useProgram(WebGLId program) { 292 if (!program) 293 return; 294 ASSERT_TRUE(hasProgram(program)); 295 } 296 297 virtual WebKit::WebGLId createShader(WebKit::WGC3Denum) { 298 unsigned shader = next_shader_id_number_; 299 shader_set_.insert(shader); 300 next_shader_id_number_++; 301 return shader; 302 } 303 304 virtual void deleteShader(WebKit::WebGLId shader) { 305 ASSERT_TRUE(hasShader(shader)); 306 shader_set_.erase(shader); 307 } 308 309 virtual void attachShader(WebGLId program, WebGLId shader) { 310 ASSERT_TRUE(hasProgram(program)); 311 ASSERT_TRUE(hasShader(shader)); 312 } 313 314 protected: 315 unsigned next_program_id_number_; 316 unsigned next_shader_id_number_; 317 std::set<unsigned> program_set_; 318 std::set<unsigned> shader_set_; 319 }; 320 321 class GLRendererShaderTest : public testing::Test { 322 protected: 323 GLRendererShaderTest() 324 : output_surface_(FakeOutputSurface::Create3d( 325 scoped_ptr<WebKit::WebGraphicsContext3D>( 326 new ShaderCreatorMockGraphicsContext()))), 327 resource_provider_(ResourceProvider::Create(output_surface_.get(), 0)), 328 renderer_(scoped_ptr<FakeRendererGL>( 329 new FakeRendererGL(&mock_client_, 330 output_surface_.get(), 331 resource_provider_.get()))) { 332 renderer_->Initialize(); 333 } 334 335 void TestRenderPassProgram() { 336 EXPECT_PROGRAM_VALID(renderer_->render_pass_program_); 337 EXPECT_EQ(renderer_->render_pass_program_->program(), 338 renderer_->program_shadow_); 339 } 340 341 void TestRenderPassColorMatrixProgram() { 342 EXPECT_PROGRAM_VALID(renderer_->render_pass_color_matrix_program_); 343 EXPECT_EQ(renderer_->render_pass_color_matrix_program_->program(), 344 renderer_->program_shadow_); 345 } 346 347 void TestRenderPassMaskProgram() { 348 EXPECT_PROGRAM_VALID(renderer_->render_pass_mask_program_); 349 EXPECT_EQ(renderer_->render_pass_mask_program_->program(), 350 renderer_->program_shadow_); 351 } 352 353 void TestRenderPassMaskColorMatrixProgram() { 354 EXPECT_PROGRAM_VALID(renderer_->render_pass_mask_color_matrix_program_); 355 EXPECT_EQ(renderer_->render_pass_mask_color_matrix_program_->program(), 356 renderer_->program_shadow_); 357 } 358 359 void TestRenderPassProgramAA() { 360 EXPECT_PROGRAM_VALID(renderer_->render_pass_program_aa_); 361 EXPECT_EQ(renderer_->render_pass_program_aa_->program(), 362 renderer_->program_shadow_); 363 } 364 365 void TestRenderPassColorMatrixProgramAA() { 366 EXPECT_PROGRAM_VALID(renderer_->render_pass_color_matrix_program_aa_); 367 EXPECT_EQ(renderer_->render_pass_color_matrix_program_aa_->program(), 368 renderer_->program_shadow_); 369 } 370 371 void TestRenderPassMaskProgramAA() { 372 EXPECT_PROGRAM_VALID(renderer_->render_pass_mask_program_aa_); 373 EXPECT_EQ(renderer_->render_pass_mask_program_aa_->program(), 374 renderer_->program_shadow_); 375 } 376 377 void TestRenderPassMaskColorMatrixProgramAA() { 378 EXPECT_PROGRAM_VALID(renderer_->render_pass_mask_color_matrix_program_aa_); 379 EXPECT_EQ(renderer_->render_pass_mask_color_matrix_program_aa_->program(), 380 renderer_->program_shadow_); 381 } 382 383 void TestSolidColorProgramAA() { 384 EXPECT_PROGRAM_VALID(renderer_->solid_color_program_aa_); 385 EXPECT_EQ(renderer_->solid_color_program_aa_->program(), 386 renderer_->program_shadow_); 387 } 388 389 scoped_ptr<OutputSurface> output_surface_; 390 FakeRendererClient mock_client_; 391 scoped_ptr<ResourceProvider> resource_provider_; 392 scoped_ptr<FakeRendererGL> renderer_; 393 }; 394 395 namespace { 396 397 // Test GLRenderer discardBackbuffer functionality: 398 // Suggest recreating framebuffer when one already exists. 399 // Expected: it does nothing. 400 TEST_F(GLRendererTest, SuggestBackbufferYesWhenItAlreadyExistsShouldDoNothing) { 401 renderer_.SetDiscardBackBufferWhenNotVisible(false); 402 EXPECT_EQ(0, mock_client_.set_full_root_layer_damage_count()); 403 EXPECT_FALSE(renderer_.IsBackbufferDiscarded()); 404 405 SwapBuffers(); 406 EXPECT_EQ(1, Context()->frame_count()); 407 } 408 409 // Test GLRenderer DiscardBackbuffer functionality: 410 // Suggest discarding framebuffer when one exists and the renderer is not 411 // visible. 412 // Expected: it is discarded and damage tracker is reset. 413 TEST_F( 414 GLRendererTest, 415 SuggestBackbufferNoShouldDiscardBackbufferAndDamageRootLayerIfNotVisible) { 416 renderer_.SetVisible(false); 417 renderer_.SetDiscardBackBufferWhenNotVisible(true); 418 EXPECT_EQ(1, mock_client_.set_full_root_layer_damage_count()); 419 EXPECT_TRUE(renderer_.IsBackbufferDiscarded()); 420 } 421 422 // Test GLRenderer DiscardBackbuffer functionality: 423 // Suggest discarding framebuffer when one exists and the renderer is visible. 424 // Expected: the allocation is ignored. 425 TEST_F(GLRendererTest, SuggestBackbufferNoDoNothingWhenVisible) { 426 renderer_.SetVisible(true); 427 renderer_.SetDiscardBackBufferWhenNotVisible(true); 428 EXPECT_EQ(0, mock_client_.set_full_root_layer_damage_count()); 429 EXPECT_FALSE(renderer_.IsBackbufferDiscarded()); 430 } 431 432 // Test GLRenderer DiscardBackbuffer functionality: 433 // Suggest discarding framebuffer when one does not exist. 434 // Expected: it does nothing. 435 TEST_F(GLRendererTest, SuggestBackbufferNoWhenItDoesntExistShouldDoNothing) { 436 renderer_.SetVisible(false); 437 renderer_.SetDiscardBackBufferWhenNotVisible(true); 438 EXPECT_EQ(1, mock_client_.set_full_root_layer_damage_count()); 439 EXPECT_TRUE(renderer_.IsBackbufferDiscarded()); 440 441 renderer_.SetDiscardBackBufferWhenNotVisible(true); 442 EXPECT_EQ(1, mock_client_.set_full_root_layer_damage_count()); 443 EXPECT_TRUE(renderer_.IsBackbufferDiscarded()); 444 } 445 446 // Test GLRenderer DiscardBackbuffer functionality: 447 // Begin drawing a frame while a framebuffer is discarded. 448 // Expected: will recreate framebuffer. 449 TEST_F(GLRendererTest, DiscardedBackbufferIsRecreatedForScopeDuration) { 450 renderer_.SetVisible(false); 451 renderer_.SetDiscardBackBufferWhenNotVisible(true); 452 EXPECT_TRUE(renderer_.IsBackbufferDiscarded()); 453 EXPECT_EQ(1, mock_client_.set_full_root_layer_damage_count()); 454 455 renderer_.SetVisible(true); 456 renderer_.DrawFrame(mock_client_.render_passes_in_draw_order()); 457 EXPECT_FALSE(renderer_.IsBackbufferDiscarded()); 458 459 SwapBuffers(); 460 EXPECT_EQ(1, Context()->frame_count()); 461 } 462 463 TEST_F(GLRendererTest, FramebufferDiscardedAfterReadbackWhenNotVisible) { 464 renderer_.SetVisible(false); 465 renderer_.SetDiscardBackBufferWhenNotVisible(true); 466 EXPECT_TRUE(renderer_.IsBackbufferDiscarded()); 467 EXPECT_EQ(1, mock_client_.set_full_root_layer_damage_count()); 468 469 char pixels[4]; 470 renderer_.DrawFrame(mock_client_.render_passes_in_draw_order()); 471 EXPECT_FALSE(renderer_.IsBackbufferDiscarded()); 472 473 renderer_.GetFramebufferPixels(pixels, gfx::Rect(0, 0, 1, 1)); 474 EXPECT_TRUE(renderer_.IsBackbufferDiscarded()); 475 EXPECT_EQ(2, mock_client_.set_full_root_layer_damage_count()); 476 } 477 478 TEST_F(GLRendererTest, ExternalStencil) { 479 EXPECT_FALSE(renderer_.stencil_enabled()); 480 481 mock_client_.EnableExternalStencilTest(); 482 mock_client_.root_render_pass()->has_transparent_background = false; 483 484 renderer_.DrawFrame(mock_client_.render_passes_in_draw_order()); 485 EXPECT_TRUE(renderer_.stencil_enabled()); 486 } 487 488 class ForbidSynchronousCallContext : public TestWebGraphicsContext3D { 489 public: 490 ForbidSynchronousCallContext() {} 491 492 virtual bool getActiveAttrib(WebGLId program, 493 WGC3Duint index, 494 ActiveInfo& info) { 495 ADD_FAILURE(); 496 return false; 497 } 498 virtual bool getActiveUniform(WebGLId program, 499 WGC3Duint index, 500 ActiveInfo& info) { 501 ADD_FAILURE(); 502 return false; 503 } 504 virtual void getAttachedShaders(WebGLId program, 505 WGC3Dsizei max_count, 506 WGC3Dsizei* count, 507 WebGLId* shaders) { 508 ADD_FAILURE(); 509 } 510 virtual WGC3Dint getAttribLocation(WebGLId program, const WGC3Dchar* name) { 511 ADD_FAILURE(); 512 return 0; 513 } 514 virtual void getBooleanv(WGC3Denum pname, WGC3Dboolean* value) { 515 ADD_FAILURE(); 516 } 517 virtual void getBufferParameteriv(WGC3Denum target, 518 WGC3Denum pname, 519 WGC3Dint* value) { 520 ADD_FAILURE(); 521 } 522 virtual Attributes getContextAttributes() { 523 ADD_FAILURE(); 524 return attributes_; 525 } 526 virtual WGC3Denum getError() { 527 ADD_FAILURE(); 528 return 0; 529 } 530 virtual void getFloatv(WGC3Denum pname, WGC3Dfloat* value) { ADD_FAILURE(); } 531 virtual void getFramebufferAttachmentParameteriv(WGC3Denum target, 532 WGC3Denum attachment, 533 WGC3Denum pname, 534 WGC3Dint* value) { 535 ADD_FAILURE(); 536 } 537 virtual void getIntegerv(WGC3Denum pname, WGC3Dint* value) { 538 if (pname == GL_MAX_TEXTURE_SIZE) { 539 // MAX_TEXTURE_SIZE is cached client side, so it's OK to query. 540 *value = 1024; 541 } else { 542 ADD_FAILURE(); 543 } 544 } 545 546 // We allow querying the shader compilation and program link status in debug 547 // mode, but not release. 548 virtual void getProgramiv(WebGLId program, WGC3Denum pname, WGC3Dint* value) { 549 #ifndef NDEBUG 550 *value = 1; 551 #else 552 ADD_FAILURE(); 553 #endif 554 } 555 556 virtual void getShaderiv(WebGLId shader, WGC3Denum pname, WGC3Dint* value) { 557 #ifndef NDEBUG 558 *value = 1; 559 #else 560 ADD_FAILURE(); 561 #endif 562 } 563 564 virtual WebString getString(WGC3Denum name) { 565 // We allow querying the extension string. 566 // TODO(enne): It'd be better to check that we only do this before starting 567 // any other expensive work (like starting a compilation) 568 if (name != GL_EXTENSIONS) 569 ADD_FAILURE(); 570 return WebString(); 571 } 572 573 virtual WebString getProgramInfoLog(WebGLId program) { 574 ADD_FAILURE(); 575 return WebString(); 576 } 577 virtual void getRenderbufferParameteriv(WGC3Denum target, 578 WGC3Denum pname, 579 WGC3Dint* value) { 580 ADD_FAILURE(); 581 } 582 583 virtual WebString getShaderInfoLog(WebGLId shader) { 584 ADD_FAILURE(); 585 return WebString(); 586 } 587 virtual void getShaderPrecisionFormat(WGC3Denum shadertype, 588 WGC3Denum precisiontype, 589 WGC3Dint* range, 590 WGC3Dint* precision) { 591 ADD_FAILURE(); 592 } 593 virtual WebString getShaderSource(WebGLId shader) { 594 ADD_FAILURE(); 595 return WebString(); 596 } 597 virtual void getTexParameterfv(WGC3Denum target, 598 WGC3Denum pname, 599 WGC3Dfloat* value) { 600 ADD_FAILURE(); 601 } 602 virtual void getTexParameteriv(WGC3Denum target, 603 WGC3Denum pname, 604 WGC3Dint* value) { 605 ADD_FAILURE(); 606 } 607 virtual void getUniformfv(WebGLId program, 608 WGC3Dint location, 609 WGC3Dfloat* value) { 610 ADD_FAILURE(); 611 } 612 virtual void getUniformiv(WebGLId program, 613 WGC3Dint location, 614 WGC3Dint* value) { 615 ADD_FAILURE(); 616 } 617 virtual WGC3Dint getUniformLocation(WebGLId program, const WGC3Dchar* name) { 618 ADD_FAILURE(); 619 return 0; 620 } 621 virtual void getVertexAttribfv(WGC3Duint index, 622 WGC3Denum pname, 623 WGC3Dfloat* value) { 624 ADD_FAILURE(); 625 } 626 virtual void getVertexAttribiv(WGC3Duint index, 627 WGC3Denum pname, 628 WGC3Dint* value) { 629 ADD_FAILURE(); 630 } 631 virtual WGC3Dsizeiptr getVertexAttribOffset(WGC3Duint index, 632 WGC3Denum pname) { 633 ADD_FAILURE(); 634 return 0; 635 } 636 }; 637 638 // This test isn't using the same fixture as GLRendererTest, and you can't mix 639 // TEST() and TEST_F() with the same name, Hence LRC2. 640 TEST(GLRendererTest2, InitializationDoesNotMakeSynchronousCalls) { 641 FakeRendererClient mock_client; 642 scoped_ptr<OutputSurface> output_surface( 643 FakeOutputSurface::Create3d(scoped_ptr<WebKit::WebGraphicsContext3D>( 644 new ForbidSynchronousCallContext))); 645 scoped_ptr<ResourceProvider> resource_provider( 646 ResourceProvider::Create(output_surface.get(), 0)); 647 FakeRendererGL renderer( 648 &mock_client, output_surface.get(), resource_provider.get()); 649 650 EXPECT_TRUE(renderer.Initialize()); 651 } 652 653 class LoseContextOnFirstGetContext : public TestWebGraphicsContext3D { 654 public: 655 LoseContextOnFirstGetContext() : context_lost_(false) {} 656 657 virtual bool makeContextCurrent() OVERRIDE { return !context_lost_; } 658 659 virtual void getProgramiv(WebGLId program, WGC3Denum pname, WGC3Dint* value) 660 OVERRIDE { 661 context_lost_ = true; 662 *value = 0; 663 } 664 665 virtual void getShaderiv(WebGLId shader, WGC3Denum pname, WGC3Dint* value) 666 OVERRIDE { 667 context_lost_ = true; 668 *value = 0; 669 } 670 671 virtual WGC3Denum getGraphicsResetStatusARB() OVERRIDE { 672 return context_lost_ ? 1 : 0; 673 } 674 675 private: 676 bool context_lost_; 677 }; 678 679 TEST(GLRendererTest2, InitializationWithQuicklyLostContextDoesNotAssert) { 680 FakeRendererClient mock_client; 681 scoped_ptr<OutputSurface> output_surface( 682 FakeOutputSurface::Create3d(scoped_ptr<WebKit::WebGraphicsContext3D>( 683 new LoseContextOnFirstGetContext))); 684 scoped_ptr<ResourceProvider> resource_provider( 685 ResourceProvider::Create(output_surface.get(), 0)); 686 FakeRendererGL renderer( 687 &mock_client, output_surface.get(), resource_provider.get()); 688 689 renderer.Initialize(); 690 } 691 692 class ClearCountingContext : public TestWebGraphicsContext3D { 693 public: 694 ClearCountingContext() : clear_(0) {} 695 696 virtual void clear(WGC3Dbitfield) { clear_++; } 697 698 int clear_count() const { return clear_; } 699 700 private: 701 int clear_; 702 }; 703 704 TEST(GLRendererTest2, OpaqueBackground) { 705 FakeRendererClient mock_client; 706 scoped_ptr<OutputSurface> output_surface(FakeOutputSurface::Create3d( 707 scoped_ptr<WebKit::WebGraphicsContext3D>(new ClearCountingContext))); 708 ClearCountingContext* context = 709 static_cast<ClearCountingContext*>(output_surface->context3d()); 710 scoped_ptr<ResourceProvider> resource_provider( 711 ResourceProvider::Create(output_surface.get(), 0)); 712 FakeRendererGL renderer( 713 &mock_client, output_surface.get(), resource_provider.get()); 714 715 mock_client.root_render_pass()->has_transparent_background = false; 716 717 EXPECT_TRUE(renderer.Initialize()); 718 719 renderer.DrawFrame(mock_client.render_passes_in_draw_order()); 720 721 // On DEBUG builds, render passes with opaque background clear to blue to 722 // easily see regions that were not drawn on the screen. 723 #ifdef NDEBUG 724 EXPECT_EQ(0, context->clear_count()); 725 #else 726 EXPECT_EQ(1, context->clear_count()); 727 #endif 728 } 729 730 TEST(GLRendererTest2, TransparentBackground) { 731 FakeRendererClient mock_client; 732 scoped_ptr<OutputSurface> output_surface(FakeOutputSurface::Create3d( 733 scoped_ptr<WebKit::WebGraphicsContext3D>(new ClearCountingContext))); 734 ClearCountingContext* context = 735 static_cast<ClearCountingContext*>(output_surface->context3d()); 736 scoped_ptr<ResourceProvider> resource_provider( 737 ResourceProvider::Create(output_surface.get(), 0)); 738 FakeRendererGL renderer( 739 &mock_client, output_surface.get(), resource_provider.get()); 740 741 mock_client.root_render_pass()->has_transparent_background = true; 742 743 EXPECT_TRUE(renderer.Initialize()); 744 745 renderer.DrawFrame(mock_client.render_passes_in_draw_order()); 746 747 EXPECT_EQ(1, context->clear_count()); 748 } 749 750 class VisibilityChangeIsLastCallTrackingContext 751 : public TestWebGraphicsContext3D { 752 public: 753 VisibilityChangeIsLastCallTrackingContext() 754 : last_call_was_set_visibility_(false) {} 755 756 // WebGraphicsContext3D methods. 757 virtual void setVisibilityCHROMIUM(bool visible) { 758 DCHECK(last_call_was_set_visibility_ == false); 759 last_call_was_set_visibility_ = true; 760 } 761 virtual void flush() { 762 last_call_was_set_visibility_ = false; 763 } 764 virtual void deleteTexture(WebGLId) { 765 last_call_was_set_visibility_ = false; 766 } 767 virtual void deleteFramebuffer(WebGLId) { 768 last_call_was_set_visibility_ = false; 769 } 770 virtual void deleteQueryEXT(WebGLId) { 771 last_call_was_set_visibility_ = false; 772 } 773 virtual void deleteRenderbuffer(WebGLId) { 774 last_call_was_set_visibility_ = false; 775 } 776 virtual void discardBackbufferCHROMIUM() { 777 last_call_was_set_visibility_ = false; 778 } 779 virtual void ensureBackbufferCHROMIUM() { 780 last_call_was_set_visibility_ = false; 781 } 782 783 // This method would normally do a glSwapBuffers under the hood. 784 virtual WebString getString(WebKit::WGC3Denum name) { 785 if (name == GL_EXTENSIONS) 786 return WebString( 787 "GL_CHROMIUM_set_visibility GL_CHROMIUM_gpu_memory_manager " 788 "GL_CHROMIUM_discard_backbuffer"); 789 return WebString(); 790 } 791 792 // Methods added for test. 793 bool last_call_was_set_visibility() const { 794 return last_call_was_set_visibility_; 795 } 796 797 private: 798 bool last_call_was_set_visibility_; 799 }; 800 801 TEST(GLRendererTest2, VisibilityChangeIsLastCall) { 802 FakeRendererClient mock_client; 803 scoped_ptr<OutputSurface> output_surface( 804 FakeOutputSurface::Create3d(scoped_ptr<WebKit::WebGraphicsContext3D>( 805 new VisibilityChangeIsLastCallTrackingContext))); 806 VisibilityChangeIsLastCallTrackingContext* context = 807 static_cast<VisibilityChangeIsLastCallTrackingContext*>( 808 output_surface->context3d()); 809 scoped_ptr<ResourceProvider> resource_provider( 810 ResourceProvider::Create(output_surface.get(), 0)); 811 FakeRendererGL renderer( 812 &mock_client, output_surface.get(), resource_provider.get()); 813 814 EXPECT_TRUE(renderer.Initialize()); 815 816 // Ensure that the call to setVisibilityCHROMIUM is the last call issue to the 817 // GPU process, after glFlush is called, and after the RendererClient's 818 // SetManagedMemoryPolicy is called. Plumb this tracking between both the 819 // RenderClient and the Context by giving them both a pointer to a variable on 820 // the stack. 821 renderer.SetVisible(true); 822 renderer.DrawFrame(mock_client.render_passes_in_draw_order()); 823 renderer.SetVisible(false); 824 EXPECT_TRUE(context->last_call_was_set_visibility()); 825 } 826 827 class TextureStateTrackingContext : public TestWebGraphicsContext3D { 828 public: 829 TextureStateTrackingContext() : active_texture_(GL_INVALID_ENUM) {} 830 831 virtual WebString getString(WGC3Denum name) { 832 if (name == GL_EXTENSIONS) 833 return WebString("GL_OES_EGL_image_external"); 834 return WebString(); 835 } 836 837 MOCK_METHOD3(texParameteri, 838 void(WGC3Denum target, WGC3Denum pname, WGC3Dint param)); 839 MOCK_METHOD4(drawElements, 840 void(WGC3Denum mode, 841 WGC3Dsizei count, 842 WGC3Denum type, 843 WGC3Dintptr offset)); 844 845 virtual void activeTexture(WGC3Denum texture) { 846 EXPECT_NE(texture, active_texture_); 847 active_texture_ = texture; 848 } 849 850 WGC3Denum active_texture() const { return active_texture_; } 851 852 private: 853 WGC3Denum active_texture_; 854 }; 855 856 TEST(GLRendererTest2, ActiveTextureState) { 857 FakeRendererClient fake_client; 858 scoped_ptr<OutputSurface> output_surface( 859 FakeOutputSurface::Create3d(scoped_ptr<WebKit::WebGraphicsContext3D>( 860 new TextureStateTrackingContext))); 861 TextureStateTrackingContext* context = 862 static_cast<TextureStateTrackingContext*>(output_surface->context3d()); 863 scoped_ptr<ResourceProvider> resource_provider( 864 ResourceProvider::Create(output_surface.get(), 0)); 865 FakeRendererGL renderer( 866 &fake_client, output_surface.get(), resource_provider.get()); 867 868 // During initialization we are allowed to set any texture parameters. 869 EXPECT_CALL(*context, texParameteri(_, _, _)).Times(AnyNumber()); 870 EXPECT_TRUE(renderer.Initialize()); 871 872 cc::RenderPass::Id id(1, 1); 873 scoped_ptr<TestRenderPass> pass = TestRenderPass::Create(); 874 pass->SetNew(id, 875 gfx::Rect(0, 0, 100, 100), 876 gfx::Rect(0, 0, 100, 100), 877 gfx::Transform()); 878 pass->AppendOneOfEveryQuadType(resource_provider.get(), RenderPass::Id(2, 1)); 879 880 // Set up expected texture filter state transitions that match the quads 881 // created in AppendOneOfEveryQuadType(). 882 Mock::VerifyAndClearExpectations(context); 883 { 884 InSequence sequence; 885 886 // yuv_quad is drawn with the default linear filter. 887 EXPECT_CALL(*context, drawElements(_, _, _, _)); 888 889 // tile_quad is drawn with GL_NEAREST because it is not transformed or 890 // scaled. 891 EXPECT_CALL( 892 *context, 893 texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST)); 894 EXPECT_CALL( 895 *context, 896 texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST)); 897 EXPECT_CALL(*context, drawElements(_, _, _, _)); 898 899 // transformed_tile_quad uses GL_LINEAR. 900 EXPECT_CALL(*context, drawElements(_, _, _, _)); 901 902 // scaled_tile_quad also uses GL_LINEAR. 903 EXPECT_CALL(*context, drawElements(_, _, _, _)); 904 905 // The remaining quads also use GL_LINEAR because nearest neighbor 906 // filtering is currently only used with tile quads. 907 EXPECT_CALL(*context, drawElements(_, _, _, _)).Times(6); 908 } 909 910 cc::DirectRenderer::DrawingFrame drawing_frame; 911 renderer.BeginDrawingFrame(&drawing_frame); 912 EXPECT_EQ(static_cast<unsigned>(GL_TEXTURE0), context->active_texture()); 913 914 for (cc::QuadList::BackToFrontIterator 915 it = pass->quad_list.BackToFrontBegin(); 916 it != pass->quad_list.BackToFrontEnd(); 917 ++it) { 918 renderer.DoDrawQuad(&drawing_frame, *it); 919 } 920 renderer.FinishDrawingQuadList(); 921 EXPECT_EQ(static_cast<unsigned>(GL_TEXTURE0), context->active_texture()); 922 Mock::VerifyAndClearExpectations(context); 923 } 924 925 class NoClearRootRenderPassFakeClient : public FakeRendererClient { 926 public: 927 virtual bool ShouldClearRootRenderPass() const OVERRIDE { return false; } 928 }; 929 930 class NoClearRootRenderPassMockContext : public TestWebGraphicsContext3D { 931 public: 932 MOCK_METHOD1(clear, void(WGC3Dbitfield mask)); 933 MOCK_METHOD4(drawElements, 934 void(WGC3Denum mode, 935 WGC3Dsizei count, 936 WGC3Denum type, 937 WGC3Dintptr offset)); 938 }; 939 940 TEST(GLRendererTest2, ShouldClearRootRenderPass) { 941 NoClearRootRenderPassFakeClient mock_client; 942 scoped_ptr<OutputSurface> output_surface( 943 FakeOutputSurface::Create3d(scoped_ptr<WebKit::WebGraphicsContext3D>( 944 new NoClearRootRenderPassMockContext))); 945 NoClearRootRenderPassMockContext* mock_context = 946 static_cast<NoClearRootRenderPassMockContext*>( 947 output_surface->context3d()); 948 scoped_ptr<ResourceProvider> resource_provider( 949 ResourceProvider::Create(output_surface.get(), 0)); 950 FakeRendererGL renderer( 951 &mock_client, output_surface.get(), resource_provider.get()); 952 EXPECT_TRUE(renderer.Initialize()); 953 954 gfx::Rect viewport_rect(mock_client.DeviceViewport()); 955 ScopedPtrVector<RenderPass>& render_passes = 956 *mock_client.render_passes_in_draw_order(); 957 render_passes.clear(); 958 959 RenderPass::Id root_pass_id(1, 0); 960 TestRenderPass* root_pass = AddRenderPass( 961 &render_passes, root_pass_id, viewport_rect, gfx::Transform()); 962 AddQuad(root_pass, viewport_rect, SK_ColorGREEN); 963 964 RenderPass::Id child_pass_id(2, 0); 965 TestRenderPass* child_pass = AddRenderPass( 966 &render_passes, child_pass_id, viewport_rect, gfx::Transform()); 967 AddQuad(child_pass, viewport_rect, SK_ColorBLUE); 968 969 AddRenderPassQuad(root_pass, child_pass); 970 971 #ifdef NDEBUG 972 GLint clear_bits = GL_COLOR_BUFFER_BIT; 973 #else 974 GLint clear_bits = GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT; 975 #endif 976 977 // First render pass is not the root one, clearing should happen. 978 EXPECT_CALL(*mock_context, clear(clear_bits)).Times(AtLeast(1)); 979 980 Expectation first_render_pass = 981 EXPECT_CALL(*mock_context, drawElements(_, _, _, _)).Times(1); 982 983 // The second render pass is the root one, clearing should be prevented. 984 EXPECT_CALL(*mock_context, clear(clear_bits)).Times(0) 985 .After(first_render_pass); 986 987 EXPECT_CALL(*mock_context, drawElements(_, _, _, _)).Times(AnyNumber()) 988 .After(first_render_pass); 989 990 renderer.DecideRenderPassAllocationsForFrame( 991 *mock_client.render_passes_in_draw_order()); 992 renderer.DrawFrame(mock_client.render_passes_in_draw_order()); 993 994 // In multiple render passes all but the root pass should clear the 995 // framebuffer. 996 Mock::VerifyAndClearExpectations(&mock_context); 997 } 998 999 class ScissorTestOnClearCheckingContext : public TestWebGraphicsContext3D { 1000 public: 1001 ScissorTestOnClearCheckingContext() : scissor_enabled_(false) {} 1002 1003 virtual void clear(WGC3Dbitfield) { EXPECT_FALSE(scissor_enabled_); } 1004 1005 virtual void enable(WGC3Denum cap) { 1006 if (cap == GL_SCISSOR_TEST) 1007 scissor_enabled_ = true; 1008 } 1009 1010 virtual void disable(WGC3Denum cap) { 1011 if (cap == GL_SCISSOR_TEST) 1012 scissor_enabled_ = false; 1013 } 1014 1015 private: 1016 bool scissor_enabled_; 1017 }; 1018 1019 TEST(GLRendererTest2, ScissorTestWhenClearing) { 1020 FakeRendererClient mock_client; 1021 scoped_ptr<OutputSurface> output_surface( 1022 FakeOutputSurface::Create3d(scoped_ptr<WebKit::WebGraphicsContext3D>( 1023 new ScissorTestOnClearCheckingContext))); 1024 scoped_ptr<ResourceProvider> resource_provider( 1025 ResourceProvider::Create(output_surface.get(), 0)); 1026 FakeRendererGL renderer( 1027 &mock_client, output_surface.get(), resource_provider.get()); 1028 EXPECT_TRUE(renderer.Initialize()); 1029 EXPECT_FALSE(renderer.Capabilities().using_partial_swap); 1030 1031 gfx::Rect viewport_rect(mock_client.DeviceViewport()); 1032 ScopedPtrVector<RenderPass>& render_passes = 1033 *mock_client.render_passes_in_draw_order(); 1034 render_passes.clear(); 1035 1036 gfx::Rect grand_child_rect(25, 25); 1037 RenderPass::Id grand_child_pass_id(3, 0); 1038 TestRenderPass* grand_child_pass = AddRenderPass( 1039 &render_passes, grand_child_pass_id, grand_child_rect, gfx::Transform()); 1040 AddClippedQuad(grand_child_pass, grand_child_rect, SK_ColorYELLOW); 1041 1042 gfx::Rect child_rect(50, 50); 1043 RenderPass::Id child_pass_id(2, 0); 1044 TestRenderPass* child_pass = AddRenderPass( 1045 &render_passes, child_pass_id, child_rect, gfx::Transform()); 1046 AddQuad(child_pass, child_rect, SK_ColorBLUE); 1047 1048 RenderPass::Id root_pass_id(1, 0); 1049 TestRenderPass* root_pass = AddRenderPass( 1050 &render_passes, root_pass_id, viewport_rect, gfx::Transform()); 1051 AddQuad(root_pass, viewport_rect, SK_ColorGREEN); 1052 1053 AddRenderPassQuad(root_pass, child_pass); 1054 AddRenderPassQuad(child_pass, grand_child_pass); 1055 1056 renderer.DecideRenderPassAllocationsForFrame( 1057 *mock_client.render_passes_in_draw_order()); 1058 renderer.DrawFrame(mock_client.render_passes_in_draw_order()); 1059 } 1060 1061 class NonReshapableOutputSurface : public FakeOutputSurface { 1062 public: 1063 explicit NonReshapableOutputSurface( 1064 scoped_ptr<WebKit::WebGraphicsContext3D> context3d) 1065 : FakeOutputSurface(context3d.Pass(), false) {} 1066 virtual gfx::Size SurfaceSize() const OVERRIDE { return gfx::Size(500, 500); } 1067 }; 1068 1069 class OffsetViewportRendererClient : public FakeRendererClient { 1070 public: 1071 virtual gfx::Rect DeviceViewport() const OVERRIDE { 1072 return gfx::Rect(10, 10, 100, 100); 1073 } 1074 }; 1075 1076 class FlippedScissorAndViewportContext : public TestWebGraphicsContext3D { 1077 public: 1078 FlippedScissorAndViewportContext() 1079 : did_call_viewport_(false), did_call_scissor_(false) {} 1080 virtual ~FlippedScissorAndViewportContext() { 1081 EXPECT_TRUE(did_call_viewport_); 1082 EXPECT_TRUE(did_call_scissor_); 1083 } 1084 1085 virtual void viewport(GLint x, GLint y, GLsizei width, GLsizei height) { 1086 EXPECT_EQ(10, x); 1087 EXPECT_EQ(390, y); 1088 EXPECT_EQ(100, width); 1089 EXPECT_EQ(100, height); 1090 did_call_viewport_ = true; 1091 } 1092 1093 virtual void scissor(GLint x, GLint y, GLsizei width, GLsizei height) { 1094 EXPECT_EQ(30, x); 1095 EXPECT_EQ(450, y); 1096 EXPECT_EQ(20, width); 1097 EXPECT_EQ(20, height); 1098 did_call_scissor_ = true; 1099 } 1100 1101 private: 1102 bool did_call_viewport_; 1103 bool did_call_scissor_; 1104 }; 1105 1106 TEST(GLRendererTest2, ScissorAndViewportWithinNonreshapableSurface) { 1107 // In Android WebView, the OutputSurface is unable to respect reshape() calls 1108 // and maintains a fixed size. This test verifies that glViewport and 1109 // glScissor's Y coordinate is flipped correctly in this environment, and that 1110 // the glViewport can be at a nonzero origin within the surface. 1111 OffsetViewportRendererClient mock_client; 1112 scoped_ptr<OutputSurface> output_surface(make_scoped_ptr( 1113 new NonReshapableOutputSurface(scoped_ptr<WebKit::WebGraphicsContext3D>( 1114 new FlippedScissorAndViewportContext)))); 1115 scoped_ptr<ResourceProvider> resource_provider( 1116 ResourceProvider::Create(output_surface.get(), 0)); 1117 FakeRendererGL renderer( 1118 &mock_client, output_surface.get(), resource_provider.get()); 1119 EXPECT_TRUE(renderer.Initialize()); 1120 EXPECT_FALSE(renderer.Capabilities().using_partial_swap); 1121 1122 gfx::Rect viewport_rect(mock_client.DeviceViewport().size()); 1123 gfx::Rect quad_rect = gfx::Rect(20, 20, 20, 20); 1124 ScopedPtrVector<RenderPass>& render_passes = 1125 *mock_client.render_passes_in_draw_order(); 1126 render_passes.clear(); 1127 1128 RenderPass::Id root_pass_id(1, 0); 1129 TestRenderPass* root_pass = AddRenderPass( 1130 &render_passes, root_pass_id, viewport_rect, gfx::Transform()); 1131 AddClippedQuad(root_pass, quad_rect, SK_ColorGREEN); 1132 1133 renderer.DecideRenderPassAllocationsForFrame( 1134 *mock_client.render_passes_in_draw_order()); 1135 renderer.DrawFrame(mock_client.render_passes_in_draw_order()); 1136 } 1137 1138 TEST_F(GLRendererShaderTest, DrawRenderPassQuadShaderPermutations) { 1139 gfx::Rect viewport_rect(mock_client_.DeviceViewport()); 1140 ScopedPtrVector<RenderPass>* render_passes = 1141 mock_client_.render_passes_in_draw_order(); 1142 1143 gfx::Rect child_rect(50, 50); 1144 RenderPass::Id child_pass_id(2, 0); 1145 TestRenderPass* child_pass; 1146 1147 RenderPass::Id root_pass_id(1, 0); 1148 TestRenderPass* root_pass; 1149 1150 cc::ResourceProvider::ResourceId mask = 1151 resource_provider_->CreateResource(gfx::Size(20, 12), 1152 resource_provider_->best_texture_format(), 1153 ResourceProvider::TextureUsageAny); 1154 resource_provider_->AllocateForTesting(mask); 1155 1156 SkScalar matrix[20]; 1157 float amount = 0.5f; 1158 matrix[0] = 0.213f + 0.787f * amount; 1159 matrix[1] = 0.715f - 0.715f * amount; 1160 matrix[2] = 1.f - (matrix[0] + matrix[1]); 1161 matrix[3] = matrix[4] = 0; 1162 matrix[5] = 0.213f - 0.213f * amount; 1163 matrix[6] = 0.715f + 0.285f * amount; 1164 matrix[7] = 1.f - (matrix[5] + matrix[6]); 1165 matrix[8] = matrix[9] = 0; 1166 matrix[10] = 0.213f - 0.213f * amount; 1167 matrix[11] = 0.715f - 0.715f * amount; 1168 matrix[12] = 1.f - (matrix[10] + matrix[11]); 1169 matrix[13] = matrix[14] = 0; 1170 matrix[15] = matrix[16] = matrix[17] = matrix[19] = 0; 1171 matrix[18] = 1; 1172 skia::RefPtr<SkColorFilter> color_filter( 1173 skia::AdoptRef(new SkColorMatrixFilter(matrix))); 1174 skia::RefPtr<SkImageFilter> filter = skia::AdoptRef( 1175 SkColorFilterImageFilter::Create(color_filter.get(), NULL)); 1176 1177 gfx::Transform transform_causing_aa; 1178 transform_causing_aa.Rotate(20.0); 1179 1180 // RenderPassProgram 1181 render_passes->clear(); 1182 1183 child_pass = AddRenderPass( 1184 render_passes, child_pass_id, child_rect, gfx::Transform()); 1185 1186 root_pass = AddRenderPass( 1187 render_passes, root_pass_id, viewport_rect, gfx::Transform()); 1188 1189 AddRenderPassQuad(root_pass, 1190 child_pass, 1191 0, 1192 skia::RefPtr<SkImageFilter>(), 1193 gfx::Transform()); 1194 1195 renderer_->DecideRenderPassAllocationsForFrame( 1196 *mock_client_.render_passes_in_draw_order()); 1197 renderer_->DrawFrame(mock_client_.render_passes_in_draw_order()); 1198 TestRenderPassProgram(); 1199 1200 // RenderPassColorMatrixProgram 1201 render_passes->clear(); 1202 1203 child_pass = AddRenderPass( 1204 render_passes, child_pass_id, child_rect, transform_causing_aa); 1205 1206 root_pass = AddRenderPass( 1207 render_passes, root_pass_id, viewport_rect, gfx::Transform()); 1208 1209 AddRenderPassQuad(root_pass, child_pass, 0, filter, gfx::Transform()); 1210 1211 renderer_->DecideRenderPassAllocationsForFrame( 1212 *mock_client_.render_passes_in_draw_order()); 1213 renderer_->DrawFrame(mock_client_.render_passes_in_draw_order()); 1214 TestRenderPassColorMatrixProgram(); 1215 1216 // RenderPassMaskProgram 1217 render_passes->clear(); 1218 1219 child_pass = AddRenderPass( 1220 render_passes, child_pass_id, child_rect, gfx::Transform()); 1221 1222 root_pass = AddRenderPass( 1223 render_passes, root_pass_id, viewport_rect, gfx::Transform()); 1224 1225 AddRenderPassQuad(root_pass, 1226 child_pass, 1227 mask, 1228 skia::RefPtr<SkImageFilter>(), 1229 gfx::Transform()); 1230 1231 renderer_->DecideRenderPassAllocationsForFrame( 1232 *mock_client_.render_passes_in_draw_order()); 1233 renderer_->DrawFrame(mock_client_.render_passes_in_draw_order()); 1234 TestRenderPassMaskProgram(); 1235 1236 // RenderPassMaskColorMatrixProgram 1237 render_passes->clear(); 1238 1239 child_pass = AddRenderPass( 1240 render_passes, child_pass_id, child_rect, gfx::Transform()); 1241 1242 root_pass = AddRenderPass( 1243 render_passes, root_pass_id, viewport_rect, gfx::Transform()); 1244 1245 AddRenderPassQuad(root_pass, child_pass, mask, filter, gfx::Transform()); 1246 1247 renderer_->DecideRenderPassAllocationsForFrame( 1248 *mock_client_.render_passes_in_draw_order()); 1249 renderer_->DrawFrame(mock_client_.render_passes_in_draw_order()); 1250 TestRenderPassMaskColorMatrixProgram(); 1251 1252 // RenderPassProgramAA 1253 render_passes->clear(); 1254 1255 child_pass = AddRenderPass( 1256 render_passes, child_pass_id, child_rect, transform_causing_aa); 1257 1258 root_pass = AddRenderPass( 1259 render_passes, root_pass_id, viewport_rect, gfx::Transform()); 1260 1261 AddRenderPassQuad(root_pass, 1262 child_pass, 1263 0, 1264 skia::RefPtr<SkImageFilter>(), 1265 transform_causing_aa); 1266 1267 renderer_->DecideRenderPassAllocationsForFrame( 1268 *mock_client_.render_passes_in_draw_order()); 1269 renderer_->DrawFrame(mock_client_.render_passes_in_draw_order()); 1270 TestRenderPassProgramAA(); 1271 1272 // RenderPassColorMatrixProgramAA 1273 render_passes->clear(); 1274 1275 child_pass = AddRenderPass( 1276 render_passes, child_pass_id, child_rect, transform_causing_aa); 1277 1278 root_pass = AddRenderPass( 1279 render_passes, root_pass_id, viewport_rect, gfx::Transform()); 1280 1281 AddRenderPassQuad(root_pass, child_pass, 0, filter, transform_causing_aa); 1282 1283 renderer_->DecideRenderPassAllocationsForFrame( 1284 *mock_client_.render_passes_in_draw_order()); 1285 renderer_->DrawFrame(mock_client_.render_passes_in_draw_order()); 1286 TestRenderPassColorMatrixProgramAA(); 1287 1288 // RenderPassMaskProgramAA 1289 render_passes->clear(); 1290 1291 child_pass = AddRenderPass(render_passes, child_pass_id, child_rect, 1292 transform_causing_aa); 1293 1294 root_pass = AddRenderPass(render_passes, root_pass_id, viewport_rect, 1295 gfx::Transform()); 1296 1297 AddRenderPassQuad(root_pass, child_pass, mask, skia::RefPtr<SkImageFilter>(), 1298 transform_causing_aa); 1299 1300 renderer_->DecideRenderPassAllocationsForFrame( 1301 *mock_client_.render_passes_in_draw_order()); 1302 renderer_->DrawFrame(mock_client_.render_passes_in_draw_order()); 1303 TestRenderPassMaskProgramAA(); 1304 1305 // RenderPassMaskColorMatrixProgramAA 1306 render_passes->clear(); 1307 1308 child_pass = AddRenderPass(render_passes, child_pass_id, child_rect, 1309 transform_causing_aa); 1310 1311 root_pass = AddRenderPass(render_passes, root_pass_id, viewport_rect, 1312 transform_causing_aa); 1313 1314 AddRenderPassQuad(root_pass, child_pass, mask, filter, transform_causing_aa); 1315 1316 renderer_->DecideRenderPassAllocationsForFrame( 1317 *mock_client_.render_passes_in_draw_order()); 1318 renderer_->DrawFrame(mock_client_.render_passes_in_draw_order()); 1319 TestRenderPassMaskColorMatrixProgramAA(); 1320 } 1321 1322 // At this time, the AA code path cannot be taken if the surface's rect would 1323 // project incorrectly by the given transform, because of w<0 clipping. 1324 TEST_F(GLRendererShaderTest, DrawRenderPassQuadSkipsAAForClippingTransform) { 1325 gfx::Rect child_rect(50, 50); 1326 RenderPass::Id child_pass_id(2, 0); 1327 TestRenderPass* child_pass; 1328 1329 gfx::Rect viewport_rect(mock_client_.DeviceViewport()); 1330 RenderPass::Id root_pass_id(1, 0); 1331 TestRenderPass* root_pass; 1332 1333 gfx::Transform transform_preventing_aa; 1334 transform_preventing_aa.ApplyPerspectiveDepth(40.0); 1335 transform_preventing_aa.RotateAboutYAxis(-20.0); 1336 transform_preventing_aa.Scale(30.0, 1.0); 1337 1338 // Verify that the test transform and test rect actually do cause the clipped 1339 // flag to trigger. Otherwise we are not testing the intended scenario. 1340 bool clipped = false; 1341 MathUtil::MapQuad(transform_preventing_aa, 1342 gfx::QuadF(child_rect), 1343 &clipped); 1344 ASSERT_TRUE(clipped); 1345 1346 // Set up the render pass quad to be drawn 1347 ScopedPtrVector<RenderPass>* render_passes = 1348 mock_client_.render_passes_in_draw_order(); 1349 1350 render_passes->clear(); 1351 1352 child_pass = AddRenderPass( 1353 render_passes, child_pass_id, child_rect, transform_preventing_aa); 1354 1355 root_pass = AddRenderPass( 1356 render_passes, root_pass_id, viewport_rect, gfx::Transform()); 1357 1358 AddRenderPassQuad(root_pass, 1359 child_pass, 1360 0, 1361 skia::RefPtr<SkImageFilter>(), 1362 transform_preventing_aa); 1363 1364 renderer_->DecideRenderPassAllocationsForFrame( 1365 *mock_client_.render_passes_in_draw_order()); 1366 renderer_->DrawFrame(mock_client_.render_passes_in_draw_order()); 1367 1368 // If use_aa incorrectly ignores clipping, it will use the 1369 // RenderPassProgramAA shader instead of the RenderPassProgram. 1370 TestRenderPassProgram(); 1371 } 1372 1373 TEST_F(GLRendererShaderTest, DrawSolidColorShader) { 1374 gfx::Rect viewport_rect(mock_client_.DeviceViewport()); 1375 ScopedPtrVector<RenderPass>* render_passes = 1376 mock_client_.render_passes_in_draw_order(); 1377 1378 RenderPass::Id root_pass_id(1, 0); 1379 TestRenderPass* root_pass; 1380 1381 gfx::Transform pixel_aligned_transform_causing_aa; 1382 pixel_aligned_transform_causing_aa.Translate(25.5f, 25.5f); 1383 pixel_aligned_transform_causing_aa.Scale(0.5f, 0.5f); 1384 1385 render_passes->clear(); 1386 1387 root_pass = AddRenderPass( 1388 render_passes, root_pass_id, viewport_rect, gfx::Transform()); 1389 AddTransformedQuad(root_pass, 1390 viewport_rect, 1391 SK_ColorYELLOW, 1392 pixel_aligned_transform_causing_aa); 1393 1394 renderer_->DecideRenderPassAllocationsForFrame( 1395 *mock_client_.render_passes_in_draw_order()); 1396 renderer_->DrawFrame(mock_client_.render_passes_in_draw_order()); 1397 1398 TestSolidColorProgramAA(); 1399 } 1400 1401 class OutputSurfaceMockContext : public TestWebGraphicsContext3D { 1402 public: 1403 // Specifically override methods even if they are unused (used in conjunction 1404 // with StrictMock). We need to make sure that GLRenderer does not issue 1405 // framebuffer-related GL calls directly. Instead these are supposed to go 1406 // through the OutputSurface abstraction. 1407 MOCK_METHOD0(ensureBackbufferCHROMIUM, void()); 1408 MOCK_METHOD0(discardBackbufferCHROMIUM, void()); 1409 MOCK_METHOD2(bindFramebuffer, void(WGC3Denum target, WebGLId framebuffer)); 1410 MOCK_METHOD0(prepareTexture, void()); 1411 MOCK_METHOD3(reshapeWithScaleFactor, 1412 void(int width, int height, float scale_factor)); 1413 MOCK_METHOD4(drawElements, 1414 void(WGC3Denum mode, 1415 WGC3Dsizei count, 1416 WGC3Denum type, 1417 WGC3Dintptr offset)); 1418 1419 virtual WebString getString(WebKit::WGC3Denum name) { 1420 if (name == GL_EXTENSIONS) 1421 return WebString( 1422 "GL_CHROMIUM_post_sub_buffer GL_CHROMIUM_discard_backbuffer"); 1423 return WebString(); 1424 } 1425 }; 1426 1427 class MockOutputSurface : public OutputSurface { 1428 public: 1429 MockOutputSurface() 1430 : OutputSurface(scoped_ptr<WebKit::WebGraphicsContext3D>( 1431 new StrictMock<OutputSurfaceMockContext>)) { 1432 surface_size_ = gfx::Size(100, 100); 1433 } 1434 virtual ~MockOutputSurface() {} 1435 1436 MOCK_METHOD0(EnsureBackbuffer, void()); 1437 MOCK_METHOD0(DiscardBackbuffer, void()); 1438 MOCK_METHOD2(Reshape, void(gfx::Size size, float scale_factor)); 1439 MOCK_METHOD0(BindFramebuffer, void()); 1440 MOCK_METHOD1(SwapBuffers, void(CompositorFrame* frame)); 1441 }; 1442 1443 class MockOutputSurfaceTest : public testing::Test, public FakeRendererClient { 1444 protected: 1445 MockOutputSurfaceTest() 1446 : resource_provider_(ResourceProvider::Create(&output_surface_, 0)), 1447 renderer_(this, &output_surface_, resource_provider_.get()) {} 1448 1449 virtual void SetUp() { EXPECT_TRUE(renderer_.Initialize()); } 1450 1451 void SwapBuffers() { renderer_.SwapBuffers(); } 1452 1453 void DrawFrame() { 1454 gfx::Rect viewport_rect(DeviceViewport()); 1455 ScopedPtrVector<RenderPass>* render_passes = render_passes_in_draw_order(); 1456 render_passes->clear(); 1457 1458 RenderPass::Id render_pass_id(1, 0); 1459 TestRenderPass* render_pass = AddRenderPass( 1460 render_passes, render_pass_id, viewport_rect, gfx::Transform()); 1461 AddQuad(render_pass, viewport_rect, SK_ColorGREEN); 1462 1463 EXPECT_CALL(output_surface_, EnsureBackbuffer()).WillRepeatedly(Return()); 1464 1465 EXPECT_CALL(output_surface_, 1466 Reshape(DeviceViewport().size(), DeviceScaleFactor())).Times(1); 1467 1468 EXPECT_CALL(output_surface_, BindFramebuffer()).Times(1); 1469 1470 EXPECT_CALL(*Context(), drawElements(_, _, _, _)).Times(1); 1471 1472 renderer_.DecideRenderPassAllocationsForFrame( 1473 *render_passes_in_draw_order()); 1474 renderer_.DrawFrame(render_passes_in_draw_order()); 1475 } 1476 1477 OutputSurfaceMockContext* Context() { 1478 return static_cast<OutputSurfaceMockContext*>(output_surface_.context3d()); 1479 } 1480 1481 StrictMock<MockOutputSurface> output_surface_; 1482 scoped_ptr<ResourceProvider> resource_provider_; 1483 FakeRendererGL renderer_; 1484 }; 1485 1486 TEST_F(MockOutputSurfaceTest, DrawFrameAndSwap) { 1487 DrawFrame(); 1488 1489 EXPECT_CALL(output_surface_, SwapBuffers(_)).Times(1); 1490 renderer_.SwapBuffers(); 1491 } 1492 1493 TEST_F(MockOutputSurfaceTest, DrawFrameAndResizeAndSwap) { 1494 DrawFrame(); 1495 EXPECT_CALL(output_surface_, SwapBuffers(_)).Times(1); 1496 renderer_.SwapBuffers(); 1497 1498 set_viewport_and_scale(gfx::Size(2, 2), 2.f); 1499 renderer_.ViewportChanged(); 1500 1501 DrawFrame(); 1502 EXPECT_CALL(output_surface_, SwapBuffers(_)).Times(1); 1503 renderer_.SwapBuffers(); 1504 1505 DrawFrame(); 1506 EXPECT_CALL(output_surface_, SwapBuffers(_)).Times(1); 1507 renderer_.SwapBuffers(); 1508 1509 set_viewport_and_scale(gfx::Size(1, 1), 1.f); 1510 renderer_.ViewportChanged(); 1511 1512 DrawFrame(); 1513 EXPECT_CALL(output_surface_, SwapBuffers(_)).Times(1); 1514 renderer_.SwapBuffers(); 1515 } 1516 1517 class GLRendererTestSyncPoint : public GLRendererPixelTest { 1518 protected: 1519 static void SyncPointCallback(int* callback_count) { 1520 ++(*callback_count); 1521 base::MessageLoop::current()->QuitWhenIdle(); 1522 } 1523 1524 static void OtherCallback(int* callback_count) { 1525 ++(*callback_count); 1526 base::MessageLoop::current()->QuitWhenIdle(); 1527 } 1528 }; 1529 1530 #if !defined(OS_ANDROID) 1531 TEST_F(GLRendererTestSyncPoint, SignalSyncPointOnLostContext) { 1532 int sync_point_callback_count = 0; 1533 int other_callback_count = 0; 1534 unsigned sync_point = output_surface_->context3d()->insertSyncPoint(); 1535 1536 output_surface_->context3d()->loseContextCHROMIUM( 1537 GL_GUILTY_CONTEXT_RESET_ARB, GL_INNOCENT_CONTEXT_RESET_ARB); 1538 1539 SyncPointHelper::SignalSyncPoint( 1540 output_surface_->context3d(), 1541 sync_point, 1542 base::Bind(&SyncPointCallback, &sync_point_callback_count)); 1543 EXPECT_EQ(0, sync_point_callback_count); 1544 EXPECT_EQ(0, other_callback_count); 1545 1546 // Make the sync point happen. 1547 output_surface_->context3d()->finish(); 1548 // Post a task after the sync point. 1549 base::MessageLoop::current()->PostTask( 1550 FROM_HERE, 1551 base::Bind(&OtherCallback, &other_callback_count)); 1552 1553 base::MessageLoop::current()->Run(); 1554 1555 // The sync point shouldn't have happened since the context was lost. 1556 EXPECT_EQ(0, sync_point_callback_count); 1557 EXPECT_EQ(1, other_callback_count); 1558 } 1559 1560 TEST_F(GLRendererTestSyncPoint, SignalSyncPoint) { 1561 int sync_point_callback_count = 0; 1562 int other_callback_count = 0; 1563 unsigned sync_point = output_surface_->context3d()->insertSyncPoint(); 1564 1565 SyncPointHelper::SignalSyncPoint( 1566 output_surface_->context3d(), 1567 sync_point, 1568 base::Bind(&SyncPointCallback, &sync_point_callback_count)); 1569 EXPECT_EQ(0, sync_point_callback_count); 1570 EXPECT_EQ(0, other_callback_count); 1571 1572 // Make the sync point happen. 1573 output_surface_->context3d()->finish(); 1574 // Post a task after the sync point. 1575 base::MessageLoop::current()->PostTask( 1576 FROM_HERE, 1577 base::Bind(&OtherCallback, &other_callback_count)); 1578 1579 base::MessageLoop::current()->Run(); 1580 1581 // The sync point should have happened. 1582 EXPECT_EQ(1, sync_point_callback_count); 1583 EXPECT_EQ(1, other_callback_count); 1584 } 1585 #endif // OS_ANDROID 1586 1587 } // namespace 1588 } // namespace cc 1589