/*
- * Copyright (c) 2021 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2023 Samsung Electronics Co., Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
#include "gles-graphics-shader.h"
// INTERNAL INCLUDES
+#include <dali/integration-api/debug.h>
#include "egl-graphics-controller.h"
namespace Dali::Graphics::GLES
{
-struct Shader::Impl
+struct ShaderImpl::Impl
{
- Impl() = default;
- ~Impl() = default;
-
- std::vector<char> source{};
- uint32_t glShader{};
-};
-
-Shader::Shader(const Graphics::ShaderCreateInfo& createInfo, Graphics::EglGraphicsController& controller)
-: ShaderResource(createInfo, controller)
-{
- // push shader to the create queue
- mImpl = std::make_unique<Impl>();
+ explicit Impl(Graphics::EglGraphicsController& _controller, const Graphics::ShaderCreateInfo& _createInfo)
+ : controller(_controller)
+ {
+ createInfo.pipelineStage = _createInfo.pipelineStage;
+ createInfo.shaderlanguage = _createInfo.shaderlanguage;
+ createInfo.sourceMode = _createInfo.sourceMode;
+ createInfo.sourceSize = _createInfo.sourceSize;
+
+ // Make a copy of source code
+ source.resize(_createInfo.sourceSize);
+ std::copy(reinterpret_cast<const char*>(_createInfo.sourceData),
+ reinterpret_cast<const char*>(_createInfo.sourceData) + _createInfo.sourceSize,
+ source.data());
+
+ // Substitute pointer
+ createInfo.sourceData = source.data();
+ }
- // Make a copy of source code
- mImpl->source.resize(createInfo.sourceSize);
- std::copy(reinterpret_cast<const char*>(mCreateInfo.sourceData),
- reinterpret_cast<const char*>(mCreateInfo.sourceData) + mCreateInfo.sourceSize,
- mImpl->source.begin());
+ ~Impl(){};
- // Substitute pointer
- mCreateInfo.sourceData = mImpl->source.data();
-}
+ bool Compile()
+ {
+ auto gl = controller.GetGL();
-Shader::~Shader() = default;
+ if(!gl)
+ {
+ return false;
+ }
-bool Shader::Compile() const
-{
- auto& gl = *GetController().GetGL();
- if(!mImpl->glShader)
- {
- GLenum pipelineStage{0u};
- switch(GetCreateInfo().pipelineStage)
+ if(!glShader)
{
- case Graphics::PipelineStage::TOP_OF_PIPELINE:
- {
- break;
- }
- case Graphics::PipelineStage::VERTEX_SHADER:
+ GLenum pipelineStage{0u};
+ switch(createInfo.pipelineStage)
{
- pipelineStage = GL_VERTEX_SHADER;
- break;
+ case Graphics::PipelineStage::TOP_OF_PIPELINE:
+ {
+ break;
+ }
+ case Graphics::PipelineStage::VERTEX_SHADER:
+ {
+ pipelineStage = GL_VERTEX_SHADER;
+ break;
+ }
+ case Graphics::PipelineStage::GEOMETRY_SHADER:
+ {
+ break;
+ }
+ case Graphics::PipelineStage::FRAGMENT_SHADER:
+ {
+ pipelineStage = GL_FRAGMENT_SHADER;
+ break;
+ }
+ case Graphics::PipelineStage::COMPUTE_SHADER:
+ {
+ break;
+ }
+ case Graphics::PipelineStage::TESSELATION_CONTROL:
+ {
+ break;
+ }
+ case Graphics::PipelineStage::TESSELATION_EVALUATION:
+ {
+ break;
+ }
+ case Graphics::PipelineStage::BOTTOM_OF_PIPELINE:
+ {
+ break;
+ }
}
- case Graphics::PipelineStage::GEOMETRY_SHADER:
- {
- break;
- }
- case Graphics::PipelineStage::FRAGMENT_SHADER:
- {
- pipelineStage = GL_FRAGMENT_SHADER;
- break;
- }
- case Graphics::PipelineStage::COMPUTE_SHADER:
- {
- break;
- }
- case Graphics::PipelineStage::TESSELATION_CONTROL:
- {
- break;
- }
- case Graphics::PipelineStage::TESSELATION_EVALUATION:
- {
- break;
- }
- case Graphics::PipelineStage::BOTTOM_OF_PIPELINE:
+
+ if(pipelineStage)
{
- break;
+ auto shader = gl->CreateShader(pipelineStage);
+ const auto src = reinterpret_cast<const char*>(createInfo.sourceData);
+ GLint size = createInfo.sourceSize;
+ gl->ShaderSource(shader, 1, const_cast<const char**>(&src), &size);
+ gl->CompileShader(shader);
+
+ GLint status{0};
+ gl->GetShaderiv(shader, GL_COMPILE_STATUS, &status);
+ if(status != GL_TRUE)
+ {
+ char output[4096];
+ GLsizei size{0u};
+ gl->GetShaderInfoLog(shader, 4096, &size, output);
+ DALI_LOG_ERROR("Code: %s\n", reinterpret_cast<const char*>(createInfo.sourceData));
+ DALI_LOG_ERROR("glCompileShader() failed: \n%s\n", output);
+ gl->DeleteShader(shader);
+ return false;
+ }
+ glShader = shader;
}
+ return true;
}
+ return true;
+ }
- if(pipelineStage)
- {
- auto shader = gl.CreateShader(pipelineStage);
- const auto src = reinterpret_cast<const char*>(GetCreateInfo().sourceData);
- GLint size = GetCreateInfo().sourceSize;
- gl.ShaderSource(shader, 1, const_cast<const char**>(&src), &size);
- gl.CompileShader(shader);
-
- GLint status{0};
- gl.GetShaderiv(shader, GL_COMPILE_STATUS, &status);
- if(status != GL_TRUE)
- {
- char output[4096];
- GLsizei size{0u};
- gl.GetShaderInfoLog(shader, 4096, &size, output);
- printf("Code: %s\n", reinterpret_cast<const char*>(GetCreateInfo().sourceData));
- printf("Log: %s\n", output);
- gl.DeleteShader(shader);
- return false;
- }
+ void Destroy()
+ {
+ auto gl = controller.GetGL();
- // TODO: check error
- mImpl->glShader = shader;
+ if(gl && glShader)
+ {
+ gl->DeleteShader(glShader);
+ glShader = 0;
}
- return true;
}
- return true;
+
+ EglGraphicsController& controller;
+ ShaderCreateInfo createInfo;
+ std::vector<char> source{};
+
+ uint32_t glShader{};
+ uint32_t refCount{0u};
+ uint32_t flushCount{0u}; ///< Number of frames at refCount=0
+};
+
+ShaderImpl::ShaderImpl(const Graphics::ShaderCreateInfo& createInfo, Graphics::EglGraphicsController& controller)
+{
+ mImpl = std::make_unique<Impl>(controller, createInfo);
+}
+
+ShaderImpl::~ShaderImpl()
+{
+ if(!mImpl->controller.IsShuttingDown())
+ {
+ mImpl->Destroy();
+ }
+}
+
+uint32_t ShaderImpl::Retain()
+{
+ mImpl->flushCount = 0;
+ return ++mImpl->refCount;
+}
+
+uint32_t ShaderImpl::Release()
+{
+ uint32_t remainingCount = --mImpl->refCount;
+ mImpl->flushCount = 0;
+ return remainingCount;
+}
+
+[[nodiscard]] uint32_t ShaderImpl::GetRefCount() const
+{
+ return mImpl->refCount;
+}
+
+[[nodiscard]] uint32_t ShaderImpl::IncreaseFlushCount()
+{
+ return ++mImpl->flushCount;
}
-uint32_t Shader::GetGLShader() const
+[[nodiscard]] uint32_t ShaderImpl::GetFlushCount() const
+{
+ return mImpl->flushCount;
+}
+
+/**
+ * @brief Compiles shader
+ *
+ * @return True on success
+ */
+[[nodiscard]] bool ShaderImpl::Compile() const
+{
+ return mImpl->Compile();
+}
+
+[[nodiscard]] uint32_t ShaderImpl::GetGLShader() const
{
return mImpl->glShader;
}
-void Shader::DestroyResource()
+const ShaderCreateInfo& ShaderImpl::GetCreateInfo() const
{
- if(mImpl->glShader)
+ return mImpl->createInfo;
+}
+
+[[nodiscard]] EglGraphicsController& ShaderImpl::GetController() const
+{
+ return mImpl->controller;
+}
+
+Shader::~Shader()
+{
+ if(!mShader->Release())
{
- auto gl = GetController().GetGL();
- if(!gl)
- {
- return;
- }
- gl->DeleteShader(mImpl->glShader);
+ GetImplementation()->GetController().GetPipelineCache().MarkShaderCacheFlushRequired();
}
}
+[[nodiscard]] const ShaderCreateInfo& Shader::GetCreateInfo() const
+{
+ return GetImplementation()->GetCreateInfo();
+}
+
void Shader::DiscardResource()
{
- GetController().DiscardResource(this);
+ auto& controller = GetImplementation()->GetController();
+ if(!controller.IsShuttingDown())
+ {
+ controller.DiscardResource(this);
+ }
}
-} // namespace Dali::Graphics::GLES
\ No newline at end of file
+} // namespace Dali::Graphics::GLES