Aaelias@chromium.orgAdd CC software renderer.
2519d396创建于 2012年9月25日历史提交
// Copyright 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "config.h"

#include "CCResourceProvider.h"
#ifdef LOG
#undef LOG
#endif

#include <limits.h>

#include "base/string_split.h"
#include "base/string_util.h"
#include "CCProxy.h"
#include "CCRendererGL.h" // For the GLC() macro.
#include "Extensions3DChromium.h"
#include "IntRect.h"
#include "LayerTextureSubImage.h"
#include "ThrottledTextureUploader.h"
#include "UnthrottledTextureUploader.h"
#include <public/WebGraphicsContext3D.h>
#include <wtf/HashSet.h>

using WebKit::WebGraphicsContext3D;

namespace cc {

static GC3Denum textureToStorageFormat(GC3Denum textureFormat)
{
    GC3Denum storageFormat = Extensions3D::RGBA8_OES;
    switch (textureFormat) {
    case GraphicsContext3D::RGBA:
        break;
    case Extensions3D::BGRA_EXT:
        storageFormat = Extensions3DChromium::BGRA8_EXT;
        break;
    default:
        ASSERT_NOT_REACHED();
        break;
    }

    return storageFormat;
}

static bool isTextureFormatSupportedForStorage(GC3Denum format)
{
    return (format == GraphicsContext3D::RGBA || format == Extensions3D::BGRA_EXT);
}

CCResourceProvider::TransferableResourceList::TransferableResourceList()
{
}

CCResourceProvider::TransferableResourceList::~TransferableResourceList()
{
}

CCResourceProvider::Resource::Resource()
    : glId(0)
    , pixels(0)
    , pool(0)
    , lockForReadCount(0)
    , lockedForWrite(false)
    , external(false)
    , exported(false)
    , size()
    , format(0)
    , type(static_cast<ResourceType>(0))
{
}

CCResourceProvider::Resource::Resource(unsigned textureId, int pool, const IntSize& size, GC3Denum format)
    : glId(textureId)
    , pixels(0)
    , pool(pool)
    , lockForReadCount(0)
    , lockedForWrite(false)
    , external(false)
    , exported(false)
    , size(size)
    , format(format)
    , type(GLTexture)
{
}

CCResourceProvider::Resource::Resource(uint8_t* pixels, int pool, const IntSize& size, GC3Denum format)
    : glId(0)
    , pixels(pixels)
    , pool(pool)
    , lockForReadCount(0)
    , lockedForWrite(false)
    , external(false)
    , exported(false)
    , size(size)
    , format(format)
    , type(Bitmap)
{
}

CCResourceProvider::Child::Child()
{
}

CCResourceProvider::Child::~Child()
{
}

PassOwnPtr<CCResourceProvider> CCResourceProvider::create(CCGraphicsContext* context)
{
    OwnPtr<CCResourceProvider> resourceProvider(adoptPtr(new CCResourceProvider(context)));
    if (!resourceProvider->initialize())
        return nullptr;
    return resourceProvider.release();
}

CCResourceProvider::~CCResourceProvider()
{
    WebGraphicsContext3D* context3d = m_context->context3D();
    if (!context3d || !context3d->makeContextCurrent())
        return;
    m_textureUploader.clear();
    m_textureCopier.clear();
}

WebGraphicsContext3D* CCResourceProvider::graphicsContext3D()
{
    ASSERT(CCProxy::isImplThread());
    return m_context->context3D();
}

bool CCResourceProvider::inUseByConsumer(ResourceId id)
{
    ASSERT(CCProxy::isImplThread());
    ResourceMap::iterator it = m_resources.find(id);
    CHECK(it != m_resources.end());
#if WTF_NEW_HASHMAP_ITERATORS_INTERFACE
    Resource* resource = &it->value;
#else
    Resource* resource = &it->second;
#endif
    return !!resource->lockForReadCount || resource->exported;
}

CCResourceProvider::ResourceId CCResourceProvider::createResource(int pool, const IntSize& size, GC3Denum format, TextureUsageHint hint)
{
    switch (m_defaultResourceType) {
    case GLTexture:
        return createGLTexture(pool, size, format, hint);
    case Bitmap:
        ASSERT(format == GraphicsContext3D::RGBA);
        return createBitmap(pool, size);
    }

    CRASH();
    return 0;
}

CCResourceProvider::ResourceId CCResourceProvider::createGLTexture(int pool, const IntSize& size, GC3Denum format, TextureUsageHint hint)
{
    ASSERT(CCProxy::isImplThread());
    unsigned textureId = 0;
    WebGraphicsContext3D* context3d = m_context->context3D();
    ASSERT(context3d);
    GLC(context3d, textureId = context3d->createTexture());
    GLC(context3d, context3d->bindTexture(GraphicsContext3D::TEXTURE_2D, textureId));
    GLC(context3d, context3d->texParameteri(GraphicsContext3D::TEXTURE_2D, GraphicsContext3D::TEXTURE_MIN_FILTER, GraphicsContext3D::LINEAR));
    GLC(context3d, context3d->texParameteri(GraphicsContext3D::TEXTURE_2D, GraphicsContext3D::TEXTURE_MAG_FILTER, GraphicsContext3D::LINEAR));
    GLC(context3d, context3d->texParameteri(GraphicsContext3D::TEXTURE_2D, GraphicsContext3D::TEXTURE_WRAP_S, GraphicsContext3D::CLAMP_TO_EDGE));
    GLC(context3d, context3d->texParameteri(GraphicsContext3D::TEXTURE_2D, GraphicsContext3D::TEXTURE_WRAP_T, GraphicsContext3D::CLAMP_TO_EDGE));

    if (m_useTextureUsageHint && hint == TextureUsageFramebuffer)
        GLC(context3d, context3d->texParameteri(GraphicsContext3D::TEXTURE_2D, Extensions3DChromium::GL_TEXTURE_USAGE_ANGLE, Extensions3DChromium::GL_FRAMEBUFFER_ATTACHMENT_ANGLE));
    if (m_useTextureStorageExt && isTextureFormatSupportedForStorage(format)) {
        GC3Denum storageFormat = textureToStorageFormat(format);
        GLC(context3d, context3d->texStorage2DEXT(GraphicsContext3D::TEXTURE_2D, 1, storageFormat, size.width(), size.height()));
    } 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, size, format);
    m_resources.add(id, resource);
    return id;
}

CCResourceProvider::ResourceId CCResourceProvider::createBitmap(int pool, const IntSize& size)
{
    ASSERT(CCProxy::isImplThread());

    uint8_t* pixels = new uint8_t[size.width() * size.height() * 4];

    ResourceId id = m_nextId++;
    Resource resource(pixels, pool, size, GraphicsContext3D::RGBA);
    m_resources.add(id, resource);
    return id;
}

CCResourceProvider::ResourceId CCResourceProvider::createResourceFromExternalTexture(unsigned textureId)
{
    ASSERT(CCProxy::isImplThread());
    ASSERT(m_context->context3D());
    ResourceId id = m_nextId++;
    Resource resource(textureId, 0, IntSize(), 0);
    resource.external = true;
    m_resources.add(id, resource);
    return id;
}

void CCResourceProvider::deleteResource(ResourceId id)
{
    ASSERT(CCProxy::isImplThread());
    ResourceMap::iterator it = m_resources.find(id);
    CHECK(it != m_resources.end());
#if WTF_NEW_HASHMAP_ITERATORS_INTERFACE
    Resource* resource = &it->value;
#else
    Resource* resource = &it->second;
#endif
    ASSERT(!resource->lockedForWrite);
    ASSERT(!resource->lockForReadCount);

    if (resource->glId && !resource->external) {
        WebGraphicsContext3D* context3d = m_context->context3D();
        ASSERT(context3d);
        GLC(context3d, context3d->deleteTexture(resource->glId));
    }
    if (resource->pixels)
        delete resource->pixels;

    m_resources.remove(it);
}

void CCResourceProvider::deleteOwnedResources(int pool)
{
    ASSERT(CCProxy::isImplThread());
    ResourceIdArray toDelete;
    for (ResourceMap::iterator it = m_resources.begin(); it != m_resources.end(); ++it) {
#if WTF_NEW_HASHMAP_ITERATORS_INTERFACE
        if (it->value.pool == pool && !it->value.external)
            toDelete.append(it->key);
#else
        if (it->second.pool == pool && !it->second.external)
            toDelete.append(it->first);
#endif
    }
    for (ResourceIdArray::iterator it = toDelete.begin(); it != toDelete.end(); ++it)
        deleteResource(*it);
}

CCResourceProvider::ResourceType CCResourceProvider::resourceType(ResourceId id)
{
    ResourceMap::iterator it = m_resources.find(id);
    CHECK(it != m_resources.end());
#if WTF_NEW_HASHMAP_ITERATORS_INTERFACE
    Resource* resource = &it->value;
#else
    Resource* resource = &it->second;
#endif
    return resource->type;
}

void CCResourceProvider::upload(ResourceId id, const uint8_t* image, const IntRect& imageRect, const IntRect& sourceRect, const IntSize& destOffset)
{
    ASSERT(CCProxy::isImplThread());
    ResourceMap::iterator it = m_resources.find(id);
    CHECK(it != m_resources.end());
#if WTF_NEW_HASHMAP_ITERATORS_INTERFACE
    Resource* resource = &it->value;
#else
    Resource* resource = &it->second;
#endif
    ASSERT(!resource->lockedForWrite);
    ASSERT(!resource->lockForReadCount);
    ASSERT(!resource->external);

    if (resource->glId) {
        WebGraphicsContext3D* context3d = m_context->context3D();
        ASSERT(context3d);
        ASSERT(m_texSubImage.get());
        context3d->bindTexture(GraphicsContext3D::TEXTURE_2D, resource->glId);
        m_texSubImage->upload(image, imageRect, sourceRect, destOffset, resource->format, context3d);
    }

    if (resource->pixels) {
        SkBitmap srcFull;
        srcFull.setConfig(SkBitmap::kARGB_8888_Config, imageRect.width(), imageRect.height());
        srcFull.setPixels(const_cast<uint8_t*>(image));
        SkBitmap srcSubset;
        SkIRect skSourceRect = SkIRect::MakeXYWH(sourceRect.x(), sourceRect.y(), sourceRect.width(), sourceRect.height());
        skSourceRect.offset(-imageRect.x(), -imageRect.y());
        srcFull.extractSubset(&srcSubset, skSourceRect);

        ScopedWriteLockSoftware lock(this, id);
        SkCanvas* dest = lock.skCanvas();
        dest->writePixels(srcSubset, destOffset.width(), destOffset.height());
    }
}

void CCResourceProvider::flush()
{
    ASSERT(CCProxy::isImplThread());
    WebGraphicsContext3D* context3d = m_context->context3D();
    if (context3d)
        context3d->flush();
}

bool CCResourceProvider::shallowFlushIfSupported()
{
    ASSERT(CCProxy::isImplThread());
    WebGraphicsContext3D* context3d = m_context->context3D();
    if (!context3d || !m_useShallowFlush)
        return false;

    context3d->shallowFlushCHROMIUM();
    return true;
}

const CCResourceProvider::Resource* CCResourceProvider::lockForRead(ResourceId id)
{
    ASSERT(CCProxy::isImplThread());
    ResourceMap::iterator it = m_resources.find(id);
    CHECK(it != m_resources.end());
#if WTF_NEW_HASHMAP_ITERATORS_INTERFACE
    Resource* resource = &it->value;
#else
    Resource* resource = &it->second;
#endif
    ASSERT(!resource->lockedForWrite);
    resource->lockForReadCount++;
    return resource;
}

void CCResourceProvider::unlockForRead(ResourceId id)
{
    ASSERT(CCProxy::isImplThread());
    ResourceMap::iterator it = m_resources.find(id);
    CHECK(it != m_resources.end());
#if WTF_NEW_HASHMAP_ITERATORS_INTERFACE
    Resource* resource = &it->value;
#else
    Resource* resource = &it->second;
#endif
    ASSERT(resource->lockForReadCount > 0);
    resource->lockForReadCount--;
}

const CCResourceProvider::Resource* CCResourceProvider::lockForWrite(ResourceId id)
{
    ASSERT(CCProxy::isImplThread());
    ResourceMap::iterator it = m_resources.find(id);
    CHECK(it != m_resources.end());
#if WTF_NEW_HASHMAP_ITERATORS_INTERFACE
    Resource* resource = &it->value;
#else
    Resource* resource = &it->second;
#endif
    ASSERT(!resource->lockedForWrite);
    ASSERT(!resource->lockForReadCount);
    ASSERT(!resource->external);
    resource->lockedForWrite = true;
    return resource;
}

void CCResourceProvider::unlockForWrite(ResourceId id)
{
    ASSERT(CCProxy::isImplThread());
    ResourceMap::iterator it = m_resources.find(id);
    CHECK(it != m_resources.end());
#if WTF_NEW_HASHMAP_ITERATORS_INTERFACE
    Resource* resource = &it->value;
#else
    Resource* resource = &it->second;
#endif
    ASSERT(resource->lockedForWrite);
    ASSERT(!resource->external);
    resource->lockedForWrite = false;
}

CCResourceProvider::ScopedReadLockGL::ScopedReadLockGL(CCResourceProvider* resourceProvider, CCResourceProvider::ResourceId resourceId)
    : m_resourceProvider(resourceProvider)
    , m_resourceId(resourceId)
    , m_textureId(resourceProvider->lockForRead(resourceId)->glId)
{
    ASSERT(m_textureId);
}

CCResourceProvider::ScopedReadLockGL::~ScopedReadLockGL()
{
    m_resourceProvider->unlockForRead(m_resourceId);
}

CCResourceProvider::ScopedWriteLockGL::ScopedWriteLockGL(CCResourceProvider* resourceProvider, CCResourceProvider::ResourceId resourceId)
    : m_resourceProvider(resourceProvider)
    , m_resourceId(resourceId)
    , m_textureId(resourceProvider->lockForWrite(resourceId)->glId)
{
    ASSERT(m_textureId);
}

CCResourceProvider::ScopedWriteLockGL::~ScopedWriteLockGL()
{
    m_resourceProvider->unlockForWrite(m_resourceId);
}

void CCResourceProvider::populateSkBitmapWithResource(SkBitmap* skBitmap, const Resource* resource)
{
    ASSERT(resource->pixels);
    ASSERT(resource->format == GraphicsContext3D::RGBA);
    skBitmap->setConfig(SkBitmap::kARGB_8888_Config, resource->size.width(), resource->size.height());
    skBitmap->setPixels(resource->pixels);
}

CCResourceProvider::ScopedReadLockSoftware::ScopedReadLockSoftware(CCResourceProvider* resourceProvider, CCResourceProvider::ResourceId resourceId)
    : m_resourceProvider(resourceProvider)
    , m_resourceId(resourceId)
{
    CCResourceProvider::populateSkBitmapWithResource(&m_skBitmap, resourceProvider->lockForRead(resourceId));
}

CCResourceProvider::ScopedReadLockSoftware::~ScopedReadLockSoftware()
{
    m_resourceProvider->unlockForRead(m_resourceId);
}

CCResourceProvider::ScopedWriteLockSoftware::ScopedWriteLockSoftware(CCResourceProvider* resourceProvider, CCResourceProvider::ResourceId resourceId)
    : m_resourceProvider(resourceProvider)
    , m_resourceId(resourceId)
{
    CCResourceProvider::populateSkBitmapWithResource(&m_skBitmap, resourceProvider->lockForWrite(resourceId));
    m_skCanvas.setBitmapDevice(m_skBitmap);
}

CCResourceProvider::ScopedWriteLockSoftware::~ScopedWriteLockSoftware()
{
    m_resourceProvider->unlockForWrite(m_resourceId);
}

CCResourceProvider::CCResourceProvider(CCGraphicsContext* context)
    : m_context(context)
    , m_nextId(1)
    , m_nextChild(1)
    , m_defaultResourceType(GLTexture)
    , m_useTextureStorageExt(false)
    , m_useTextureUsageHint(false)
    , m_useShallowFlush(false)
    , m_maxTextureSize(0)
{
}

bool CCResourceProvider::initialize()
{
    ASSERT(CCProxy::isImplThread());
    WebGraphicsContext3D* context3d = m_context->context3D();
    if (!context3d) {
        m_maxTextureSize = INT_MAX / 2;
        m_textureUploader = UnthrottledTextureUploader::create();
        return true;
    }
    if (!context3d->makeContextCurrent())
        return false;

    std::string extensionsString = UTF16ToASCII(context3d->getString(GraphicsContext3D::EXTENSIONS));
    std::vector<std::string> extensions;
    base::SplitString(extensionsString, ' ', &extensions);
    bool useMapSub = false;
    bool useBindUniform = false;
    for (size_t i = 0; i < extensions.size(); ++i) {
        if (extensions[i] == "GL_EXT_texture_storage")
            m_useTextureStorageExt = true;
        else if (extensions[i] == "GL_ANGLE_texture_usage")
            m_useTextureUsageHint = true;
        else if (extensions[i] == "GL_CHROMIUM_map_sub")
            useMapSub = true;
        else if (extensions[i] == "GL_CHROMIUM_shallow_flush")
            m_useShallowFlush = true;
        else if (extensions[i] == "GL_CHROMIUM_bind_uniform_location")
            useBindUniform = true;
    }

    m_texSubImage = adoptPtr(new LayerTextureSubImage(useMapSub));
    m_textureCopier = AcceleratedTextureCopier::create(context3d, useBindUniform);

    m_textureUploader = ThrottledTextureUploader::create(context3d);
    GLC(context3d, context3d->getIntegerv(GraphicsContext3D::MAX_TEXTURE_SIZE, &m_maxTextureSize));
    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());
#if WTF_NEW_HASHMAP_ITERATORS_INTERFACE
    deleteOwnedResources(it->value.pool);
#else
    deleteOwnedResources(it->second.pool);
#endif
    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());
#if WTF_NEW_HASHMAP_ITERATORS_INTERFACE
    return it->value.childToParentMap;
#else
    return it->second.childToParentMap;
#endif
}

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)) {
#if WTF_NEW_HASHMAP_ITERATORS_INTERFACE
            m_resources.find(*it)->value.exported = true;
#else
            m_resources.find(*it)->second.exported = true;
#endif
            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;
    }
#if WTF_NEW_HASHMAP_ITERATORS_INTERFACE
    Child& childInfo = m_children.find(child)->value;
#else
    Child& childInfo = m_children.find(child)->second;
#endif
    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));
    }
#if WTF_NEW_HASHMAP_ITERATORS_INTERFACE
    Child& childInfo = m_children.find(child)->value;
#else
    Child& childInfo = m_children.find(child)->second;
#endif
    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) {
#if WTF_NEW_HASHMAP_ITERATORS_INTERFACE
        Resource* resource = &m_resources.find(it->id)->value;
#else
        Resource* resource = &m_resources.find(it->id)->second;
#endif
        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);
    CHECK(it != m_resources.end());
#if WTF_NEW_HASHMAP_ITERATORS_INTERFACE
    const Resource* source = &it->value;
#else
    const Resource* source = &it->second;
#endif
    ASSERT(!source->lockedForWrite);
    ASSERT(!source->lockForReadCount);
    ASSERT(!source->external);
    if (source->exported)
        return false;
    resource->id = id;
    resource->format = source->format;
    resource->size = source->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, source->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 WTF_NEW_HASHMAP_ITERATORS_INTERFACE
            if (!it->value.exported && !it->value.external)
#else
            if (!it->second.exported && !it->second.external)
#endif
                ++maxMailboxCount;
        }
    } else {
        HashSet<int> childPoolSet;
        for (ChildMap::iterator it = m_children.begin(); it != m_children.end(); ++it)
#if WTF_NEW_HASHMAP_ITERATORS_INTERFACE
            childPoolSet.add(it->value.pool);
#else
            childPoolSet.add(it->second.pool);
#endif
        for (ResourceMap::iterator it = m_resources.begin(); it != m_resources.end(); ++it) {
#if WTF_NEW_HASHMAP_ITERATORS_INTERFACE
            if (childPoolSet.contains(it->value.pool))
#else
            if (childPoolSet.contains(it->second.pool))
#endif
                ++maxMailboxCount;
        }
    }
    while (m_mailboxes.size() > maxMailboxCount)
        m_mailboxes.removeFirst();
}

}