Title: [125838] trunk/Source
Revision
125838
Author
[email protected]
Date
2012-08-16 18:16:42 -0700 (Thu, 16 Aug 2012)

Log Message

[chromium] Add resource transfer functions to CCResourceProvider
https://bugs.webkit.org/show_bug.cgi?id=93524

Reviewed by James Robinson.

This adds methods to CCResourceProvider to be able to transport
resources from a child to a parent.

Added test to CCResourceProviderTest.

Source/WebCore:

* platform/graphics/chromium/cc/CCResourceProvider.cpp:
(WebCore::CCResourceProvider::inUseByConsumer):
(WebCore::CCResourceProvider::createResource):
(WebCore::CCResourceProvider::createResourceFromExternalTexture):
(WebCore::CCResourceProvider::CCResourceProvider):
(WebCore::CCResourceProvider::createChild):
(WebCore):
(WebCore::CCResourceProvider::destroyChild):
(WebCore::CCResourceProvider::getChildToParentMap):
(WebCore::CCResourceProvider::prepareSendToParent):
(WebCore::CCResourceProvider::prepareSendToChild):
(WebCore::CCResourceProvider::receiveFromChild):
(WebCore::CCResourceProvider::receiveFromParent):
(WebCore::CCResourceProvider::transferResource):
* platform/graphics/chromium/cc/CCResourceProvider.h:
(Mailbox):
(TransferableResource):
(TransferableResourceList):
(CCResourceProvider):
(Resource):
(Child):

Source/WebKit/chromium:

* tests/CCResourceProviderTest.cpp:
(WebKit::textureSize):
(WebKit):
(WebKit::Texture::Texture):
(Texture):
(ContextSharedData):
(WebKit::ContextSharedData::create):
(WebKit::ContextSharedData::insertSyncPoint):
(WebKit::ContextSharedData::genMailbox):
(WebKit::ContextSharedData::produceTexture):
(WebKit::ContextSharedData::consumeTexture):
(WebKit::ContextSharedData::ContextSharedData):
(WebKit::ResourceProviderContext::create):
(ResourceProviderContext):
(WebKit::ResourceProviderContext::insertSyncPoint):
(WebKit::ResourceProviderContext::waitSyncPoint):
(WebKit::ResourceProviderContext::genMailboxCHROMIUM):
(WebKit::ResourceProviderContext::produceTextureCHROMIUM):
(WebKit::ResourceProviderContext::consumeTextureCHROMIUM):
(WebKit::ResourceProviderContext::ResourceProviderContext):
(PendingProduceTexture):
(WebKit::CCResourceProviderTest::CCResourceProviderTest):
(CCResourceProviderTest):
(WebKit::TEST_F):

Modified Paths

Diff

Modified: trunk/Source/WebCore/ChangeLog (125837 => 125838)


--- trunk/Source/WebCore/ChangeLog	2012-08-17 01:06:49 UTC (rev 125837)
+++ trunk/Source/WebCore/ChangeLog	2012-08-17 01:16:42 UTC (rev 125838)
@@ -1,3 +1,37 @@
+2012-08-16  Antoine Labour  <[email protected]>
+
+        [chromium] Add resource transfer functions to CCResourceProvider
+        https://bugs.webkit.org/show_bug.cgi?id=93524
+
+        Reviewed by James Robinson.
+
+        This adds methods to CCResourceProvider to be able to transport
+        resources from a child to a parent.
+
+        Added test to CCResourceProviderTest.
+
+        * platform/graphics/chromium/cc/CCResourceProvider.cpp:
+        (WebCore::CCResourceProvider::inUseByConsumer):
+        (WebCore::CCResourceProvider::createResource):
+        (WebCore::CCResourceProvider::createResourceFromExternalTexture):
+        (WebCore::CCResourceProvider::CCResourceProvider):
+        (WebCore::CCResourceProvider::createChild):
+        (WebCore):
+        (WebCore::CCResourceProvider::destroyChild):
+        (WebCore::CCResourceProvider::getChildToParentMap):
+        (WebCore::CCResourceProvider::prepareSendToParent):
+        (WebCore::CCResourceProvider::prepareSendToChild):
+        (WebCore::CCResourceProvider::receiveFromChild):
+        (WebCore::CCResourceProvider::receiveFromParent):
+        (WebCore::CCResourceProvider::transferResource):
+        * platform/graphics/chromium/cc/CCResourceProvider.h:
+        (Mailbox):
+        (TransferableResource):
+        (TransferableResourceList):
+        (CCResourceProvider):
+        (Resource):
+        (Child):
+
 2012-08-16  Kent Tamura  <[email protected]>
 
         [Chromium-win] Use native digits in a case of "context" substitution setting too.

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/ChangeLog (125837 => 125838)


--- trunk/Source/WebKit/chromium/ChangeLog	2012-08-17 01:06:49 UTC (rev 125837)
+++ trunk/Source/WebKit/chromium/ChangeLog	2012-08-17 01:16:42 UTC (rev 125838)
@@ -1,3 +1,40 @@
+2012-08-16  Antoine Labour  <[email protected]>
+
+        [chromium] Add resource transfer functions to CCResourceProvider
+        https://bugs.webkit.org/show_bug.cgi?id=93524
+
+        Reviewed by James Robinson.
+
+        This adds methods to CCResourceProvider to be able to transport
+        resources from a child to a parent.
+
+        Added test to CCResourceProviderTest.
+
+        * tests/CCResourceProviderTest.cpp:
+        (WebKit::textureSize):
+        (WebKit):
+        (WebKit::Texture::Texture):
+        (Texture):
+        (ContextSharedData):
+        (WebKit::ContextSharedData::create):
+        (WebKit::ContextSharedData::insertSyncPoint):
+        (WebKit::ContextSharedData::genMailbox):
+        (WebKit::ContextSharedData::produceTexture):
+        (WebKit::ContextSharedData::consumeTexture):
+        (WebKit::ContextSharedData::ContextSharedData):
+        (WebKit::ResourceProviderContext::create):
+        (ResourceProviderContext):
+        (WebKit::ResourceProviderContext::insertSyncPoint):
+        (WebKit::ResourceProviderContext::waitSyncPoint):
+        (WebKit::ResourceProviderContext::genMailboxCHROMIUM):
+        (WebKit::ResourceProviderContext::produceTextureCHROMIUM):
+        (WebKit::ResourceProviderContext::consumeTextureCHROMIUM):
+        (WebKit::ResourceProviderContext::ResourceProviderContext):
+        (PendingProduceTexture):
+        (WebKit::CCResourceProviderTest::CCResourceProviderTest):
+        (CCResourceProviderTest):
+        (WebKit::TEST_F):
+
 2012-08-16  Alexandre Elias  <[email protected]>
 
         [chromium] Replace destRect with destOffset in texture upload

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
_______________________________________________
webkit-changes mailing list
[email protected]
http://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to