Merge changes I784ba99d,Ieaaeab17 into devel/master
[platform/core/uifw/dali-adaptor.git] / dali / internal / graphics / gles-impl / gles-graphics-program.cpp
1 /*
2  * Copyright (c) 2024 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     // Create new reference of std::string_view.
88     name            = std::string(info.name);
89     createInfo.name = name;
90   }
91
92   ~Impl()
93   {
94     delete createInfo.shaderState;
95   }
96
97   EglGraphicsController& controller;
98   ProgramCreateInfo      createInfo;
99   std::string            name;
100   uint32_t               glProgram{};
101   uint32_t               refCount{0u};
102
103   std::unique_ptr<GLES::Reflection> reflection{nullptr};
104
105   // Uniform cache
106   std::vector<uint8_t> uniformData;
107
108   // List of standalone uniform setters
109   std::vector<UniformSetter> uniformSetters;
110 };
111
112 ProgramImpl::ProgramImpl(const Graphics::ProgramCreateInfo& createInfo, Graphics::EglGraphicsController& controller)
113 {
114   // Create implementation
115   mImpl = std::make_unique<Impl>(controller, createInfo);
116
117   // Build reflection
118   mImpl->reflection = std::make_unique<GLES::Reflection>(*this, controller);
119 }
120
121 ProgramImpl::~ProgramImpl() = default;
122
123 bool ProgramImpl::Destroy()
124 {
125   if(mImpl->glProgram)
126   {
127     auto gl = mImpl->controller.GetGL();
128     if(!gl)
129     {
130       return false;
131     }
132     gl->DeleteProgram(mImpl->glProgram);
133     return true;
134   }
135   return false;
136 }
137
138 bool ProgramImpl::Create()
139 {
140   // Create and link new program
141   auto gl = mImpl->controller.GetGL();
142   if(!gl)
143   {
144     // Do nothing during shutdown
145     return false;
146   }
147
148   auto program = gl->CreateProgram();
149
150   DALI_LOG_INFO(gGraphicsProgramLogFilter, Debug::Verbose, "Program[%s] create program id : %u\n", mImpl->name.c_str(), program);
151
152   const auto& info = mImpl->createInfo;
153   for(const auto& state : *info.shaderState)
154   {
155     const auto* shader = static_cast<const GLES::Shader*>(state.shader);
156
157     // Compile shader first (ignored when compiled)
158     if(shader->GetImplementation()->Compile())
159     {
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);
163     }
164   }
165
166   DALI_LOG_INFO(gGraphicsProgramLogFilter, Debug::Verbose, "Program[%s] call glLinkProgram\n", mImpl->name.c_str());
167   gl->LinkProgram(program);
168
169   GLint status{0};
170   gl->GetProgramiv(program, GL_LINK_STATUS, &status);
171   if(status != GL_TRUE)
172   {
173     char    output[4096];
174     GLsizei size{0u};
175     gl->GetProgramInfoLog(program, 4096, &size, output);
176
177     // log on error
178     DALI_LOG_ERROR("glLinkProgam[%s] failed:\n%s\n", mImpl->name.c_str(), output);
179     gl->DeleteProgram(program);
180     return false;
181   }
182
183   mImpl->glProgram = program;
184
185   // Initialize reflection
186   mImpl->reflection->BuildVertexAttributeReflection();
187   mImpl->reflection->BuildUniformBlockReflection();
188
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())
193   {
194     UniformBlockInfo blockInfo;
195     reflection->GetUniformBlock(0, blockInfo);
196     auto uniformCacheSize = blockInfo.size;
197     mImpl->uniformData.resize(uniformCacheSize);
198
199     std::fill(mImpl->uniformData.begin(), mImpl->uniformData.end(), 0);
200
201     BuildStandaloneUniformCache();
202   }
203
204   // Set up uniform block bindings
205   auto binding    = 0u;
206   auto blockCount = reflection->GetUniformBlockCount();
207   for(uint32_t i = 1; i < blockCount; ++i) // Ignore emulated block at #0
208   {
209     UniformBlockInfo uboInfo{};
210     reflection->GetUniformBlock(i, uboInfo);
211
212     // make binding point
213     auto blockIndex = gl->GetUniformBlockIndex(program, uboInfo.name.c_str());
214     gl->UniformBlockBinding(program, blockIndex, binding++);
215   }
216
217   return true;
218 }
219
220 uint32_t ProgramImpl::GetGlProgram() const
221 {
222   return mImpl->glProgram;
223 }
224
225 uint32_t ProgramImpl::Retain()
226 {
227   return ++mImpl->refCount;
228 }
229
230 uint32_t ProgramImpl::Release()
231 {
232   return --mImpl->refCount;
233 }
234
235 uint32_t ProgramImpl::GetRefCount() const
236 {
237   return mImpl->refCount;
238 }
239
240 const GLES::Reflection& ProgramImpl::GetReflection() const
241 {
242   return *mImpl->reflection;
243 }
244
245 bool ProgramImpl::GetParameter(uint32_t parameterId, void* out)
246 {
247   if(parameterId == 1) // a magic number to access program id
248   {
249     *reinterpret_cast<decltype(&mImpl->glProgram)>(out) = mImpl->glProgram;
250     return true;
251   }
252   return false;
253 }
254
255 EglGraphicsController& ProgramImpl::GetController() const
256 {
257   return mImpl->controller;
258 }
259
260 const ProgramCreateInfo& ProgramImpl::GetCreateInfo() const
261 {
262   return mImpl->createInfo;
263 }
264
265 void ProgramImpl::UpdateStandaloneUniformBlock(const char* ptr)
266 {
267   const auto& reflection = GetReflection();
268
269   const auto& extraInfos = reflection.GetStandaloneUniformExtraInfo();
270
271   auto* gl = GetController().GetGL();
272   if(!gl)
273   {
274     return; // Early out if no GL found
275   }
276
277   // Set uniforms
278   int  index    = 0;
279   auto cachePtr = reinterpret_cast<char*>(mImpl->uniformData.data());
280   for(const auto& info : extraInfos)
281   {
282     auto& setter = mImpl->uniformSetters[index++];
283     auto  offset = info.offset;
284     if(!memcmp4(&cachePtr[offset], &ptr[offset], info.size * info.arraySize))
285     {
286       switch(setter.type)
287       {
288         case UniformSetter::Type::FLOAT:
289         {
290           (gl->*(setter.uniformfProc))(info.location, info.arraySize, reinterpret_cast<const float*>(&ptr[offset]));
291           break;
292         }
293         case UniformSetter::Type::INT:
294         {
295           (gl->*(setter.uniformiProc))(info.location, info.arraySize, reinterpret_cast<const int*>(&ptr[offset]));
296           break;
297         }
298         case UniformSetter::Type::MATRIX:
299         {
300           (gl->*(setter.uniformMatrixProc))(info.location, info.arraySize, GL_FALSE, reinterpret_cast<const float*>(&ptr[offset]));
301           break;
302         }
303         case UniformSetter::Type::UNDEFINED:
304         {
305         }
306       }
307     }
308   }
309   // Update caches
310   memmove(mImpl->uniformData.data(), ptr, mImpl->uniformData.size());
311 }
312
313 void ProgramImpl::BuildStandaloneUniformCache()
314 {
315   const auto& reflection = GetReflection();
316   const auto& extraInfos = reflection.GetStandaloneUniformExtraInfo();
317
318   // Prepare pointers to the uniform setter calls
319   mImpl->uniformSetters.resize(extraInfos.size());
320   int index = 0;
321   for(const auto& info : extraInfos)
322   {
323     auto type                         = GLTypeConversion(info.type).type;
324     mImpl->uniformSetters[index].type = UniformSetter::Type::UNDEFINED;
325     switch(type)
326     {
327       case GLType::FLOAT_VEC2:
328       {
329         mImpl->uniformSetters[index].uniformfProc = &GlAbstraction::Uniform2fv;
330         mImpl->uniformSetters[index].type         = UniformSetter::Type::FLOAT;
331         break;
332       }
333       case GLType::FLOAT_VEC3:
334       {
335         mImpl->uniformSetters[index].uniformfProc = &GlAbstraction::Uniform3fv;
336         mImpl->uniformSetters[index].type         = UniformSetter::Type::FLOAT;
337         break;
338       }
339       case GLType::FLOAT_VEC4:
340       {
341         mImpl->uniformSetters[index].uniformfProc = &GlAbstraction::Uniform4fv;
342         mImpl->uniformSetters[index].type         = UniformSetter::Type::FLOAT;
343         break;
344       }
345       case GLType::INT_VEC2:
346       {
347         mImpl->uniformSetters[index].uniformiProc = &GlAbstraction::Uniform2iv;
348         mImpl->uniformSetters[index].type         = UniformSetter::Type::INT;
349         break;
350       }
351       case GLType::INT_VEC3:
352       {
353         mImpl->uniformSetters[index].uniformiProc = &GlAbstraction::Uniform3iv;
354         mImpl->uniformSetters[index].type         = UniformSetter::Type::INT;
355         break;
356       }
357       case GLType::INT_VEC4:
358       {
359         mImpl->uniformSetters[index].uniformiProc = &GlAbstraction::Uniform4iv;
360         mImpl->uniformSetters[index].type         = UniformSetter::Type::INT;
361         break;
362       }
363       case GLType::INT:
364       {
365         mImpl->uniformSetters[index].uniformiProc = &GlAbstraction::Uniform1iv;
366         mImpl->uniformSetters[index].type         = UniformSetter::Type::INT;
367         break;
368       }
369       case GLType::BOOL:
370       case GLType::BOOL_VEC2:
371       case GLType::BOOL_VEC3:
372       case GLType::BOOL_VEC4:
373       case GLType::FLOAT:
374       {
375         mImpl->uniformSetters[index].uniformfProc = &GlAbstraction::Uniform1fv;
376         mImpl->uniformSetters[index].type         = UniformSetter::Type::FLOAT;
377         break;
378       }
379       case GLType::FLOAT_MAT2:
380       {
381         mImpl->uniformSetters[index].uniformMatrixProc = &GlAbstraction::UniformMatrix2fv;
382         mImpl->uniformSetters[index].type              = UniformSetter::Type::MATRIX;
383         break;
384       }
385       case GLType::FLOAT_MAT3:
386       {
387         mImpl->uniformSetters[index].uniformMatrixProc = &GlAbstraction::UniformMatrix3fv;
388         mImpl->uniformSetters[index].type              = UniformSetter::Type::MATRIX;
389         break;
390       }
391       case GLType::FLOAT_MAT4:
392       {
393         mImpl->uniformSetters[index].uniformMatrixProc = &GlAbstraction::UniformMatrix4fv;
394         mImpl->uniformSetters[index].type              = UniformSetter::Type::MATRIX;
395         break;
396       }
397       case GLType::SAMPLER_2D:
398       case GLType::SAMPLER_CUBE:
399       default:
400       {
401       }
402     }
403     index++;
404   }
405 }
406
407 Program::~Program()
408 {
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())
413   {
414     mProgram->Destroy();
415   }
416 }
417
418 const GLES::Reflection& Program::GetReflection() const
419 {
420   return mProgram->GetReflection();
421 }
422
423 EglGraphicsController& Program::GetController() const
424 {
425   return GetImplementation()->GetController();
426 }
427
428 const ProgramCreateInfo& Program::GetCreateInfo() const
429 {
430   return GetImplementation()->GetCreateInfo();
431 }
432
433 void Program::DiscardResource()
434 {
435   GetController().DiscardResource(this);
436 }
437
438 }; // namespace Dali::Graphics::GLES