2 * Copyright (c) 2024 Samsung Electronics Co., Ltd.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
18 #include "gles-graphics-program.h"
21 #include "egl-graphics-controller.h"
22 #include "gles-graphics-reflection.h"
23 #include "gles-graphics-shader.h"
26 #include <dali/integration-api/gl-abstraction.h>
27 #include <dali/integration-api/gl-defines.h>
29 #if defined(DEBUG_ENABLED)
30 Debug::Filter* gGraphicsProgramLogFilter = Debug::Filter::New(Debug::NoLogging, false, "LOG_GRAPHICS_PROGRAM");
33 namespace Dali::Graphics::GLES
35 using Integration::GlAbstraction;
38 * Memory compare working on 4-byte types. Since all types used in shaders are
39 * size of 4*N then no need for size and alignment checks.
41 template<class A, class B>
42 inline bool memcmp4(A* a, B* b, uint32_t size)
44 auto* pa = reinterpret_cast<const uint32_t*>(a);
45 auto* pb = reinterpret_cast<const uint32_t*>(b);
47 while(size-- && *pa++ == *pb++)
53 * Structure stores pointer to the function
54 * which will set the uniform of particular type
60 void (GlAbstraction::*uniformfProc)(GLint, GLsizei, const float*);
61 void (GlAbstraction::*uniformiProc)(GLint, GLsizei, const int*);
62 void (GlAbstraction::*uniformMatrixProc)(GLint, GLsizei, GLboolean, const float*);
76 struct ProgramImpl::Impl
78 explicit Impl(EglGraphicsController& _controller, const ProgramCreateInfo& info)
79 : controller(_controller)
84 createInfo.shaderState = new std::vector<ShaderState>(*info.shaderState);
87 // Create new reference of std::string_view.
88 name = std::string(info.name);
89 createInfo.name = name;
94 delete createInfo.shaderState;
97 EglGraphicsController& controller;
98 ProgramCreateInfo createInfo;
100 uint32_t glProgram{};
101 uint32_t refCount{0u};
103 std::unique_ptr<GLES::Reflection> reflection{nullptr};
106 std::vector<uint8_t> uniformData;
108 // List of standalone uniform setters
109 std::vector<UniformSetter> uniformSetters;
112 ProgramImpl::ProgramImpl(const Graphics::ProgramCreateInfo& createInfo, Graphics::EglGraphicsController& controller)
114 // Create implementation
115 mImpl = std::make_unique<Impl>(controller, createInfo);
118 mImpl->reflection = std::make_unique<GLES::Reflection>(*this, controller);
121 ProgramImpl::~ProgramImpl() = default;
123 bool ProgramImpl::Destroy()
127 auto gl = mImpl->controller.GetGL();
132 gl->DeleteProgram(mImpl->glProgram);
138 bool ProgramImpl::Create()
140 // Create and link new program
141 auto gl = mImpl->controller.GetGL();
144 // Do nothing during shutdown
148 auto program = gl->CreateProgram();
150 DALI_LOG_INFO(gGraphicsProgramLogFilter, Debug::Verbose, "Program[%s] create program id : %u\n", mImpl->name.c_str(), program);
152 const auto& info = mImpl->createInfo;
153 for(const auto& state : *info.shaderState)
155 const auto* shader = static_cast<const GLES::Shader*>(state.shader);
157 // Compile shader first (ignored when compiled)
158 if(shader->GetImplementation()->Compile())
160 auto shaderId = shader->GetImplementation()->GetGLShader();
161 DALI_LOG_INFO(gGraphicsProgramLogFilter, Debug::Verbose, "Program[%s] attach shader : %u\n", mImpl->name.c_str(), shaderId);
162 gl->AttachShader(program, shaderId);
166 DALI_LOG_INFO(gGraphicsProgramLogFilter, Debug::Verbose, "Program[%s] call glLinkProgram\n", mImpl->name.c_str());
167 gl->LinkProgram(program);
170 gl->GetProgramiv(program, GL_LINK_STATUS, &status);
171 if(status != GL_TRUE)
175 gl->GetProgramInfoLog(program, 4096, &size, output);
178 DALI_LOG_ERROR("glLinkProgam[%s] failed:\n%s\n", mImpl->name.c_str(), output);
179 gl->DeleteProgram(program);
183 mImpl->glProgram = program;
185 // Initialize reflection
186 mImpl->reflection->BuildVertexAttributeReflection();
187 mImpl->reflection->BuildUniformBlockReflection();
189 // populate uniform cache memory for standalone uniforms (it's not needed
190 // for real UBOs as real UBOs work with whole memory blocks)
191 auto& reflection = mImpl->reflection;
192 if(!reflection->GetStandaloneUniformExtraInfo().empty())
194 UniformBlockInfo blockInfo;
195 reflection->GetUniformBlock(0, blockInfo);
196 auto uniformCacheSize = blockInfo.size;
197 mImpl->uniformData.resize(uniformCacheSize);
199 std::fill(mImpl->uniformData.begin(), mImpl->uniformData.end(), 0);
201 BuildStandaloneUniformCache();
204 // Set up uniform block bindings
206 auto blockCount = reflection->GetUniformBlockCount();
207 for(uint32_t i = 1; i < blockCount; ++i) // Ignore emulated block at #0
209 UniformBlockInfo uboInfo{};
210 reflection->GetUniformBlock(i, uboInfo);
212 // make binding point
213 auto blockIndex = gl->GetUniformBlockIndex(program, uboInfo.name.c_str());
214 gl->UniformBlockBinding(program, blockIndex, binding++);
220 uint32_t ProgramImpl::GetGlProgram() const
222 return mImpl->glProgram;
225 uint32_t ProgramImpl::Retain()
227 return ++mImpl->refCount;
230 uint32_t ProgramImpl::Release()
232 return --mImpl->refCount;
235 uint32_t ProgramImpl::GetRefCount() const
237 return mImpl->refCount;
240 const GLES::Reflection& ProgramImpl::GetReflection() const
242 return *mImpl->reflection;
245 bool ProgramImpl::GetParameter(uint32_t parameterId, void* out)
247 if(parameterId == 1) // a magic number to access program id
249 *reinterpret_cast<decltype(&mImpl->glProgram)>(out) = mImpl->glProgram;
255 EglGraphicsController& ProgramImpl::GetController() const
257 return mImpl->controller;
260 const ProgramCreateInfo& ProgramImpl::GetCreateInfo() const
262 return mImpl->createInfo;
265 void ProgramImpl::UpdateStandaloneUniformBlock(const char* ptr)
267 const auto& reflection = GetReflection();
269 const auto& extraInfos = reflection.GetStandaloneUniformExtraInfo();
271 auto* gl = GetController().GetGL();
274 return; // Early out if no GL found
279 auto cachePtr = reinterpret_cast<char*>(mImpl->uniformData.data());
280 for(const auto& info : extraInfos)
282 auto& setter = mImpl->uniformSetters[index++];
283 auto offset = info.offset;
284 if(!memcmp4(&cachePtr[offset], &ptr[offset], info.size * info.arraySize))
288 case UniformSetter::Type::FLOAT:
290 (gl->*(setter.uniformfProc))(info.location, info.arraySize, reinterpret_cast<const float*>(&ptr[offset]));
293 case UniformSetter::Type::INT:
295 (gl->*(setter.uniformiProc))(info.location, info.arraySize, reinterpret_cast<const int*>(&ptr[offset]));
298 case UniformSetter::Type::MATRIX:
300 (gl->*(setter.uniformMatrixProc))(info.location, info.arraySize, GL_FALSE, reinterpret_cast<const float*>(&ptr[offset]));
303 case UniformSetter::Type::UNDEFINED:
310 memmove(mImpl->uniformData.data(), ptr, mImpl->uniformData.size());
313 void ProgramImpl::BuildStandaloneUniformCache()
315 const auto& reflection = GetReflection();
316 const auto& extraInfos = reflection.GetStandaloneUniformExtraInfo();
318 // Prepare pointers to the uniform setter calls
319 mImpl->uniformSetters.resize(extraInfos.size());
321 for(const auto& info : extraInfos)
323 auto type = GLTypeConversion(info.type).type;
324 mImpl->uniformSetters[index].type = UniformSetter::Type::UNDEFINED;
327 case GLType::FLOAT_VEC2:
329 mImpl->uniformSetters[index].uniformfProc = &GlAbstraction::Uniform2fv;
330 mImpl->uniformSetters[index].type = UniformSetter::Type::FLOAT;
333 case GLType::FLOAT_VEC3:
335 mImpl->uniformSetters[index].uniformfProc = &GlAbstraction::Uniform3fv;
336 mImpl->uniformSetters[index].type = UniformSetter::Type::FLOAT;
339 case GLType::FLOAT_VEC4:
341 mImpl->uniformSetters[index].uniformfProc = &GlAbstraction::Uniform4fv;
342 mImpl->uniformSetters[index].type = UniformSetter::Type::FLOAT;
345 case GLType::INT_VEC2:
347 mImpl->uniformSetters[index].uniformiProc = &GlAbstraction::Uniform2iv;
348 mImpl->uniformSetters[index].type = UniformSetter::Type::INT;
351 case GLType::INT_VEC3:
353 mImpl->uniformSetters[index].uniformiProc = &GlAbstraction::Uniform3iv;
354 mImpl->uniformSetters[index].type = UniformSetter::Type::INT;
357 case GLType::INT_VEC4:
359 mImpl->uniformSetters[index].uniformiProc = &GlAbstraction::Uniform4iv;
360 mImpl->uniformSetters[index].type = UniformSetter::Type::INT;
365 mImpl->uniformSetters[index].uniformiProc = &GlAbstraction::Uniform1iv;
366 mImpl->uniformSetters[index].type = UniformSetter::Type::INT;
370 case GLType::BOOL_VEC2:
371 case GLType::BOOL_VEC3:
372 case GLType::BOOL_VEC4:
375 mImpl->uniformSetters[index].uniformfProc = &GlAbstraction::Uniform1fv;
376 mImpl->uniformSetters[index].type = UniformSetter::Type::FLOAT;
379 case GLType::FLOAT_MAT2:
381 mImpl->uniformSetters[index].uniformMatrixProc = &GlAbstraction::UniformMatrix2fv;
382 mImpl->uniformSetters[index].type = UniformSetter::Type::MATRIX;
385 case GLType::FLOAT_MAT3:
387 mImpl->uniformSetters[index].uniformMatrixProc = &GlAbstraction::UniformMatrix3fv;
388 mImpl->uniformSetters[index].type = UniformSetter::Type::MATRIX;
391 case GLType::FLOAT_MAT4:
393 mImpl->uniformSetters[index].uniformMatrixProc = &GlAbstraction::UniformMatrix4fv;
394 mImpl->uniformSetters[index].type = UniformSetter::Type::MATRIX;
397 case GLType::SAMPLER_2D:
398 case GLType::SAMPLER_CUBE:
409 // Destroy GL resources of implementation. This should happen
410 // only if there's no more pipelines using this program so
411 // it is safe to do it in the destructor
412 if(!mProgram->Release())
418 const GLES::Reflection& Program::GetReflection() const
420 return mProgram->GetReflection();
423 EglGraphicsController& Program::GetController() const
425 return GetImplementation()->GetController();
428 const ProgramCreateInfo& Program::GetCreateInfo() const
430 return GetImplementation()->GetCreateInfo();
433 void Program::DiscardResource()
435 GetController().DiscardResource(this);
438 }; // namespace Dali::Graphics::GLES