diff options
author | Simon Hausmann <simon.hausmann@nokia.com> | 2012-08-24 08:29:43 +0200 |
---|---|---|
committer | Simon Hausmann <simon.hausmann@nokia.com> | 2012-08-24 08:29:43 +0200 |
commit | 2e2ba8ff45915f40ed3e014101269c175f2a89a0 (patch) | |
tree | 3b94a9a9fa83efa384b8dac611cf8c6495532a62 /Source/WebKit/chromium/tests/CCRendererGLTest.cpp | |
parent | f53e6f8e798362ed712d4a51633b0d0b03dbc213 (diff) | |
download | qtwebkit-2e2ba8ff45915f40ed3e014101269c175f2a89a0.tar.gz |
Imported WebKit commit bf0b0213bbf3886c96610020602012ca7d11b084 (http://svn.webkit.org/repository/webkit/trunk@126545)
New snapshot with clang and python build fixes
Diffstat (limited to 'Source/WebKit/chromium/tests/CCRendererGLTest.cpp')
-rw-r--r-- | Source/WebKit/chromium/tests/CCRendererGLTest.cpp | 449 |
1 files changed, 449 insertions, 0 deletions
diff --git a/Source/WebKit/chromium/tests/CCRendererGLTest.cpp b/Source/WebKit/chromium/tests/CCRendererGLTest.cpp new file mode 100644 index 000000000..2f3fd6a08 --- /dev/null +++ b/Source/WebKit/chromium/tests/CCRendererGLTest.cpp @@ -0,0 +1,449 @@ +/* + * Copyright (C) 2012 Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "CCRendererGL.h" + +#include "CCDrawQuad.h" +#include "CCPrioritizedTextureManager.h" +#include "CCSettings.h" +#include "CCSingleThreadProxy.h" +#include "CCTestCommon.h" +#include "FakeWebCompositorOutputSurface.h" +#include "FakeWebGraphicsContext3D.h" +#include "GraphicsContext3D.h" +#include <gmock/gmock.h> +#include <gtest/gtest.h> +#include <public/WebCompositor.h> +#include <public/WebTransformationMatrix.h> + +using namespace WebCore; +using namespace WebKit; +using namespace WebKitTests; + +class FrameCountingMemoryAllocationSettingContext : public FakeWebGraphicsContext3D { +public: + FrameCountingMemoryAllocationSettingContext() : m_frame(0) { } + + // WebGraphicsContext3D methods. + + // This method would normally do a glSwapBuffers under the hood. + virtual void prepareTexture() { m_frame++; } + virtual void setMemoryAllocationChangedCallbackCHROMIUM(WebGraphicsMemoryAllocationChangedCallbackCHROMIUM* callback) { m_memoryAllocationChangedCallback = callback; } + virtual WebString getString(WebKit::WGC3Denum name) + { + if (name == GraphicsContext3D::EXTENSIONS) + return WebString("GL_CHROMIUM_set_visibility GL_CHROMIUM_gpu_memory_manager GL_CHROMIUM_discard_framebuffer"); + return WebString(); + } + + // Methods added for test. + int frameCount() { return m_frame; } + void setMemoryAllocation(WebGraphicsMemoryAllocation allocation) + { + ASSERT(CCProxy::isImplThread()); + // In single threaded mode we expect this callback on main thread. + DebugScopedSetMainThread main; + m_memoryAllocationChangedCallback->onMemoryAllocationChanged(allocation); + } + +private: + int m_frame; + WebGraphicsMemoryAllocationChangedCallbackCHROMIUM* m_memoryAllocationChangedCallback; +}; + +class FakeCCRendererClient : public CCRendererClient { +public: + FakeCCRendererClient() + : m_setFullRootLayerDamageCount(0) + , m_rootLayer(CCLayerImpl::create(1)) + , m_memoryAllocationLimitBytes(CCPrioritizedTextureManager::defaultMemoryAllocationLimit()) + { + OwnPtr<CCRenderPass> rootRenderPass = CCRenderPass::create(m_rootLayer->id(), IntRect(), WebTransformationMatrix()); + m_renderPassesInDrawOrder.append(rootRenderPass.get()); + m_renderPasses.set(m_rootLayer->id(), rootRenderPass.release()); + } + + // CCRendererClient methods. + virtual const IntSize& deviceViewportSize() const OVERRIDE { static IntSize fakeSize(1, 1); return fakeSize; } + virtual const CCLayerTreeSettings& settings() const OVERRIDE { static CCLayerTreeSettings fakeSettings; return fakeSettings; } + virtual void didLoseContext() OVERRIDE { } + virtual void onSwapBuffersComplete() OVERRIDE { } + virtual void setFullRootLayerDamage() OVERRIDE { m_setFullRootLayerDamageCount++; } + virtual void releaseContentsTextures() OVERRIDE { } + virtual void setMemoryAllocationLimitBytes(size_t bytes) OVERRIDE { m_memoryAllocationLimitBytes = bytes; } + + // Methods added for test. + int setFullRootLayerDamageCount() const { return m_setFullRootLayerDamageCount; } + + CCRenderPass* rootRenderPass() { return m_renderPassesInDrawOrder.last(); } + const CCRenderPassList& renderPassesInDrawOrder() const { return m_renderPassesInDrawOrder; } + const CCRenderPassIdHashMap& renderPasses() const { return m_renderPasses; } + + size_t memoryAllocationLimitBytes() const { return m_memoryAllocationLimitBytes; } + +private: + int m_setFullRootLayerDamageCount; + DebugScopedSetImplThread m_implThread; + OwnPtr<CCLayerImpl> m_rootLayer; + CCRenderPassList m_renderPassesInDrawOrder; + CCRenderPassIdHashMap m_renderPasses; + size_t m_memoryAllocationLimitBytes; +}; + +class FakeCCRendererGL : public CCRendererGL { +public: + FakeCCRendererGL(CCRendererClient* client, CCResourceProvider* resourceProvider) : CCRendererGL(client, resourceProvider, UnthrottledUploader) { } + + // CCRendererGL methods. + + // Changing visibility to public. + using CCRendererGL::initialize; + using CCRendererGL::isFramebufferDiscarded; +}; + +class CCRendererGLTest : public testing::Test { +protected: + CCRendererGLTest() + : m_suggestHaveBackbufferYes(1, true) + , m_suggestHaveBackbufferNo(1, false) + , m_context(FakeWebCompositorOutputSurface::create(adoptPtr(new FrameCountingMemoryAllocationSettingContext()))) + , m_resourceProvider(CCResourceProvider::create(m_context.get())) + , m_renderer(&m_mockClient, m_resourceProvider.get()) + { + } + + virtual void SetUp() + { + WebKit::WebCompositor::initialize(0); + m_renderer.initialize(); + } + + virtual void TearDown() + { + WebKit::WebCompositor::shutdown(); + } + + void swapBuffers() + { + m_renderer.swapBuffers(); + } + + FrameCountingMemoryAllocationSettingContext* context() { return static_cast<FrameCountingMemoryAllocationSettingContext*>(m_context->context3D()); } + + WebGraphicsMemoryAllocation m_suggestHaveBackbufferYes; + WebGraphicsMemoryAllocation m_suggestHaveBackbufferNo; + + OwnPtr<CCGraphicsContext> m_context; + FakeCCRendererClient m_mockClient; + OwnPtr<CCResourceProvider> m_resourceProvider; + FakeCCRendererGL m_renderer; + CCScopedSettings m_scopedSettings; +}; + +// Test CCRendererGL discardFramebuffer functionality: +// Suggest recreating framebuffer when one already exists. +// Expected: it does nothing. +TEST_F(CCRendererGLTest, SuggestBackbufferYesWhenItAlreadyExistsShouldDoNothing) +{ + context()->setMemoryAllocation(m_suggestHaveBackbufferYes); + EXPECT_EQ(0, m_mockClient.setFullRootLayerDamageCount()); + EXPECT_FALSE(m_renderer.isFramebufferDiscarded()); + + swapBuffers(); + EXPECT_EQ(1, context()->frameCount()); +} + +// Test CCRendererGL discardFramebuffer functionality: +// Suggest discarding framebuffer when one exists and the renderer is not visible. +// Expected: it is discarded and damage tracker is reset. +TEST_F(CCRendererGLTest, SuggestBackbufferNoShouldDiscardBackbufferAndDamageRootLayerWhileNotVisible) +{ + m_renderer.setVisible(false); + context()->setMemoryAllocation(m_suggestHaveBackbufferNo); + EXPECT_EQ(1, m_mockClient.setFullRootLayerDamageCount()); + EXPECT_TRUE(m_renderer.isFramebufferDiscarded()); +} + +// Test CCRendererGL discardFramebuffer functionality: +// Suggest discarding framebuffer when one exists and the renderer is visible. +// Expected: the allocation is ignored. +TEST_F(CCRendererGLTest, SuggestBackbufferNoDoNothingWhenVisible) +{ + m_renderer.setVisible(true); + context()->setMemoryAllocation(m_suggestHaveBackbufferNo); + EXPECT_EQ(0, m_mockClient.setFullRootLayerDamageCount()); + EXPECT_FALSE(m_renderer.isFramebufferDiscarded()); +} + + +// Test CCRendererGL discardFramebuffer functionality: +// Suggest discarding framebuffer when one does not exist. +// Expected: it does nothing. +TEST_F(CCRendererGLTest, SuggestBackbufferNoWhenItDoesntExistShouldDoNothing) +{ + m_renderer.setVisible(false); + context()->setMemoryAllocation(m_suggestHaveBackbufferNo); + EXPECT_EQ(1, m_mockClient.setFullRootLayerDamageCount()); + EXPECT_TRUE(m_renderer.isFramebufferDiscarded()); + + context()->setMemoryAllocation(m_suggestHaveBackbufferNo); + EXPECT_EQ(1, m_mockClient.setFullRootLayerDamageCount()); + EXPECT_TRUE(m_renderer.isFramebufferDiscarded()); +} + +// Test CCRendererGL discardFramebuffer functionality: +// Begin drawing a frame while a framebuffer is discarded. +// Expected: will recreate framebuffer. +TEST_F(CCRendererGLTest, DiscardedBackbufferIsRecreatedForScopeDuration) +{ + m_renderer.setVisible(false); + context()->setMemoryAllocation(m_suggestHaveBackbufferNo); + EXPECT_TRUE(m_renderer.isFramebufferDiscarded()); + EXPECT_EQ(1, m_mockClient.setFullRootLayerDamageCount()); + + m_renderer.setVisible(true); + m_renderer.drawFrame(m_mockClient.renderPassesInDrawOrder(), m_mockClient.renderPasses()); + EXPECT_FALSE(m_renderer.isFramebufferDiscarded()); + + swapBuffers(); + EXPECT_EQ(1, context()->frameCount()); +} + +TEST_F(CCRendererGLTest, FramebufferDiscardedAfterReadbackWhenNotVisible) +{ + m_renderer.setVisible(false); + context()->setMemoryAllocation(m_suggestHaveBackbufferNo); + EXPECT_TRUE(m_renderer.isFramebufferDiscarded()); + EXPECT_EQ(1, m_mockClient.setFullRootLayerDamageCount()); + + char pixels[4]; + m_renderer.drawFrame(m_mockClient.renderPassesInDrawOrder(), m_mockClient.renderPasses()); + EXPECT_FALSE(m_renderer.isFramebufferDiscarded()); + + m_renderer.getFramebufferPixels(pixels, IntRect(0, 0, 1, 1)); + EXPECT_TRUE(m_renderer.isFramebufferDiscarded()); + EXPECT_EQ(2, m_mockClient.setFullRootLayerDamageCount()); +} + +class ForbidSynchronousCallContext : public FakeWebGraphicsContext3D { +public: + ForbidSynchronousCallContext() { } + + virtual bool getActiveAttrib(WebGLId program, WGC3Duint index, ActiveInfo&) { ADD_FAILURE(); return false; } + virtual bool getActiveUniform(WebGLId program, WGC3Duint index, ActiveInfo&) { ADD_FAILURE(); return false; } + virtual void getAttachedShaders(WebGLId program, WGC3Dsizei maxCount, WGC3Dsizei* count, WebGLId* shaders) { ADD_FAILURE(); } + virtual WGC3Dint getAttribLocation(WebGLId program, const WGC3Dchar* name) { ADD_FAILURE(); return 0; } + virtual void getBooleanv(WGC3Denum pname, WGC3Dboolean* value) { ADD_FAILURE(); } + virtual void getBufferParameteriv(WGC3Denum target, WGC3Denum pname, WGC3Dint* value) { ADD_FAILURE(); } + virtual Attributes getContextAttributes() { ADD_FAILURE(); return m_attrs; } + virtual WGC3Denum getError() { ADD_FAILURE(); return 0; } + virtual void getFloatv(WGC3Denum pname, WGC3Dfloat* value) { ADD_FAILURE(); } + virtual void getFramebufferAttachmentParameteriv(WGC3Denum target, WGC3Denum attachment, WGC3Denum pname, WGC3Dint* value) { ADD_FAILURE(); } + virtual void getIntegerv(WGC3Denum pname, WGC3Dint* value) + { + if (pname == WebCore::GraphicsContext3D::MAX_TEXTURE_SIZE) + *value = 1024; // MAX_TEXTURE_SIZE is cached client side, so it's OK to query. + else + ADD_FAILURE(); + } + + // We allow querying the shader compilation and program link status in debug mode, but not release. + virtual void getProgramiv(WebGLId program, WGC3Denum pname, WGC3Dint* value) + { +#ifndef NDEBUG + *value = 1; +#else + ADD_FAILURE(); +#endif + } + + virtual void getShaderiv(WebGLId shader, WGC3Denum pname, WGC3Dint* value) + { +#ifndef NDEBUG + *value = 1; +#else + ADD_FAILURE(); +#endif + } + + virtual WebString getString(WGC3Denum name) + { + // We allow querying the extension string. + // FIXME: It'd be better to check that we only do this before starting any other expensive work (like starting a compilation) + if (name != WebCore::GraphicsContext3D::EXTENSIONS) + ADD_FAILURE(); + return WebString(); + } + + virtual WebString getProgramInfoLog(WebGLId program) { ADD_FAILURE(); return WebString(); } + virtual void getRenderbufferParameteriv(WGC3Denum target, WGC3Denum pname, WGC3Dint* value) { ADD_FAILURE(); } + + virtual WebString getShaderInfoLog(WebGLId shader) { ADD_FAILURE(); return WebString(); } + virtual void getShaderPrecisionFormat(WGC3Denum shadertype, WGC3Denum precisiontype, WGC3Dint* range, WGC3Dint* precision) { ADD_FAILURE(); } + virtual WebString getShaderSource(WebGLId shader) { ADD_FAILURE(); return WebString(); } + virtual void getTexParameterfv(WGC3Denum target, WGC3Denum pname, WGC3Dfloat* value) { ADD_FAILURE(); } + virtual void getTexParameteriv(WGC3Denum target, WGC3Denum pname, WGC3Dint* value) { ADD_FAILURE(); } + virtual void getUniformfv(WebGLId program, WGC3Dint location, WGC3Dfloat* value) { ADD_FAILURE(); } + virtual void getUniformiv(WebGLId program, WGC3Dint location, WGC3Dint* value) { ADD_FAILURE(); } + virtual WGC3Dint getUniformLocation(WebGLId program, const WGC3Dchar* name) { ADD_FAILURE(); return 0; } + virtual void getVertexAttribfv(WGC3Duint index, WGC3Denum pname, WGC3Dfloat* value) { ADD_FAILURE(); } + virtual void getVertexAttribiv(WGC3Duint index, WGC3Denum pname, WGC3Dint* value) { ADD_FAILURE(); } + virtual WGC3Dsizeiptr getVertexAttribOffset(WGC3Duint index, WGC3Denum pname) { ADD_FAILURE(); return 0; } +}; + +// This test isn't using the same fixture as CCRendererGLTest, and you can't mix TEST() and TEST_F() with the same name, hence LRC2. +TEST(CCRendererGLTest2, initializationDoesNotMakeSynchronousCalls) +{ + CCScopedSettings scopedSettings; + FakeCCRendererClient mockClient; + OwnPtr<CCGraphicsContext> context(FakeWebCompositorOutputSurface::create(adoptPtr(new ForbidSynchronousCallContext))); + OwnPtr<CCResourceProvider> resourceProvider(CCResourceProvider::create(context.get())); + FakeCCRendererGL renderer(&mockClient, resourceProvider.get()); + + EXPECT_TRUE(renderer.initialize()); +} + +class LoseContextOnFirstGetContext : public FakeWebGraphicsContext3D { +public: + LoseContextOnFirstGetContext() + : m_contextLost(false) + { + } + + virtual bool makeContextCurrent() OVERRIDE + { + return !m_contextLost; + } + + virtual void getProgramiv(WebGLId program, WGC3Denum pname, WGC3Dint* value) OVERRIDE + { + m_contextLost = true; + *value = 0; + } + + virtual void getShaderiv(WebGLId shader, WGC3Denum pname, WGC3Dint* value) OVERRIDE + { + m_contextLost = true; + *value = 0; + } + + virtual WGC3Denum getGraphicsResetStatusARB() OVERRIDE + { + return m_contextLost ? 1 : 0; + } + +private: + bool m_contextLost; +}; + +TEST(CCRendererGLTest2, initializationWithQuicklyLostContextDoesNotAssert) +{ + CCScopedSettings scopedSettings; + FakeCCRendererClient mockClient; + OwnPtr<CCGraphicsContext> context(FakeWebCompositorOutputSurface::create(adoptPtr(new LoseContextOnFirstGetContext))); + OwnPtr<CCResourceProvider> resourceProvider(CCResourceProvider::create(context.get())); + FakeCCRendererGL renderer(&mockClient, resourceProvider.get()); + + renderer.initialize(); +} + +class ContextThatDoesNotSupportMemoryManagmentExtensions : public FakeWebGraphicsContext3D { +public: + ContextThatDoesNotSupportMemoryManagmentExtensions() { } + + // WebGraphicsContext3D methods. + + // This method would normally do a glSwapBuffers under the hood. + virtual void prepareTexture() { } + virtual void setMemoryAllocationChangedCallbackCHROMIUM(WebGraphicsMemoryAllocationChangedCallbackCHROMIUM* callback) { } + virtual WebString getString(WebKit::WGC3Denum name) { return WebString(); } +}; + +TEST(CCRendererGLTest2, initializationWithoutGpuMemoryManagerExtensionSupportShouldDefaultToNonZeroAllocation) +{ + FakeCCRendererClient mockClient; + OwnPtr<CCGraphicsContext> context(FakeWebCompositorOutputSurface::create(adoptPtr(new ContextThatDoesNotSupportMemoryManagmentExtensions))); + OwnPtr<CCResourceProvider> resourceProvider(CCResourceProvider::create(context.get())); + FakeCCRendererGL renderer(&mockClient, resourceProvider.get()); + + renderer.initialize(); + + EXPECT_GT(mockClient.memoryAllocationLimitBytes(), 0ul); +} + +class ClearCountingContext : public FakeWebGraphicsContext3D { +public: + ClearCountingContext() : m_clear(0) { } + + virtual void clear(WGC3Dbitfield) + { + m_clear++; + } + + int clearCount() const { return m_clear; } + +private: + int m_clear; +}; + +TEST(CCRendererGLTest2, opaqueBackground) +{ + FakeCCRendererClient mockClient; + OwnPtr<CCGraphicsContext> ccContext(FakeWebCompositorOutputSurface::create(adoptPtr(new ClearCountingContext))); + ClearCountingContext* context = static_cast<ClearCountingContext*>(ccContext->context3D()); + OwnPtr<CCResourceProvider> resourceProvider(CCResourceProvider::create(ccContext.get())); + FakeCCRendererGL renderer(&mockClient, resourceProvider.get()); + + mockClient.rootRenderPass()->setHasTransparentBackground(false); + + EXPECT_TRUE(renderer.initialize()); + + renderer.drawFrame(mockClient.renderPassesInDrawOrder(), mockClient.renderPasses()); + + // On DEBUG builds, render passes with opaque background clear to blue to + // easily see regions that were not drawn on the screen. +#if defined(NDEBUG) + EXPECT_EQ(0, context->clearCount()); +#else + EXPECT_EQ(1, context->clearCount()); +#endif +} + +TEST(CCRendererGLTest2, transparentBackground) +{ + FakeCCRendererClient mockClient; + OwnPtr<CCGraphicsContext> ccContext(FakeWebCompositorOutputSurface::create(adoptPtr(new ClearCountingContext))); + ClearCountingContext* context = static_cast<ClearCountingContext*>(ccContext->context3D()); + OwnPtr<CCResourceProvider> resourceProvider(CCResourceProvider::create(ccContext.get())); + FakeCCRendererGL renderer(&mockClient, resourceProvider.get()); + + mockClient.rootRenderPass()->setHasTransparentBackground(true); + + EXPECT_TRUE(renderer.initialize()); + + renderer.drawFrame(mockClient.renderPassesInDrawOrder(), mockClient.renderPasses()); + + EXPECT_EQ(1, context->clearCount()); +} |