Edit

kc3-lang/angle/src/libANGLE/ResourceManager.cpp

Branch :

  • Show log

    Commit

  • Author : Jamie Madill
    Date : 2017-06-27 16:49:21
    Hash : 96a483bc
    Message : Add a ResourceMap class for faster GL resource maps. This gives a very fast query time for handles that are within a fixed range. For WebGL, where we don't allow create-on-bind, this will be 100% of the time, unless we create a very large number of resources. It is implemented as a two-tier map - the first uses a flat array to index into a handle buffer. The second tier uses a map for out-of- range values. BUG=angleproject:1458 Change-Id: I421bb3725cf523918cdfdbfaab035ad0dd3bf82d Reviewed-on: https://chromium-review.googlesource.com/544684 Commit-Queue: Jamie Madill <jmadill@chromium.org> Reviewed-by: Corentin Wallez <cwallez@chromium.org>

  • src/libANGLE/ResourceManager.cpp
  • //
    // Copyright (c) 2002-2016 The ANGLE Project Authors. All rights reserved.
    // Use of this source code is governed by a BSD-style license that can be
    // found in the LICENSE file.
    //
    
    // ResourceManager.cpp: Implements the the ResourceManager classes, which handle allocation and
    // lifetime of GL objects.
    
    #include "libANGLE/ResourceManager.h"
    
    #include "libANGLE/Buffer.h"
    #include "libANGLE/Fence.h"
    #include "libANGLE/Path.h"
    #include "libANGLE/Program.h"
    #include "libANGLE/Renderbuffer.h"
    #include "libANGLE/Sampler.h"
    #include "libANGLE/Shader.h"
    #include "libANGLE/Texture.h"
    #include "libANGLE/renderer/GLImplFactory.h"
    
    namespace gl
    {
    
    namespace
    {
    
    template <typename ResourceType>
    GLuint AllocateEmptyObject(HandleAllocator *handleAllocator, ResourceMap<ResourceType> *objectMap)
    {
        GLuint handle = handleAllocator->allocate();
        objectMap->assign(handle, nullptr);
        return handle;
    }
    
    }  // anonymous namespace
    
    template <typename HandleAllocatorType>
    ResourceManagerBase<HandleAllocatorType>::ResourceManagerBase() : mRefCount(1)
    {
    }
    
    template <typename HandleAllocatorType>
    void ResourceManagerBase<HandleAllocatorType>::addRef()
    {
        mRefCount++;
    }
    
    template <typename HandleAllocatorType>
    void ResourceManagerBase<HandleAllocatorType>::release(const Context *context)
    {
        if (--mRefCount == 0)
        {
            reset(context);
            delete this;
        }
    }
    
    template <typename ResourceType, typename HandleAllocatorType, typename ImplT>
    TypedResourceManager<ResourceType, HandleAllocatorType, ImplT>::~TypedResourceManager()
    {
        ASSERT(mObjectMap.empty());
    }
    
    template <typename ResourceType, typename HandleAllocatorType, typename ImplT>
    void TypedResourceManager<ResourceType, HandleAllocatorType, ImplT>::reset(const Context *context)
    {
        this->mHandleAllocator.reset();
        for (const auto &resource : mObjectMap)
        {
            if (resource.second)
            {
                ImplT::DeleteObject(context, resource.second);
            }
        }
        mObjectMap.clear();
    }
    
    template <typename ResourceType, typename HandleAllocatorType, typename ImplT>
    void TypedResourceManager<ResourceType, HandleAllocatorType, ImplT>::deleteObject(
        const Context *context,
        GLuint handle)
    {
        ResourceType *resource = nullptr;
        if (!mObjectMap.erase(handle, &resource))
        {
            return;
        }
    
        // Requires an explicit this-> because of C++ template rules.
        this->mHandleAllocator.release(handle);
    
        if (resource)
        {
            ImplT::DeleteObject(context, resource);
        }
    }
    
    template class ResourceManagerBase<HandleAllocator>;
    template class ResourceManagerBase<HandleRangeAllocator>;
    template class TypedResourceManager<Buffer, HandleAllocator, BufferManager>;
    template class TypedResourceManager<Texture, HandleAllocator, TextureManager>;
    template class TypedResourceManager<Renderbuffer, HandleAllocator, RenderbufferManager>;
    template class TypedResourceManager<Sampler, HandleAllocator, SamplerManager>;
    template class TypedResourceManager<FenceSync, HandleAllocator, FenceSyncManager>;
    template class TypedResourceManager<Framebuffer, HandleAllocator, FramebufferManager>;
    
    // BufferManager Implementation.
    
    // static
    Buffer *BufferManager::AllocateNewObject(rx::GLImplFactory *factory, GLuint handle)
    {
        Buffer *buffer = new Buffer(factory, handle);
        buffer->addRef();
        return buffer;
    }
    
    // static
    void BufferManager::DeleteObject(const Context *context, Buffer *buffer)
    {
        buffer->release(context);
    }
    
    GLuint BufferManager::createBuffer()
    {
        return AllocateEmptyObject(&mHandleAllocator, &mObjectMap);
    }
    
    Buffer *BufferManager::getBuffer(GLuint handle) const
    {
        return mObjectMap.query(handle);
    }
    
    // ShaderProgramManager Implementation.
    
    ShaderProgramManager::~ShaderProgramManager()
    {
        ASSERT(mPrograms.empty());
        ASSERT(mShaders.empty());
    }
    
    void ShaderProgramManager::reset(const Context *context)
    {
        while (!mPrograms.empty())
        {
            deleteProgram(context, mPrograms.begin()->first);
        }
        mPrograms.clear();
        while (!mShaders.empty())
        {
            deleteShader(context, mShaders.begin()->first);
        }
        mShaders.clear();
    }
    
    GLuint ShaderProgramManager::createShader(rx::GLImplFactory *factory,
                                              const gl::Limitations &rendererLimitations,
                                              GLenum type)
    {
        ASSERT(type == GL_VERTEX_SHADER || type == GL_FRAGMENT_SHADER || type == GL_COMPUTE_SHADER);
        GLuint handle    = mHandleAllocator.allocate();
        mShaders.assign(handle, new Shader(this, factory, rendererLimitations, type, handle));
        return handle;
    }
    
    void ShaderProgramManager::deleteShader(const Context *context, GLuint shader)
    {
        deleteObject(context, &mShaders, shader);
    }
    
    Shader *ShaderProgramManager::getShader(GLuint handle) const
    {
        return mShaders.query(handle);
    }
    
    GLuint ShaderProgramManager::createProgram(rx::GLImplFactory *factory)
    {
        GLuint handle = mHandleAllocator.allocate();
        mPrograms.assign(handle, new Program(factory, this, handle));
        return handle;
    }
    
    void ShaderProgramManager::deleteProgram(const gl::Context *context, GLuint program)
    {
        deleteObject(context, &mPrograms, program);
    }
    
    Program *ShaderProgramManager::getProgram(GLuint handle) const
    {
        return mPrograms.query(handle);
    }
    
    template <typename ObjectType>
    void ShaderProgramManager::deleteObject(const Context *context,
                                            ResourceMap<ObjectType> *objectMap,
                                            GLuint id)
    {
        ObjectType *object = objectMap->query(id);
        if (!object)
        {
            return;
        }
    
        if (object->getRefCount() == 0)
        {
            mHandleAllocator.release(id);
            object->onDestroy(context);
            objectMap->erase(id, &object);
        }
        else
        {
            object->flagForDeletion();
        }
    }
    
    // TextureManager Implementation.
    
    // static
    Texture *TextureManager::AllocateNewObject(rx::GLImplFactory *factory, GLuint handle, GLenum target)
    {
        Texture *texture = new Texture(factory, handle, target);
        texture->addRef();
        return texture;
    }
    
    // static
    void TextureManager::DeleteObject(const Context *context, Texture *texture)
    {
        texture->release(context);
    }
    
    GLuint TextureManager::createTexture()
    {
        return AllocateEmptyObject(&mHandleAllocator, &mObjectMap);
    }
    
    Texture *TextureManager::getTexture(GLuint handle) const
    {
        ASSERT(mObjectMap.query(0) == nullptr);
        return mObjectMap.query(handle);
    }
    
    void TextureManager::invalidateTextureComplenessCache() const
    {
        for (const auto &texture : mObjectMap)
        {
            if (texture.second)
            {
                texture.second->invalidateCompletenessCache();
            }
        }
    }
    
    // RenderbufferManager Implementation.
    
    // static
    Renderbuffer *RenderbufferManager::AllocateNewObject(rx::GLImplFactory *factory, GLuint handle)
    {
        Renderbuffer *renderbuffer = new Renderbuffer(factory->createRenderbuffer(), handle);
        renderbuffer->addRef();
        return renderbuffer;
    }
    
    // static
    void RenderbufferManager::DeleteObject(const Context *context, Renderbuffer *renderbuffer)
    {
        renderbuffer->release(context);
    }
    
    GLuint RenderbufferManager::createRenderbuffer()
    {
        return AllocateEmptyObject(&mHandleAllocator, &mObjectMap);
    }
    
    Renderbuffer *RenderbufferManager::getRenderbuffer(GLuint handle)
    {
        return mObjectMap.query(handle);
    }
    
    // SamplerManager Implementation.
    
    // static
    Sampler *SamplerManager::AllocateNewObject(rx::GLImplFactory *factory, GLuint handle)
    {
        Sampler *sampler = new Sampler(factory, handle);
        sampler->addRef();
        return sampler;
    }
    
    // static
    void SamplerManager::DeleteObject(const Context *context, Sampler *sampler)
    {
        sampler->release(context);
    }
    
    GLuint SamplerManager::createSampler()
    {
        return AllocateEmptyObject(&mHandleAllocator, &mObjectMap);
    }
    
    Sampler *SamplerManager::getSampler(GLuint handle)
    {
        return mObjectMap.query(handle);
    }
    
    bool SamplerManager::isSampler(GLuint sampler)
    {
        return mObjectMap.contains(sampler);
    }
    
    // FenceSyncManager Implementation.
    
    // static
    void FenceSyncManager::DeleteObject(const Context *context, FenceSync *fenceSync)
    {
        fenceSync->release(context);
    }
    
    GLuint FenceSyncManager::createFenceSync(rx::GLImplFactory *factory)
    {
        GLuint handle        = mHandleAllocator.allocate();
        FenceSync *fenceSync = new FenceSync(factory->createFenceSync(), handle);
        fenceSync->addRef();
        mObjectMap.assign(handle, fenceSync);
        return handle;
    }
    
    FenceSync *FenceSyncManager::getFenceSync(GLuint handle)
    {
        return mObjectMap.query(handle);
    }
    
    // PathManager Implementation.
    
    ErrorOrResult<GLuint> PathManager::createPaths(rx::GLImplFactory *factory, GLsizei range)
    {
        // Allocate client side handles.
        const GLuint client = mHandleAllocator.allocateRange(static_cast<GLuint>(range));
        if (client == HandleRangeAllocator::kInvalidHandle)
            return OutOfMemory() << "Failed to allocate path handle range.";
    
        const auto &paths = factory->createPaths(range);
        if (paths.empty())
        {
            mHandleAllocator.releaseRange(client, range);
            return OutOfMemory() << "Failed to allocate path objects.";
        }
    
        for (GLsizei i = 0; i < range; ++i)
        {
            const auto impl = paths[static_cast<unsigned>(i)];
            const auto id   = client + i;
            mPaths.assign(id, new Path(impl));
        }
        return client;
    }
    
    void PathManager::deletePaths(GLuint first, GLsizei range)
    {
        for (GLsizei i = 0; i < range; ++i)
        {
            const auto id = first + i;
            Path *p       = nullptr;
            if (!mPaths.erase(id, &p))
                continue;
            delete p;
        }
        mHandleAllocator.releaseRange(first, static_cast<GLuint>(range));
    }
    
    Path *PathManager::getPath(GLuint handle) const
    {
        return mPaths.query(handle);
    }
    
    bool PathManager::hasPath(GLuint handle) const
    {
        return mHandleAllocator.isUsed(handle);
    }
    
    PathManager::~PathManager()
    {
        ASSERT(mPaths.empty());
    }
    
    void PathManager::reset(const Context *context)
    {
        for (auto path : mPaths)
        {
            SafeDelete(path.second);
        }
        mPaths.clear();
    }
    
    // FramebufferManager Implementation.
    
    // static
    Framebuffer *FramebufferManager::AllocateNewObject(rx::GLImplFactory *factory,
                                                       GLuint handle,
                                                       const Caps &caps)
    {
        return new Framebuffer(caps, factory, handle);
    }
    
    // static
    void FramebufferManager::DeleteObject(const Context *context, Framebuffer *framebuffer)
    {
        // Default framebuffer are owned by their respective Surface
        if (framebuffer->id() != 0)
        {
            framebuffer->onDestroy(context);
            delete framebuffer;
        }
    }
    
    GLuint FramebufferManager::createFramebuffer()
    {
        return AllocateEmptyObject(&mHandleAllocator, &mObjectMap);
    }
    
    Framebuffer *FramebufferManager::getFramebuffer(GLuint handle) const
    {
        return mObjectMap.query(handle);
    }
    
    void FramebufferManager::setDefaultFramebuffer(Framebuffer *framebuffer)
    {
        ASSERT(framebuffer == nullptr || framebuffer->id() == 0);
        mObjectMap.assign(0, framebuffer);
    }
    
    void FramebufferManager::invalidateFramebufferComplenessCache() const
    {
        for (const auto &framebuffer : mObjectMap)
        {
            if (framebuffer.second)
            {
                framebuffer.second->invalidateCompletenessCache();
            }
        }
    }
    
    }  // namespace gl