summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authoralexst@chromium.org <alexst@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-01-08 15:28:46 +0000
committeralexst@chromium.org <alexst@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-01-08 15:28:46 +0000
commitde44a15528ee0c0e85ef1f822f072ee99de64c0c (patch)
tree0f1a725fa28776d259948bdc604d027d94bdf704
parent754ea8b7d01365edefd3a06a293879739011679e (diff)
downloadchromium_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.cc39
-rw-r--r--cc/resource_provider.h12
-rw-r--r--cc/texture_layer.cc51
-rw-r--r--cc/texture_layer.h16
-rw-r--r--cc/texture_layer_impl.cc49
-rw-r--r--cc/texture_layer_impl.h16
-rw-r--r--cc/texture_layer_unittest.cc217
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