| // | |
| // 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 |