diff options
author | alexst@chromium.org <alexst@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-01-08 15:28:46 +0000 |
---|---|---|
committer | alexst@chromium.org <alexst@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-01-08 15:28:46 +0000 |
commit | de44a15528ee0c0e85ef1f822f072ee99de64c0c (patch) | |
tree | 0f1a725fa28776d259948bdc604d027d94bdf704 | |
parent | 754ea8b7d01365edefd3a06a293879739011679e (diff) | |
download | chromium_src-de44a15528ee0c0e85ef1f822f072ee99de64c0c.zip chromium_src-de44a15528ee0c0e85ef1f822f072ee99de64c0c.tar.gz chromium_src-de44a15528ee0c0e85ef1f822f072ee99de64c0c.tar.bz2 |
Mailbox support for texture layers.
A callback object is passed along with the mailbox name to the layer. This callback is triggered with a sync point to signal when the mailbox is no longer in use by the compositor.
TextureLayerImpl packages a mailbox up as a resource on willDraw
and releases it when a new mailbox is ready for consumption or when the layer is destroyed.
BUG=123444
Review URL: https://chromiumcodereview.appspot.com/11638028
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@175529 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r-- | cc/resource_provider.cc | 39 | ||||
-rw-r--r-- | cc/resource_provider.h | 12 | ||||
-rw-r--r-- | cc/texture_layer.cc | 51 | ||||
-rw-r--r-- | cc/texture_layer.h | 16 | ||||
-rw-r--r-- | cc/texture_layer_impl.cc | 49 | ||||
-rw-r--r-- | cc/texture_layer_impl.h | 16 | ||||
-rw-r--r-- | cc/texture_layer_unittest.cc | 217 |
7 files changed, 382 insertions, 18 deletions
diff --git a/cc/resource_provider.cc b/cc/resource_provider.cc index 2cbafae..2155224 100644 --- a/cc/resource_provider.cc +++ b/cc/resource_provider.cc @@ -66,6 +66,10 @@ ResourceProvider::Resource::Resource() { } +ResourceProvider::Resource::~Resource() +{ +} + ResourceProvider::Resource::Resource(unsigned textureId, const gfx::Size& size, GLenum format, GLenum filter) : glId(textureId) , glPixelBufferId(0) @@ -234,6 +238,28 @@ ResourceProvider::ResourceId ResourceProvider::createResourceFromExternalTexture return id; } +ResourceProvider::ResourceId ResourceProvider::createResourceFromTextureMailbox(const std::string& mailbox, const base::Callback<void(unsigned)>& releaseCallback) +{ + DCHECK(m_threadChecker.CalledOnValidThread()); + + // FIXME: As an optimization, delay consuming the mailbox + // and creating the texture ID until lockForRead. + const int8* name = reinterpret_cast<const int8*>(mailbox.data()); + WebGraphicsContext3D* context3d = m_outputSurface->Context3D(); + DCHECK(context3d); + unsigned textureId = context3d->createTexture(); + GLC(context3d, context3d->bindTexture(GL_TEXTURE_2D, textureId)); + GLC(context3d, context3d->consumeTextureCHROMIUM(GL_TEXTURE_2D, name)); + + ResourceId id = m_nextId++; + Resource resource(textureId, gfx::Size(), 0, GL_LINEAR); + resource.external = true; + resource.mailbox.setName(name); + resource.mailboxReleaseCallback = releaseCallback; + m_resources[id] = resource; + return id; +} + void ResourceProvider::deleteResource(ResourceId id) { DCHECK(m_threadChecker.CalledOnValidThread()); @@ -269,6 +295,17 @@ void ResourceProvider::deleteResourceInternal(ResourceMap::iterator it) DCHECK(context3d); GLC(context3d, context3d->deleteBuffer(resource->glPixelBufferId)); } + if (!resource->mailbox.isZero() && resource->external) { + WebGraphicsContext3D* context3d = m_outputSurface->Context3D(); + DCHECK(context3d); + GLC(context3d, context3d->bindTexture(GL_TEXTURE_2D, resource->glId)); + GLC(context3d, context3d->produceTextureCHROMIUM(GL_TEXTURE_2D, resource->mailbox.name)); + GLC(context3d, context3d->deleteTexture(resource->glId)); + if (!resource->mailboxReleaseCallback.is_null()) { + unsigned syncPoint = context3d->insertSyncPoint(); + resource->mailboxReleaseCallback.Run(syncPoint); + } + } if (resource->pixels) delete[] resource->pixels; if (resource->pixelBuffer) @@ -684,7 +721,7 @@ bool ResourceProvider::transferResource(WebGraphicsContext3D* context, ResourceI Resource* source = &it->second; DCHECK(!source->lockedForWrite); DCHECK(!source->lockForReadCount); - DCHECK(!source->external); + DCHECK(!source->external || (source->external && !source->mailbox.isZero())); if (source->exported) return false; resource->id = id; diff --git a/cc/resource_provider.h b/cc/resource_provider.h index d90d224..af271eb 100644 --- a/cc/resource_provider.h +++ b/cc/resource_provider.h @@ -5,7 +5,12 @@ #ifndef CC_RESOURCE_PROVIDER_H_ #define CC_RESOURCE_PROVIDER_H_ +#include <deque> +#include <string> +#include <vector> + #include "base/basictypes.h" +#include "base/callback.h" #include "base/hash_tables.h" #include "base/memory/scoped_ptr.h" #include "base/threading/thread_checker.h" @@ -17,8 +22,6 @@ #include "third_party/skia/include/core/SkBitmap.h" #include "third_party/skia/include/core/SkCanvas.h" #include "ui/gfx/size.h" -#include <deque> -#include <vector> namespace WebKit { class WebGraphicsContext3D; @@ -82,6 +85,9 @@ public: // Wraps an external texture into a GL resource. ResourceId createResourceFromExternalTexture(unsigned textureId); + // Wraps an external texture mailbox into a GL resource. + ResourceId createResourceFromTextureMailbox(const std::string& mailboxName, const base::Callback<void(unsigned)>& releaseCallback); + void deleteResource(ResourceId); // Update pixels from image, copying sourceRect (in image) into destRect (in the resource). @@ -233,6 +239,7 @@ public: private: struct Resource { Resource(); + ~Resource(); Resource(unsigned textureId, const gfx::Size& size, GLenum format, GLenum filter); Resource(uint8_t* pixels, const gfx::Size& size, GLenum format, GLenum filter); @@ -242,6 +249,7 @@ private: // Query used to determine when asynchronous set pixels complete. unsigned glUploadQueryId; Mailbox mailbox; + base::Callback<void(unsigned)> mailboxReleaseCallback; uint8_t* pixels; uint8_t* pixelBuffer; int lockForReadCount; diff --git a/cc/texture_layer.cc b/cc/texture_layer.cc index 36c4220..ddfa097 100644 --- a/cc/texture_layer.cc +++ b/cc/texture_layer.cc @@ -7,19 +7,35 @@ #include "cc/layer_tree_host.h" #include "cc/texture_layer_client.h" #include "cc/texture_layer_impl.h" +#include "cc/thread.h" #include "third_party/WebKit/Source/Platform/chromium/public/WebGraphicsContext3D.h" -#include "third_party/khronos/GLES2/gl2.h" namespace cc { +static void runCallbackOnMainThread(const TextureLayer::MailboxCallback& callback, unsigned syncPoint) +{ + callback.Run(syncPoint); +} + +static void postCallbackToMainThread(Thread *mainThread, const TextureLayer::MailboxCallback& callback, unsigned syncPoint) +{ + mainThread->postTask(base::Bind(&runCallbackOnMainThread, callback, syncPoint)); +} + scoped_refptr<TextureLayer> TextureLayer::create(TextureLayerClient* client) { - return scoped_refptr<TextureLayer>(new TextureLayer(client)); + return scoped_refptr<TextureLayer>(new TextureLayer(client, false)); +} + +scoped_refptr<TextureLayer> TextureLayer::createForMailbox() +{ + return scoped_refptr<TextureLayer>(new TextureLayer(0, true)); } -TextureLayer::TextureLayer(TextureLayerClient* client) +TextureLayer::TextureLayer(TextureLayerClient* client, bool usesMailbox) : Layer() , m_client(client) + , m_usesMailbox(usesMailbox) , m_flipped(true) , m_uvRect(0, 0, 1, 1) , m_premultipliedAlpha(true) @@ -42,11 +58,13 @@ TextureLayer::~TextureLayer() if (m_rateLimitContext && m_client) layerTreeHost()->stopRateLimiter(m_client->context()); } + if (!m_contentCommitted && !m_mailboxName.empty()) + m_mailboxReleaseCallback.Run(0); } scoped_ptr<LayerImpl> TextureLayer::createLayerImpl(LayerTreeImpl* treeImpl) { - return TextureLayerImpl::create(treeImpl, m_layerId).PassAs<LayerImpl>(); + return TextureLayerImpl::create(treeImpl, m_layerId, m_usesMailbox).PassAs<LayerImpl>(); } void TextureLayer::setFlipped(bool flipped) @@ -92,6 +110,7 @@ void TextureLayer::setRateLimitContext(bool rateLimit) void TextureLayer::setTextureId(unsigned id) { + DCHECK(!m_usesMailbox); if (m_textureId == id) return; if (m_textureId && layerTreeHost()) @@ -100,6 +119,21 @@ void TextureLayer::setTextureId(unsigned id) setNeedsCommit(); } +void TextureLayer::setTextureMailbox(const std::string& mailboxName, const MailboxCallback& callback) +{ + DCHECK(m_usesMailbox); + DCHECK(mailboxName.empty() == callback.is_null()); + if (m_mailboxName.compare(mailboxName) == 0) + return; + // If we never commited the mailbox, we need to release it here + if (!m_contentCommitted && !m_mailboxName.empty()) + m_mailboxReleaseCallback.Run(0); + m_mailboxReleaseCallback = callback; + m_mailboxName = mailboxName; + + setNeedsCommit(); +} + void TextureLayer::willModifyTexture() { if (layerTreeHost() && (drawsContent() || m_contentCommitted)) { @@ -125,7 +159,7 @@ void TextureLayer::setLayerTreeHost(LayerTreeHost* host) bool TextureLayer::drawsContent() const { - return (m_client || m_textureId) && !m_contextLost && Layer::drawsContent(); + return (m_client || m_textureId || !m_mailboxName.empty()) && !m_contextLost && Layer::drawsContent(); } void TextureLayer::update(ResourceUpdateQueue& queue, const OcclusionTracker*, RenderingStats&) @@ -147,7 +181,12 @@ void TextureLayer::pushPropertiesTo(LayerImpl* layer) textureLayer->setUVRect(m_uvRect); textureLayer->setVertexOpacity(m_vertexOpacity); textureLayer->setPremultipliedAlpha(m_premultipliedAlpha); - textureLayer->setTextureId(m_textureId); + if (m_usesMailbox) { + Thread* mainThread = layerTreeHost()->proxy()->mainThread(); + textureLayer->setTextureMailbox(m_mailboxName, base::Bind(&postCallbackToMainThread, mainThread, m_mailboxReleaseCallback)); + } else { + textureLayer->setTextureId(m_textureId); + } m_contentCommitted = drawsContent(); } diff --git a/cc/texture_layer.h b/cc/texture_layer.h index 2e7921e..4fea928 100644 --- a/cc/texture_layer.h +++ b/cc/texture_layer.h @@ -5,6 +5,9 @@ #ifndef CC_TEXTURE_LAYER_H_ #define CC_TEXTURE_LAYER_H_ +#include <string> + +#include "base/callback.h" #include "cc/cc_export.h" #include "cc/layer.h" @@ -19,11 +22,16 @@ class TextureLayerClient; // A Layer containing a the rendered output of a plugin instance. class CC_EXPORT TextureLayer : public Layer { public: + typedef base::Callback<void(unsigned)> MailboxCallback; + // If this texture layer requires special preparation logic for each frame driven by // the compositor, pass in a non-nil client. Pass in a nil client pointer if texture updates // are driven by an external process. static scoped_refptr<TextureLayer> create(TextureLayerClient*); + // Used when mailbox names are specified instead of texture IDs. + static scoped_refptr<TextureLayer> createForMailbox(); + void clearClient() { m_client = 0; } virtual scoped_ptr<LayerImpl> createLayerImpl(LayerTreeImpl* treeImpl) OVERRIDE; @@ -48,6 +56,9 @@ public: // Code path for plugins which supply their own texture ID. void setTextureId(unsigned); + // Code path for plugins which supply their own texture ID. + void setTextureMailbox(const std::string&, const MailboxCallback&); + void willModifyTexture(); virtual void setNeedsDisplayRect(const gfx::RectF&) OVERRIDE; @@ -59,11 +70,13 @@ public: virtual bool blocksPendingCommit() const OVERRIDE; protected: - explicit TextureLayer(TextureLayerClient*); + TextureLayer(TextureLayerClient*, bool usesMailbox); virtual ~TextureLayer(); private: TextureLayerClient* m_client; + bool m_usesMailbox; + MailboxCallback m_mailboxReleaseCallback; bool m_flipped; gfx::RectF m_uvRect; @@ -75,6 +88,7 @@ private: bool m_contentCommitted; unsigned m_textureId; + std::string m_mailboxName; }; } diff --git a/cc/texture_layer_impl.cc b/cc/texture_layer_impl.cc index 433ce34..1d54616 100644 --- a/cc/texture_layer_impl.cc +++ b/cc/texture_layer_impl.cc @@ -5,19 +5,22 @@ #include "cc/texture_layer_impl.h" #include "base/stringprintf.h" +#include "cc/layer_tree_impl.h" #include "cc/quad_sink.h" #include "cc/renderer.h" #include "cc/texture_draw_quad.h" namespace cc { -TextureLayerImpl::TextureLayerImpl(LayerTreeImpl* treeImpl, int id) +TextureLayerImpl::TextureLayerImpl(LayerTreeImpl* treeImpl, int id, bool usesMailbox) : LayerImpl(treeImpl, id) , m_textureId(0) , m_externalTextureResource(0) , m_premultipliedAlpha(true) , m_flipped(true) , m_uvRect(0, 0, 1, 1) + , m_hasPendingMailbox(false) + , m_usesMailbox(usesMailbox) { m_vertexOpacity[0] = 1.0f; m_vertexOpacity[1] = 1.0f; @@ -27,14 +30,50 @@ TextureLayerImpl::TextureLayerImpl(LayerTreeImpl* treeImpl, int id) TextureLayerImpl::~TextureLayerImpl() { + if (m_externalTextureResource) { + DCHECK(m_usesMailbox); + ResourceProvider* provider = layerTreeImpl()->resource_provider(); + provider->deleteResource(m_externalTextureResource); + } + if (m_hasPendingMailbox && !m_pendingMailboxName.empty()) + m_pendingMailboxReleaseCallback.Run(0); +} + +void TextureLayerImpl::setTextureMailbox(const std::string& mailboxName, const base::Callback<void(unsigned)>& releaseCallback) +{ + DCHECK(m_usesMailbox); + // Same mailbox name was commited, nothing to do. + if (m_pendingMailboxName.compare(mailboxName) == 0) + return; + // Two commits without a draw, ack the previous mailbox. + if (m_hasPendingMailbox && !m_pendingMailboxReleaseCallback.is_null()) + m_pendingMailboxReleaseCallback.Run(0); + + m_pendingMailboxName = mailboxName; + m_hasPendingMailbox = true; + m_pendingMailboxReleaseCallback = releaseCallback; } void TextureLayerImpl::willDraw(ResourceProvider* resourceProvider) { - if (!m_textureId) + if (!m_usesMailbox) { + if (!m_textureId) + return; + DCHECK(!m_externalTextureResource); + m_externalTextureResource = resourceProvider->createResourceFromExternalTexture(m_textureId); return; - DCHECK(!m_externalTextureResource); - m_externalTextureResource = resourceProvider->createResourceFromExternalTexture(m_textureId); + } + + if (!m_hasPendingMailbox) + return; + + if (m_externalTextureResource) { + resourceProvider->deleteResource(m_externalTextureResource); + m_externalTextureResource = 0; + } + if (!m_pendingMailboxName.empty()) + m_externalTextureResource = resourceProvider->createResourceFromTextureMailbox(m_pendingMailboxName, m_pendingMailboxReleaseCallback); + m_hasPendingMailbox = false; } void TextureLayerImpl::appendQuads(QuadSink& quadSink, AppendQuadsData& appendQuadsData) @@ -59,6 +98,8 @@ void TextureLayerImpl::appendQuads(QuadSink& quadSink, AppendQuadsData& appendQu void TextureLayerImpl::didDraw(ResourceProvider* resourceProvider) { + if (m_usesMailbox) + return; if (!m_externalTextureResource) return; // FIXME: the following assert will not be true when sending resources to a diff --git a/cc/texture_layer_impl.h b/cc/texture_layer_impl.h index 47e9ca5..7e434e44 100644 --- a/cc/texture_layer_impl.h +++ b/cc/texture_layer_impl.h @@ -5,6 +5,9 @@ #ifndef CC_TEXTURE_LAYER_IMPL_H_ #define CC_TEXTURE_LAYER_IMPL_H_ +#include <string> + +#include "base/callback.h" #include "cc/cc_export.h" #include "cc/layer_impl.h" @@ -12,9 +15,9 @@ namespace cc { class CC_EXPORT TextureLayerImpl : public LayerImpl { public: - static scoped_ptr<TextureLayerImpl> create(LayerTreeImpl* treeImpl, int id) + static scoped_ptr<TextureLayerImpl> create(LayerTreeImpl* treeImpl, int id, bool usesMailbox) { - return make_scoped_ptr(new TextureLayerImpl(treeImpl, id)); + return make_scoped_ptr(new TextureLayerImpl(treeImpl, id, usesMailbox)); } virtual ~TextureLayerImpl(); @@ -37,8 +40,10 @@ public: // 0--3 void setVertexOpacity(const float vertexOpacity[4]); + void setTextureMailbox(const std::string& mailboxName, const base::Callback<void(unsigned)>& releaseCallback); + private: - TextureLayerImpl(LayerTreeImpl* treeImpl, int id); + TextureLayerImpl(LayerTreeImpl* treeImpl, int id, bool usesMailbox); virtual const char* layerTypeAsString() const OVERRIDE; @@ -48,6 +53,11 @@ private: bool m_flipped; gfx::RectF m_uvRect; float m_vertexOpacity[4]; + + bool m_hasPendingMailbox; + std::string m_pendingMailboxName; + base::Callback<void(unsigned)> m_pendingMailboxReleaseCallback; + bool m_usesMailbox; }; } diff --git a/cc/texture_layer_unittest.cc b/cc/texture_layer_unittest.cc index c58ae90..85d90b2 100644 --- a/cc/texture_layer_unittest.cc +++ b/cc/texture_layer_unittest.cc @@ -4,11 +4,16 @@ #include "cc/texture_layer.h" +#include <string> + +#include "base/callback.h" #include "cc/layer_tree_host.h" +#include "cc/layer_tree_impl.h" #include "cc/single_thread_proxy.h" #include "cc/test/fake_impl_proxy.h" #include "cc/test/fake_layer_tree_host_client.h" #include "cc/test/fake_layer_tree_host_impl.h" +#include "cc/test/layer_tree_test_common.h" #include "cc/texture_layer_impl.h" #include "cc/thread.h" #include "testing/gmock/include/gmock/gmock.h" @@ -100,7 +105,7 @@ TEST_F(TextureLayerTest, syncImplWhenDrawing) scoped_refptr<TextureLayer> testLayer = TextureLayer::create(0); ASSERT_TRUE(testLayer); scoped_ptr<TextureLayerImpl> implLayer; - implLayer = TextureLayerImpl::create(m_hostImpl.activeTree(), 1); + implLayer = TextureLayerImpl::create(m_hostImpl.activeTree(), 1, false); ASSERT_TRUE(implLayer); EXPECT_CALL(*m_layerTreeHost, acquireLayerTextures()).Times(AnyNumber()); @@ -184,5 +189,215 @@ TEST_F(TextureLayerTest, syncImplWhenRemovingFromTree) Mock::VerifyAndClearExpectations(m_layerTreeHost.get()); } +class MockMailboxCallback { +public: + MOCK_METHOD2(Release, void(const std::string& mailbox, unsigned syncPoint)); +}; + +struct CommonMailboxObjects { + CommonMailboxObjects() + : m_mailbox1(64, '1') + , m_mailbox2(64, '2') + { + m_releaseMailbox1 = base::Bind(&MockMailboxCallback::Release, + base::Unretained(&m_mockCallback), + m_mailbox1); + m_releaseMailbox2 = base::Bind(&MockMailboxCallback::Release, + base::Unretained(&m_mockCallback), + m_mailbox2); + } + + std::string m_mailbox1; + std::string m_mailbox2; + MockMailboxCallback m_mockCallback; + TextureLayer::MailboxCallback m_releaseMailbox1; + TextureLayer::MailboxCallback m_releaseMailbox2; +}; + +class TextureLayerWithMailboxTest : public TextureLayerTest { +protected: + virtual void TearDown() + { + Mock::VerifyAndClearExpectations(&m_testData.m_mockCallback); + EXPECT_CALL(m_testData.m_mockCallback, + Release(m_testData.m_mailbox1, _)).Times(1); + TextureLayerTest::TearDown(); + } + + CommonMailboxObjects m_testData; +}; + +TEST_F(TextureLayerWithMailboxTest, replaceMailboxOnMainThreadBeforeCommit) +{ + scoped_refptr<TextureLayer> testLayer = TextureLayer::createForMailbox(); + ASSERT_TRUE(testLayer); + + EXPECT_CALL(*m_layerTreeHost, acquireLayerTextures()).Times(0); + EXPECT_CALL(*m_layerTreeHost, setNeedsCommit()).Times(AnyNumber()); + m_layerTreeHost->setRootLayer(testLayer); + Mock::VerifyAndClearExpectations(m_layerTreeHost.get()); + + EXPECT_CALL(*m_layerTreeHost, acquireLayerTextures()).Times(0); + EXPECT_CALL(*m_layerTreeHost, setNeedsCommit()).Times(AtLeast(1)); + testLayer->setTextureMailbox(m_testData.m_mailbox1, + m_testData.m_releaseMailbox1); + Mock::VerifyAndClearExpectations(m_layerTreeHost.get()); + + EXPECT_CALL(*m_layerTreeHost, acquireLayerTextures()).Times(0); + EXPECT_CALL(*m_layerTreeHost, setNeedsCommit()).Times(AtLeast(1)); + EXPECT_CALL(m_testData.m_mockCallback, + Release(m_testData.m_mailbox1, _)).Times(1); + testLayer->setTextureMailbox(m_testData.m_mailbox2, + m_testData.m_releaseMailbox2); + Mock::VerifyAndClearExpectations(m_layerTreeHost.get()); + Mock::VerifyAndClearExpectations(&m_testData.m_mockCallback); + + EXPECT_CALL(*m_layerTreeHost, acquireLayerTextures()).Times(0); + EXPECT_CALL(*m_layerTreeHost, setNeedsCommit()).Times(AtLeast(1)); + EXPECT_CALL(m_testData.m_mockCallback, + Release(m_testData.m_mailbox2, _)).Times(1); + testLayer->setTextureMailbox(std::string(), + TextureLayer::MailboxCallback()); + Mock::VerifyAndClearExpectations(m_layerTreeHost.get()); + Mock::VerifyAndClearExpectations(&m_testData.m_mockCallback); + + // Test destructor. + EXPECT_CALL(*m_layerTreeHost, setNeedsCommit()).Times(AtLeast(1)); + testLayer->setTextureMailbox(m_testData.m_mailbox1, + m_testData.m_releaseMailbox1); +} + +class TextureLayerImplWithMailboxThreadedCallback : public ThreadedTest { +public: + TextureLayerImplWithMailboxThreadedCallback() + : m_resetMailbox(false) + { + } + + // Make sure callback is received on main and doesn't block the impl thread. + void releaseCallback(unsigned syncPoint) { + EXPECT_EQ(true, proxy()->isMainThread()); + endTest(); + } + + virtual void beginTest() OVERRIDE + { + m_layer = TextureLayer::createForMailbox(); + m_layer->setIsDrawable(true); + m_layerTreeHost->setRootLayer(m_layer); + m_layer->setTextureMailbox( + std::string(64, '1'), + base::Bind( + &TextureLayerImplWithMailboxThreadedCallback::releaseCallback, + base::Unretained(this))); + postSetNeedsCommitToMainThread(); + } + + virtual void didCommit() OVERRIDE + { + if (m_resetMailbox) + return; + + m_layer->setTextureMailbox(std::string(), + TextureLayer::MailboxCallback()); + m_resetMailbox = true; + } + + virtual void afterTest() OVERRIDE + { + } + +private: + bool m_resetMailbox; + scoped_refptr<TextureLayer> m_layer; +}; + +SINGLE_AND_MULTI_THREAD_TEST_F(TextureLayerImplWithMailboxThreadedCallback); + +class TextureLayerImplWithMailboxTest : public TextureLayerTest { +protected: + virtual void SetUp() + { + TextureLayerTest::SetUp(); + m_layerTreeHost.reset(new MockLayerImplTreeHost); + EXPECT_TRUE(m_hostImpl.initializeRenderer(createFakeOutputSurface())); + } + + CommonMailboxObjects m_testData; +}; + +TEST_F(TextureLayerImplWithMailboxTest, testImplLayerCallbacks) +{ + scoped_ptr<TextureLayerImpl> implLayer; + implLayer = TextureLayerImpl::create(m_hostImpl.activeTree(), 1, true); + ASSERT_TRUE(implLayer); + + // Test setting identical mailbox. + EXPECT_CALL(m_testData.m_mockCallback, Release(_, _)).Times(0); + implLayer->setTextureMailbox(m_testData.m_mailbox1, + m_testData.m_releaseMailbox1); + implLayer->setTextureMailbox(m_testData.m_mailbox1, + m_testData.m_releaseMailbox1); + Mock::VerifyAndClearExpectations(&m_testData.m_mockCallback); + + // Test multiple commits without a draw. + EXPECT_CALL(m_testData.m_mockCallback, + Release(m_testData.m_mailbox1, _)).Times(1); + implLayer->setTextureMailbox(m_testData.m_mailbox2, + m_testData.m_releaseMailbox2); + Mock::VerifyAndClearExpectations(&m_testData.m_mockCallback); + + // Test resetting the mailbox. + EXPECT_CALL(m_testData.m_mockCallback, + Release(m_testData.m_mailbox2, _)).Times(1); + implLayer->setTextureMailbox(std::string(), + TextureLayer::MailboxCallback()); + Mock::VerifyAndClearExpectations(&m_testData.m_mockCallback); + + // Test destructor. + EXPECT_CALL(m_testData.m_mockCallback, + Release(m_testData.m_mailbox1, _)).Times(1); + implLayer->setTextureMailbox(m_testData.m_mailbox1, + m_testData.m_releaseMailbox1); +} + +TEST_F(TextureLayerImplWithMailboxTest, testDestructorCallbackOnCreatedResource) +{ + scoped_ptr<TextureLayerImpl> implLayer; + implLayer = TextureLayerImpl::create(m_hostImpl.activeTree(), 1, true); + ASSERT_TRUE(implLayer); + + EXPECT_CALL(m_testData.m_mockCallback, + Release(m_testData.m_mailbox1, _)).Times(1); + implLayer->setTextureMailbox(m_testData.m_mailbox1, + m_testData.m_releaseMailbox1); + implLayer->willDraw(m_hostImpl.activeTree()->resource_provider()); + implLayer->didDraw(m_hostImpl.activeTree()->resource_provider()); + implLayer->setTextureMailbox(std::string(), + TextureLayer::MailboxCallback()); +} + +TEST_F(TextureLayerImplWithMailboxTest, testCallbackOnInUseResource) +{ + ResourceProvider *provider = m_hostImpl.activeTree()->resource_provider(); + ResourceProvider::ResourceId id = + provider->createResourceFromTextureMailbox( + m_testData.m_mailbox1, + m_testData.m_releaseMailbox1); + + // Transfer some resources to the parent. + ResourceProvider::ResourceIdArray resourceIdsToTransfer; + resourceIdsToTransfer.push_back(id); + TransferableResourceList list; + provider->prepareSendToParent(resourceIdsToTransfer, &list); + EXPECT_TRUE(provider->inUseByConsumer(id)); + EXPECT_CALL(m_testData.m_mockCallback, Release(_, _)).Times(0); + provider->deleteResource(id); + Mock::VerifyAndClearExpectations(&m_testData.m_mockCallback); + EXPECT_CALL(m_testData.m_mockCallback, + Release(m_testData.m_mailbox1, _)).Times(1); + provider->receiveFromParent(list); +} + } // namespace } // namespace cc |