// Copyright (c) 2023 Dominic Masters // // This software is released under the MIT License. // https://opensource.org/licenses/MIT #pragma once #include "display/shader/Shader.hpp" namespace Dawn { typedef int64_t shaderlock_t; typedef int16_t shaderid_t; class ShaderManager { private: int32_t nextId; shaderlock_t nextLock; std::map> shaders; std::map shaderLocks; std::map> shaderLocksByShader; /** * Returns the shader id for the given shader type, or -1 if it is not * loaded. * * @return The shader id for the shader, or -1 if it is not loaded. */ template shaderid_t getShaderId() { auto it = shaders.begin(); while(it != shaders.end()) { auto asT = std::dynamic_pointer_cast(it->second); if(asT != nullptr) return asT->shaderId; ++it; } return -1; } public: /** * Creates a new shader manager. */ ShaderManager(); /** * Locks a shader of the given type. If the shader is not already loaded, * it will be loaded. If the shader is already loaded, it will be * returned. * * @return The shader lock for the shader of the given type. */ template shaderlock_t lockShader() { auto shaderId = this->getShaderId(); if(shaderId == -1) { auto shader = std::make_shared(); shader->compile(); shader->shaderId = this->nextId++; this->shaders[shader->shaderId] = shader; shaderId = shader->shaderId; } shaderlock_t lock = this->nextLock++; this->shaderLocks[lock] = shaderId; this->shaderLocksByShader[shaderId].push_back(lock); return lock; } /** * Returns the shader for the given lock. * * @param lock The shader lock. * @return The shader for the given lock. */ template std::shared_ptr getShader(shaderlock_t lock) { auto shaderId = this->shaderLocks[lock]; return std::static_pointer_cast(this->shaders[shaderId]); } /** * Releases the shader for the given lock. This will unload any shader * that is no longer in use. * * @param lock Lock to release. */ template void releaseShader(shaderlock_t lock) { auto shaderId = this->shaderLocks[lock]; this->shaderLocks.erase(lock); auto& locks = this->shaderLocksByShader[shaderId]; auto it = std::find(locks.begin(), locks.end(), lock); if(it != locks.end()) locks.erase(it); if(locks.size() == 0) { this->shaderLocksByShader.erase(shaderId); this->shaders.erase(shaderId); } } /** * Destroys the shader manager. */ ~ShaderManager(); }; }