Modified: trunk/Source/WebCore/platform/graphics/chromium/cc/CCResourceProvider.cpp (125837 => 125838)
--- trunk/Source/WebCore/platform/graphics/chromium/cc/CCResourceProvider.cpp 2012-08-17 01:06:49 UTC (rev 125837)
+++ trunk/Source/WebCore/platform/graphics/chromium/cc/CCResourceProvider.cpp 2012-08-17 01:16:42 UTC (rev 125838)
@@ -32,6 +32,7 @@
#include "LayerTextureSubImage.h"
#include "cc/CCProxy.h"
#include <public/WebGraphicsContext3D.h>
+#include <wtf/HashSet.h>
using WebKit::WebGraphicsContext3D;
@@ -82,7 +83,7 @@
ASSERT(CCProxy::isImplThread());
ResourceMap::iterator it = m_resources.find(id);
ASSERT(it != m_resources.end());
- return !!it->second.lockForReadCount;
+ return !!it->second.lockForReadCount || it->second.exported;
}
CCResourceProvider::ResourceId CCResourceProvider::createResource(int pool, const IntSize& size, GC3Denum format, TextureUsageHint hint)
@@ -109,7 +110,7 @@
} else
GLC(context3d, context3d->texImage2D(GraphicsContext3D::TEXTURE_2D, 0, format, size.width(), size.height(), 0, format, GraphicsContext3D::UNSIGNED_BYTE, 0));
ResourceId id = m_nextId++;
- Resource resource = {textureId, pool, 0, false, false, size, format};
+ Resource resource(textureId, pool, size, format);
m_resources.add(id, resource);
return id;
}
@@ -118,7 +119,9 @@
{
ASSERT(CCProxy::isImplThread());
ResourceId id = m_nextId++;
- Resource resource = {textureId, 0, 0, false, true, IntSize(), 0};
+ Resource resource;
+ resource.glId = textureId;
+ resource.external = true;
m_resources.add(id, resource);
return id;
}
@@ -141,12 +144,12 @@
void CCResourceProvider::deleteOwnedResources(int pool)
{
ASSERT(CCProxy::isImplThread());
- Vector<ResourceId> toDelete;
+ ResourceIdArray toDelete;
for (ResourceMap::iterator it = m_resources.begin(); it != m_resources.end(); ++it) {
if (it->second.pool == pool && !it->second.external)
toDelete.append(it->first);
}
- for (Vector<ResourceId>::iterator it = toDelete.begin(); it != toDelete.end(); ++it)
+ for (ResourceIdArray::iterator it = toDelete.begin(); it != toDelete.end(); ++it)
deleteResource(*it);
}
@@ -228,6 +231,7 @@
CCResourceProvider::CCResourceProvider(CCGraphicsContext* context)
: m_context(context)
, m_nextId(1)
+ , m_nextChild(1)
, m_useTextureStorageExt(false)
, m_useTextureUsageHint(false)
, m_useShallowFlush(false)
@@ -264,4 +268,177 @@
return true;
}
+int CCResourceProvider::createChild(int pool)
+{
+ ASSERT(CCProxy::isImplThread());
+ Child childInfo;
+ childInfo.pool = pool;
+ int child = m_nextChild++;
+ m_children.add(child, childInfo);
+ return child;
}
+
+void CCResourceProvider::destroyChild(int child)
+{
+ ASSERT(CCProxy::isImplThread());
+ ChildMap::iterator it = m_children.find(child);
+ ASSERT(it != m_children.end());
+ deleteOwnedResources(it->second.pool);
+ m_children.remove(it);
+ trimMailboxDeque();
+}
+
+const CCResourceProvider::ResourceIdMap& CCResourceProvider::getChildToParentMap(int child) const
+{
+ ASSERT(CCProxy::isImplThread());
+ ChildMap::const_iterator it = m_children.find(child);
+ ASSERT(it != m_children.end());
+ return it->second.childToParentMap;
+}
+
+CCResourceProvider::TransferableResourceList CCResourceProvider::prepareSendToParent(const ResourceIdArray& resources)
+{
+ ASSERT(CCProxy::isImplThread());
+ TransferableResourceList list;
+ list.syncPoint = 0;
+ WebGraphicsContext3D* context3d = m_context->context3D();
+ if (!context3d || !context3d->makeContextCurrent()) {
+ // FIXME: Implement this path for software compositing.
+ return list;
+ }
+ for (ResourceIdArray::const_iterator it = resources.begin(); it != resources.end(); ++it) {
+ TransferableResource resource;
+ if (transferResource(context3d, *it, &resource)) {
+ m_resources.find(*it)->second.exported = true;
+ list.resources.append(resource);
+ }
+ }
+ if (list.resources.size())
+ list.syncPoint = context3d->insertSyncPoint();
+ return list;
+}
+
+CCResourceProvider::TransferableResourceList CCResourceProvider::prepareSendToChild(int child, const ResourceIdArray& resources)
+{
+ ASSERT(CCProxy::isImplThread());
+ TransferableResourceList list;
+ list.syncPoint = 0;
+ WebGraphicsContext3D* context3d = m_context->context3D();
+ if (!context3d || !context3d->makeContextCurrent()) {
+ // FIXME: Implement this path for software compositing.
+ return list;
+ }
+ Child& childInfo = m_children.find(child)->second;
+ for (ResourceIdArray::const_iterator it = resources.begin(); it != resources.end(); ++it) {
+ TransferableResource resource;
+ if (!transferResource(context3d, *it, &resource))
+ ASSERT_NOT_REACHED();
+ resource.id = childInfo.parentToChildMap.get(*it);
+ childInfo.parentToChildMap.remove(*it);
+ childInfo.childToParentMap.remove(resource.id);
+ list.resources.append(resource);
+ deleteResource(*it);
+ }
+ if (list.resources.size())
+ list.syncPoint = context3d->insertSyncPoint();
+ return list;
+}
+
+void CCResourceProvider::receiveFromChild(int child, const TransferableResourceList& resources)
+{
+ ASSERT(CCProxy::isImplThread());
+ WebGraphicsContext3D* context3d = m_context->context3D();
+ if (!context3d || !context3d->makeContextCurrent()) {
+ // FIXME: Implement this path for software compositing.
+ return;
+ }
+ if (resources.syncPoint) {
+ // NOTE: If the parent is a browser and the child a renderer, the parent
+ // is not supposed to have its context wait, because that could induce
+ // deadlocks and/or security issues. The caller is responsible for
+ // waiting asynchronously, and resetting syncPoint before calling this.
+ // However if the parent is a renderer (e.g. browser tag), it may be ok
+ // (and is simpler) to wait.
+ GLC(context3d, context3d->waitSyncPoint(resources.syncPoint));
+ }
+ Child& childInfo = m_children.find(child)->second;
+ for (Vector<TransferableResource>::const_iterator it = resources.resources.begin(); it != resources.resources.end(); ++it) {
+ unsigned textureId;
+ GLC(context3d, textureId = context3d->createTexture());
+ GLC(context3d, context3d->bindTexture(GraphicsContext3D::TEXTURE_2D, textureId));
+ GLC(context3d, context3d->consumeTextureCHROMIUM(GraphicsContext3D::TEXTURE_2D, it->mailbox.name));
+ ResourceId id = m_nextId++;
+ Resource resource(textureId, childInfo.pool, it->size, it->format);
+ m_resources.add(id, resource);
+ m_mailboxes.append(it->mailbox);
+ childInfo.parentToChildMap.add(id, it->id);
+ childInfo.childToParentMap.add(it->id, id);
+ }
+}
+
+void CCResourceProvider::receiveFromParent(const TransferableResourceList& resources)
+{
+ ASSERT(CCProxy::isImplThread());
+ WebGraphicsContext3D* context3d = m_context->context3D();
+ if (!context3d || !context3d->makeContextCurrent()) {
+ // FIXME: Implement this path for software compositing.
+ return;
+ }
+ if (resources.syncPoint)
+ GLC(context3d, context3d->waitSyncPoint(resources.syncPoint));
+ for (Vector<TransferableResource>::const_iterator it = resources.resources.begin(); it != resources.resources.end(); ++it) {
+ Resource& resource = m_resources.find(it->id)->second;
+ ASSERT(resource.exported);
+ resource.exported = false;
+ GLC(context3d, context3d->bindTexture(GraphicsContext3D::TEXTURE_2D, resource.glId));
+ GLC(context3d, context3d->consumeTextureCHROMIUM(GraphicsContext3D::TEXTURE_2D, it->mailbox.name));
+ m_mailboxes.append(it->mailbox);
+ }
+}
+
+bool CCResourceProvider::transferResource(WebGraphicsContext3D* context, ResourceId id, TransferableResource* resource)
+{
+ ASSERT(CCProxy::isImplThread());
+ ResourceMap::const_iterator it = m_resources.find(id);
+ ASSERT(it != m_resources.end() && !it->second.lockedForWrite && !it->second.lockForReadCount && !it->second.external);
+ if (it->second.exported)
+ return false;
+ resource->id = id;
+ resource->format = it->second.format;
+ resource->size = it->second.size;
+ if (!m_mailboxes.isEmpty())
+ resource->mailbox = m_mailboxes.takeFirst();
+ else
+ GLC(context, context->genMailboxCHROMIUM(resource->mailbox.name));
+ GLC(context, context->bindTexture(GraphicsContext3D::TEXTURE_2D, it->second.glId));
+ GLC(context, context->produceTextureCHROMIUM(GraphicsContext3D::TEXTURE_2D, resource->mailbox.name));
+ return true;
+}
+
+void CCResourceProvider::trimMailboxDeque()
+{
+ // Trim the mailbox deque to the maximum number of resources we may need to
+ // send.
+ // If we have a parent, any non-external resource not already transfered is
+ // eligible to be sent to the parent. Otherwise, all resources belonging to
+ // a child might need to be sent back to the child.
+ size_t maxMailboxCount = 0;
+ if (m_context->capabilities().hasParentCompositor) {
+ for (ResourceMap::iterator it = m_resources.begin(); it != m_resources.end(); ++it) {
+ if (!it->second.exported && !it->second.external)
+ ++maxMailboxCount;
+ }
+ } else {
+ HashSet<int> childPoolSet;
+ for (ChildMap::iterator it = m_children.begin(); it != m_children.end(); ++it)
+ childPoolSet.add(it->second.pool);
+ for (ResourceMap::iterator it = m_resources.begin(); it != m_resources.end(); ++it) {
+ if (childPoolSet.contains(it->second.pool))
+ ++maxMailboxCount;
+ }
+ }
+ while (m_mailboxes.size() > maxMailboxCount)
+ m_mailboxes.removeFirst();
+}
+
+}
Modified: trunk/Source/WebCore/platform/graphics/chromium/cc/CCResourceProvider.h (125837 => 125838)
--- trunk/Source/WebCore/platform/graphics/chromium/cc/CCResourceProvider.h 2012-08-17 01:06:49 UTC (rev 125837)
+++ trunk/Source/WebCore/platform/graphics/chromium/cc/CCResourceProvider.h 2012-08-17 01:16:42 UTC (rev 125838)
@@ -30,11 +30,13 @@
#include "GraphicsContext3D.h"
#include "IntSize.h"
#include "cc/CCGraphicsContext.h"
+#include <wtf/Deque.h>
#include <wtf/HashMap.h>
#include <wtf/OwnPtr.h>
#include <wtf/PassOwnPtr.h>
#include <wtf/PassRefPtr.h>
#include <wtf/RefPtr.h>
+#include <wtf/Vector.h>
namespace WebKit {
class WebGraphicsContext3D;
@@ -53,7 +55,23 @@
WTF_MAKE_NONCOPYABLE(CCResourceProvider);
public:
typedef unsigned ResourceId;
+ typedef Vector<ResourceId> ResourceIdArray;
+ typedef HashMap<ResourceId, ResourceId> ResourceIdMap;
enum TextureUsageHint { TextureUsageAny, TextureUsageFramebuffer };
+ struct Mailbox {
+ GC3Dbyte name[64];
+ };
+ struct TransferableResource {
+ unsigned id;
+ GC3Denum format;
+ IntSize size;
+ Mailbox mailbox;
+ };
+ typedef Vector<TransferableResource> TransferableResourceArray;
+ struct TransferableResourceList {
+ TransferableResourceArray resources;
+ unsigned syncPoint;
+ };
static PassOwnPtr<CCResourceProvider> create(CCGraphicsContext*);
@@ -90,20 +108,86 @@
// Returns true if the shallow flush occurred, false otherwise.
bool shallowFlushIfSupported();
+ // Creates accounting for a child, and associate it with a pool. Resources
+ // transfered from that child will go to that pool. Returns a child ID.
+ int createChild(int pool);
+
+ // Destroys accounting for the child, deleting all resources from that pool.
+ void destroyChild(int child);
+
+ // Gets the child->parent resource ID map.
+ const ResourceIdMap& getChildToParentMap(int child) const;
+
+ // Prepares resources to be transfered to the parent, moving them to
+ // mailboxes and serializing meta-data into TransferableResources.
+ // Resources are not removed from the CCResourceProvider, but are markes as
+ // "in use".
+ TransferableResourceList prepareSendToParent(const ResourceIdArray&);
+
+ // Prepares resources to be transfered back to the child, moving them to
+ // mailboxes and serializing meta-data into TransferableResources.
+ // Resources are removed from the CCResourceProvider. Note: the resource IDs
+ // passed are in the parent namespace and will be translated to the child
+ // namespace when returned.
+ TransferableResourceList prepareSendToChild(int child, const ResourceIdArray&);
+
+ // Receives resources from a child, moving them from mailboxes. Resource IDs
+ // passed are in the child namespace, and will be translated to the parent
+ // namespace, added to the child->parent map.
+ // NOTE: if the syncPoint filed in TransferableResourceList is set, this
+ // will wait on it.
+ void receiveFromChild(int child, const TransferableResourceList&);
+
+ // Receives resources from the parent, moving them from mailboxes. Resource IDs
+ // passed are in the child namespace.
+ // NOTE: if the syncPoint filed in TransferableResourceList is set, this
+ // will wait on it.
+ void receiveFromParent(const TransferableResourceList&);
+
+ // Only for testing
+ size_t mailboxCount() const { return m_mailboxes.size(); }
+
private:
friend class CCScopedLockResourceForRead;
friend class CCScopedLockResourceForWrite;
struct Resource {
+ Resource()
+ : glId(0)
+ , pool(0)
+ , lockForReadCount(0)
+ , lockedForWrite(false)
+ , external(false)
+ , exported(false)
+ , size()
+ , format(0)
+ { }
+ Resource(unsigned textureId, int pool, const IntSize& size, GC3Denum format)
+ : glId(textureId)
+ , pool(pool)
+ , lockForReadCount(0)
+ , lockedForWrite(false)
+ , external(false)
+ , exported(false)
+ , size(size)
+ , format(format)
+ { }
unsigned glId;
int pool;
int lockForReadCount;
bool lockedForWrite;
bool external;
+ bool exported;
IntSize size;
GC3Denum format;
};
typedef HashMap<ResourceId, Resource> ResourceMap;
+ struct Child {
+ int pool;
+ ResourceIdMap childToParentMap;
+ ResourceIdMap parentToChildMap;
+ };
+ typedef HashMap<int, Child> ChildMap;
explicit CCResourceProvider(CCGraphicsContext*);
bool initialize();
@@ -116,10 +200,17 @@
unsigned lockForRead(ResourceId);
void unlockForRead(ResourceId);
+ bool transferResource(WebKit::WebGraphicsContext3D*, ResourceId, TransferableResource*);
+ void trimMailboxDeque();
+
CCGraphicsContext* m_context;
ResourceId m_nextId;
ResourceMap m_resources;
+ int m_nextChild;
+ ChildMap m_children;
+ Deque<Mailbox> m_mailboxes;
+
bool m_useTextureStorageExt;
bool m_useTextureUsageHint;
bool m_useShallowFlush;
Modified: trunk/Source/WebKit/chromium/tests/CCResourceProviderTest.cpp (125837 => 125838)
--- trunk/Source/WebKit/chromium/tests/CCResourceProviderTest.cpp 2012-08-17 01:06:49 UTC (rev 125837)
+++ trunk/Source/WebKit/chromium/tests/CCResourceProviderTest.cpp 2012-08-17 01:16:42 UTC (rev 125838)
@@ -42,10 +42,99 @@
namespace {
+size_t textureSize(const IntSize& size, WGC3Denum format)
+{
+ unsigned int componentsPerPixel = 4;
+ unsigned int bytesPerComponent = 1;
+ GraphicsContext3D::computeFormatAndTypeParameters(format, GraphicsContext3D::UNSIGNED_BYTE, &componentsPerPixel, &bytesPerComponent);
+ return size.width() * size.height() * componentsPerPixel * bytesPerComponent;
+}
+
+struct Texture {
+ Texture(const IntSize& size, WGC3Denum format)
+ : size(size)
+ , format(format)
+ , data(adoptArrayPtr(new uint8_t[textureSize(size, format)]))
+ {
+ }
+
+ IntSize size;
+ WGC3Denum format;
+ OwnArrayPtr<uint8_t> data;
+};
+
+// Shared data between multiple ResourceProviderContext. This contains mailbox
+// contents as well as information about sync points.
+class ContextSharedData {
+public:
+ static PassOwnPtr<ContextSharedData> create() { return adoptPtr(new ContextSharedData()); }
+
+ unsigned insertSyncPoint() { return m_nextSyncPoint++; }
+
+ void genMailbox(WGC3Dbyte* mailbox)
+ {
+ memset(mailbox, 0, sizeof(WGC3Dbyte[64]));
+ memcpy(mailbox, &m_nextMailBox, sizeof(m_nextMailBox));
+ ++m_nextMailBox;
+ }
+
+ void produceTexture(const WGC3Dbyte* mailboxName, unsigned syncPoint, PassOwnPtr<Texture> texture)
+ {
+ unsigned mailbox = 0;
+ memcpy(&mailbox, mailboxName, sizeof(mailbox));
+ ASSERT(mailbox && mailbox < m_nextMailBox);
+ m_textures.set(mailbox, texture);
+ ASSERT(m_syncPointForMailbox.get(mailbox) < syncPoint);
+ m_syncPointForMailbox.set(mailbox, syncPoint);
+ }
+
+ PassOwnPtr<Texture> consumeTexture(const WGC3Dbyte* mailboxName, unsigned syncPoint)
+ {
+ unsigned mailbox = 0;
+ memcpy(&mailbox, mailboxName, sizeof(mailbox));
+ ASSERT(mailbox && mailbox < m_nextMailBox);
+
+ // If the latest sync point the context has waited on is before the sync
+ // point for when the mailbox was set, pretend we never saw that
+ // produceTexture.
+ if (m_syncPointForMailbox.get(mailbox) < syncPoint)
+ return nullptr;
+ return m_textures.take(mailbox);
+ }
+
+private:
+ ContextSharedData()
+ : m_nextSyncPoint(1)
+ , m_nextMailBox(1)
+ { }
+
+ unsigned m_nextSyncPoint;
+ unsigned m_nextMailBox;
+ typedef HashMap<unsigned, OwnPtr<Texture> > TextureMap;
+ TextureMap m_textures;
+ HashMap<unsigned, unsigned> m_syncPointForMailbox;
+};
+
class ResourceProviderContext : public CompositorFakeWebGraphicsContext3D {
public:
- static PassOwnPtr<ResourceProviderContext> create() { return adoptPtr(new ResourceProviderContext(Attributes())); }
+ static PassOwnPtr<ResourceProviderContext> create(ContextSharedData* sharedData) { return adoptPtr(new ResourceProviderContext(Attributes(), sharedData)); }
+ virtual unsigned insertSyncPoint()
+ {
+ unsigned syncPoint = m_sharedData->insertSyncPoint();
+ // Commit the produceTextureCHROMIUM calls at this point, so that
+ // they're associated with the sync point.
+ for (PendingProduceTextureList::iterator it = m_pendingProduceTextures.begin(); it != m_pendingProduceTextures.end(); ++it)
+ m_sharedData->produceTexture((*it)->mailbox, syncPoint, (*it)->texture.release());
+ m_pendingProduceTextures.clear();
+ return syncPoint;
+ }
+
+ virtual void waitSyncPoint(unsigned syncPoint)
+ {
+ m_lastWaitedSyncPoint = std::max(syncPoint, m_lastWaitedSyncPoint);
+ }
+
virtual void bindTexture(WGC3Denum target, WebGLId texture)
{
ASSERT(target == GraphicsContext3D::TEXTURE_2D);
@@ -113,6 +202,29 @@
setPixels(xoffset, yoffset, width, height, pixels);
}
+ virtual void genMailboxCHROMIUM(WGC3Dbyte* mailbox) { return m_sharedData->genMailbox(mailbox); }
+ virtual void produceTextureCHROMIUM(WGC3Denum target, const WGC3Dbyte* mailbox)
+ {
+ ASSERT(m_currentTexture);
+ ASSERT(target == GraphicsContext3D::TEXTURE_2D);
+
+ // Delay movind the texture into the mailbox until the next
+ // insertSyncPoint, so that it is not visible to other contexts that
+ // haven't waited on that sync point.
+ OwnPtr<PendingProduceTexture> pending = adoptPtr(new PendingProduceTexture);
+ memcpy(pending->mailbox, mailbox, sizeof(pending->mailbox));
+ pending->texture = m_textures.take(m_currentTexture);
+ m_textures.set(m_currentTexture, nullptr);
+ m_pendingProduceTextures.append(pending.release());
+ }
+
+ virtual void consumeTextureCHROMIUM(WGC3Denum target, const WGC3Dbyte* mailbox)
+ {
+ ASSERT(m_currentTexture);
+ ASSERT(target == GraphicsContext3D::TEXTURE_2D);
+ m_textures.set(m_currentTexture, m_sharedData->consumeTexture(mailbox, m_lastWaitedSyncPoint));
+ }
+
void getPixels(const IntSize& size, WGC3Denum format, uint8_t* pixels)
{
ASSERT(m_currentTexture);
@@ -128,34 +240,15 @@
return m_textures.size();
}
- static size_t textureSize(const IntSize& size, WGC3Denum format)
- {
- unsigned int componentsPerPixel = 4;
- unsigned int bytesPerComponent = 1;
- GraphicsContext3D::computeFormatAndTypeParameters(format, GraphicsContext3D::UNSIGNED_BYTE, &componentsPerPixel, &bytesPerComponent);
- return size.width() * size.height() * componentsPerPixel * bytesPerComponent;
- }
-
protected:
- explicit ResourceProviderContext(const Attributes& attrs)
+ ResourceProviderContext(const Attributes& attrs, ContextSharedData* sharedData)
: CompositorFakeWebGraphicsContext3D(attrs)
+ , m_sharedData(sharedData)
, m_currentTexture(0)
+ , m_lastWaitedSyncPoint(0)
{ }
private:
- struct Texture {
- Texture(const IntSize& size_, WGC3Denum format_)
- : size(size_)
- , format(format_)
- , data(adoptArrayPtr(new uint8_t[textureSize(size, format)]))
- {
- }
-
- IntSize size;
- WGC3Denum format;
- OwnArrayPtr<uint8_t> data;
- };
-
void allocateTexture(const IntSize& size, WGC3Denum format)
{
ASSERT(m_currentTexture);
@@ -182,14 +275,23 @@
}
typedef HashMap<WebGLId, OwnPtr<Texture> > TextureMap;
+ struct PendingProduceTexture {
+ WGC3Dbyte mailbox[64];
+ OwnPtr<Texture> texture;
+ };
+ typedef Deque<OwnPtr<PendingProduceTexture> > PendingProduceTextureList;
+ ContextSharedData* m_sharedData;
WebGLId m_currentTexture;
TextureMap m_textures;
+ unsigned m_lastWaitedSyncPoint;
+ PendingProduceTextureList m_pendingProduceTextures;
};
class CCResourceProviderTest : public testing::Test {
public:
CCResourceProviderTest()
- : m_context(FakeWebCompositorOutputSurface::create(ResourceProviderContext::create()))
+ : m_sharedData(ContextSharedData::create())
+ , m_context(FakeWebCompositorOutputSurface::create(ResourceProviderContext::create(m_sharedData.get())))
, m_resourceProvider(CCResourceProvider::create(m_context.get()))
{
}
@@ -206,6 +308,7 @@
protected:
DebugScopedSetImplThread implThread;
+ OwnPtr<ContextSharedData> m_sharedData;
OwnPtr<CCGraphicsContext> m_context;
OwnPtr<CCResourceProvider> m_resourceProvider;
};
@@ -215,7 +318,7 @@
IntSize size(1, 1);
WGC3Denum format = GraphicsContext3D::RGBA;
int pool = 1;
- size_t pixelSize = ResourceProviderContext::textureSize(size, format);
+ size_t pixelSize = textureSize(size, format);
ASSERT_EQ(4U, pixelSize);
CCResourceProvider::ResourceId id = m_resourceProvider->createResource(pool, size, format, CCResourceProvider::TextureUsageAny);
@@ -256,7 +359,7 @@
IntSize size(2, 2);
WGC3Denum format = GraphicsContext3D::RGBA;
int pool = 1;
- size_t pixelSize = ResourceProviderContext::textureSize(size, format);
+ size_t pixelSize = textureSize(size, format);
ASSERT_EQ(16U, pixelSize);
CCResourceProvider::ResourceId id = m_resourceProvider->createResource(pool, size, format, CCResourceProvider::TextureUsageAny);
@@ -303,4 +406,117 @@
m_resourceProvider->deleteResource(id);
}
+TEST_F(CCResourceProviderTest, TransferResources)
+{
+ OwnPtr<CCGraphicsContext> childContext(FakeWebCompositorOutputSurface::create(ResourceProviderContext::create(m_sharedData.get())));
+ OwnPtr<CCResourceProvider> childResourceProvider(CCResourceProvider::create(childContext.get()));
+
+ IntSize size(1, 1);
+ WGC3Denum format = GraphicsContext3D::RGBA;
+ int pool = 1;
+ size_t pixelSize = textureSize(size, format);
+ ASSERT_EQ(4U, pixelSize);
+
+ CCResourceProvider::ResourceId id1 = childResourceProvider->createResource(pool, size, format, CCResourceProvider::TextureUsageAny);
+ uint8_t data1[4] = {1, 2, 3, 4};
+ IntRect rect(IntPoint(), size);
+ childResourceProvider->upload(id1, data1, rect, rect, IntSize());
+
+ CCResourceProvider::ResourceId id2 = childResourceProvider->createResource(pool, size, format, CCResourceProvider::TextureUsageAny);
+ uint8_t data2[4] = {5, 5, 5, 5};
+ childResourceProvider->upload(id2, data2, rect, rect, IntSize());
+
+ int childPool = 2;
+ int childId = m_resourceProvider->createChild(childPool);
+
+ {
+ // Transfer some resources to the parent.
+ CCResourceProvider::ResourceIdArray resourceIdsToTransfer;
+ resourceIdsToTransfer.append(id1);
+ resourceIdsToTransfer.append(id2);
+ CCResourceProvider::TransferableResourceList list = childResourceProvider->prepareSendToParent(resourceIdsToTransfer);
+ EXPECT_NE(0u, list.syncPoint);
+ EXPECT_EQ(2u, list.resources.size());
+ EXPECT_TRUE(childResourceProvider->inUseByConsumer(id1));
+ EXPECT_TRUE(childResourceProvider->inUseByConsumer(id2));
+ m_resourceProvider->receiveFromChild(childId, list);
+ }
+
+ EXPECT_EQ(2u, m_resourceProvider->numResources());
+ EXPECT_EQ(2u, m_resourceProvider->mailboxCount());
+ CCResourceProvider::ResourceIdMap resourceMap = m_resourceProvider->getChildToParentMap(childId);
+ CCResourceProvider::ResourceId mappedId1 = resourceMap.get(id1);
+ CCResourceProvider::ResourceId mappedId2 = resourceMap.get(id2);
+ EXPECT_NE(0u, mappedId1);
+ EXPECT_NE(0u, mappedId2);
+ EXPECT_FALSE(m_resourceProvider->inUseByConsumer(id1));
+ EXPECT_FALSE(m_resourceProvider->inUseByConsumer(id2));
+
+ uint8_t result[4] = {0};
+ getResourcePixels(mappedId1, size, format, result);
+ EXPECT_EQ(0, memcmp(data1, result, pixelSize));
+
+ getResourcePixels(mappedId2, size, format, result);
+ EXPECT_EQ(0, memcmp(data2, result, pixelSize));
+
+ {
+ // Check that transfering again the same resource from the child to the
+ // parent is a noop.
+ CCResourceProvider::ResourceIdArray resourceIdsToTransfer;
+ resourceIdsToTransfer.append(id1);
+ CCResourceProvider::TransferableResourceList list = childResourceProvider->prepareSendToParent(resourceIdsToTransfer);
+ EXPECT_EQ(0u, list.syncPoint);
+ EXPECT_EQ(0u, list.resources.size());
+ }
+
+ {
+ // Transfer resources back from the parent to the child.
+ CCResourceProvider::ResourceIdArray resourceIdsToTransfer;
+ resourceIdsToTransfer.append(mappedId1);
+ resourceIdsToTransfer.append(mappedId2);
+ CCResourceProvider::TransferableResourceList list = m_resourceProvider->prepareSendToChild(childId, resourceIdsToTransfer);
+ EXPECT_NE(0u, list.syncPoint);
+ EXPECT_EQ(2u, list.resources.size());
+ childResourceProvider->receiveFromParent(list);
+ }
+ EXPECT_EQ(0u, m_resourceProvider->mailboxCount());
+ EXPECT_EQ(2u, childResourceProvider->mailboxCount());
+ EXPECT_FALSE(childResourceProvider->inUseByConsumer(id1));
+ EXPECT_FALSE(childResourceProvider->inUseByConsumer(id2));
+
+ ResourceProviderContext* childContext3D = static_cast<ResourceProviderContext*>(childContext->context3D());
+ {
+ CCScopedLockResourceForRead lock(childResourceProvider.get(), id1);
+ ASSERT_NE(0U, lock.textureId());
+ childContext3D->bindTexture(GraphicsContext3D::TEXTURE_2D, lock.textureId());
+ childContext3D->getPixels(size, format, result);
+ EXPECT_EQ(0, memcmp(data1, result, pixelSize));
+ }
+ {
+ CCScopedLockResourceForRead lock(childResourceProvider.get(), id2);
+ ASSERT_NE(0U, lock.textureId());
+ childContext3D->bindTexture(GraphicsContext3D::TEXTURE_2D, lock.textureId());
+ childContext3D->getPixels(size, format, result);
+ EXPECT_EQ(0, memcmp(data2, result, pixelSize));
+ }
+
+ {
+ // Transfer resources to the parent again.
+ CCResourceProvider::ResourceIdArray resourceIdsToTransfer;
+ resourceIdsToTransfer.append(id1);
+ resourceIdsToTransfer.append(id2);
+ CCResourceProvider::TransferableResourceList list = childResourceProvider->prepareSendToParent(resourceIdsToTransfer);
+ EXPECT_NE(0u, list.syncPoint);
+ EXPECT_EQ(2u, list.resources.size());
+ EXPECT_TRUE(childResourceProvider->inUseByConsumer(id1));
+ EXPECT_TRUE(childResourceProvider->inUseByConsumer(id2));
+ m_resourceProvider->receiveFromChild(childId, list);
+ }
+
+ EXPECT_EQ(2u, m_resourceProvider->numResources());
+ m_resourceProvider->destroyChild(childId);
+ EXPECT_EQ(0u, m_resourceProvider->numResources());
+ EXPECT_EQ(0u, m_resourceProvider->mailboxCount());
+}
+
} // namespace