| // |
| // 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 = PackParam<IDType>(handleAllocator->allocate()); |
| objectMap->assign(handle, nullptr); |
| return handle; |
| } |
| |
| } // anonymous namespace |
| |
| ResourceManagerBase::ResourceManagerBase() : mRefCount(1) {} |
| |
| ResourceManagerBase::~ResourceManagerBase() = default; |
| |
| void ResourceManagerBase::addRef() |
| { |
| mRefCount++; |
| } |
| |
| void ResourceManagerBase::release(const Context *context) |
| { |
| if (--mRefCount == 0) |
| { |
| reset(context); |
| delete this; |
| } |
| } |
| |
| template <typename ResourceType, typename ImplT, typename IDType> |
| TypedResourceManager<ResourceType, ImplT, IDType>::~TypedResourceManager() |
| { |
| ASSERT(mObjectMap.empty()); |
| } |
| |
| template <typename ResourceType, typename ImplT, typename IDType> |
| void TypedResourceManager<ResourceType, 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 ImplT, typename IDType> |
| void TypedResourceManager<ResourceType, 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 TypedResourceManager<Buffer, BufferManager, BufferID>; |
| template class TypedResourceManager<Texture, TextureManager, TextureID>; |
| template class TypedResourceManager<Renderbuffer, RenderbufferManager, RenderbufferID>; |
| template class TypedResourceManager<Sampler, SamplerManager, SamplerID>; |
| template class TypedResourceManager<Sync, SyncManager, GLuint>; |
| template class TypedResourceManager<Framebuffer, FramebufferManager, FramebufferID>; |
| template class TypedResourceManager<ProgramPipeline, ProgramPipelineManager, ProgramPipelineID>; |
| |
| // BufferManager Implementation. |
| BufferManager::~BufferManager() = default; |
| |
| // 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. |
| |
| TextureManager::~TextureManager() = default; |
| |
| // 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. |
| |
| RenderbufferManager::~RenderbufferManager() = default; |
| |
| // 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. |
| |
| SamplerManager::~SamplerManager() = default; |
| |
| // 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. |
| |
| SyncManager::~SyncManager() = default; |
| |
| // 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. |
| |
| FramebufferManager::~FramebufferManager() = default; |
| |
| // static |
| Framebuffer *FramebufferManager::AllocateNewObject(rx::GLImplFactory *factory, |
| FramebufferID handle, |
| const Caps &caps, |
| egl::ShareGroup *shareGroup) |
| { |
| // Make sure the caller isn't using a reserved handle. |
| ASSERT(handle != Framebuffer::kDefaultDrawFramebufferHandle); |
| return new Framebuffer(caps, factory, handle, shareGroup); |
| } |
| |
| // 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); |
| } |
| |
| Framebuffer *FramebufferManager::getDefaultFramebuffer() const |
| { |
| return getFramebuffer(Framebuffer::kDefaultDrawFramebufferHandle); |
| } |
| |
| void FramebufferManager::invalidateFramebufferCompletenessCache() const |
| { |
| for (const auto &framebuffer : mObjectMap) |
| { |
| if (framebuffer.second) |
| { |
| framebuffer.second->invalidateCompletenessCache(); |
| } |
| } |
| } |
| |
| // ProgramPipelineManager Implementation. |
| |
| ProgramPipelineManager::~ProgramPipelineManager() = default; |
| |
| // 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 |