blob: cc008cafa4370d14e2b4b9975b306ac2257c1e9e [file] [log] [blame]
//
// 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/Path.h"
#include "libANGLE/Program.h"
#include "libANGLE/ProgramPipeline.h"
#include "libANGLE/Renderbuffer.h"
#include "libANGLE/Sampler.h"
#include "libANGLE/Shader.h"
#include "libANGLE/Texture.h"
#include "libANGLE/renderer/ContextImpl.h"
namespace gl
{
namespace
{
template <typename ResourceType>
GLuint AllocateEmptyObject(HandleAllocator *handleAllocator, ResourceMap<ResourceType> *objectMap)
{
GLuint handle = 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>
TypedResourceManager<ResourceType, HandleAllocatorType, ImplT>::~TypedResourceManager()
{
ASSERT(mObjectMap.empty());
}
template <typename ResourceType, typename HandleAllocatorType, typename ImplT>
void TypedResourceManager<ResourceType, HandleAllocatorType, ImplT>::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>
void TypedResourceManager<ResourceType, HandleAllocatorType, ImplT>::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<HandleAllocator>;
template class ResourceManagerBase<HandleRangeAllocator>;
template class TypedResourceManager<Buffer, HandleAllocator, BufferManager>;
template class TypedResourceManager<Texture, HandleAllocator, TextureManager>;
template class TypedResourceManager<Renderbuffer, HandleAllocator, RenderbufferManager>;
template class TypedResourceManager<Sampler, HandleAllocator, SamplerManager>;
template class TypedResourceManager<Sync, HandleAllocator, SyncManager>;
template class TypedResourceManager<Framebuffer, HandleAllocator, FramebufferManager>;
template class TypedResourceManager<ProgramPipeline, HandleAllocator, ProgramPipelineManager>;
// 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 <typename ObjectType>
void ShaderProgramManager::deleteObject(const Context *context,
ResourceMap<ObjectType> *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 Context *context) 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(context, 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<GLuint>(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<unsigned>(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<GLuint>(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 Context *context) const
{
for (const auto &framebuffer : mObjectMap)
{
if (framebuffer.second)
{
framebuffer.second->invalidateCompletenessCache(context);
}
}
}
// 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);
}
} // namespace gl