// // 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 IDType AllocateEmptyObject(HandleAllocator *handleAllocator, ResourceMap *objectMap) { IDType handle = PackParam(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 TypedResourceManager::~TypedResourceManager() { ASSERT(mObjectMap.empty()); } template void TypedResourceManager::reset(const Context *context) { this->mHandleAllocator.reset(); for (const auto &resource : mObjectMap) { if (resource.second) { ImplT::DeleteObject(context, resource.second); } } mObjectMap.clear(); } template void TypedResourceManager::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); } } // Unclear why Clang warns about weak vtables in this case. ANGLE_DISABLE_WEAK_TEMPLATE_VTABLES_WARNING template class TypedResourceManager; template class TypedResourceManager; template class TypedResourceManager; template class TypedResourceManager; template class TypedResourceManager; template class TypedResourceManager; template class TypedResourceManager; ANGLE_REENABLE_WEAK_TEMPLATE_VTABLES_WARNING // 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 void ShaderProgramManager::deleteObject(const Context *context, ResourceMap *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