Edit

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

Branch :

  • Show log

    Commit

  • Author : Jamie Madill
    Date : 2020-04-02 10:29:52
    Hash : c9c4e4ed
    Message : Track rendering feedback loops by-context. This fixes an issue where feedback loops detection would trigger false positives based on texture use in multiple contexts. 1) there are two contexts, C1 and C2, sharing resources 2) in C1, there is a texture T bound to GL_TEXTURE_2D, and a program in use that will sample C1 3) in C2, a framebuffer is created and T is bound to it This fix indexes each set of active bindings in an object by ContextID. We can potentially redo this solution in the future if this proves to have too much tracking overhead. Includes a test writen by Ken Russell. Bug: angleproject:4517 Change-Id: I67012e68947c42d863dca193972576c82d5f3712 Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/2134406 Commit-Queue: Jamie Madill <jmadill@chromium.org> Reviewed-by: Kenneth Russell <kbr@chromium.org>

  • src/libANGLE/ResourceManager.cpp
  • //
    // Copyright 2002 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/Context.h"
    #include "libANGLE/Fence.h"
    #include "libANGLE/MemoryObject.h"
    #include "libANGLE/Program.h"
    #include "libANGLE/ProgramPipeline.h"
    #include "libANGLE/Query.h"
    #include "libANGLE/Renderbuffer.h"
    #include "libANGLE/Sampler.h"
    #include "libANGLE/Semaphore.h"
    #include "libANGLE/Shader.h"
    #include "libANGLE/Texture.h"
    #include "libANGLE/renderer/ContextImpl.h"
    
    namespace gl
    {
    
    namespace
    {
    
    template <typename ResourceType, typename IDType>
    IDType AllocateEmptyObject(HandleAllocator *handleAllocator,
                               ResourceMap<ResourceType, IDType> *objectMap)
    {
        IDType handle = FromGL<IDType>(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, typename IDType>
    TypedResourceManager<ResourceType, HandleAllocatorType, ImplT, IDType>::~TypedResourceManager()
    {
        ASSERT(mObjectMap.empty());
    }
    
    template <typename ResourceType, typename HandleAllocatorType, typename ImplT, typename IDType>
    void TypedResourceManager<ResourceType, HandleAllocatorType, ImplT, IDType>::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, typename IDType>
    void TypedResourceManager<ResourceType, HandleAllocatorType, ImplT, IDType>::deleteObject(
        const Context *context,
        IDType handle)
    {
        ResourceType *resource = nullptr;
        if (!mObjectMap.erase(handle, &resource))
        {
            return;
        }
    
        // Requires an explicit this-> because of C++ template rules.
        this->mHandleAllocator.release(GetIDValue(handle));
    
        if (resource)
        {
            ImplT::DeleteObject(context, resource);
        }
    }
    
    template class ResourceManagerBase<HandleAllocator>;
    template class TypedResourceManager<Buffer, HandleAllocator, BufferManager, BufferID>;
    template class TypedResourceManager<Texture, HandleAllocator, TextureManager, TextureID>;
    template class TypedResourceManager<Renderbuffer,
                                        HandleAllocator,
                                        RenderbufferManager,
                                        RenderbufferID>;
    template class TypedResourceManager<Sampler, HandleAllocator, SamplerManager, SamplerID>;
    template class TypedResourceManager<Sync, HandleAllocator, SyncManager, GLuint>;
    template class TypedResourceManager<Framebuffer,
                                        HandleAllocator,
                                        FramebufferManager,
                                        FramebufferID>;
    template class TypedResourceManager<ProgramPipeline,
                                        HandleAllocator,
                                        ProgramPipelineManager,
                                        ProgramPipelineID>;
    
    // BufferManager Implementation.
    
    // static
    Buffer *BufferManager::AllocateNewObject(rx::GLImplFactory *factory, BufferID handle)
    {
        Buffer *buffer = new Buffer(factory, handle);
        buffer->addRef();
        return buffer;
    }
    
    // static
    void BufferManager::DeleteObject(const Context *context, Buffer *buffer)
    {
        buffer->release(context);
    }
    
    BufferID BufferManager::createBuffer()
    {
        return AllocateEmptyObject(&mHandleAllocator, &mObjectMap);
    }
    
    Buffer *BufferManager::getBuffer(BufferID handle) const
    {
        return mObjectMap.query(handle);
    }
    
    // ShaderProgramManager Implementation.
    
    ShaderProgramManager::ShaderProgramManager() {}
    
    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();
    }
    
    ShaderProgramID ShaderProgramManager::createShader(rx::GLImplFactory *factory,
                                                       const gl::Limitations &rendererLimitations,
                                                       ShaderType type)
    {
        ASSERT(type != ShaderType::InvalidEnum);
        ShaderProgramID handle = ShaderProgramID{mHandleAllocator.allocate()};
        mShaders.assign(handle, new Shader(this, factory, rendererLimitations, type, handle));
        return handle;
    }
    
    void ShaderProgramManager::deleteShader(const Context *context, ShaderProgramID shader)
    {
        deleteObject(context, &mShaders, shader);
    }
    
    Shader *ShaderProgramManager::getShader(ShaderProgramID handle) const
    {
        return mShaders.query(handle);
    }
    
    ShaderProgramID ShaderProgramManager::createProgram(rx::GLImplFactory *factory)
    {
        ShaderProgramID handle = ShaderProgramID{mHandleAllocator.allocate()};
        mPrograms.assign(handle, new Program(factory, this, handle));
        return handle;
    }
    
    void ShaderProgramManager::deleteProgram(const gl::Context *context, ShaderProgramID program)
    {
        deleteObject(context, &mPrograms, program);
    }
    
    template <typename ObjectType, typename IDType>
    void ShaderProgramManager::deleteObject(const Context *context,
                                            ResourceMap<ObjectType, IDType> *objectMap,
                                            IDType id)
    {
        ObjectType *object = objectMap->query(id);
        if (!object)
        {
            return;
        }
    
        if (object->getRefCount() == 0)
        {
            mHandleAllocator.release(id.value);
            object->onDestroy(context);
            objectMap->erase(id, &object);
        }
        else
        {
            object->flagForDeletion();
        }
    }
    
    // TextureManager Implementation.
    
    // static
    Texture *TextureManager::AllocateNewObject(rx::GLImplFactory *factory,
                                               TextureID handle,
                                               TextureType type)
    {
        Texture *texture = new Texture(factory, handle, type);
        texture->addRef();
        return texture;
    }
    
    // static
    void TextureManager::DeleteObject(const Context *context, Texture *texture)
    {
        texture->release(context);
    }
    
    TextureID TextureManager::createTexture()
    {
        return AllocateEmptyObject(&mHandleAllocator, &mObjectMap);
    }
    
    void TextureManager::signalAllTexturesDirty() const
    {
        for (const auto &texture : mObjectMap)
        {
            if (texture.second)
            {
                // We don't know if the Texture needs init, but that's ok, since it will only force
                // a re-check, and will not initialize the pixels if it's not needed.
                texture.second->signalDirtyStorage(InitState::MayNeedInit);
            }
        }
    }
    
    void TextureManager::enableHandleAllocatorLogging()
    {
        mHandleAllocator.enableLogging(true);
    }
    
    // RenderbufferManager Implementation.
    
    // static
    Renderbuffer *RenderbufferManager::AllocateNewObject(rx::GLImplFactory *factory,
                                                         RenderbufferID handle)
    {
        Renderbuffer *renderbuffer = new Renderbuffer(factory, handle);
        renderbuffer->addRef();
        return renderbuffer;
    }
    
    // static
    void RenderbufferManager::DeleteObject(const Context *context, Renderbuffer *renderbuffer)
    {
        renderbuffer->release(context);
    }
    
    RenderbufferID RenderbufferManager::createRenderbuffer()
    {
        return {AllocateEmptyObject(&mHandleAllocator, &mObjectMap)};
    }
    
    Renderbuffer *RenderbufferManager::getRenderbuffer(RenderbufferID handle) const
    {
        return mObjectMap.query(handle);
    }
    
    // SamplerManager Implementation.
    
    // static
    Sampler *SamplerManager::AllocateNewObject(rx::GLImplFactory *factory, SamplerID handle)
    {
        Sampler *sampler = new Sampler(factory, handle);
        sampler->addRef();
        return sampler;
    }
    
    // static
    void SamplerManager::DeleteObject(const Context *context, Sampler *sampler)
    {
        sampler->release(context);
    }
    
    SamplerID SamplerManager::createSampler()
    {
        return AllocateEmptyObject(&mHandleAllocator, &mObjectMap);
    }
    
    Sampler *SamplerManager::getSampler(SamplerID handle) const
    {
        return mObjectMap.query(handle);
    }
    
    bool SamplerManager::isSampler(SamplerID sampler) const
    {
        return mObjectMap.contains(sampler);
    }
    
    // SyncManager Implementation.
    
    // static
    void SyncManager::DeleteObject(const Context *context, Sync *sync)
    {
        sync->release(context);
    }
    
    GLuint SyncManager::createSync(rx::GLImplFactory *factory)
    {
        GLuint handle = mHandleAllocator.allocate();
        Sync *sync    = new Sync(factory, handle);
        sync->addRef();
        mObjectMap.assign(handle, sync);
        return handle;
    }
    
    Sync *SyncManager::getSync(GLuint handle) const
    {
        return mObjectMap.query(handle);
    }
    
    // FramebufferManager Implementation.
    
    // static
    Framebuffer *FramebufferManager::AllocateNewObject(rx::GLImplFactory *factory,
                                                       FramebufferID handle,
                                                       const Caps &caps,
                                                       ContextID owningContextID)
    {
        // Make sure the caller isn't using a reserved handle.
        ASSERT(handle != Framebuffer::kDefaultDrawFramebufferHandle);
        return new Framebuffer(caps, factory, handle, owningContextID);
    }
    
    // static
    void FramebufferManager::DeleteObject(const Context *context, Framebuffer *framebuffer)
    {
        framebuffer->onDestroy(context);
        delete framebuffer;
    }
    
    FramebufferID FramebufferManager::createFramebuffer()
    {
        return AllocateEmptyObject(&mHandleAllocator, &mObjectMap);
    }
    
    Framebuffer *FramebufferManager::getFramebuffer(FramebufferID handle) const
    {
        return mObjectMap.query(handle);
    }
    
    void FramebufferManager::setDefaultFramebuffer(Framebuffer *framebuffer)
    {
        ASSERT(framebuffer == nullptr || framebuffer->isDefault());
        mObjectMap.assign(Framebuffer::kDefaultDrawFramebufferHandle, framebuffer);
    }
    
    void FramebufferManager::invalidateFramebufferCompletenessCache() const
    {
        for (const auto &framebuffer : mObjectMap)
        {
            if (framebuffer.second)
            {
                framebuffer.second->invalidateCompletenessCache();
            }
        }
    }
    
    // ProgramPipelineManager Implementation.
    
    // static
    ProgramPipeline *ProgramPipelineManager::AllocateNewObject(rx::GLImplFactory *factory,
                                                               ProgramPipelineID handle)
    {
        ProgramPipeline *pipeline = new ProgramPipeline(factory, handle);
        pipeline->addRef();
        return pipeline;
    }
    
    // static
    void ProgramPipelineManager::DeleteObject(const Context *context, ProgramPipeline *pipeline)
    {
        pipeline->release(context);
    }
    
    ProgramPipelineID ProgramPipelineManager::createProgramPipeline()
    {
        return AllocateEmptyObject(&mHandleAllocator, &mObjectMap);
    }
    
    ProgramPipeline *ProgramPipelineManager::getProgramPipeline(ProgramPipelineID handle) const
    {
        return mObjectMap.query(handle);
    }
    
    // MemoryObjectManager Implementation.
    
    MemoryObjectManager::MemoryObjectManager() {}
    
    MemoryObjectManager::~MemoryObjectManager()
    {
        ASSERT(mMemoryObjects.empty());
    }
    
    void MemoryObjectManager::reset(const Context *context)
    {
        while (!mMemoryObjects.empty())
        {
            deleteMemoryObject(context, {mMemoryObjects.begin()->first});
        }
        mMemoryObjects.clear();
    }
    
    MemoryObjectID MemoryObjectManager::createMemoryObject(rx::GLImplFactory *factory)
    {
        MemoryObjectID handle      = MemoryObjectID{mHandleAllocator.allocate()};
        MemoryObject *memoryObject = new MemoryObject(factory, handle);
        memoryObject->addRef();
        mMemoryObjects.assign(handle, memoryObject);
        return handle;
    }
    
    void MemoryObjectManager::deleteMemoryObject(const Context *context, MemoryObjectID handle)
    {
        MemoryObject *memoryObject = nullptr;
        if (!mMemoryObjects.erase(handle, &memoryObject))
        {
            return;
        }
    
        // Requires an explicit this-> because of C++ template rules.
        this->mHandleAllocator.release(handle.value);
    
        if (memoryObject)
        {
            memoryObject->release(context);
        }
    }
    
    MemoryObject *MemoryObjectManager::getMemoryObject(MemoryObjectID handle) const
    {
        return mMemoryObjects.query(handle);
    }
    
    // SemaphoreManager Implementation.
    
    SemaphoreManager::SemaphoreManager() {}
    
    SemaphoreManager::~SemaphoreManager()
    {
        ASSERT(mSemaphores.empty());
    }
    
    void SemaphoreManager::reset(const Context *context)
    {
        while (!mSemaphores.empty())
        {
            deleteSemaphore(context, {mSemaphores.begin()->first});
        }
        mSemaphores.clear();
    }
    
    SemaphoreID SemaphoreManager::createSemaphore(rx::GLImplFactory *factory)
    {
        SemaphoreID handle   = SemaphoreID{mHandleAllocator.allocate()};
        Semaphore *semaphore = new Semaphore(factory, handle);
        semaphore->addRef();
        mSemaphores.assign(handle, semaphore);
        return handle;
    }
    
    void SemaphoreManager::deleteSemaphore(const Context *context, SemaphoreID handle)
    {
        Semaphore *semaphore = nullptr;
        if (!mSemaphores.erase(handle, &semaphore))
        {
            return;
        }
    
        // Requires an explicit this-> because of C++ template rules.
        this->mHandleAllocator.release(handle.value);
    
        if (semaphore)
        {
            semaphore->release(context);
        }
    }
    
    Semaphore *SemaphoreManager::getSemaphore(SemaphoreID handle) const
    {
        return mSemaphores.query(handle);
    }
    }  // namespace gl