/*
- * 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 <dali/integration-api/gl-abstraction.h>
#include <dali/integration-api/gl-defines.h>
+#if defined(DEBUG_ENABLED)
+Debug::Filter* gGraphicsProgramLogFilter = Debug::Filter::New(Debug::NoLogging, false, "LOG_GRAPHICS_PROGRAM");
+#endif
+
namespace Dali::Graphics::GLES
{
+using Integration::GlAbstraction;
+
+/**
+ * Memory compare working on 4-byte types. Since all types used in shaders are
+ * size of 4*N then no need for size and alignment checks.
+ */
+template<class A, class B>
+inline bool memcmp4(A* a, B* b, uint32_t size)
+{
+ auto* pa = reinterpret_cast<const uint32_t*>(a);
+ auto* pb = reinterpret_cast<const uint32_t*>(b);
+ size >>= 2;
+ while(size-- && *pa++ == *pb++)
+ ;
+ return (-1u == size);
+};
+
+/**
+ * Structure stores pointer to the function
+ * which will set the uniform of particular type
+ */
+struct UniformSetter
+{
+ union
+ {
+ void (GlAbstraction::*uniformfProc)(GLint, GLsizei, const float*);
+ void (GlAbstraction::*uniformiProc)(GLint, GLsizei, const int*);
+ void (GlAbstraction::*uniformMatrixProc)(GLint, GLsizei, GLboolean, const float*);
+ };
+
+ enum class Type
+ {
+ UNDEFINED = 0,
+ FLOAT,
+ INT,
+ MATRIX
+ };
+
+ Type type;
+};
+
struct ProgramImpl::Impl
{
explicit Impl(EglGraphicsController& _controller, const ProgramCreateInfo& info)
uint32_t refCount{0u};
std::unique_ptr<GLES::Reflection> reflection{nullptr};
+
+ // Uniform cache
+ std::vector<uint8_t> uniformData;
+
+ // List of standalone uniform setters
+ std::vector<UniformSetter> uniformSetters;
};
ProgramImpl::ProgramImpl(const Graphics::ProgramCreateInfo& createInfo, Graphics::EglGraphicsController& controller)
{
if(mImpl->glProgram)
{
- auto& gl = *mImpl->controller.GetGL();
- gl.DeleteProgram(mImpl->glProgram);
+ auto gl = mImpl->controller.GetGL();
+ if(!gl)
+ {
+ return false;
+ }
+ gl->DeleteProgram(mImpl->glProgram);
return true;
}
return false;
bool ProgramImpl::Create()
{
// Create and link new program
- auto& gl = *mImpl->controller.GetGL();
- auto program = gl.CreateProgram();
+ auto gl = mImpl->controller.GetGL();
+ if(!gl)
+ {
+ // Do nothing during shutdown
+ return false;
+ }
+
+ auto program = gl->CreateProgram();
const auto& info = mImpl->createInfo;
for(const auto& state : *info.shaderState)
const auto* shader = static_cast<const GLES::Shader*>(state.shader);
// Compile shader first (ignored when compiled)
- shader->Compile();
-
- gl.AttachShader(program, shader->GetGLShader());
+ if(shader->GetImplementation()->Compile())
+ {
+ gl->AttachShader(program, shader->GetImplementation()->GetGLShader());
+ }
}
- gl.LinkProgram(program);
+ gl->LinkProgram(program);
GLint status{0};
- gl.GetProgramiv(program, GL_LINK_STATUS, &status);
+ gl->GetProgramiv(program, GL_LINK_STATUS, &status);
if(status != GL_TRUE)
{
char output[4096];
GLsizei size{0u};
- gl.GetProgramInfoLog(program, 4096, &size, output);
+ gl->GetProgramInfoLog(program, 4096, &size, output);
// log on error
- // TODO: un-printf-it
- printf("Log: %s\n", output);
- gl.DeleteProgram(program);
+ DALI_LOG_ERROR("glLinkProgam failed:\n%s\n", output);
+ gl->DeleteProgram(program);
return false;
}
mImpl->glProgram = program;
// Initialize reflection
- mImpl->reflection->BuildUniformReflection();
mImpl->reflection->BuildVertexAttributeReflection();
+ mImpl->reflection->BuildUniformBlockReflection();
+
+ // populate uniform cache memory for standalone uniforms (it's not needed
+ // for real UBOs as real UBOs work with whole memory blocks)
+ auto& reflection = mImpl->reflection;
+ if(!reflection->GetStandaloneUniformExtraInfo().empty())
+ {
+ UniformBlockInfo blockInfo;
+ reflection->GetUniformBlock(0, blockInfo);
+ auto uniformCacheSize = blockInfo.size;
+ mImpl->uniformData.resize(uniformCacheSize);
+
+ std::fill(mImpl->uniformData.begin(), mImpl->uniformData.end(), 0);
+
+ BuildStandaloneUniformCache();
+ }
+
+ // Set up uniform block bindings
+ auto binding = 0u;
+ auto blockCount = reflection->GetUniformBlockCount();
+ for(uint32_t i = 1; i < blockCount; ++i) // Ignore emulated block at #0
+ {
+ UniformBlockInfo uboInfo{};
+ reflection->GetUniformBlock(i, uboInfo);
+
+ // make binding point
+ auto blockIndex = gl->GetUniformBlockIndex(program, uboInfo.name.c_str());
+ gl->UniformBlockBinding(program, blockIndex, binding++);
+ }
return true;
}
return --mImpl->refCount;
}
+uint32_t ProgramImpl::GetRefCount() const
+{
+ return mImpl->refCount;
+}
+
const GLES::Reflection& ProgramImpl::GetReflection() const
{
return *mImpl->reflection;
return mImpl->createInfo;
}
+void ProgramImpl::UpdateStandaloneUniformBlock(const char* ptr)
+{
+ const auto& reflection = GetReflection();
+
+ const auto& extraInfos = reflection.GetStandaloneUniformExtraInfo();
+
+ auto& gl = *GetController().GetGL();
+
+ // Set uniforms
+ int index = 0;
+ auto cachePtr = reinterpret_cast<char*>(mImpl->uniformData.data());
+ for(const auto& info : extraInfos)
+ {
+ auto& setter = mImpl->uniformSetters[index++];
+ auto offset = info.offset;
+ if(!memcmp4(&cachePtr[offset], &ptr[offset], info.size * info.arraySize))
+ {
+ switch(setter.type)
+ {
+ case UniformSetter::Type::FLOAT:
+ {
+ (gl.*(setter.uniformfProc))(info.location, info.arraySize, reinterpret_cast<const float*>(&ptr[offset]));
+ break;
+ }
+ case UniformSetter::Type::INT:
+ {
+ (gl.*(setter.uniformiProc))(info.location, info.arraySize, reinterpret_cast<const int*>(&ptr[offset]));
+ break;
+ }
+ case UniformSetter::Type::MATRIX:
+ {
+ (gl.*(setter.uniformMatrixProc))(info.location, info.arraySize, GL_FALSE, reinterpret_cast<const float*>(&ptr[offset]));
+ break;
+ }
+ case UniformSetter::Type::UNDEFINED:
+ {
+ }
+ }
+ }
+ }
+ // Update caches
+ memmove(mImpl->uniformData.data(), ptr, mImpl->uniformData.size());
+}
+
+void ProgramImpl::BuildStandaloneUniformCache()
+{
+ const auto& reflection = GetReflection();
+ const auto& extraInfos = reflection.GetStandaloneUniformExtraInfo();
+
+ // Prepare pointers to the uniform setter calls
+ mImpl->uniformSetters.resize(extraInfos.size());
+ int index = 0;
+ for(const auto& info : extraInfos)
+ {
+ auto type = GLTypeConversion(info.type).type;
+ mImpl->uniformSetters[index].type = UniformSetter::Type::UNDEFINED;
+ switch(type)
+ {
+ case GLType::FLOAT_VEC2:
+ {
+ mImpl->uniformSetters[index].uniformfProc = &GlAbstraction::Uniform2fv;
+ mImpl->uniformSetters[index].type = UniformSetter::Type::FLOAT;
+ break;
+ }
+ case GLType::FLOAT_VEC3:
+ {
+ mImpl->uniformSetters[index].uniformfProc = &GlAbstraction::Uniform3fv;
+ mImpl->uniformSetters[index].type = UniformSetter::Type::FLOAT;
+ break;
+ }
+ case GLType::FLOAT_VEC4:
+ {
+ mImpl->uniformSetters[index].uniformfProc = &GlAbstraction::Uniform4fv;
+ mImpl->uniformSetters[index].type = UniformSetter::Type::FLOAT;
+ break;
+ }
+ case GLType::INT_VEC2:
+ {
+ mImpl->uniformSetters[index].uniformiProc = &GlAbstraction::Uniform2iv;
+ mImpl->uniformSetters[index].type = UniformSetter::Type::INT;
+ break;
+ }
+ case GLType::INT_VEC3:
+ {
+ mImpl->uniformSetters[index].uniformiProc = &GlAbstraction::Uniform3iv;
+ mImpl->uniformSetters[index].type = UniformSetter::Type::INT;
+ break;
+ }
+ case GLType::INT_VEC4:
+ {
+ mImpl->uniformSetters[index].uniformiProc = &GlAbstraction::Uniform4iv;
+ mImpl->uniformSetters[index].type = UniformSetter::Type::INT;
+ break;
+ }
+ case GLType::INT:
+ {
+ mImpl->uniformSetters[index].uniformiProc = &GlAbstraction::Uniform1iv;
+ mImpl->uniformSetters[index].type = UniformSetter::Type::INT;
+ break;
+ }
+ case GLType::BOOL:
+ case GLType::BOOL_VEC2:
+ case GLType::BOOL_VEC3:
+ case GLType::BOOL_VEC4:
+ case GLType::FLOAT:
+ {
+ mImpl->uniformSetters[index].uniformfProc = &GlAbstraction::Uniform1fv;
+ mImpl->uniformSetters[index].type = UniformSetter::Type::FLOAT;
+ break;
+ }
+ case GLType::FLOAT_MAT2:
+ {
+ mImpl->uniformSetters[index].uniformMatrixProc = &GlAbstraction::UniformMatrix2fv;
+ mImpl->uniformSetters[index].type = UniformSetter::Type::MATRIX;
+ break;
+ }
+ case GLType::FLOAT_MAT3:
+ {
+ mImpl->uniformSetters[index].uniformMatrixProc = &GlAbstraction::UniformMatrix3fv;
+ mImpl->uniformSetters[index].type = UniformSetter::Type::MATRIX;
+ break;
+ }
+ case GLType::FLOAT_MAT4:
+ {
+ mImpl->uniformSetters[index].uniformMatrixProc = &GlAbstraction::UniformMatrix4fv;
+ mImpl->uniformSetters[index].type = UniformSetter::Type::MATRIX;
+ break;
+ }
+ case GLType::SAMPLER_2D:
+ case GLType::SAMPLER_CUBE:
+ default:
+ {
+ }
+ }
+ index++;
+ }
+}
+
Program::~Program()
{
// Destroy GL resources of implementation. This should happen