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