// // 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/Context.h" #include "libANGLE/Fence.h" #include "libANGLE/MemoryObject.h" #include "libANGLE/Path.h" #include "libANGLE/Program.h" #include "libANGLE/ProgramPipeline.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 GLuint AllocateEmptyObject(HandleAllocator *handleAllocator, ResourceMap *objectMap) { GLuint handle = handleAllocator->allocate(); objectMap->assign(handle, nullptr); return handle; } } // anonymous namespace template ResourceManagerBase::ResourceManagerBase() : mRefCount(1) {} template void ResourceManagerBase::addRef() { mRefCount++; } template 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, 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; template class ResourceManagerBase; template class TypedResourceManager; template class TypedResourceManager; template class TypedResourceManager; template class TypedResourceManager; template class TypedResourceManager; template class TypedResourceManager; template class TypedResourceManager; // 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() {} 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, ShaderType type) { ASSERT(type != ShaderType::InvalidEnum); 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); } template void ShaderProgramManager::deleteObject(const Context *context, ResourceMap *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, 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); } GLuint 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, GLuint handle) { Renderbuffer *renderbuffer = new Renderbuffer(factory, 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) const { 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) const { return mObjectMap.query(handle); } bool SamplerManager::isSampler(GLuint 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->createSync(), handle); sync->addRef(); mObjectMap.assign(handle, sync); return handle; } Sync *SyncManager::getSync(GLuint handle) const { return mObjectMap.query(handle); } // PathManager Implementation. PathManager::PathManager() = default; angle::Result PathManager::createPaths(Context *context, GLsizei range, GLuint *createdOut) { *createdOut = 0; // Allocate client side handles. const GLuint client = mHandleAllocator.allocateRange(static_cast(range)); if (client == HandleRangeAllocator::kInvalidHandle) { context->handleError(GL_OUT_OF_MEMORY, "Failed to allocate path handle range.", __FILE__, ANGLE_FUNCTION, __LINE__); return angle::Result::Stop; } const auto &paths = context->getImplementation()->createPaths(range); if (paths.empty()) { mHandleAllocator.releaseRange(client, range); context->handleError(GL_OUT_OF_MEMORY, "Failed to allocate path objects.", __FILE__, ANGLE_FUNCTION, __LINE__); return angle::Result::Stop; } for (GLsizei i = 0; i < range; ++i) { rx::PathImpl *impl = paths[static_cast(i)]; const auto id = client + i; mPaths.assign(id, new Path(impl)); } *createdOut = client; return angle::Result::Continue; } 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(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) { 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(); } } } // ProgramPipelineManager Implementation. // static ProgramPipeline *ProgramPipelineManager::AllocateNewObject(rx::GLImplFactory *factory, GLuint handle) { ProgramPipeline *pipeline = new ProgramPipeline(factory, handle); pipeline->addRef(); return pipeline; } // static void ProgramPipelineManager::DeleteObject(const Context *context, ProgramPipeline *pipeline) { pipeline->release(context); } GLuint ProgramPipelineManager::createProgramPipeline() { return AllocateEmptyObject(&mHandleAllocator, &mObjectMap); } ProgramPipeline *ProgramPipelineManager::getProgramPipeline(GLuint 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(); } GLuint MemoryObjectManager::createMemoryObject(rx::GLImplFactory *factory) { GLuint handle = mHandleAllocator.allocate(); MemoryObject *memoryObject = new MemoryObject(factory, handle); memoryObject->addRef(); mMemoryObjects.assign(handle, memoryObject); return handle; } void MemoryObjectManager::deleteMemoryObject(const Context *context, GLuint handle) { MemoryObject *memoryObject = nullptr; if (!mMemoryObjects.erase(handle, &memoryObject)) { return; } // Requires an explicit this-> because of C++ template rules. this->mHandleAllocator.release(handle); if (memoryObject) { memoryObject->release(context); } } MemoryObject *MemoryObjectManager::getMemoryObject(GLuint 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(); } GLuint SemaphoreManager::createSemaphore(rx::GLImplFactory *factory) { GLuint handle = mHandleAllocator.allocate(); Semaphore *semaphore = new Semaphore(factory, handle); semaphore->addRef(); mSemaphores.assign(handle, semaphore); return handle; } void SemaphoreManager::deleteSemaphore(const Context *context, GLuint handle) { Semaphore *semaphore = nullptr; if (!mSemaphores.erase(handle, &semaphore)) { return; } // Requires an explicit this-> because of C++ template rules. this->mHandleAllocator.release(handle); if (semaphore) { semaphore->release(context); } } Semaphore *SemaphoreManager::getSemaphore(GLuint handle) const { return mSemaphores.query(handle); } } // namespace gl