#include #include #include #include namespace scwx { namespace qt { namespace gl { static const std::string logPrefix_ = "scwx::qt::gl::gl_context"; class GlContext::Impl { public: explicit Impl() : gl_ {}, shaderProgramMap_ {}, shaderProgramMutex_ {}, textureAtlas_ {GL_INVALID_INDEX}, textureMutex_ {} { } ~Impl() {} void InitializeGL(); static std::size_t GetShaderKey(std::initializer_list> shaders); gl::OpenGLFunctions gl_; QOpenGLFunctions_3_0 gl30_; bool glInitialized_ {false}; std::unordered_map> shaderProgramMap_; std::mutex shaderProgramMutex_; GLuint textureAtlas_; std::mutex textureMutex_; std::uint64_t textureBufferCount_ {}; }; GlContext::GlContext() : p(std::make_unique()) {} GlContext::~GlContext() = default; GlContext::GlContext(GlContext&&) noexcept = default; GlContext& GlContext::operator=(GlContext&&) noexcept = default; gl::OpenGLFunctions& GlContext::gl() { return p->gl_; } QOpenGLFunctions_3_0& GlContext::gl30() { return p->gl30_; } std::uint64_t GlContext::texture_buffer_count() const { return p->textureBufferCount_; } void GlContext::Impl::InitializeGL() { if (glInitialized_) { return; } gl_.initializeOpenGLFunctions(); gl30_.initializeOpenGLFunctions(); gl_.glGenTextures(1, &textureAtlas_); glInitialized_ = true; } std::shared_ptr GlContext::GetShaderProgram(const std::string& vertexPath, const std::string& fragmentPath) { return GetShaderProgram( {{GL_VERTEX_SHADER, vertexPath}, {GL_FRAGMENT_SHADER, fragmentPath}}); } std::shared_ptr GlContext::GetShaderProgram( std::initializer_list> shaders) { const auto key = Impl::GetShaderKey(shaders); std::shared_ptr shaderProgram; std::unique_lock lock(p->shaderProgramMutex_); auto it = p->shaderProgramMap_.find(key); if (it == p->shaderProgramMap_.end()) { shaderProgram = std::make_shared(p->gl_); shaderProgram->Load(shaders); p->shaderProgramMap_[key] = shaderProgram; } else { shaderProgram = it->second; } return shaderProgram; } GLuint GlContext::GetTextureAtlas() { p->InitializeGL(); std::unique_lock lock(p->textureMutex_); auto& textureAtlas = util::TextureAtlas::Instance(); if (p->textureBufferCount_ != textureAtlas.BuildCount()) { p->textureBufferCount_ = textureAtlas.BuildCount(); textureAtlas.BufferAtlas(p->gl_, p->textureAtlas_); } return p->textureAtlas_; } void GlContext::Initialize() { p->InitializeGL(); } void GlContext::StartFrame() { auto& gl = p->gl_; gl.glClearColor(0.0f, 0.0f, 0.0f, 1.0f); gl.glClear(GL_COLOR_BUFFER_BIT); } std::size_t GlContext::Impl::GetShaderKey( std::initializer_list> shaders) { std::size_t seed = 0; for (auto& shader : shaders) { boost::hash_combine(seed, shader.first); boost::hash_combine(seed, shader.second); } return seed; } } // namespace gl } // namespace qt } // namespace scwx