DALi Version 2.2.53
[platform/core/uifw/dali-adaptor.git] / dali / internal / graphics / gles-impl / gles-graphics-program.cpp
1 /*
2  * Copyright (c) 2023 Samsung Electronics Co., Ltd.
3  *
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
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
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.
15  */
16
17 // CLASS HEADER
18 #include "gles-graphics-program.h"
19
20 // INTERNAL HEADERS
21 #include "egl-graphics-controller.h"
22 #include "gles-graphics-reflection.h"
23 #include "gles-graphics-shader.h"
24
25 // EXTERNAL HEADERS
26 #include <dali/integration-api/gl-abstraction.h>
27 #include <dali/integration-api/gl-defines.h>
28
29 #if defined(DEBUG_ENABLED)
30 Debug::Filter* gGraphicsProgramLogFilter = Debug::Filter::New(Debug::NoLogging, false, "LOG_GRAPHICS_PROGRAM");
31 #endif
32
33 namespace Dali::Graphics::GLES
34 {
35 using Integration::GlAbstraction;
36
37 /**
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.
40  */
41 template<class A, class B>
42 inline bool memcmp4(A* a, B* b, uint32_t size)
43 {
44   auto* pa = reinterpret_cast<const uint32_t*>(a);
45   auto* pb = reinterpret_cast<const uint32_t*>(b);
46   size >>= 2;
47   while(size-- && *pa++ == *pb++)
48     ;
49   return (-1u == size);
50 };
51
52 /**
53  * Structure stores pointer to the function
54  * which will set the uniform of particular type
55  */
56 struct UniformSetter
57 {
58   union
59   {
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*);
63   };
64
65   enum class Type
66   {
67     UNDEFINED = 0,
68     FLOAT,
69     INT,
70     MATRIX
71   };
72
73   Type type;
74 };
75
76 struct ProgramImpl::Impl
77 {
78   explicit Impl(EglGraphicsController& _controller, const ProgramCreateInfo& info)
79   : controller(_controller)
80   {
81     createInfo = info;
82     if(info.shaderState)
83     {
84       createInfo.shaderState = new std::vector<ShaderState>(*info.shaderState);
85     }
86   }
87
88   ~Impl()
89   {
90     delete createInfo.shaderState;
91   }
92
93   EglGraphicsController& controller;
94   ProgramCreateInfo      createInfo;
95   uint32_t               glProgram{};
96   uint32_t               refCount{0u};
97
98   std::unique_ptr<GLES::Reflection> reflection{nullptr};
99
100   // Uniform cache
101   std::vector<uint8_t> uniformData;
102
103   // List of standalone uniform setters
104   std::vector<UniformSetter> uniformSetters;
105 };
106
107 ProgramImpl::ProgramImpl(const Graphics::ProgramCreateInfo& createInfo, Graphics::EglGraphicsController& controller)
108 {
109   // Create implementation
110   mImpl = std::make_unique<Impl>(controller, createInfo);
111
112   // Build reflection
113   mImpl->reflection = std::make_unique<GLES::Reflection>(*this, controller);
114 }
115
116 ProgramImpl::~ProgramImpl() = default;
117
118 bool ProgramImpl::Destroy()
119 {
120   if(mImpl->glProgram)
121   {
122     auto gl = mImpl->controller.GetGL();
123     if(!gl)
124     {
125       return false;
126     }
127     gl->DeleteProgram(mImpl->glProgram);
128     return true;
129   }
130   return false;
131 }
132
133 bool ProgramImpl::Create()
134 {
135   // Create and link new program
136   auto gl = mImpl->controller.GetGL();
137   if(!gl)
138   {
139     // Do nothing during shutdown
140     return false;
141   }
142
143   auto program = gl->CreateProgram();
144
145   const auto& info = mImpl->createInfo;
146   for(const auto& state : *info.shaderState)
147   {
148     const auto* shader = static_cast<const GLES::Shader*>(state.shader);
149
150     // Compile shader first (ignored when compiled)
151     if(shader->Compile())
152     {
153       gl->AttachShader(program, shader->GetGLShader());
154     }
155   }
156   gl->LinkProgram(program);
157
158   GLint status{0};
159   gl->GetProgramiv(program, GL_LINK_STATUS, &status);
160   if(status != GL_TRUE)
161   {
162     char    output[4096];
163     GLsizei size{0u};
164     gl->GetProgramInfoLog(program, 4096, &size, output);
165
166     // log on error
167     DALI_LOG_ERROR("glLinkProgam failed:\n%s\n", output);
168     gl->DeleteProgram(program);
169     return false;
170   }
171
172   mImpl->glProgram = program;
173
174   // Initialize reflection
175   mImpl->reflection->BuildVertexAttributeReflection();
176   mImpl->reflection->BuildUniformBlockReflection();
177
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())
182   {
183     UniformBlockInfo blockInfo;
184     reflection->GetUniformBlock(0, blockInfo);
185     auto uniformCacheSize = blockInfo.size;
186     mImpl->uniformData.resize(uniformCacheSize);
187
188     std::fill(mImpl->uniformData.begin(), mImpl->uniformData.end(), 0);
189
190     BuildStandaloneUniformCache();
191   }
192
193   // Set up uniform block bindings
194   auto binding    = 0u;
195   auto blockCount = reflection->GetUniformBlockCount();
196   for(uint32_t i = 1; i < blockCount; ++i) // Ignore emulated block at #0
197   {
198     UniformBlockInfo uboInfo{};
199     reflection->GetUniformBlock(i, uboInfo);
200
201     // make binding point
202     auto blockIndex = gl->GetUniformBlockIndex(program, uboInfo.name.c_str());
203     gl->UniformBlockBinding(program, blockIndex, binding++);
204   }
205
206   return true;
207 }
208
209 uint32_t ProgramImpl::GetGlProgram() const
210 {
211   return mImpl->glProgram;
212 }
213
214 uint32_t ProgramImpl::Retain()
215 {
216   return ++mImpl->refCount;
217 }
218
219 uint32_t ProgramImpl::Release()
220 {
221   return --mImpl->refCount;
222 }
223
224 uint32_t ProgramImpl::GetRefCount() const
225 {
226   return mImpl->refCount;
227 }
228
229 const GLES::Reflection& ProgramImpl::GetReflection() const
230 {
231   return *mImpl->reflection;
232 }
233
234 bool ProgramImpl::GetParameter(uint32_t parameterId, void* out)
235 {
236   if(parameterId == 1) // a magic number to access program id
237   {
238     *reinterpret_cast<decltype(&mImpl->glProgram)>(out) = mImpl->glProgram;
239     return true;
240   }
241   return false;
242 }
243
244 EglGraphicsController& ProgramImpl::GetController() const
245 {
246   return mImpl->controller;
247 }
248
249 const ProgramCreateInfo& ProgramImpl::GetCreateInfo() const
250 {
251   return mImpl->createInfo;
252 }
253
254 void ProgramImpl::UpdateStandaloneUniformBlock(const char* ptr)
255 {
256   const auto& reflection = GetReflection();
257
258   const auto& extraInfos = reflection.GetStandaloneUniformExtraInfo();
259
260   auto& gl = *GetController().GetGL();
261
262   // Set uniforms
263   int  index    = 0;
264   auto cachePtr = reinterpret_cast<char*>(mImpl->uniformData.data());
265   for(const auto& info : extraInfos)
266   {
267     auto& setter = mImpl->uniformSetters[index++];
268     auto  offset = info.offset;
269     if(!memcmp4(&cachePtr[offset], &ptr[offset], info.size * info.arraySize))
270     {
271       switch(setter.type)
272       {
273         case UniformSetter::Type::FLOAT:
274         {
275           (gl.*(setter.uniformfProc))(info.location, info.arraySize, reinterpret_cast<const float*>(&ptr[offset]));
276           break;
277         }
278         case UniformSetter::Type::INT:
279         {
280           (gl.*(setter.uniformiProc))(info.location, info.arraySize, reinterpret_cast<const int*>(&ptr[offset]));
281           break;
282         }
283         case UniformSetter::Type::MATRIX:
284         {
285           (gl.*(setter.uniformMatrixProc))(info.location, info.arraySize, GL_FALSE, reinterpret_cast<const float*>(&ptr[offset]));
286           break;
287         }
288         case UniformSetter::Type::UNDEFINED:
289         {
290         }
291       }
292     }
293   }
294   // Update caches
295   memmove(mImpl->uniformData.data(), ptr, mImpl->uniformData.size());
296 }
297
298 void ProgramImpl::BuildStandaloneUniformCache()
299 {
300   const auto& reflection = GetReflection();
301   const auto& extraInfos = reflection.GetStandaloneUniformExtraInfo();
302
303   // Prepare pointers to the uniform setter calls
304   mImpl->uniformSetters.resize(extraInfos.size());
305   int index = 0;
306   for(const auto& info : extraInfos)
307   {
308     auto type                         = GLTypeConversion(info.type).type;
309     mImpl->uniformSetters[index].type = UniformSetter::Type::UNDEFINED;
310     switch(type)
311     {
312       case GLType::FLOAT_VEC2:
313       {
314         mImpl->uniformSetters[index].uniformfProc = &GlAbstraction::Uniform2fv;
315         mImpl->uniformSetters[index].type         = UniformSetter::Type::FLOAT;
316         break;
317       }
318       case GLType::FLOAT_VEC3:
319       {
320         mImpl->uniformSetters[index].uniformfProc = &GlAbstraction::Uniform3fv;
321         mImpl->uniformSetters[index].type         = UniformSetter::Type::FLOAT;
322         break;
323       }
324       case GLType::FLOAT_VEC4:
325       {
326         mImpl->uniformSetters[index].uniformfProc = &GlAbstraction::Uniform4fv;
327         mImpl->uniformSetters[index].type         = UniformSetter::Type::FLOAT;
328         break;
329       }
330       case GLType::INT_VEC2:
331       {
332         mImpl->uniformSetters[index].uniformiProc = &GlAbstraction::Uniform2iv;
333         mImpl->uniformSetters[index].type         = UniformSetter::Type::INT;
334         break;
335       }
336       case GLType::INT_VEC3:
337       {
338         mImpl->uniformSetters[index].uniformiProc = &GlAbstraction::Uniform3iv;
339         mImpl->uniformSetters[index].type         = UniformSetter::Type::INT;
340         break;
341       }
342       case GLType::INT_VEC4:
343       {
344         mImpl->uniformSetters[index].uniformiProc = &GlAbstraction::Uniform4iv;
345         mImpl->uniformSetters[index].type         = UniformSetter::Type::INT;
346         break;
347       }
348       case GLType::INT:
349       {
350         mImpl->uniformSetters[index].uniformiProc = &GlAbstraction::Uniform1iv;
351         mImpl->uniformSetters[index].type         = UniformSetter::Type::INT;
352         break;
353       }
354       case GLType::BOOL:
355       case GLType::BOOL_VEC2:
356       case GLType::BOOL_VEC3:
357       case GLType::BOOL_VEC4:
358       case GLType::FLOAT:
359       {
360         mImpl->uniformSetters[index].uniformfProc = &GlAbstraction::Uniform1fv;
361         mImpl->uniformSetters[index].type         = UniformSetter::Type::FLOAT;
362         break;
363       }
364       case GLType::FLOAT_MAT2:
365       {
366         mImpl->uniformSetters[index].uniformMatrixProc = &GlAbstraction::UniformMatrix2fv;
367         mImpl->uniformSetters[index].type              = UniformSetter::Type::MATRIX;
368         break;
369       }
370       case GLType::FLOAT_MAT3:
371       {
372         mImpl->uniformSetters[index].uniformMatrixProc = &GlAbstraction::UniformMatrix3fv;
373         mImpl->uniformSetters[index].type              = UniformSetter::Type::MATRIX;
374         break;
375       }
376       case GLType::FLOAT_MAT4:
377       {
378         mImpl->uniformSetters[index].uniformMatrixProc = &GlAbstraction::UniformMatrix4fv;
379         mImpl->uniformSetters[index].type              = UniformSetter::Type::MATRIX;
380         break;
381       }
382       case GLType::SAMPLER_2D:
383       case GLType::SAMPLER_CUBE:
384       default:
385       {
386       }
387     }
388     index++;
389   }
390 }
391
392 Program::~Program()
393 {
394   // Destroy GL resources of implementation. This should happen
395   // only if there's no more pipelines using this program so
396   // it is safe to do it in the destructor
397   if(!mProgram->Release())
398   {
399     mProgram->Destroy();
400   }
401 }
402
403 const GLES::Reflection& Program::GetReflection() const
404 {
405   return mProgram->GetReflection();
406 }
407
408 EglGraphicsController& Program::GetController() const
409 {
410   return GetImplementation()->GetController();
411 }
412
413 const ProgramCreateInfo& Program::GetCreateInfo() const
414 {
415   return GetImplementation()->GetCreateInfo();
416 }
417
418 void Program::DiscardResource()
419 {
420   GetController().DiscardResource(this);
421 }
422
423 }; // namespace Dali::Graphics::GLES