| OLD | NEW |
| (Empty) |
| 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/gl_renderer.h" | |
| 6 | |
| 7 #include "cc/compositor_frame_metadata.h" | |
| 8 #include "cc/draw_quad.h" | |
| 9 #include "cc/prioritized_resource_manager.h" | |
| 10 #include "cc/resource_provider.h" | |
| 11 #include "cc/test/fake_impl_proxy.h" | |
| 12 #include "cc/test/fake_layer_tree_host_impl.h" | |
| 13 #include "cc/test/fake_output_surface.h" | |
| 14 #include "cc/test/pixel_test.h" | |
| 15 #include "cc/test/render_pass_test_common.h" | |
| 16 #include "cc/test/render_pass_test_utils.h" | |
| 17 #include "cc/test/test_web_graphics_context_3d.h" | |
| 18 #include "testing/gmock/include/gmock/gmock.h" | |
| 19 #include "testing/gtest/include/gtest/gtest.h" | |
| 20 #include "third_party/khronos/GLES2/gl2.h" | |
| 21 #include "ui/gfx/transform.h" | |
| 22 | |
| 23 using namespace WebKit; | |
| 24 | |
| 25 using testing::_; | |
| 26 using testing::AnyNumber; | |
| 27 using testing::AtLeast; | |
| 28 using testing::Expectation; | |
| 29 using testing::InSequence; | |
| 30 using testing::Mock; | |
| 31 using testing::Return; | |
| 32 using testing::StrictMock; | |
| 33 | |
| 34 namespace cc { | |
| 35 | |
| 36 #define EXPECT_PROGRAM_VALID(program_binding) \ | |
| 37 do { \ | |
| 38 EXPECT_TRUE(program_binding->program()); \ | |
| 39 EXPECT_TRUE(program_binding->initialized()); \ | |
| 40 } while (false) | |
| 41 | |
| 42 // Explicitly named to be a friend in GLRenderer for shader access. | |
| 43 class GLRendererShaderTest : public PixelTest { | |
| 44 public: | |
| 45 void TestShaders() { | |
| 46 ASSERT_FALSE(renderer_->IsContextLost()); | |
| 47 EXPECT_PROGRAM_VALID(renderer_->GetTileProgram()); | |
| 48 EXPECT_PROGRAM_VALID(renderer_->GetTileProgramOpaque()); | |
| 49 EXPECT_PROGRAM_VALID(renderer_->GetTileProgramAA()); | |
| 50 EXPECT_PROGRAM_VALID(renderer_->GetTileProgramSwizzle()); | |
| 51 EXPECT_PROGRAM_VALID(renderer_->GetTileProgramSwizzleOpaque()); | |
| 52 EXPECT_PROGRAM_VALID(renderer_->GetTileProgramSwizzleAA()); | |
| 53 EXPECT_PROGRAM_VALID(renderer_->GetTileCheckerboardProgram()); | |
| 54 EXPECT_PROGRAM_VALID(renderer_->GetRenderPassProgram()); | |
| 55 EXPECT_PROGRAM_VALID(renderer_->GetRenderPassProgramAA()); | |
| 56 EXPECT_PROGRAM_VALID(renderer_->GetRenderPassMaskProgram()); | |
| 57 EXPECT_PROGRAM_VALID(renderer_->GetRenderPassMaskProgramAA()); | |
| 58 EXPECT_PROGRAM_VALID(renderer_->GetTextureProgram()); | |
| 59 EXPECT_PROGRAM_VALID(renderer_->GetTextureProgramFlip()); | |
| 60 EXPECT_PROGRAM_VALID(renderer_->GetTextureIOSurfaceProgram()); | |
| 61 EXPECT_PROGRAM_VALID(renderer_->GetVideoYUVProgram()); | |
| 62 // This is unlikely to be ever true in tests due to usage of osmesa. | |
| 63 if (renderer_->Capabilities().using_egl_image) | |
| 64 EXPECT_PROGRAM_VALID(renderer_->GetVideoStreamTextureProgram()); | |
| 65 else | |
| 66 EXPECT_FALSE(renderer_->GetVideoStreamTextureProgram()); | |
| 67 EXPECT_PROGRAM_VALID(renderer_->GetDebugBorderProgram()); | |
| 68 EXPECT_PROGRAM_VALID(renderer_->GetSolidColorProgram()); | |
| 69 EXPECT_PROGRAM_VALID(renderer_->GetSolidColorProgramAA()); | |
| 70 ASSERT_FALSE(renderer_->IsContextLost()); | |
| 71 } | |
| 72 }; | |
| 73 | |
| 74 namespace { | |
| 75 | |
| 76 #if !defined(OS_ANDROID) | |
| 77 TEST_F(GLRendererShaderTest, AllShadersCompile) { | |
| 78 TestShaders(); | |
| 79 } | |
| 80 #endif | |
| 81 | |
| 82 class FrameCountingMemoryAllocationSettingContext : public TestWebGraphicsContex
t3D { | |
| 83 public: | |
| 84 FrameCountingMemoryAllocationSettingContext() : m_frame(0) { } | |
| 85 | |
| 86 // WebGraphicsContext3D methods. | |
| 87 | |
| 88 // This method would normally do a glSwapBuffers under the hood. | |
| 89 virtual void prepareTexture() { m_frame++; } | |
| 90 virtual void setMemoryAllocationChangedCallbackCHROMIUM(WebGraphicsMemoryAll
ocationChangedCallbackCHROMIUM* callback) { m_memoryAllocationChangedCallback =
callback; } | |
| 91 virtual WebString getString(WebKit::WGC3Denum name) | |
| 92 { | |
| 93 if (name == GL_EXTENSIONS) | |
| 94 return WebString("GL_CHROMIUM_set_visibility GL_CHROMIUM_gpu_memory_
manager GL_CHROMIUM_discard_backbuffer"); | |
| 95 return WebString(); | |
| 96 } | |
| 97 | |
| 98 // Methods added for test. | |
| 99 int frameCount() { return m_frame; } | |
| 100 void setMemoryAllocation(WebGraphicsMemoryAllocation allocation) | |
| 101 { | |
| 102 m_memoryAllocationChangedCallback->onMemoryAllocationChanged(allocation)
; | |
| 103 } | |
| 104 | |
| 105 private: | |
| 106 int m_frame; | |
| 107 WebGraphicsMemoryAllocationChangedCallbackCHROMIUM* m_memoryAllocationChange
dCallback; | |
| 108 }; | |
| 109 | |
| 110 class FakeRendererClient : public RendererClient { | |
| 111 public: | |
| 112 FakeRendererClient() | |
| 113 : m_hostImpl(&m_proxy) | |
| 114 , m_setFullRootLayerDamageCount(0) | |
| 115 , m_lastCallWasSetVisibility(0) | |
| 116 , m_rootLayer(LayerImpl::Create(m_hostImpl.active_tree(), 1)) | |
| 117 , m_memoryAllocationLimitBytes(PrioritizedResourceManager::defaultMemory
AllocationLimit()) | |
| 118 { | |
| 119 m_rootLayer->CreateRenderSurface(); | |
| 120 RenderPass::Id renderPassId = m_rootLayer->render_surface()->RenderPassI
d(); | |
| 121 scoped_ptr<RenderPass> root_render_pass = RenderPass::Create(); | |
| 122 root_render_pass->SetNew(renderPassId, gfx::Rect(), gfx::Rect(), gfx::Tr
ansform()); | |
| 123 m_renderPassesInDrawOrder.push_back(root_render_pass.Pass()); | |
| 124 } | |
| 125 | |
| 126 // RendererClient methods. | |
| 127 virtual gfx::Size DeviceViewportSize() const OVERRIDE { static gfx::Size fak
eSize(1, 1); return fakeSize; } | |
| 128 virtual const LayerTreeSettings& Settings() const OVERRIDE { static LayerTre
eSettings fakeSettings; return fakeSettings; } | |
| 129 virtual void DidLoseOutputSurface() OVERRIDE { } | |
| 130 virtual void OnSwapBuffersComplete() OVERRIDE { } | |
| 131 virtual void SetFullRootLayerDamage() OVERRIDE { m_setFullRootLayerDamageCou
nt++; } | |
| 132 virtual void SetManagedMemoryPolicy(const ManagedMemoryPolicy& policy) OVERR
IDE { m_memoryAllocationLimitBytes = policy.bytesLimitWhenVisible; } | |
| 133 virtual void EnforceManagedMemoryPolicy(const ManagedMemoryPolicy& policy) O
VERRIDE { if (m_lastCallWasSetVisibility) *m_lastCallWasSetVisibility = false; } | |
| 134 virtual bool HasImplThread() const OVERRIDE { return false; } | |
| 135 virtual bool ShouldClearRootRenderPass() const OVERRIDE { return true; } | |
| 136 virtual CompositorFrameMetadata MakeCompositorFrameMetadata() const | |
| 137 OVERRIDE { return CompositorFrameMetadata(); } | |
| 138 | |
| 139 // Methods added for test. | |
| 140 int setFullRootLayerDamageCount() const { return m_setFullRootLayerDamageCou
nt; } | |
| 141 void setLastCallWasSetVisibilityPointer(bool* lastCallWasSetVisibility) { m_
lastCallWasSetVisibility = lastCallWasSetVisibility; } | |
| 142 | |
| 143 RenderPass* root_render_pass() { return m_renderPassesInDrawOrder.back(); } | |
| 144 RenderPassList& renderPassesInDrawOrder() { return m_renderPassesInDrawOrder
; } | |
| 145 | |
| 146 size_t memoryAllocationLimitBytes() const { return m_memoryAllocationLimitBy
tes; } | |
| 147 | |
| 148 private: | |
| 149 FakeImplProxy m_proxy; | |
| 150 FakeLayerTreeHostImpl m_hostImpl; | |
| 151 int m_setFullRootLayerDamageCount; | |
| 152 bool* m_lastCallWasSetVisibility; | |
| 153 scoped_ptr<LayerImpl> m_rootLayer; | |
| 154 RenderPassList m_renderPassesInDrawOrder; | |
| 155 size_t m_memoryAllocationLimitBytes; | |
| 156 }; | |
| 157 | |
| 158 class FakeRendererGL : public GLRenderer { | |
| 159 public: | |
| 160 FakeRendererGL(RendererClient* client, OutputSurface* outputSurface, Resourc
eProvider* resourceProvider) : GLRenderer(client, outputSurface, resourceProvide
r) { } | |
| 161 | |
| 162 // GLRenderer methods. | |
| 163 | |
| 164 // Changing visibility to public. | |
| 165 using GLRenderer::Initialize; | |
| 166 using GLRenderer::IsBackbufferDiscarded; | |
| 167 using GLRenderer::DoDrawQuad; | |
| 168 using GLRenderer::BeginDrawingFrame; | |
| 169 using GLRenderer::FinishDrawingQuadList; | |
| 170 }; | |
| 171 | |
| 172 class GLRendererTest : public testing::Test { | |
| 173 protected: | |
| 174 GLRendererTest() | |
| 175 : m_suggestHaveBackbufferYes(1, true) | |
| 176 , m_suggestHaveBackbufferNo(1, false) | |
| 177 , m_outputSurface(FakeOutputSurface::Create3d(scoped_ptr<WebKit::WebGrap
hicsContext3D>(new FrameCountingMemoryAllocationSettingContext()))) | |
| 178 , resource_provider_(ResourceProvider::Create(m_outputSurface.get())) | |
| 179 , m_renderer(&m_mockClient, m_outputSurface.get(), resource_provider_.ge
t()) | |
| 180 { | |
| 181 } | |
| 182 | |
| 183 virtual void SetUp() | |
| 184 { | |
| 185 m_renderer.Initialize(); | |
| 186 } | |
| 187 | |
| 188 void SwapBuffers() | |
| 189 { | |
| 190 m_renderer.SwapBuffers(); | |
| 191 } | |
| 192 | |
| 193 FrameCountingMemoryAllocationSettingContext* context() { return static_cast<
FrameCountingMemoryAllocationSettingContext*>(m_outputSurface->context3d()); } | |
| 194 | |
| 195 WebGraphicsMemoryAllocation m_suggestHaveBackbufferYes; | |
| 196 WebGraphicsMemoryAllocation m_suggestHaveBackbufferNo; | |
| 197 | |
| 198 scoped_ptr<OutputSurface> m_outputSurface; | |
| 199 FakeRendererClient m_mockClient; | |
| 200 scoped_ptr<ResourceProvider> resource_provider_; | |
| 201 FakeRendererGL m_renderer; | |
| 202 }; | |
| 203 | |
| 204 // Test GLRenderer discardBackbuffer functionality: | |
| 205 // Suggest recreating framebuffer when one already exists. | |
| 206 // Expected: it does nothing. | |
| 207 TEST_F(GLRendererTest, SuggestBackbufferYesWhenItAlreadyExistsShouldDoNothing) | |
| 208 { | |
| 209 context()->setMemoryAllocation(m_suggestHaveBackbufferYes); | |
| 210 EXPECT_EQ(0, m_mockClient.setFullRootLayerDamageCount()); | |
| 211 EXPECT_FALSE(m_renderer.IsBackbufferDiscarded()); | |
| 212 | |
| 213 SwapBuffers(); | |
| 214 EXPECT_EQ(1, context()->frameCount()); | |
| 215 } | |
| 216 | |
| 217 // Test GLRenderer discardBackbuffer functionality: | |
| 218 // Suggest discarding framebuffer when one exists and the renderer is not visibl
e. | |
| 219 // Expected: it is discarded and damage tracker is reset. | |
| 220 TEST_F(GLRendererTest, SuggestBackbufferNoShouldDiscardBackbufferAndDamageRootLa
yerWhileNotVisible) | |
| 221 { | |
| 222 m_renderer.SetVisible(false); | |
| 223 context()->setMemoryAllocation(m_suggestHaveBackbufferNo); | |
| 224 EXPECT_EQ(1, m_mockClient.setFullRootLayerDamageCount()); | |
| 225 EXPECT_TRUE(m_renderer.IsBackbufferDiscarded()); | |
| 226 } | |
| 227 | |
| 228 // Test GLRenderer discardBackbuffer functionality: | |
| 229 // Suggest discarding framebuffer when one exists and the renderer is visible. | |
| 230 // Expected: the allocation is ignored. | |
| 231 TEST_F(GLRendererTest, SuggestBackbufferNoDoNothingWhenVisible) | |
| 232 { | |
| 233 m_renderer.SetVisible(true); | |
| 234 context()->setMemoryAllocation(m_suggestHaveBackbufferNo); | |
| 235 EXPECT_EQ(0, m_mockClient.setFullRootLayerDamageCount()); | |
| 236 EXPECT_FALSE(m_renderer.IsBackbufferDiscarded()); | |
| 237 } | |
| 238 | |
| 239 | |
| 240 // Test GLRenderer discardBackbuffer functionality: | |
| 241 // Suggest discarding framebuffer when one does not exist. | |
| 242 // Expected: it does nothing. | |
| 243 TEST_F(GLRendererTest, SuggestBackbufferNoWhenItDoesntExistShouldDoNothing) | |
| 244 { | |
| 245 m_renderer.SetVisible(false); | |
| 246 context()->setMemoryAllocation(m_suggestHaveBackbufferNo); | |
| 247 EXPECT_EQ(1, m_mockClient.setFullRootLayerDamageCount()); | |
| 248 EXPECT_TRUE(m_renderer.IsBackbufferDiscarded()); | |
| 249 | |
| 250 context()->setMemoryAllocation(m_suggestHaveBackbufferNo); | |
| 251 EXPECT_EQ(1, m_mockClient.setFullRootLayerDamageCount()); | |
| 252 EXPECT_TRUE(m_renderer.IsBackbufferDiscarded()); | |
| 253 } | |
| 254 | |
| 255 // Test GLRenderer discardBackbuffer functionality: | |
| 256 // Begin drawing a frame while a framebuffer is discarded. | |
| 257 // Expected: will recreate framebuffer. | |
| 258 TEST_F(GLRendererTest, DiscardedBackbufferIsRecreatedForScopeDuration) | |
| 259 { | |
| 260 m_renderer.SetVisible(false); | |
| 261 context()->setMemoryAllocation(m_suggestHaveBackbufferNo); | |
| 262 EXPECT_TRUE(m_renderer.IsBackbufferDiscarded()); | |
| 263 EXPECT_EQ(1, m_mockClient.setFullRootLayerDamageCount()); | |
| 264 | |
| 265 m_renderer.SetVisible(true); | |
| 266 m_renderer.DrawFrame(m_mockClient.renderPassesInDrawOrder()); | |
| 267 EXPECT_FALSE(m_renderer.IsBackbufferDiscarded()); | |
| 268 | |
| 269 SwapBuffers(); | |
| 270 EXPECT_EQ(1, context()->frameCount()); | |
| 271 } | |
| 272 | |
| 273 TEST_F(GLRendererTest, FramebufferDiscardedAfterReadbackWhenNotVisible) | |
| 274 { | |
| 275 m_renderer.SetVisible(false); | |
| 276 context()->setMemoryAllocation(m_suggestHaveBackbufferNo); | |
| 277 EXPECT_TRUE(m_renderer.IsBackbufferDiscarded()); | |
| 278 EXPECT_EQ(1, m_mockClient.setFullRootLayerDamageCount()); | |
| 279 | |
| 280 char pixels[4]; | |
| 281 m_renderer.DrawFrame(m_mockClient.renderPassesInDrawOrder()); | |
| 282 EXPECT_FALSE(m_renderer.IsBackbufferDiscarded()); | |
| 283 | |
| 284 m_renderer.GetFramebufferPixels(pixels, gfx::Rect(0, 0, 1, 1)); | |
| 285 EXPECT_TRUE(m_renderer.IsBackbufferDiscarded()); | |
| 286 EXPECT_EQ(2, m_mockClient.setFullRootLayerDamageCount()); | |
| 287 } | |
| 288 | |
| 289 class ForbidSynchronousCallContext : public TestWebGraphicsContext3D { | |
| 290 public: | |
| 291 ForbidSynchronousCallContext() { } | |
| 292 | |
| 293 virtual bool getActiveAttrib(WebGLId program, WGC3Duint index, ActiveInfo&)
{ ADD_FAILURE(); return false; } | |
| 294 virtual bool getActiveUniform(WebGLId program, WGC3Duint index, ActiveInfo&)
{ ADD_FAILURE(); return false; } | |
| 295 virtual void getAttachedShaders(WebGLId program, WGC3Dsizei maxCount, WGC3Ds
izei* count, WebGLId* shaders) { ADD_FAILURE(); } | |
| 296 virtual WGC3Dint getAttribLocation(WebGLId program, const WGC3Dchar* name) {
ADD_FAILURE(); return 0; } | |
| 297 virtual void getBooleanv(WGC3Denum pname, WGC3Dboolean* value) { ADD_FAILURE
(); } | |
| 298 virtual void getBufferParameteriv(WGC3Denum target, WGC3Denum pname, WGC3Din
t* value) { ADD_FAILURE(); } | |
| 299 virtual Attributes getContextAttributes() { ADD_FAILURE(); return attributes
_; } | |
| 300 virtual WGC3Denum getError() { ADD_FAILURE(); return 0; } | |
| 301 virtual void getFloatv(WGC3Denum pname, WGC3Dfloat* value) { ADD_FAILURE();
} | |
| 302 virtual void getFramebufferAttachmentParameteriv(WGC3Denum target, WGC3Denum
attachment, WGC3Denum pname, WGC3Dint* value) { ADD_FAILURE(); } | |
| 303 virtual void getIntegerv(WGC3Denum pname, WGC3Dint* value) | |
| 304 { | |
| 305 if (pname == GL_MAX_TEXTURE_SIZE) | |
| 306 *value = 1024; // MAX_TEXTURE_SIZE is cached client side, so it's OK
to query. | |
| 307 else | |
| 308 ADD_FAILURE(); | |
| 309 } | |
| 310 | |
| 311 // We allow querying the shader compilation and program link status in debug
mode, but not release. | |
| 312 virtual void getProgramiv(WebGLId program, WGC3Denum pname, WGC3Dint* value) | |
| 313 { | |
| 314 #ifndef NDEBUG | |
| 315 *value = 1; | |
| 316 #else | |
| 317 ADD_FAILURE(); | |
| 318 #endif | |
| 319 } | |
| 320 | |
| 321 virtual void getShaderiv(WebGLId shader, WGC3Denum pname, WGC3Dint* value) | |
| 322 { | |
| 323 #ifndef NDEBUG | |
| 324 *value = 1; | |
| 325 #else | |
| 326 ADD_FAILURE(); | |
| 327 #endif | |
| 328 } | |
| 329 | |
| 330 virtual WebString getString(WGC3Denum name) | |
| 331 { | |
| 332 // We allow querying the extension string. | |
| 333 // FIXME: It'd be better to check that we only do this before starting a
ny other expensive work (like starting a compilation) | |
| 334 if (name != GL_EXTENSIONS) | |
| 335 ADD_FAILURE(); | |
| 336 return WebString(); | |
| 337 } | |
| 338 | |
| 339 virtual WebString getProgramInfoLog(WebGLId program) { ADD_FAILURE(); return
WebString(); } | |
| 340 virtual void getRenderbufferParameteriv(WGC3Denum target, WGC3Denum pname, W
GC3Dint* value) { ADD_FAILURE(); } | |
| 341 | |
| 342 virtual WebString getShaderInfoLog(WebGLId shader) { ADD_FAILURE(); return W
ebString(); } | |
| 343 virtual void getShaderPrecisionFormat(WGC3Denum shadertype, WGC3Denum precis
iontype, WGC3Dint* range, WGC3Dint* precision) { ADD_FAILURE(); } | |
| 344 virtual WebString getShaderSource(WebGLId shader) { ADD_FAILURE(); return We
bString(); } | |
| 345 virtual void getTexParameterfv(WGC3Denum target, WGC3Denum pname, WGC3Dfloat
* value) { ADD_FAILURE(); } | |
| 346 virtual void getTexParameteriv(WGC3Denum target, WGC3Denum pname, WGC3Dint*
value) { ADD_FAILURE(); } | |
| 347 virtual void getUniformfv(WebGLId program, WGC3Dint location, WGC3Dfloat* va
lue) { ADD_FAILURE(); } | |
| 348 virtual void getUniformiv(WebGLId program, WGC3Dint location, WGC3Dint* valu
e) { ADD_FAILURE(); } | |
| 349 virtual WGC3Dint getUniformLocation(WebGLId program, const WGC3Dchar* name)
{ ADD_FAILURE(); return 0; } | |
| 350 virtual void getVertexAttribfv(WGC3Duint index, WGC3Denum pname, WGC3Dfloat*
value) { ADD_FAILURE(); } | |
| 351 virtual void getVertexAttribiv(WGC3Duint index, WGC3Denum pname, WGC3Dint* v
alue) { ADD_FAILURE(); } | |
| 352 virtual WGC3Dsizeiptr getVertexAttribOffset(WGC3Duint index, WGC3Denum pname
) { ADD_FAILURE(); return 0; } | |
| 353 }; | |
| 354 | |
| 355 // This test isn't using the same fixture as GLRendererTest, and you can't mix T
EST() and TEST_F() with the same name, hence LRC2. | |
| 356 TEST(GLRendererTest2, initializationDoesNotMakeSynchronousCalls) | |
| 357 { | |
| 358 FakeRendererClient mockClient; | |
| 359 scoped_ptr<OutputSurface> outputSurface(FakeOutputSurface::Create3d(scoped_p
tr<WebKit::WebGraphicsContext3D>(new ForbidSynchronousCallContext))); | |
| 360 scoped_ptr<ResourceProvider> resourceProvider(ResourceProvider::Create(outpu
tSurface.get())); | |
| 361 FakeRendererGL renderer(&mockClient, outputSurface.get(), resourceProvider.g
et()); | |
| 362 | |
| 363 EXPECT_TRUE(renderer.Initialize()); | |
| 364 } | |
| 365 | |
| 366 class LoseContextOnFirstGetContext : public TestWebGraphicsContext3D { | |
| 367 public: | |
| 368 LoseContextOnFirstGetContext() | |
| 369 : m_contextLost(false) | |
| 370 { | |
| 371 } | |
| 372 | |
| 373 virtual bool makeContextCurrent() OVERRIDE | |
| 374 { | |
| 375 return !m_contextLost; | |
| 376 } | |
| 377 | |
| 378 virtual void getProgramiv(WebGLId program, WGC3Denum pname, WGC3Dint* value)
OVERRIDE | |
| 379 { | |
| 380 m_contextLost = true; | |
| 381 *value = 0; | |
| 382 } | |
| 383 | |
| 384 virtual void getShaderiv(WebGLId shader, WGC3Denum pname, WGC3Dint* value) O
VERRIDE | |
| 385 { | |
| 386 m_contextLost = true; | |
| 387 *value = 0; | |
| 388 } | |
| 389 | |
| 390 virtual WGC3Denum getGraphicsResetStatusARB() OVERRIDE | |
| 391 { | |
| 392 return m_contextLost ? 1 : 0; | |
| 393 } | |
| 394 | |
| 395 private: | |
| 396 bool m_contextLost; | |
| 397 }; | |
| 398 | |
| 399 TEST(GLRendererTest2, initializationWithQuicklyLostContextDoesNotAssert) | |
| 400 { | |
| 401 FakeRendererClient mockClient; | |
| 402 scoped_ptr<OutputSurface> outputSurface(FakeOutputSurface::Create3d(scoped_p
tr<WebKit::WebGraphicsContext3D>(new LoseContextOnFirstGetContext))); | |
| 403 scoped_ptr<ResourceProvider> resourceProvider(ResourceProvider::Create(outpu
tSurface.get())); | |
| 404 FakeRendererGL renderer(&mockClient, outputSurface.get(), resourceProvider.g
et()); | |
| 405 | |
| 406 renderer.Initialize(); | |
| 407 } | |
| 408 | |
| 409 class ContextThatDoesNotSupportMemoryManagmentExtensions : public TestWebGraphic
sContext3D { | |
| 410 public: | |
| 411 ContextThatDoesNotSupportMemoryManagmentExtensions() { } | |
| 412 | |
| 413 // WebGraphicsContext3D methods. | |
| 414 | |
| 415 // This method would normally do a glSwapBuffers under the hood. | |
| 416 virtual void prepareTexture() { } | |
| 417 virtual void setMemoryAllocationChangedCallbackCHROMIUM(WebGraphicsMemoryAll
ocationChangedCallbackCHROMIUM* callback) { } | |
| 418 virtual WebString getString(WebKit::WGC3Denum name) { return WebString(); } | |
| 419 }; | |
| 420 | |
| 421 TEST(GLRendererTest2, initializationWithoutGpuMemoryManagerExtensionSupportShoul
dDefaultToNonZeroAllocation) | |
| 422 { | |
| 423 FakeRendererClient mockClient; | |
| 424 scoped_ptr<OutputSurface> outputSurface(FakeOutputSurface::Create3d(scoped_p
tr<WebKit::WebGraphicsContext3D>(new ContextThatDoesNotSupportMemoryManagmentExt
ensions))); | |
| 425 scoped_ptr<ResourceProvider> resourceProvider(ResourceProvider::Create(outpu
tSurface.get())); | |
| 426 FakeRendererGL renderer(&mockClient, outputSurface.get(), resourceProvider.g
et()); | |
| 427 | |
| 428 renderer.Initialize(); | |
| 429 | |
| 430 EXPECT_GT(mockClient.memoryAllocationLimitBytes(), 0ul); | |
| 431 } | |
| 432 | |
| 433 class ClearCountingContext : public TestWebGraphicsContext3D { | |
| 434 public: | |
| 435 ClearCountingContext() : m_clear(0) { } | |
| 436 | |
| 437 virtual void clear(WGC3Dbitfield) | |
| 438 { | |
| 439 m_clear++; | |
| 440 } | |
| 441 | |
| 442 int clearCount() const { return m_clear; } | |
| 443 | |
| 444 private: | |
| 445 int m_clear; | |
| 446 }; | |
| 447 | |
| 448 TEST(GLRendererTest2, opaqueBackground) | |
| 449 { | |
| 450 FakeRendererClient mockClient; | |
| 451 scoped_ptr<OutputSurface> outputSurface(FakeOutputSurface::Create3d(scoped_p
tr<WebKit::WebGraphicsContext3D>(new ClearCountingContext))); | |
| 452 ClearCountingContext* context = static_cast<ClearCountingContext*>(outputSur
face->context3d()); | |
| 453 scoped_ptr<ResourceProvider> resourceProvider(ResourceProvider::Create(outpu
tSurface.get())); | |
| 454 FakeRendererGL renderer(&mockClient, outputSurface.get(), resourceProvider.g
et()); | |
| 455 | |
| 456 mockClient.root_render_pass()->has_transparent_background = false; | |
| 457 | |
| 458 EXPECT_TRUE(renderer.Initialize()); | |
| 459 | |
| 460 renderer.DrawFrame(mockClient.renderPassesInDrawOrder()); | |
| 461 | |
| 462 // On DEBUG builds, render passes with opaque background clear to blue to | |
| 463 // easily see regions that were not drawn on the screen. | |
| 464 #ifdef NDEBUG | |
| 465 EXPECT_EQ(0, context->clearCount()); | |
| 466 #else | |
| 467 EXPECT_EQ(1, context->clearCount()); | |
| 468 #endif | |
| 469 } | |
| 470 | |
| 471 TEST(GLRendererTest2, transparentBackground) | |
| 472 { | |
| 473 FakeRendererClient mockClient; | |
| 474 scoped_ptr<OutputSurface> outputSurface(FakeOutputSurface::Create3d(scoped_p
tr<WebKit::WebGraphicsContext3D>(new ClearCountingContext))); | |
| 475 ClearCountingContext* context = static_cast<ClearCountingContext*>(outputSur
face->context3d()); | |
| 476 scoped_ptr<ResourceProvider> resourceProvider(ResourceProvider::Create(outpu
tSurface.get())); | |
| 477 FakeRendererGL renderer(&mockClient, outputSurface.get(), resourceProvider.g
et()); | |
| 478 | |
| 479 mockClient.root_render_pass()->has_transparent_background = true; | |
| 480 | |
| 481 EXPECT_TRUE(renderer.Initialize()); | |
| 482 | |
| 483 renderer.DrawFrame(mockClient.renderPassesInDrawOrder()); | |
| 484 | |
| 485 EXPECT_EQ(1, context->clearCount()); | |
| 486 } | |
| 487 | |
| 488 class VisibilityChangeIsLastCallTrackingContext : public TestWebGraphicsContext3
D { | |
| 489 public: | |
| 490 VisibilityChangeIsLastCallTrackingContext() | |
| 491 : m_lastCallWasSetVisibility(0) | |
| 492 { | |
| 493 } | |
| 494 | |
| 495 // WebGraphicsContext3D methods. | |
| 496 virtual void setVisibilityCHROMIUM(bool visible) { | |
| 497 if (!m_lastCallWasSetVisibility) | |
| 498 return; | |
| 499 DCHECK(*m_lastCallWasSetVisibility == false); | |
| 500 *m_lastCallWasSetVisibility = true; | |
| 501 } | |
| 502 virtual void flush() { if (m_lastCallWasSetVisibility) *m_lastCallWasSetVisi
bility = false; } | |
| 503 virtual void deleteTexture(WebGLId) { if (m_lastCallWasSetVisibility) *m_las
tCallWasSetVisibility = false; } | |
| 504 virtual void deleteFramebuffer(WebGLId) { if (m_lastCallWasSetVisibility) *m
_lastCallWasSetVisibility = false; } | |
| 505 virtual void deleteRenderbuffer(WebGLId) { if (m_lastCallWasSetVisibility) *
m_lastCallWasSetVisibility = false; } | |
| 506 | |
| 507 // This method would normally do a glSwapBuffers under the hood. | |
| 508 virtual WebString getString(WebKit::WGC3Denum name) | |
| 509 { | |
| 510 if (name == GL_EXTENSIONS) | |
| 511 return WebString("GL_CHROMIUM_set_visibility GL_CHROMIUM_gpu_memory_
manager GL_CHROMIUM_discard_backbuffer"); | |
| 512 return WebString(); | |
| 513 } | |
| 514 | |
| 515 // Methods added for test. | |
| 516 void setLastCallWasSetVisibilityPointer(bool* lastCallWasSetVisibility) { m_
lastCallWasSetVisibility = lastCallWasSetVisibility; } | |
| 517 | |
| 518 private: | |
| 519 bool* m_lastCallWasSetVisibility; | |
| 520 }; | |
| 521 | |
| 522 TEST(GLRendererTest2, visibilityChangeIsLastCall) | |
| 523 { | |
| 524 FakeRendererClient mockClient; | |
| 525 scoped_ptr<OutputSurface> outputSurface(FakeOutputSurface::Create3d(scoped_p
tr<WebKit::WebGraphicsContext3D>(new VisibilityChangeIsLastCallTrackingContext))
); | |
| 526 VisibilityChangeIsLastCallTrackingContext* context = static_cast<VisibilityC
hangeIsLastCallTrackingContext*>(outputSurface->context3d()); | |
| 527 scoped_ptr<ResourceProvider> resourceProvider(ResourceProvider::Create(outpu
tSurface.get())); | |
| 528 FakeRendererGL renderer(&mockClient, outputSurface.get(), resourceProvider.g
et()); | |
| 529 | |
| 530 EXPECT_TRUE(renderer.Initialize()); | |
| 531 | |
| 532 bool lastCallWasSetVisiblity = false; | |
| 533 // Ensure that the call to setVisibilityCHROMIUM is the last call issue to t
he GPU | |
| 534 // process, after glFlush is called, and after the RendererClient's enforceM
anagedMemoryPolicy | |
| 535 // is called. Plumb this tracking between both the RenderClient and the Cont
ext by giving | |
| 536 // them both a pointer to a variable on the stack. | |
| 537 context->setLastCallWasSetVisibilityPointer(&lastCallWasSetVisiblity); | |
| 538 mockClient.setLastCallWasSetVisibilityPointer(&lastCallWasSetVisiblity); | |
| 539 renderer.SetVisible(true); | |
| 540 renderer.DrawFrame(mockClient.renderPassesInDrawOrder()); | |
| 541 renderer.SetVisible(false); | |
| 542 EXPECT_TRUE(lastCallWasSetVisiblity); | |
| 543 } | |
| 544 | |
| 545 class TextureStateTrackingContext : public TestWebGraphicsContext3D { | |
| 546 public: | |
| 547 TextureStateTrackingContext() | |
| 548 : m_activeTexture(GL_INVALID_ENUM) | |
| 549 { | |
| 550 } | |
| 551 | |
| 552 virtual WebString getString(WGC3Denum name) | |
| 553 { | |
| 554 if (name == GL_EXTENSIONS) | |
| 555 return WebString("GL_OES_EGL_image_external"); | |
| 556 return WebString(); | |
| 557 } | |
| 558 | |
| 559 MOCK_METHOD3(texParameteri, void(WGC3Denum target, WGC3Denum pname, WGC3Dint
param)); | |
| 560 MOCK_METHOD4(drawElements, void(WGC3Denum mode, WGC3Dsizei count, WGC3Denum
type, WGC3Dintptr offset)); | |
| 561 | |
| 562 virtual void activeTexture(WGC3Denum texture) | |
| 563 { | |
| 564 EXPECT_NE(texture, m_activeTexture); | |
| 565 m_activeTexture = texture; | |
| 566 } | |
| 567 | |
| 568 WGC3Denum activeTexture() const { return m_activeTexture; } | |
| 569 | |
| 570 private: | |
| 571 WGC3Denum m_activeTexture; | |
| 572 }; | |
| 573 | |
| 574 TEST(GLRendererTest2, activeTextureState) | |
| 575 { | |
| 576 FakeRendererClient fakeClient; | |
| 577 scoped_ptr<OutputSurface> outputSurface(FakeOutputSurface::Create3d(scoped_p
tr<WebKit::WebGraphicsContext3D>(new TextureStateTrackingContext))); | |
| 578 TextureStateTrackingContext* context = static_cast<TextureStateTrackingConte
xt*>(outputSurface->context3d()); | |
| 579 scoped_ptr<ResourceProvider> resourceProvider(ResourceProvider::Create(outpu
tSurface.get())); | |
| 580 FakeRendererGL renderer(&fakeClient, outputSurface.get(), resourceProvider.g
et()); | |
| 581 | |
| 582 // During initialization we are allowed to set any texture parameters. | |
| 583 EXPECT_CALL(*context, texParameteri(_, _, _)).Times(AnyNumber()); | |
| 584 EXPECT_TRUE(renderer.Initialize()); | |
| 585 | |
| 586 cc::RenderPass::Id id(1, 1); | |
| 587 scoped_ptr<TestRenderPass> pass = TestRenderPass::Create(); | |
| 588 pass->SetNew(id, gfx::Rect(0, 0, 100, 100), gfx::Rect(0, 0, 100, 100), gfx::
Transform()); | |
| 589 pass->AppendOneOfEveryQuadType(resourceProvider.get(), RenderPass::Id(2, 1))
; | |
| 590 | |
| 591 // Set up expected texture filter state transitions that match the quads | |
| 592 // created in AppendOneOfEveryQuadType(). | |
| 593 Mock::VerifyAndClearExpectations(context); | |
| 594 { | |
| 595 InSequence sequence; | |
| 596 | |
| 597 // yuv_quad is drawn with the default linear filter. | |
| 598 EXPECT_CALL(*context, drawElements(_, _, _, _)); | |
| 599 | |
| 600 // tile_quad is drawn with GL_NEAREST because it is not transformed or | |
| 601 // scaled. | |
| 602 EXPECT_CALL(*context, texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER
, GL_NEAREST)); | |
| 603 EXPECT_CALL(*context, texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER
, GL_NEAREST)); | |
| 604 EXPECT_CALL(*context, drawElements(_, _, _, _)); | |
| 605 | |
| 606 // transformed_tile_quad uses GL_LINEAR. | |
| 607 EXPECT_CALL(*context, drawElements(_, _, _, _)); | |
| 608 | |
| 609 // scaled_tile_quad also uses GL_LINEAR. | |
| 610 EXPECT_CALL(*context, drawElements(_, _, _, _)); | |
| 611 | |
| 612 // The remaining quads also use GL_LINEAR because nearest neighbor | |
| 613 // filtering is currently only used with tile quads. | |
| 614 EXPECT_CALL(*context, drawElements(_, _, _, _)).Times(6); | |
| 615 } | |
| 616 | |
| 617 cc::DirectRenderer::DrawingFrame drawingFrame; | |
| 618 renderer.BeginDrawingFrame(drawingFrame); | |
| 619 EXPECT_EQ(context->activeTexture(), GL_TEXTURE0); | |
| 620 | |
| 621 for (cc::QuadList::backToFrontIterator it = pass->quad_list.backToFrontBegin
(); | |
| 622 it != pass->quad_list.backToFrontEnd(); ++it) { | |
| 623 renderer.DoDrawQuad(drawingFrame, *it); | |
| 624 } | |
| 625 renderer.FinishDrawingQuadList(); | |
| 626 EXPECT_EQ(context->activeTexture(), GL_TEXTURE0); | |
| 627 Mock::VerifyAndClearExpectations(context); | |
| 628 } | |
| 629 | |
| 630 class NoClearRootRenderPassFakeClient : public FakeRendererClient { | |
| 631 public: | |
| 632 virtual bool ShouldClearRootRenderPass() const OVERRIDE { return false; } | |
| 633 }; | |
| 634 | |
| 635 class NoClearRootRenderPassMockContext : public TestWebGraphicsContext3D { | |
| 636 public: | |
| 637 MOCK_METHOD1(clear, void(WGC3Dbitfield mask)); | |
| 638 MOCK_METHOD4(drawElements, void(WGC3Denum mode, WGC3Dsizei count, WGC3Denum
type, WGC3Dintptr offset)); | |
| 639 }; | |
| 640 | |
| 641 TEST(GLRendererTest2, shouldClearRootRenderPass) | |
| 642 { | |
| 643 NoClearRootRenderPassFakeClient mockClient; | |
| 644 scoped_ptr<OutputSurface> outputSurface(FakeOutputSurface::Create3d(scoped_p
tr<WebKit::WebGraphicsContext3D>(new NoClearRootRenderPassMockContext))); | |
| 645 NoClearRootRenderPassMockContext* mockContext = static_cast<NoClearRootRende
rPassMockContext*>(outputSurface->context3d()); | |
| 646 scoped_ptr<ResourceProvider> resourceProvider(ResourceProvider::Create(outpu
tSurface.get())); | |
| 647 FakeRendererGL renderer(&mockClient, outputSurface.get(), resourceProvider.g
et()); | |
| 648 EXPECT_TRUE(renderer.Initialize()); | |
| 649 | |
| 650 gfx::Rect viewportRect(mockClient.DeviceViewportSize()); | |
| 651 ScopedPtrVector<RenderPass>& renderPasses = mockClient.renderPassesInDrawOrd
er(); | |
| 652 renderPasses.clear(); | |
| 653 | |
| 654 RenderPass::Id rootPassId(1, 0); | |
| 655 TestRenderPass* rootPass = addRenderPass(renderPasses, rootPassId, viewportR
ect, gfx::Transform()); | |
| 656 addQuad(rootPass, viewportRect, SK_ColorGREEN); | |
| 657 | |
| 658 RenderPass::Id childPassId(2, 0); | |
| 659 TestRenderPass* childPass = addRenderPass(renderPasses, childPassId, viewpor
tRect, gfx::Transform()); | |
| 660 addQuad(childPass, viewportRect, SK_ColorBLUE); | |
| 661 | |
| 662 addRenderPassQuad(rootPass, childPass); | |
| 663 | |
| 664 // First render pass is not the root one, clearing should happen. | |
| 665 EXPECT_CALL(*mockContext, clear(GL_COLOR_BUFFER_BIT)) | |
| 666 .Times(AtLeast(1)); | |
| 667 | |
| 668 Expectation firstRenderPass = EXPECT_CALL(*mockContext, drawElements(_, _, _
, _)) | |
| 669 .Times(1); | |
| 670 | |
| 671 // The second render pass is the root one, clearing should be prevented. | |
| 672 EXPECT_CALL(*mockContext, clear(GL_COLOR_BUFFER_BIT)) | |
| 673 .Times(0) | |
| 674 .After(firstRenderPass); | |
| 675 | |
| 676 EXPECT_CALL(*mockContext, drawElements(_, _, _, _)) | |
| 677 .Times(AnyNumber()) | |
| 678 .After(firstRenderPass); | |
| 679 | |
| 680 renderer.DecideRenderPassAllocationsForFrame(mockClient.renderPassesInDrawOr
der()); | |
| 681 renderer.DrawFrame(mockClient.renderPassesInDrawOrder()); | |
| 682 | |
| 683 // In multiple render passes all but the root pass should clear the framebuf
fer. | |
| 684 Mock::VerifyAndClearExpectations(&mockContext); | |
| 685 } | |
| 686 | |
| 687 class ScissorTestOnClearCheckingContext : public TestWebGraphicsContext3D { | |
| 688 public: | |
| 689 ScissorTestOnClearCheckingContext() : m_scissorEnabled(false) { } | |
| 690 | |
| 691 virtual void clear(WGC3Dbitfield) | |
| 692 { | |
| 693 EXPECT_FALSE(m_scissorEnabled); | |
| 694 } | |
| 695 | |
| 696 virtual void enable(WGC3Denum cap) | |
| 697 { | |
| 698 if (cap == GL_SCISSOR_TEST) | |
| 699 m_scissorEnabled = true; | |
| 700 } | |
| 701 | |
| 702 virtual void disable(WGC3Denum cap) | |
| 703 { | |
| 704 if (cap == GL_SCISSOR_TEST) | |
| 705 m_scissorEnabled = false; | |
| 706 } | |
| 707 | |
| 708 private: | |
| 709 bool m_scissorEnabled; | |
| 710 }; | |
| 711 | |
| 712 TEST(GLRendererTest2, scissorTestWhenClearing) { | |
| 713 FakeRendererClient mockClient; | |
| 714 scoped_ptr<OutputSurface> outputSurface(FakeOutputSurface::Create3d(scoped_p
tr<WebKit::WebGraphicsContext3D>(new ScissorTestOnClearCheckingContext))); | |
| 715 scoped_ptr<ResourceProvider> resourceProvider(ResourceProvider::Create(outpu
tSurface.get())); | |
| 716 FakeRendererGL renderer(&mockClient, outputSurface.get(), resourceProvider.g
et()); | |
| 717 EXPECT_TRUE(renderer.Initialize()); | |
| 718 EXPECT_FALSE(renderer.Capabilities().using_partial_swap); | |
| 719 | |
| 720 gfx::Rect viewportRect(mockClient.DeviceViewportSize()); | |
| 721 ScopedPtrVector<RenderPass>& renderPasses = mockClient.renderPassesInDrawOrd
er(); | |
| 722 renderPasses.clear(); | |
| 723 | |
| 724 gfx::Rect grandChildRect(25, 25); | |
| 725 RenderPass::Id grandChildPassId(3, 0); | |
| 726 TestRenderPass* grandChildPass = addRenderPass(renderPasses, grandChildPassI
d, grandChildRect, gfx::Transform()); | |
| 727 addClippedQuad(grandChildPass, grandChildRect, SK_ColorYELLOW); | |
| 728 | |
| 729 gfx::Rect childRect(50, 50); | |
| 730 RenderPass::Id childPassId(2, 0); | |
| 731 TestRenderPass* childPass = addRenderPass(renderPasses, childPassId, childRe
ct, gfx::Transform()); | |
| 732 addQuad(childPass, childRect, SK_ColorBLUE); | |
| 733 | |
| 734 RenderPass::Id rootPassId(1, 0); | |
| 735 TestRenderPass* rootPass = addRenderPass(renderPasses, rootPassId, viewportR
ect, gfx::Transform()); | |
| 736 addQuad(rootPass, viewportRect, SK_ColorGREEN); | |
| 737 | |
| 738 addRenderPassQuad(rootPass, childPass); | |
| 739 addRenderPassQuad(childPass, grandChildPass); | |
| 740 | |
| 741 renderer.DecideRenderPassAllocationsForFrame(mockClient.renderPassesInDrawOr
der()); | |
| 742 renderer.DrawFrame(mockClient.renderPassesInDrawOrder()); | |
| 743 } | |
| 744 | |
| 745 class OutputSurfaceMockContext : public TestWebGraphicsContext3D { | |
| 746 public: | |
| 747 // Specifically override methods even if they are unused (used in conjunctio
n with StrictMock). | |
| 748 // We need to make sure that GLRenderer does not issue framebuffer-related G
L calls directly. Instead these | |
| 749 // are supposed to go through the OutputSurface abstraction. | |
| 750 MOCK_METHOD0(ensureBackbufferCHROMIUM, void()); | |
| 751 MOCK_METHOD0(discardBackbufferCHROMIUM, void()); | |
| 752 MOCK_METHOD2(bindFramebuffer, void(WGC3Denum target, WebGLId framebuffer)); | |
| 753 MOCK_METHOD0(prepareTexture, void()); | |
| 754 MOCK_METHOD2(reshape, void(int width, int height)); | |
| 755 MOCK_METHOD4(drawElements, void(WGC3Denum mode, WGC3Dsizei count, WGC3Denum
type, WGC3Dintptr offset)); | |
| 756 | |
| 757 virtual WebString getString(WebKit::WGC3Denum name) | |
| 758 { | |
| 759 if (name == GL_EXTENSIONS) | |
| 760 return WebString("GL_CHROMIUM_post_sub_buffer GL_CHROMIUM_discard_ba
ckbuffer"); | |
| 761 return WebString(); | |
| 762 } | |
| 763 }; | |
| 764 | |
| 765 class MockOutputSurface : public OutputSurface { | |
| 766 public: | |
| 767 MockOutputSurface() | |
| 768 : OutputSurface(scoped_ptr<WebKit::WebGraphicsContext3D>(new StrictMock<
OutputSurfaceMockContext>)) { } | |
| 769 virtual ~MockOutputSurface() { } | |
| 770 | |
| 771 MOCK_METHOD1(SendFrameToParentCompositor, void(CompositorFrame* frame)); | |
| 772 MOCK_METHOD0(EnsureBackbuffer, void()); | |
| 773 MOCK_METHOD0(DiscardBackbuffer, void()); | |
| 774 MOCK_METHOD1(Reshape, void(gfx::Size size)); | |
| 775 MOCK_METHOD0(BindFramebuffer, void()); | |
| 776 MOCK_METHOD1(PostSubBuffer, void(gfx::Rect rect)); | |
| 777 MOCK_METHOD0(SwapBuffers, void()); | |
| 778 }; | |
| 779 | |
| 780 class MockOutputSurfaceTest : public testing::Test, | |
| 781 public FakeRendererClient { | |
| 782 protected: | |
| 783 MockOutputSurfaceTest() | |
| 784 : resource_provider_(ResourceProvider::Create(&m_outputSurface)) | |
| 785 , m_renderer(this, &m_outputSurface, resource_provider_.get()) | |
| 786 { | |
| 787 } | |
| 788 | |
| 789 virtual void SetUp() | |
| 790 { | |
| 791 EXPECT_TRUE(m_renderer.Initialize()); | |
| 792 } | |
| 793 | |
| 794 void SwapBuffers() | |
| 795 { | |
| 796 m_renderer.SwapBuffers(); | |
| 797 } | |
| 798 | |
| 799 void DrawFrame() | |
| 800 { | |
| 801 gfx::Rect viewportRect(DeviceViewportSize()); | |
| 802 ScopedPtrVector<RenderPass>& renderPasses = renderPassesInDrawOrder(); | |
| 803 renderPasses.clear(); | |
| 804 | |
| 805 RenderPass::Id renderPassId(1, 0); | |
| 806 TestRenderPass* renderPass = addRenderPass(renderPasses, renderPassId, v
iewportRect, gfx::Transform()); | |
| 807 addQuad(renderPass, viewportRect, SK_ColorGREEN); | |
| 808 | |
| 809 EXPECT_CALL(m_outputSurface, EnsureBackbuffer()) | |
| 810 .WillRepeatedly(Return()); | |
| 811 | |
| 812 EXPECT_CALL(m_outputSurface, Reshape(_)) | |
| 813 .Times(1); | |
| 814 | |
| 815 EXPECT_CALL(m_outputSurface, BindFramebuffer()) | |
| 816 .Times(1); | |
| 817 | |
| 818 EXPECT_CALL(*context(), drawElements(_, _, _, _)) | |
| 819 .Times(1); | |
| 820 | |
| 821 m_renderer.DecideRenderPassAllocationsForFrame(renderPassesInDrawOrder()
); | |
| 822 m_renderer.DrawFrame(renderPassesInDrawOrder()); | |
| 823 } | |
| 824 | |
| 825 OutputSurfaceMockContext* context() { return static_cast<OutputSurfaceMockCo
ntext*>(m_outputSurface.context3d()); } | |
| 826 | |
| 827 StrictMock<MockOutputSurface> m_outputSurface; | |
| 828 scoped_ptr<ResourceProvider> resource_provider_; | |
| 829 FakeRendererGL m_renderer; | |
| 830 }; | |
| 831 | |
| 832 TEST_F(MockOutputSurfaceTest, DrawFrameAndSwap) | |
| 833 { | |
| 834 DrawFrame(); | |
| 835 | |
| 836 EXPECT_CALL(m_outputSurface, SwapBuffers()) | |
| 837 .Times(1); | |
| 838 m_renderer.SwapBuffers(); | |
| 839 } | |
| 840 | |
| 841 class MockOutputSurfaceTestWithPartialSwap : public MockOutputSurfaceTest { | |
| 842 public: | |
| 843 virtual const LayerTreeSettings& Settings() const OVERRIDE | |
| 844 { | |
| 845 static LayerTreeSettings fakeSettings; | |
| 846 fakeSettings.partialSwapEnabled = true; | |
| 847 return fakeSettings; | |
| 848 } | |
| 849 }; | |
| 850 | |
| 851 TEST_F(MockOutputSurfaceTestWithPartialSwap, DrawFrameAndSwap) | |
| 852 { | |
| 853 DrawFrame(); | |
| 854 | |
| 855 EXPECT_CALL(m_outputSurface, PostSubBuffer(_)) | |
| 856 .Times(1); | |
| 857 m_renderer.SwapBuffers(); | |
| 858 } | |
| 859 | |
| 860 class MockOutputSurfaceTestWithSendCompositorFrame : public MockOutputSurfaceTes
t { | |
| 861 public: | |
| 862 virtual const LayerTreeSettings& Settings() const OVERRIDE | |
| 863 { | |
| 864 static LayerTreeSettings fakeSettings; | |
| 865 fakeSettings.compositorFrameMessage = true; | |
| 866 return fakeSettings; | |
| 867 } | |
| 868 }; | |
| 869 | |
| 870 TEST_F(MockOutputSurfaceTestWithSendCompositorFrame, DrawFrame) | |
| 871 { | |
| 872 EXPECT_CALL(m_outputSurface, SendFrameToParentCompositor(_)) | |
| 873 .Times(1); | |
| 874 DrawFrame(); | |
| 875 } | |
| 876 | |
| 877 } // namespace | |
| 878 } // namespace cc | |
| OLD | NEW |