2 * Copyright (c) 2021 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 namespace Dali::Graphics::GLES
31 using Integration::GlAbstraction;
34 * Structure stores pointer to the function
35 * which will set the uniform of particular type
41 void (GlAbstraction::*uniformfProc)(GLint, GLsizei, const float*);
42 void (GlAbstraction::*uniformiProc)(GLint, GLsizei, const int*);
43 void (GlAbstraction::*uniformMatrixProc)(GLint, GLsizei, GLboolean, const float*);
57 struct ProgramImpl::Impl
59 explicit Impl(EglGraphicsController& _controller, const ProgramCreateInfo& info)
60 : controller(_controller)
65 createInfo.shaderState = new std::vector<ShaderState>(*info.shaderState);
71 delete createInfo.shaderState;
74 EglGraphicsController& controller;
75 ProgramCreateInfo createInfo;
77 uint32_t refCount{0u};
79 std::unique_ptr<GLES::Reflection> reflection{nullptr};
82 std::vector<uint8_t> uniformData;
84 // List of standalone uniform setters
85 std::vector<UniformSetter> uniformSetters;
88 ProgramImpl::ProgramImpl(const Graphics::ProgramCreateInfo& createInfo, Graphics::EglGraphicsController& controller)
90 // Create implementation
91 mImpl = std::make_unique<Impl>(controller, createInfo);
94 mImpl->reflection = std::make_unique<GLES::Reflection>(*this, controller);
97 ProgramImpl::~ProgramImpl() = default;
99 bool ProgramImpl::Destroy()
103 auto gl = mImpl->controller.GetGL();
108 gl->DeleteProgram(mImpl->glProgram);
114 bool ProgramImpl::Create()
116 // Create and link new program
117 auto gl = mImpl->controller.GetGL();
120 // Do nothing during shutdown
124 auto program = gl->CreateProgram();
126 const auto& info = mImpl->createInfo;
127 for(const auto& state : *info.shaderState)
129 const auto* shader = static_cast<const GLES::Shader*>(state.shader);
131 // Compile shader first (ignored when compiled)
132 if(shader->Compile())
134 gl->AttachShader(program, shader->GetGLShader());
137 gl->LinkProgram(program);
140 gl->GetProgramiv(program, GL_LINK_STATUS, &status);
141 if(status != GL_TRUE)
145 gl->GetProgramInfoLog(program, 4096, &size, output);
148 // TODO: un-printf-it
149 printf("Log: %s\n", output);
150 gl->DeleteProgram(program);
154 mImpl->glProgram = program;
156 // Initialize reflection
157 mImpl->reflection->BuildUniformReflection();
158 mImpl->reflection->BuildVertexAttributeReflection();
160 // populate uniform cache memory for standalone uniforms (it's not needed
161 // for real UBOs as real UBOs work with whole memory blocks)
162 auto& reflection = mImpl->reflection;
163 if(!reflection->GetStandaloneUniformExtraInfo().empty())
165 UniformBlockInfo blockInfo;
166 mImpl->reflection->GetUniformBlock(0, blockInfo);
167 auto uniformCacheSize = blockInfo.size;
168 mImpl->uniformData.resize(uniformCacheSize);
170 std::fill(mImpl->uniformData.begin(), mImpl->uniformData.end(), 0);
172 BuildStandaloneUniformCache();
177 uint32_t ProgramImpl::GetGlProgram() const
179 return mImpl->glProgram;
182 uint32_t ProgramImpl::Retain()
184 return ++mImpl->refCount;
187 uint32_t ProgramImpl::Release()
189 return --mImpl->refCount;
192 const GLES::Reflection& ProgramImpl::GetReflection() const
194 return *mImpl->reflection;
197 bool ProgramImpl::GetParameter(uint32_t parameterId, void* out)
199 if(parameterId == 1) // a magic number to access program id
201 *reinterpret_cast<decltype(&mImpl->glProgram)>(out) = mImpl->glProgram;
207 EglGraphicsController& ProgramImpl::GetController() const
209 return mImpl->controller;
212 const ProgramCreateInfo& ProgramImpl::GetCreateInfo() const
214 return mImpl->createInfo;
217 void ProgramImpl::UpdateStandaloneUniformBlock(const char* ptr)
219 const auto& reflection = GetReflection();
221 const auto& extraInfos = reflection.GetStandaloneUniformExtraInfo();
223 auto& gl = *GetController().GetGL();
227 auto cachePtr = reinterpret_cast<char*>(mImpl->uniformData.data());
228 for(const auto& info : extraInfos)
230 auto& setter = mImpl->uniformSetters[index++];
232 auto offset = info.offset;
235 case UniformSetter::Type::FLOAT:
237 if(0 != memcmp(&cachePtr[offset], &ptr[offset], info.size * info.arraySize))
239 (gl.*(setter.uniformfProc))(info.location, info.arraySize, reinterpret_cast<const float*>(&ptr[offset]));
240 memcpy(&cachePtr[offset], &ptr[offset], info.size * info.arraySize);
244 case UniformSetter::Type::INT:
246 if(0 != memcmp(&cachePtr[offset], &ptr[offset], info.size * info.arraySize))
248 (gl.*(setter.uniformiProc))(info.location, info.arraySize, reinterpret_cast<const int*>(&ptr[offset]));
249 memcpy(&cachePtr[offset], &ptr[offset], info.size * info.arraySize);
253 case UniformSetter::Type::MATRIX:
255 if(0 != memcmp(&cachePtr[offset], &ptr[offset], info.size * info.arraySize))
257 (gl.*(setter.uniformMatrixProc))(info.location, info.arraySize, GL_FALSE, reinterpret_cast<const float*>(&ptr[offset]));
258 memcpy(&cachePtr[offset], &ptr[offset], info.size * info.arraySize);
262 case UniformSetter::Type::UNDEFINED:
269 void ProgramImpl::BuildStandaloneUniformCache()
271 const auto& reflection = GetReflection();
272 const auto& extraInfos = reflection.GetStandaloneUniformExtraInfo();
274 // Prepare pointers to the uniform setter calls
275 mImpl->uniformSetters.resize(extraInfos.size());
277 for(const auto& info : extraInfos)
279 auto type = GLTypeConversion(info.type).type;
280 mImpl->uniformSetters[index].type = UniformSetter::Type::UNDEFINED;
283 case GLType::FLOAT_VEC2:
285 mImpl->uniformSetters[index].uniformfProc = &GlAbstraction::Uniform2fv;
286 mImpl->uniformSetters[index].type = UniformSetter::Type::FLOAT;
289 case GLType::FLOAT_VEC3:
291 mImpl->uniformSetters[index].uniformfProc = &GlAbstraction::Uniform3fv;
292 mImpl->uniformSetters[index].type = UniformSetter::Type::FLOAT;
295 case GLType::FLOAT_VEC4:
297 mImpl->uniformSetters[index].uniformfProc = &GlAbstraction::Uniform4fv;
298 mImpl->uniformSetters[index].type = UniformSetter::Type::FLOAT;
301 case GLType::INT_VEC2:
303 mImpl->uniformSetters[index].uniformiProc = &GlAbstraction::Uniform2iv;
304 mImpl->uniformSetters[index].type = UniformSetter::Type::INT;
307 case GLType::INT_VEC3:
309 mImpl->uniformSetters[index].uniformiProc = &GlAbstraction::Uniform3iv;
310 mImpl->uniformSetters[index].type = UniformSetter::Type::INT;
313 case GLType::INT_VEC4:
315 mImpl->uniformSetters[index].uniformiProc = &GlAbstraction::Uniform4iv;
316 mImpl->uniformSetters[index].type = UniformSetter::Type::INT;
320 case GLType::BOOL_VEC2:
321 case GLType::BOOL_VEC3:
322 case GLType::BOOL_VEC4:
325 mImpl->uniformSetters[index].uniformfProc = &GlAbstraction::Uniform1fv;
326 mImpl->uniformSetters[index].type = UniformSetter::Type::FLOAT;
329 case GLType::FLOAT_MAT2:
331 mImpl->uniformSetters[index].uniformMatrixProc = &GlAbstraction::UniformMatrix2fv;
332 mImpl->uniformSetters[index].type = UniformSetter::Type::MATRIX;
335 case GLType::FLOAT_MAT3:
337 mImpl->uniformSetters[index].uniformMatrixProc = &GlAbstraction::UniformMatrix3fv;
338 mImpl->uniformSetters[index].type = UniformSetter::Type::MATRIX;
341 case GLType::FLOAT_MAT4:
343 mImpl->uniformSetters[index].uniformMatrixProc = &GlAbstraction::UniformMatrix4fv;
344 mImpl->uniformSetters[index].type = UniformSetter::Type::MATRIX;
347 case GLType::SAMPLER_2D:
348 case GLType::SAMPLER_CUBE:
359 // Destroy GL resources of implementation. This should happen
360 // only if there's no more pipelines using this program so
361 // it is safe to do it in the destructor
362 if(!mProgram->Release())
368 const GLES::Reflection& Program::GetReflection() const
370 return mProgram->GetReflection();
373 EglGraphicsController& Program::GetController() const
375 return GetImplementation()->GetController();
378 const ProgramCreateInfo& Program::GetCreateInfo() const
380 return GetImplementation()->GetCreateInfo();
383 void Program::DiscardResource()
385 GetController().DiscardResource(this);
388 }; // namespace Dali::Graphics::GLES