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.
5 #include "cc/gl_renderer.h"
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/fake_web_graphics_context_3d.h"
15 #include "cc/test/render_pass_test_common.h"
16 #include "cc/test/render_pass_test_utils.h"
17 #include "testing/gmock/include/gmock/gmock.h"
18 #include "testing/gtest/include/gtest/gtest.h"
19 #include "third_party/khronos/GLES2/gl2.h"
20 #include "ui/gfx/transform.h"
22 using namespace WebKit
;
25 using testing::AnyNumber
;
26 using testing::AtLeast
;
27 using testing::Expectation
;
28 using testing::InSequence
;
34 class FrameCountingMemoryAllocationSettingContext
: public FakeWebGraphicsContext3D
{
36 FrameCountingMemoryAllocationSettingContext() : m_frame(0) { }
38 // WebGraphicsContext3D methods.
40 // This method would normally do a glSwapBuffers under the hood.
41 virtual void prepareTexture() { m_frame
++; }
42 virtual void setMemoryAllocationChangedCallbackCHROMIUM(WebGraphicsMemoryAllocationChangedCallbackCHROMIUM
* callback
) { m_memoryAllocationChangedCallback
= callback
; }
43 virtual WebString
getString(WebKit::WGC3Denum name
)
45 if (name
== GL_EXTENSIONS
)
46 return WebString("GL_CHROMIUM_set_visibility GL_CHROMIUM_gpu_memory_manager GL_CHROMIUM_discard_backbuffer");
50 // Methods added for test.
51 int frameCount() { return m_frame
; }
52 void setMemoryAllocation(WebGraphicsMemoryAllocation allocation
)
54 m_memoryAllocationChangedCallback
->onMemoryAllocationChanged(allocation
);
59 WebGraphicsMemoryAllocationChangedCallbackCHROMIUM
* m_memoryAllocationChangedCallback
;
62 class FakeRendererClient
: public RendererClient
{
65 : m_hostImpl(&m_proxy
)
66 , m_setFullRootLayerDamageCount(0)
67 , m_lastCallWasSetVisibility(0)
68 , m_rootLayer(LayerImpl::create(m_hostImpl
.activeTree(), 1))
69 , m_memoryAllocationLimitBytes(PrioritizedResourceManager::defaultMemoryAllocationLimit())
71 m_rootLayer
->createRenderSurface();
72 RenderPass::Id renderPassId
= m_rootLayer
->renderSurface()->renderPassId();
73 scoped_ptr
<RenderPass
> rootRenderPass
= RenderPass::Create();
74 rootRenderPass
->SetNew(renderPassId
, gfx::Rect(), gfx::Rect(), gfx::Transform());
75 m_renderPassesInDrawOrder
.append(rootRenderPass
.Pass());
78 // RendererClient methods.
79 virtual const gfx::Size
& deviceViewportSize() const OVERRIDE
{ static gfx::Size
fakeSize(1, 1); return fakeSize
; }
80 virtual const LayerTreeSettings
& settings() const OVERRIDE
{ static LayerTreeSettings fakeSettings
; return fakeSettings
; }
81 virtual void didLoseOutputSurface() OVERRIDE
{ }
82 virtual void onSwapBuffersComplete() OVERRIDE
{ }
83 virtual void setFullRootLayerDamage() OVERRIDE
{ m_setFullRootLayerDamageCount
++; }
84 virtual void setManagedMemoryPolicy(const ManagedMemoryPolicy
& policy
) OVERRIDE
{ m_memoryAllocationLimitBytes
= policy
.bytesLimitWhenVisible
; }
85 virtual void enforceManagedMemoryPolicy(const ManagedMemoryPolicy
& policy
) OVERRIDE
{ if (m_lastCallWasSetVisibility
) *m_lastCallWasSetVisibility
= false; }
86 virtual bool hasImplThread() const OVERRIDE
{ return false; }
87 virtual bool shouldClearRootRenderPass() const OVERRIDE
{ return true; }
88 virtual CompositorFrameMetadata
makeCompositorFrameMetadata() const
89 OVERRIDE
{ return CompositorFrameMetadata(); }
91 // Methods added for test.
92 int setFullRootLayerDamageCount() const { return m_setFullRootLayerDamageCount
; }
93 void setLastCallWasSetVisibilityPointer(bool* lastCallWasSetVisibility
) { m_lastCallWasSetVisibility
= lastCallWasSetVisibility
; }
95 RenderPass
* rootRenderPass() { return m_renderPassesInDrawOrder
.last(); }
96 RenderPassList
& renderPassesInDrawOrder() { return m_renderPassesInDrawOrder
; }
98 size_t memoryAllocationLimitBytes() const { return m_memoryAllocationLimitBytes
; }
101 FakeImplProxy m_proxy
;
102 FakeLayerTreeHostImpl m_hostImpl
;
103 int m_setFullRootLayerDamageCount
;
104 bool* m_lastCallWasSetVisibility
;
105 scoped_ptr
<LayerImpl
> m_rootLayer
;
106 RenderPassList m_renderPassesInDrawOrder
;
107 size_t m_memoryAllocationLimitBytes
;
110 class FakeRendererGL
: public GLRenderer
{
112 FakeRendererGL(RendererClient
* client
, OutputSurface
* outputSurface
, ResourceProvider
* resourceProvider
) : GLRenderer(client
, outputSurface
, resourceProvider
) { }
114 // GLRenderer methods.
116 // Changing visibility to public.
117 using GLRenderer::initialize
;
118 using GLRenderer::isBackbufferDiscarded
;
119 using GLRenderer::drawQuad
;
120 using GLRenderer::beginDrawingFrame
;
121 using GLRenderer::finishDrawingQuadList
;
124 class GLRendererTest
: public testing::Test
{
127 : m_suggestHaveBackbufferYes(1, true)
128 , m_suggestHaveBackbufferNo(1, false)
129 , m_outputSurface(FakeOutputSurface::Create3d(scoped_ptr
<WebKit::WebGraphicsContext3D
>(new FrameCountingMemoryAllocationSettingContext())))
130 , m_resourceProvider(ResourceProvider::create(m_outputSurface
.get()))
131 , m_renderer(&m_mockClient
, m_outputSurface
.get(), m_resourceProvider
.get())
137 m_renderer
.initialize();
142 m_renderer
.swapBuffers();
145 FrameCountingMemoryAllocationSettingContext
* context() { return static_cast<FrameCountingMemoryAllocationSettingContext
*>(m_outputSurface
->Context3D()); }
147 WebGraphicsMemoryAllocation m_suggestHaveBackbufferYes
;
148 WebGraphicsMemoryAllocation m_suggestHaveBackbufferNo
;
150 scoped_ptr
<OutputSurface
> m_outputSurface
;
151 FakeRendererClient m_mockClient
;
152 scoped_ptr
<ResourceProvider
> m_resourceProvider
;
153 FakeRendererGL m_renderer
;
156 // Test GLRenderer discardBackbuffer functionality:
157 // Suggest recreating framebuffer when one already exists.
158 // Expected: it does nothing.
159 TEST_F(GLRendererTest
, SuggestBackbufferYesWhenItAlreadyExistsShouldDoNothing
)
161 context()->setMemoryAllocation(m_suggestHaveBackbufferYes
);
162 EXPECT_EQ(0, m_mockClient
.setFullRootLayerDamageCount());
163 EXPECT_FALSE(m_renderer
.isBackbufferDiscarded());
166 EXPECT_EQ(1, context()->frameCount());
169 // Test GLRenderer discardBackbuffer functionality:
170 // Suggest discarding framebuffer when one exists and the renderer is not visible.
171 // Expected: it is discarded and damage tracker is reset.
172 TEST_F(GLRendererTest
, SuggestBackbufferNoShouldDiscardBackbufferAndDamageRootLayerWhileNotVisible
)
174 m_renderer
.setVisible(false);
175 context()->setMemoryAllocation(m_suggestHaveBackbufferNo
);
176 EXPECT_EQ(1, m_mockClient
.setFullRootLayerDamageCount());
177 EXPECT_TRUE(m_renderer
.isBackbufferDiscarded());
180 // Test GLRenderer discardBackbuffer functionality:
181 // Suggest discarding framebuffer when one exists and the renderer is visible.
182 // Expected: the allocation is ignored.
183 TEST_F(GLRendererTest
, SuggestBackbufferNoDoNothingWhenVisible
)
185 m_renderer
.setVisible(true);
186 context()->setMemoryAllocation(m_suggestHaveBackbufferNo
);
187 EXPECT_EQ(0, m_mockClient
.setFullRootLayerDamageCount());
188 EXPECT_FALSE(m_renderer
.isBackbufferDiscarded());
192 // Test GLRenderer discardBackbuffer functionality:
193 // Suggest discarding framebuffer when one does not exist.
194 // Expected: it does nothing.
195 TEST_F(GLRendererTest
, SuggestBackbufferNoWhenItDoesntExistShouldDoNothing
)
197 m_renderer
.setVisible(false);
198 context()->setMemoryAllocation(m_suggestHaveBackbufferNo
);
199 EXPECT_EQ(1, m_mockClient
.setFullRootLayerDamageCount());
200 EXPECT_TRUE(m_renderer
.isBackbufferDiscarded());
202 context()->setMemoryAllocation(m_suggestHaveBackbufferNo
);
203 EXPECT_EQ(1, m_mockClient
.setFullRootLayerDamageCount());
204 EXPECT_TRUE(m_renderer
.isBackbufferDiscarded());
207 // Test GLRenderer discardBackbuffer functionality:
208 // Begin drawing a frame while a framebuffer is discarded.
209 // Expected: will recreate framebuffer.
210 TEST_F(GLRendererTest
, DiscardedBackbufferIsRecreatedForScopeDuration
)
212 m_renderer
.setVisible(false);
213 context()->setMemoryAllocation(m_suggestHaveBackbufferNo
);
214 EXPECT_TRUE(m_renderer
.isBackbufferDiscarded());
215 EXPECT_EQ(1, m_mockClient
.setFullRootLayerDamageCount());
217 m_renderer
.setVisible(true);
218 m_renderer
.drawFrame(m_mockClient
.renderPassesInDrawOrder());
219 EXPECT_FALSE(m_renderer
.isBackbufferDiscarded());
222 EXPECT_EQ(1, context()->frameCount());
225 TEST_F(GLRendererTest
, FramebufferDiscardedAfterReadbackWhenNotVisible
)
227 m_renderer
.setVisible(false);
228 context()->setMemoryAllocation(m_suggestHaveBackbufferNo
);
229 EXPECT_TRUE(m_renderer
.isBackbufferDiscarded());
230 EXPECT_EQ(1, m_mockClient
.setFullRootLayerDamageCount());
233 m_renderer
.drawFrame(m_mockClient
.renderPassesInDrawOrder());
234 EXPECT_FALSE(m_renderer
.isBackbufferDiscarded());
236 m_renderer
.getFramebufferPixels(pixels
, gfx::Rect(0, 0, 1, 1));
237 EXPECT_TRUE(m_renderer
.isBackbufferDiscarded());
238 EXPECT_EQ(2, m_mockClient
.setFullRootLayerDamageCount());
241 class ForbidSynchronousCallContext
: public FakeWebGraphicsContext3D
{
243 ForbidSynchronousCallContext() { }
245 virtual bool getActiveAttrib(WebGLId program
, WGC3Duint index
, ActiveInfo
&) { ADD_FAILURE(); return false; }
246 virtual bool getActiveUniform(WebGLId program
, WGC3Duint index
, ActiveInfo
&) { ADD_FAILURE(); return false; }
247 virtual void getAttachedShaders(WebGLId program
, WGC3Dsizei maxCount
, WGC3Dsizei
* count
, WebGLId
* shaders
) { ADD_FAILURE(); }
248 virtual WGC3Dint
getAttribLocation(WebGLId program
, const WGC3Dchar
* name
) { ADD_FAILURE(); return 0; }
249 virtual void getBooleanv(WGC3Denum pname
, WGC3Dboolean
* value
) { ADD_FAILURE(); }
250 virtual void getBufferParameteriv(WGC3Denum target
, WGC3Denum pname
, WGC3Dint
* value
) { ADD_FAILURE(); }
251 virtual Attributes
getContextAttributes() { ADD_FAILURE(); return attributes_
; }
252 virtual WGC3Denum
getError() { ADD_FAILURE(); return 0; }
253 virtual void getFloatv(WGC3Denum pname
, WGC3Dfloat
* value
) { ADD_FAILURE(); }
254 virtual void getFramebufferAttachmentParameteriv(WGC3Denum target
, WGC3Denum attachment
, WGC3Denum pname
, WGC3Dint
* value
) { ADD_FAILURE(); }
255 virtual void getIntegerv(WGC3Denum pname
, WGC3Dint
* value
)
257 if (pname
== GL_MAX_TEXTURE_SIZE
)
258 *value
= 1024; // MAX_TEXTURE_SIZE is cached client side, so it's OK to query.
263 // We allow querying the shader compilation and program link status in debug mode, but not release.
264 virtual void getProgramiv(WebGLId program
, WGC3Denum pname
, WGC3Dint
* value
)
273 virtual void getShaderiv(WebGLId shader
, WGC3Denum pname
, WGC3Dint
* value
)
282 virtual WebString
getString(WGC3Denum name
)
284 // We allow querying the extension string.
285 // FIXME: It'd be better to check that we only do this before starting any other expensive work (like starting a compilation)
286 if (name
!= GL_EXTENSIONS
)
291 virtual WebString
getProgramInfoLog(WebGLId program
) { ADD_FAILURE(); return WebString(); }
292 virtual void getRenderbufferParameteriv(WGC3Denum target
, WGC3Denum pname
, WGC3Dint
* value
) { ADD_FAILURE(); }
294 virtual WebString
getShaderInfoLog(WebGLId shader
) { ADD_FAILURE(); return WebString(); }
295 virtual void getShaderPrecisionFormat(WGC3Denum shadertype
, WGC3Denum precisiontype
, WGC3Dint
* range
, WGC3Dint
* precision
) { ADD_FAILURE(); }
296 virtual WebString
getShaderSource(WebGLId shader
) { ADD_FAILURE(); return WebString(); }
297 virtual void getTexParameterfv(WGC3Denum target
, WGC3Denum pname
, WGC3Dfloat
* value
) { ADD_FAILURE(); }
298 virtual void getTexParameteriv(WGC3Denum target
, WGC3Denum pname
, WGC3Dint
* value
) { ADD_FAILURE(); }
299 virtual void getUniformfv(WebGLId program
, WGC3Dint location
, WGC3Dfloat
* value
) { ADD_FAILURE(); }
300 virtual void getUniformiv(WebGLId program
, WGC3Dint location
, WGC3Dint
* value
) { ADD_FAILURE(); }
301 virtual WGC3Dint
getUniformLocation(WebGLId program
, const WGC3Dchar
* name
) { ADD_FAILURE(); return 0; }
302 virtual void getVertexAttribfv(WGC3Duint index
, WGC3Denum pname
, WGC3Dfloat
* value
) { ADD_FAILURE(); }
303 virtual void getVertexAttribiv(WGC3Duint index
, WGC3Denum pname
, WGC3Dint
* value
) { ADD_FAILURE(); }
304 virtual WGC3Dsizeiptr
getVertexAttribOffset(WGC3Duint index
, WGC3Denum pname
) { ADD_FAILURE(); return 0; }
307 // This test isn't using the same fixture as GLRendererTest, and you can't mix TEST() and TEST_F() with the same name, hence LRC2.
308 TEST(GLRendererTest2
, initializationDoesNotMakeSynchronousCalls
)
310 FakeRendererClient mockClient
;
311 scoped_ptr
<OutputSurface
> outputSurface(FakeOutputSurface::Create3d(scoped_ptr
<WebKit::WebGraphicsContext3D
>(new ForbidSynchronousCallContext
)));
312 scoped_ptr
<ResourceProvider
> resourceProvider(ResourceProvider::create(outputSurface
.get()));
313 FakeRendererGL
renderer(&mockClient
, outputSurface
.get(), resourceProvider
.get());
315 EXPECT_TRUE(renderer
.initialize());
318 class LoseContextOnFirstGetContext
: public FakeWebGraphicsContext3D
{
320 LoseContextOnFirstGetContext()
321 : m_contextLost(false)
325 virtual bool makeContextCurrent() OVERRIDE
327 return !m_contextLost
;
330 virtual void getProgramiv(WebGLId program
, WGC3Denum pname
, WGC3Dint
* value
) OVERRIDE
332 m_contextLost
= true;
336 virtual void getShaderiv(WebGLId shader
, WGC3Denum pname
, WGC3Dint
* value
) OVERRIDE
338 m_contextLost
= true;
342 virtual WGC3Denum
getGraphicsResetStatusARB() OVERRIDE
344 return m_contextLost
? 1 : 0;
351 TEST(GLRendererTest2
, initializationWithQuicklyLostContextDoesNotAssert
)
353 FakeRendererClient mockClient
;
354 scoped_ptr
<OutputSurface
> outputSurface(FakeOutputSurface::Create3d(scoped_ptr
<WebKit::WebGraphicsContext3D
>(new LoseContextOnFirstGetContext
)));
355 scoped_ptr
<ResourceProvider
> resourceProvider(ResourceProvider::create(outputSurface
.get()));
356 FakeRendererGL
renderer(&mockClient
, outputSurface
.get(), resourceProvider
.get());
358 renderer
.initialize();
361 class ContextThatDoesNotSupportMemoryManagmentExtensions
: public FakeWebGraphicsContext3D
{
363 ContextThatDoesNotSupportMemoryManagmentExtensions() { }
365 // WebGraphicsContext3D methods.
367 // This method would normally do a glSwapBuffers under the hood.
368 virtual void prepareTexture() { }
369 virtual void setMemoryAllocationChangedCallbackCHROMIUM(WebGraphicsMemoryAllocationChangedCallbackCHROMIUM
* callback
) { }
370 virtual WebString
getString(WebKit::WGC3Denum name
) { return WebString(); }
373 TEST(GLRendererTest2
, initializationWithoutGpuMemoryManagerExtensionSupportShouldDefaultToNonZeroAllocation
)
375 FakeRendererClient mockClient
;
376 scoped_ptr
<OutputSurface
> outputSurface(FakeOutputSurface::Create3d(scoped_ptr
<WebKit::WebGraphicsContext3D
>(new ContextThatDoesNotSupportMemoryManagmentExtensions
)));
377 scoped_ptr
<ResourceProvider
> resourceProvider(ResourceProvider::create(outputSurface
.get()));
378 FakeRendererGL
renderer(&mockClient
, outputSurface
.get(), resourceProvider
.get());
380 renderer
.initialize();
382 EXPECT_GT(mockClient
.memoryAllocationLimitBytes(), 0ul);
385 class ClearCountingContext
: public FakeWebGraphicsContext3D
{
387 ClearCountingContext() : m_clear(0) { }
389 virtual void clear(WGC3Dbitfield
)
394 int clearCount() const { return m_clear
; }
400 TEST(GLRendererTest2
, opaqueBackground
)
402 FakeRendererClient mockClient
;
403 scoped_ptr
<OutputSurface
> outputSurface(FakeOutputSurface::Create3d(scoped_ptr
<WebKit::WebGraphicsContext3D
>(new ClearCountingContext
)));
404 ClearCountingContext
* context
= static_cast<ClearCountingContext
*>(outputSurface
->Context3D());
405 scoped_ptr
<ResourceProvider
> resourceProvider(ResourceProvider::create(outputSurface
.get()));
406 FakeRendererGL
renderer(&mockClient
, outputSurface
.get(), resourceProvider
.get());
408 mockClient
.rootRenderPass()->has_transparent_background
= false;
410 EXPECT_TRUE(renderer
.initialize());
412 renderer
.drawFrame(mockClient
.renderPassesInDrawOrder());
414 // On DEBUG builds, render passes with opaque background clear to blue to
415 // easily see regions that were not drawn on the screen.
417 EXPECT_EQ(0, context
->clearCount());
419 EXPECT_EQ(1, context
->clearCount());
423 TEST(GLRendererTest2
, transparentBackground
)
425 FakeRendererClient mockClient
;
426 scoped_ptr
<OutputSurface
> outputSurface(FakeOutputSurface::Create3d(scoped_ptr
<WebKit::WebGraphicsContext3D
>(new ClearCountingContext
)));
427 ClearCountingContext
* context
= static_cast<ClearCountingContext
*>(outputSurface
->Context3D());
428 scoped_ptr
<ResourceProvider
> resourceProvider(ResourceProvider::create(outputSurface
.get()));
429 FakeRendererGL
renderer(&mockClient
, outputSurface
.get(), resourceProvider
.get());
431 mockClient
.rootRenderPass()->has_transparent_background
= true;
433 EXPECT_TRUE(renderer
.initialize());
435 renderer
.drawFrame(mockClient
.renderPassesInDrawOrder());
437 EXPECT_EQ(1, context
->clearCount());
440 class VisibilityChangeIsLastCallTrackingContext
: public FakeWebGraphicsContext3D
{
442 VisibilityChangeIsLastCallTrackingContext()
443 : m_lastCallWasSetVisibility(0)
447 // WebGraphicsContext3D methods.
448 virtual void setVisibilityCHROMIUM(bool visible
) {
449 if (!m_lastCallWasSetVisibility
)
451 DCHECK(*m_lastCallWasSetVisibility
== false);
452 *m_lastCallWasSetVisibility
= true;
454 virtual void flush() { if (m_lastCallWasSetVisibility
) *m_lastCallWasSetVisibility
= false; }
455 virtual void deleteTexture(WebGLId
) { if (m_lastCallWasSetVisibility
) *m_lastCallWasSetVisibility
= false; }
456 virtual void deleteFramebuffer(WebGLId
) { if (m_lastCallWasSetVisibility
) *m_lastCallWasSetVisibility
= false; }
457 virtual void deleteRenderbuffer(WebGLId
) { if (m_lastCallWasSetVisibility
) *m_lastCallWasSetVisibility
= false; }
459 // This method would normally do a glSwapBuffers under the hood.
460 virtual WebString
getString(WebKit::WGC3Denum name
)
462 if (name
== GL_EXTENSIONS
)
463 return WebString("GL_CHROMIUM_set_visibility GL_CHROMIUM_gpu_memory_manager GL_CHROMIUM_discard_backbuffer");
467 // Methods added for test.
468 void setLastCallWasSetVisibilityPointer(bool* lastCallWasSetVisibility
) { m_lastCallWasSetVisibility
= lastCallWasSetVisibility
; }
471 bool* m_lastCallWasSetVisibility
;
474 TEST(GLRendererTest2
, visibilityChangeIsLastCall
)
476 FakeRendererClient mockClient
;
477 scoped_ptr
<OutputSurface
> outputSurface(FakeOutputSurface::Create3d(scoped_ptr
<WebKit::WebGraphicsContext3D
>(new VisibilityChangeIsLastCallTrackingContext
)));
478 VisibilityChangeIsLastCallTrackingContext
* context
= static_cast<VisibilityChangeIsLastCallTrackingContext
*>(outputSurface
->Context3D());
479 scoped_ptr
<ResourceProvider
> resourceProvider(ResourceProvider::create(outputSurface
.get()));
480 FakeRendererGL
renderer(&mockClient
, outputSurface
.get(), resourceProvider
.get());
482 EXPECT_TRUE(renderer
.initialize());
484 bool lastCallWasSetVisiblity
= false;
485 // Ensure that the call to setVisibilityCHROMIUM is the last call issue to the GPU
486 // process, after glFlush is called, and after the RendererClient's enforceManagedMemoryPolicy
487 // is called. Plumb this tracking between both the RenderClient and the Context by giving
488 // them both a pointer to a variable on the stack.
489 context
->setLastCallWasSetVisibilityPointer(&lastCallWasSetVisiblity
);
490 mockClient
.setLastCallWasSetVisibilityPointer(&lastCallWasSetVisiblity
);
491 renderer
.setVisible(true);
492 renderer
.drawFrame(mockClient
.renderPassesInDrawOrder());
493 renderer
.setVisible(false);
494 EXPECT_TRUE(lastCallWasSetVisiblity
);
497 class TextureStateTrackingContext
: public FakeWebGraphicsContext3D
{
499 TextureStateTrackingContext()
500 : m_activeTexture(GL_INVALID_ENUM
)
504 virtual WebString
getString(WGC3Denum name
)
506 if (name
== GL_EXTENSIONS
)
507 return WebString("GL_OES_EGL_image_external");
511 MOCK_METHOD3(texParameteri
, void(WGC3Denum target
, WGC3Denum pname
, WGC3Dint param
));
512 MOCK_METHOD4(drawElements
, void(WGC3Denum mode
, WGC3Dsizei count
, WGC3Denum type
, WGC3Dintptr offset
));
514 virtual void activeTexture(WGC3Denum texture
)
516 EXPECT_NE(texture
, m_activeTexture
);
517 m_activeTexture
= texture
;
520 WGC3Denum
activeTexture() const { return m_activeTexture
; }
523 WGC3Denum m_activeTexture
;
526 TEST(GLRendererTest2
, activeTextureState
)
528 FakeRendererClient fakeClient
;
529 scoped_ptr
<OutputSurface
> outputSurface(FakeOutputSurface::Create3d(scoped_ptr
<WebKit::WebGraphicsContext3D
>(new TextureStateTrackingContext
)));
530 TextureStateTrackingContext
* context
= static_cast<TextureStateTrackingContext
*>(outputSurface
->Context3D());
531 scoped_ptr
<ResourceProvider
> resourceProvider(ResourceProvider::create(outputSurface
.get()));
532 FakeRendererGL
renderer(&fakeClient
, outputSurface
.get(), resourceProvider
.get());
534 // During initialization we are allowed to set any texture parameters.
535 EXPECT_CALL(*context
, texParameteri(_
, _
, _
)).Times(AnyNumber());
536 EXPECT_TRUE(renderer
.initialize());
538 cc::RenderPass::Id
id(1, 1);
539 scoped_ptr
<TestRenderPass
> pass
= TestRenderPass::Create();
540 pass
->SetNew(id
, gfx::Rect(0, 0, 100, 100), gfx::Rect(0, 0, 100, 100), gfx::Transform());
541 pass
->AppendOneOfEveryQuadType(resourceProvider
.get());
543 // Set up expected texture filter state transitions that match the quads
544 // created in AppendOneOfEveryQuadType().
545 Mock::VerifyAndClearExpectations(context
);
549 // yuv_quad is drawn with the default filter.
550 EXPECT_CALL(*context
, drawElements(_
, _
, _
, _
));
552 // tile_quad is drawn with GL_NEAREST because it is not transformed or
554 EXPECT_CALL(*context
, texParameteri(GL_TEXTURE_2D
, GL_TEXTURE_MIN_FILTER
, GL_NEAREST
));
555 EXPECT_CALL(*context
, texParameteri(GL_TEXTURE_2D
, GL_TEXTURE_MAG_FILTER
, GL_NEAREST
));
556 EXPECT_CALL(*context
, drawElements(_
, _
, _
, _
));
558 // transformed_tile_quad uses GL_LINEAR.
559 EXPECT_CALL(*context
, texParameteri(GL_TEXTURE_2D
, GL_TEXTURE_MIN_FILTER
, GL_LINEAR
));
560 EXPECT_CALL(*context
, texParameteri(GL_TEXTURE_2D
, GL_TEXTURE_MAG_FILTER
, GL_LINEAR
));
561 EXPECT_CALL(*context
, drawElements(_
, _
, _
, _
));
563 // scaled_tile_quad also uses GL_LINEAR.
564 EXPECT_CALL(*context
, drawElements(_
, _
, _
, _
));
566 // The remaining quads also use GL_LINEAR because nearest neighbor
567 // filtering is currently only used with tile quads.
568 EXPECT_CALL(*context
, drawElements(_
, _
, _
, _
)).Times(6);
571 cc::DirectRenderer::DrawingFrame drawingFrame
;
572 renderer
.beginDrawingFrame(drawingFrame
);
573 EXPECT_EQ(context
->activeTexture(), GL_TEXTURE0
);
575 for (cc::QuadList::backToFrontIterator it
= pass
->quad_list
.backToFrontBegin();
576 it
!= pass
->quad_list
.backToFrontEnd(); ++it
) {
577 renderer
.drawQuad(drawingFrame
, *it
);
579 renderer
.finishDrawingQuadList();
580 EXPECT_EQ(context
->activeTexture(), GL_TEXTURE0
);
581 Mock::VerifyAndClearExpectations(context
);
584 class NoClearRootRenderPassFakeClient
: public FakeRendererClient
{
586 virtual bool shouldClearRootRenderPass() const { return false; }
589 class NoClearRootRenderPassMockContext
: public FakeWebGraphicsContext3D
{
591 MOCK_METHOD1(clear
, void(WGC3Dbitfield mask
));
592 MOCK_METHOD4(drawElements
, void(WGC3Denum mode
, WGC3Dsizei count
, WGC3Denum type
, WGC3Dintptr offset
));
595 TEST(GLRendererTest2
, shouldClearRootRenderPass
)
597 NoClearRootRenderPassFakeClient mockClient
;
598 scoped_ptr
<OutputSurface
> outputSurface(FakeOutputSurface::Create3d(scoped_ptr
<WebKit::WebGraphicsContext3D
>(new NoClearRootRenderPassMockContext
)));
599 NoClearRootRenderPassMockContext
* mockContext
= static_cast<NoClearRootRenderPassMockContext
*>(outputSurface
->Context3D());
600 scoped_ptr
<ResourceProvider
> resourceProvider(ResourceProvider::create(outputSurface
.get()));
601 FakeRendererGL
renderer(&mockClient
, outputSurface
.get(), resourceProvider
.get());
602 EXPECT_TRUE(renderer
.initialize());
604 gfx::Rect
viewportRect(mockClient
.deviceViewportSize());
605 ScopedPtrVector
<RenderPass
>& renderPasses
= mockClient
.renderPassesInDrawOrder();
606 renderPasses
.clear();
608 RenderPass::Id
rootPassId(1, 0);
609 TestRenderPass
* rootPass
= addRenderPass(renderPasses
, rootPassId
, viewportRect
, gfx::Transform());
610 addQuad(rootPass
, viewportRect
, SK_ColorGREEN
);
612 RenderPass::Id
childPassId(2, 0);
613 TestRenderPass
* childPass
= addRenderPass(renderPasses
, childPassId
, viewportRect
, gfx::Transform());
614 addQuad(childPass
, viewportRect
, SK_ColorBLUE
);
616 addRenderPassQuad(rootPass
, childPass
);
618 // First render pass is not the root one, clearing should happen.
619 EXPECT_CALL(*mockContext
, clear(GL_COLOR_BUFFER_BIT
))
622 Expectation firstRenderPass
= EXPECT_CALL(*mockContext
, drawElements(_
, _
, _
, _
))
625 // The second render pass is the root one, clearing should be prevented.
626 EXPECT_CALL(*mockContext
, clear(GL_COLOR_BUFFER_BIT
))
628 .After(firstRenderPass
);
630 EXPECT_CALL(*mockContext
, drawElements(_
, _
, _
, _
))
632 .After(firstRenderPass
);
634 renderer
.decideRenderPassAllocationsForFrame(mockClient
.renderPassesInDrawOrder());
635 renderer
.drawFrame(mockClient
.renderPassesInDrawOrder());
637 // In multiple render passes all but the root pass should clear the framebuffer.
638 Mock::VerifyAndClearExpectations(&mockContext
);