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);
90 delete createInfo.shaderState;
93 EglGraphicsController& controller;
94 ProgramCreateInfo createInfo;
96 uint32_t refCount{0u};
98 std::unique_ptr<GLES::Reflection> reflection{nullptr};
101 std::vector<uint8_t> uniformData;
103 // List of standalone uniform setters
104 std::vector<UniformSetter> uniformSetters;
107 ProgramImpl::ProgramImpl(const Graphics::ProgramCreateInfo& createInfo, Graphics::EglGraphicsController& controller)
109 // Create implementation
110 mImpl = std::make_unique<Impl>(controller, createInfo);
113 mImpl->reflection = std::make_unique<GLES::Reflection>(*this, controller);
116 ProgramImpl::~ProgramImpl() = default;
118 bool ProgramImpl::Destroy()
122 auto gl = mImpl->controller.GetGL();
127 gl->DeleteProgram(mImpl->glProgram);
133 bool ProgramImpl::Create()
135 // Create and link new program
136 auto gl = mImpl->controller.GetGL();
139 // Do nothing during shutdown
143 auto program = gl->CreateProgram();
145 const auto& info = mImpl->createInfo;
146 for(const auto& state : *info.shaderState)
148 const auto* shader = static_cast<const GLES::Shader*>(state.shader);
150 // Compile shader first (ignored when compiled)
151 if(shader->GetImplementation()->Compile())
153 gl->AttachShader(program, shader->GetImplementation()->GetGLShader());
156 gl->LinkProgram(program);
159 gl->GetProgramiv(program, GL_LINK_STATUS, &status);
160 if(status != GL_TRUE)
164 gl->GetProgramInfoLog(program, 4096, &size, output);
167 DALI_LOG_ERROR("glLinkProgam failed:\n%s\n", output);
168 gl->DeleteProgram(program);
172 mImpl->glProgram = program;
174 // Initialize reflection
175 mImpl->reflection->BuildVertexAttributeReflection();
176 mImpl->reflection->BuildUniformBlockReflection();
178 // populate uniform cache memory for standalone uniforms (it's not needed
179 // for real UBOs as real UBOs work with whole memory blocks)
180 auto& reflection = mImpl->reflection;
181 if(!reflection->GetStandaloneUniformExtraInfo().empty())
183 UniformBlockInfo blockInfo;
184 reflection->GetUniformBlock(0, blockInfo);
185 auto uniformCacheSize = blockInfo.size;
186 mImpl->uniformData.resize(uniformCacheSize);
188 std::fill(mImpl->uniformData.begin(), mImpl->uniformData.end(), 0);
190 BuildStandaloneUniformCache();
193 // Set up uniform block bindings
195 auto blockCount = reflection->GetUniformBlockCount();
196 for(uint32_t i = 1; i < blockCount; ++i) // Ignore emulated block at #0
198 UniformBlockInfo uboInfo{};
199 reflection->GetUniformBlock(i, uboInfo);
201 // make binding point
202 auto blockIndex = gl->GetUniformBlockIndex(program, uboInfo.name.c_str());
203 gl->UniformBlockBinding(program, blockIndex, binding++);
209 uint32_t ProgramImpl::GetGlProgram() const
211 return mImpl->glProgram;
214 uint32_t ProgramImpl::Retain()
216 return ++mImpl->refCount;
219 uint32_t ProgramImpl::Release()
221 return --mImpl->refCount;
224 uint32_t ProgramImpl::GetRefCount() const
226 return mImpl->refCount;
229 const GLES::Reflection& ProgramImpl::GetReflection() const
231 return *mImpl->reflection;
234 bool ProgramImpl::GetParameter(uint32_t parameterId, void* out)
236 if(parameterId == 1) // a magic number to access program id
238 *reinterpret_cast<decltype(&mImpl->glProgram)>(out) = mImpl->glProgram;
244 EglGraphicsController& ProgramImpl::GetController() const
246 return mImpl->controller;
249 const ProgramCreateInfo& ProgramImpl::GetCreateInfo() const
251 return mImpl->createInfo;
254 void ProgramImpl::UpdateStandaloneUniformBlock(const char* ptr)
256 const auto& reflection = GetReflection();
258 const auto& extraInfos = reflection.GetStandaloneUniformExtraInfo();
260 auto* gl = GetController().GetGL();
263 return; // Early out if no GL found
268 auto cachePtr = reinterpret_cast<char*>(mImpl->uniformData.data());
269 for(const auto& info : extraInfos)
271 auto& setter = mImpl->uniformSetters[index++];
272 auto offset = info.offset;
273 if(!memcmp4(&cachePtr[offset], &ptr[offset], info.size * info.arraySize))
277 case UniformSetter::Type::FLOAT:
279 (gl->*(setter.uniformfProc))(info.location, info.arraySize, reinterpret_cast<const float*>(&ptr[offset]));
282 case UniformSetter::Type::INT:
284 (gl->*(setter.uniformiProc))(info.location, info.arraySize, reinterpret_cast<const int*>(&ptr[offset]));
287 case UniformSetter::Type::MATRIX:
289 (gl->*(setter.uniformMatrixProc))(info.location, info.arraySize, GL_FALSE, reinterpret_cast<const float*>(&ptr[offset]));
292 case UniformSetter::Type::UNDEFINED:
299 memmove(mImpl->uniformData.data(), ptr, mImpl->uniformData.size());
302 void ProgramImpl::BuildStandaloneUniformCache()
304 const auto& reflection = GetReflection();
305 const auto& extraInfos = reflection.GetStandaloneUniformExtraInfo();
307 // Prepare pointers to the uniform setter calls
308 mImpl->uniformSetters.resize(extraInfos.size());
310 for(const auto& info : extraInfos)
312 auto type = GLTypeConversion(info.type).type;
313 mImpl->uniformSetters[index].type = UniformSetter::Type::UNDEFINED;
316 case GLType::FLOAT_VEC2:
318 mImpl->uniformSetters[index].uniformfProc = &GlAbstraction::Uniform2fv;
319 mImpl->uniformSetters[index].type = UniformSetter::Type::FLOAT;
322 case GLType::FLOAT_VEC3:
324 mImpl->uniformSetters[index].uniformfProc = &GlAbstraction::Uniform3fv;
325 mImpl->uniformSetters[index].type = UniformSetter::Type::FLOAT;
328 case GLType::FLOAT_VEC4:
330 mImpl->uniformSetters[index].uniformfProc = &GlAbstraction::Uniform4fv;
331 mImpl->uniformSetters[index].type = UniformSetter::Type::FLOAT;
334 case GLType::INT_VEC2:
336 mImpl->uniformSetters[index].uniformiProc = &GlAbstraction::Uniform2iv;
337 mImpl->uniformSetters[index].type = UniformSetter::Type::INT;
340 case GLType::INT_VEC3:
342 mImpl->uniformSetters[index].uniformiProc = &GlAbstraction::Uniform3iv;
343 mImpl->uniformSetters[index].type = UniformSetter::Type::INT;
346 case GLType::INT_VEC4:
348 mImpl->uniformSetters[index].uniformiProc = &GlAbstraction::Uniform4iv;
349 mImpl->uniformSetters[index].type = UniformSetter::Type::INT;
354 mImpl->uniformSetters[index].uniformiProc = &GlAbstraction::Uniform1iv;
355 mImpl->uniformSetters[index].type = UniformSetter::Type::INT;
359 case GLType::BOOL_VEC2:
360 case GLType::BOOL_VEC3:
361 case GLType::BOOL_VEC4:
364 mImpl->uniformSetters[index].uniformfProc = &GlAbstraction::Uniform1fv;
365 mImpl->uniformSetters[index].type = UniformSetter::Type::FLOAT;
368 case GLType::FLOAT_MAT2:
370 mImpl->uniformSetters[index].uniformMatrixProc = &GlAbstraction::UniformMatrix2fv;
371 mImpl->uniformSetters[index].type = UniformSetter::Type::MATRIX;
374 case GLType::FLOAT_MAT3:
376 mImpl->uniformSetters[index].uniformMatrixProc = &GlAbstraction::UniformMatrix3fv;
377 mImpl->uniformSetters[index].type = UniformSetter::Type::MATRIX;
380 case GLType::FLOAT_MAT4:
382 mImpl->uniformSetters[index].uniformMatrixProc = &GlAbstraction::UniformMatrix4fv;
383 mImpl->uniformSetters[index].type = UniformSetter::Type::MATRIX;
386 case GLType::SAMPLER_2D:
387 case GLType::SAMPLER_CUBE:
398 // Destroy GL resources of implementation. This should happen
399 // only if there's no more pipelines using this program so
400 // it is safe to do it in the destructor
401 if(!mProgram->Release())
407 const GLES::Reflection& Program::GetReflection() const
409 return mProgram->GetReflection();
412 EglGraphicsController& Program::GetController() const
414 return GetImplementation()->GetController();
417 const ProgramCreateInfo& Program::GetCreateInfo() const
419 return GetImplementation()->GetCreateInfo();
422 void Program::DiscardResource()
424 GetController().DiscardResource(this);
427 }; // namespace Dali::Graphics::GLES