[dali_2.3.34] Merge branch '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 <dali/internal/graphics/common/shader-parser.h>
22 #include "egl-graphics-controller.h"
23 #include "gles-graphics-reflection.h"
24 #include "gles-graphics-shader.h"
25
26 // EXTERNAL HEADERS
27 #include <iostream>
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 void ProgramImpl::Preprocess()
139 {
140   // For now only Vertex and Fragment shader stages supported
141   // and one per stage
142   std::string  vertexString;
143   std::string  fragmentString;
144   std::string* currentString = nullptr;
145
146   const GLES::Shader* vsh = nullptr;
147   const GLES::Shader* fsh = nullptr;
148
149   const auto& info = mImpl->createInfo;
150
151   for(const auto& state : *info.shaderState)
152   {
153     const auto* shader = static_cast<const GLES::Shader*>(state.shader);
154     if(state.pipelineStage == PipelineStage::VERTEX_SHADER)
155     {
156       // Only TEXT source mode can be processed
157       currentString = &vertexString;
158       vsh           = shader;
159     }
160     else if(state.pipelineStage == PipelineStage::FRAGMENT_SHADER)
161     {
162       // Only TEXT source mode can be processed
163       currentString = &fragmentString;
164       fsh           = shader;
165     }
166     else
167     {
168       // no valid stream to push
169       currentString = nullptr;
170       DALI_LOG_ERROR("Shader state contains invalid shader source (most likely binary)! Can't process!");
171     }
172
173     // Check if stream valid
174     if(currentString && currentString->empty() && shader->GetCreateInfo().sourceMode == ShaderSourceMode::TEXT)
175     {
176       *currentString = std::string(reinterpret_cast<const char*>(shader->GetCreateInfo().sourceData),
177                                    shader->GetCreateInfo().sourceSize);
178     }
179     else
180     {
181       DALI_LOG_ERROR("Preprocessing of binary shaders isn't allowed!");
182     }
183   }
184
185   // if we have both streams ready
186   if(!vertexString.empty() && !fragmentString.empty())
187   {
188     // In case we have one modern shader and one legacy counterpart we need to enforce
189     // output language.
190     Internal::ShaderParser::ShaderParserInfo parseInfo{};
191     parseInfo.vertexShaderCode            = &vertexString;
192     parseInfo.fragmentShaderCode          = &fragmentString;
193     parseInfo.vertexShaderLegacyVersion   = vsh->GetGLSLVersion();
194     parseInfo.fragmentShaderLegacyVersion = fsh->GetGLSLVersion();
195     parseInfo.language                    = Internal::ShaderParser::OutputLanguage::GLSL3; // We default to GLSL3
196     parseInfo.outputVersion               = std::max(vsh->GetGLSLVersion(), fsh->GetGLSLVersion());
197
198     std::vector<std::string> newShaders;
199
200     Internal::ShaderParser::Parse(parseInfo, newShaders);
201
202     // substitute shader code
203     vsh->GetImplementation()->SetPreprocessedCode(newShaders[0].data(), newShaders[0].size());
204     fsh->GetImplementation()->SetPreprocessedCode(newShaders[1].data(), newShaders[1].size());
205   }
206   else
207   {
208     DALI_LOG_ERROR("Preprocessing shader code failed!");
209   }
210 }
211
212 bool ProgramImpl::Create()
213 {
214   // Create and link new program
215   auto gl = mImpl->controller.GetGL();
216   if(!gl)
217   {
218     // Do nothing during shutdown
219     return false;
220   }
221
222   auto program = gl->CreateProgram();
223
224   DALI_LOG_DEBUG_INFO("Program[%s] create program id : %u\n", mImpl->name.c_str(), program);
225
226   const auto& info = mImpl->createInfo;
227
228   Preprocess();
229
230   for(const auto& state : *info.shaderState)
231   {
232     const auto* shader = static_cast<const GLES::Shader*>(state.shader);
233
234     // Compile shader first (ignored when compiled)
235     if(shader->GetImplementation()->Compile())
236     {
237       auto shaderId = shader->GetImplementation()->GetGLShader();
238       DALI_LOG_DEBUG_INFO("Program[%s] attach shader : %u\n", mImpl->name.c_str(), shaderId);
239       gl->AttachShader(program, shaderId);
240     }
241   }
242
243   DALI_LOG_DEBUG_INFO("Program[%s] call glLinkProgram\n", mImpl->name.c_str());
244   gl->LinkProgram(program);
245
246   GLint status{0};
247   gl->GetProgramiv(program, GL_LINK_STATUS, &status);
248   if(status != GL_TRUE)
249   {
250     char    output[4096];
251     GLsizei size{0u};
252     gl->GetProgramInfoLog(program, 4096, &size, output);
253
254     // log on error
255     DALI_LOG_ERROR("glLinkProgram[%s] failed:\n%s\n", mImpl->name.c_str(), output);
256     gl->DeleteProgram(program);
257     return false;
258   }
259
260   mImpl->glProgram = program;
261
262   // Initialize reflection
263   mImpl->reflection->BuildVertexAttributeReflection();
264   mImpl->reflection->BuildUniformBlockReflection();
265
266   // populate uniform cache memory for standalone uniforms (it's not needed
267   // for real UBOs as real UBOs work with whole memory blocks)
268   auto& reflection = mImpl->reflection;
269   if(!reflection->GetStandaloneUniformExtraInfo().empty())
270   {
271     UniformBlockInfo blockInfo;
272     reflection->GetUniformBlock(0, blockInfo);
273     auto uniformCacheSize = blockInfo.size;
274     mImpl->uniformData.resize(uniformCacheSize);
275
276     std::fill(mImpl->uniformData.begin(), mImpl->uniformData.end(), 0);
277
278     BuildStandaloneUniformCache();
279   }
280
281   // Set up uniform block bindings
282   auto binding    = 0u;
283   auto blockCount = reflection->GetUniformBlockCount();
284   for(uint32_t i = 1; i < blockCount; ++i) // Ignore emulated block at #0
285   {
286     UniformBlockInfo uboInfo{};
287     reflection->GetUniformBlock(i, uboInfo);
288
289     // make binding point
290     auto blockIndex = gl->GetUniformBlockIndex(program, uboInfo.name.c_str());
291     gl->UniformBlockBinding(program, blockIndex, binding++);
292   }
293
294   return true;
295 }
296
297 uint32_t ProgramImpl::GetGlProgram() const
298 {
299   return mImpl->glProgram;
300 }
301
302 uint32_t ProgramImpl::Retain()
303 {
304   return ++mImpl->refCount;
305 }
306
307 uint32_t ProgramImpl::Release()
308 {
309   return --mImpl->refCount;
310 }
311
312 uint32_t ProgramImpl::GetRefCount() const
313 {
314   return mImpl->refCount;
315 }
316
317 const GLES::Reflection& ProgramImpl::GetReflection() const
318 {
319   return *mImpl->reflection;
320 }
321
322 bool ProgramImpl::GetParameter(uint32_t parameterId, void* out)
323 {
324   if(parameterId == 1) // a magic number to access program id
325   {
326     *reinterpret_cast<decltype(&mImpl->glProgram)>(out) = mImpl->glProgram;
327     return true;
328   }
329   return false;
330 }
331
332 EglGraphicsController& ProgramImpl::GetController() const
333 {
334   return mImpl->controller;
335 }
336
337 const ProgramCreateInfo& ProgramImpl::GetCreateInfo() const
338 {
339   return mImpl->createInfo;
340 }
341
342 void ProgramImpl::UpdateStandaloneUniformBlock(const char* ptr)
343 {
344   const auto& reflection = GetReflection();
345
346   const auto& extraInfos = reflection.GetStandaloneUniformExtraInfo();
347
348   auto* gl = GetController().GetGL();
349   if(!gl)
350   {
351     return; // Early out if no GL found
352   }
353
354   // Set uniforms
355   int  index    = 0;
356   auto cachePtr = reinterpret_cast<char*>(mImpl->uniformData.data());
357   for(const auto& info : extraInfos)
358   {
359     auto& setter = mImpl->uniformSetters[index++];
360     auto  offset = info.offset;
361     if(!memcmp4(&cachePtr[offset], &ptr[offset], info.size * info.arraySize))
362     {
363       switch(setter.type)
364       {
365         case UniformSetter::Type::FLOAT:
366         {
367           (gl->*(setter.uniformfProc))(info.location, info.arraySize, reinterpret_cast<const float*>(&ptr[offset]));
368           break;
369         }
370         case UniformSetter::Type::INT:
371         {
372           (gl->*(setter.uniformiProc))(info.location, info.arraySize, reinterpret_cast<const int*>(&ptr[offset]));
373           break;
374         }
375         case UniformSetter::Type::MATRIX:
376         {
377           (gl->*(setter.uniformMatrixProc))(info.location, info.arraySize, GL_FALSE, reinterpret_cast<const float*>(&ptr[offset]));
378           break;
379         }
380         case UniformSetter::Type::UNDEFINED:
381         {
382         }
383       }
384     }
385   }
386   // Update caches
387   memmove(mImpl->uniformData.data(), ptr, mImpl->uniformData.size());
388 }
389
390 void ProgramImpl::BuildStandaloneUniformCache()
391 {
392   const auto& reflection = GetReflection();
393   const auto& extraInfos = reflection.GetStandaloneUniformExtraInfo();
394
395   // Prepare pointers to the uniform setter calls
396   mImpl->uniformSetters.resize(extraInfos.size());
397   int index = 0;
398   for(const auto& info : extraInfos)
399   {
400     auto type                         = GLTypeConversion(info.type).type;
401     mImpl->uniformSetters[index].type = UniformSetter::Type::UNDEFINED;
402     switch(type)
403     {
404       case GLType::FLOAT_VEC2:
405       {
406         mImpl->uniformSetters[index].uniformfProc = &GlAbstraction::Uniform2fv;
407         mImpl->uniformSetters[index].type         = UniformSetter::Type::FLOAT;
408         break;
409       }
410       case GLType::FLOAT_VEC3:
411       {
412         mImpl->uniformSetters[index].uniformfProc = &GlAbstraction::Uniform3fv;
413         mImpl->uniformSetters[index].type         = UniformSetter::Type::FLOAT;
414         break;
415       }
416       case GLType::FLOAT_VEC4:
417       {
418         mImpl->uniformSetters[index].uniformfProc = &GlAbstraction::Uniform4fv;
419         mImpl->uniformSetters[index].type         = UniformSetter::Type::FLOAT;
420         break;
421       }
422       case GLType::INT_VEC2:
423       {
424         mImpl->uniformSetters[index].uniformiProc = &GlAbstraction::Uniform2iv;
425         mImpl->uniformSetters[index].type         = UniformSetter::Type::INT;
426         break;
427       }
428       case GLType::INT_VEC3:
429       {
430         mImpl->uniformSetters[index].uniformiProc = &GlAbstraction::Uniform3iv;
431         mImpl->uniformSetters[index].type         = UniformSetter::Type::INT;
432         break;
433       }
434       case GLType::INT_VEC4:
435       {
436         mImpl->uniformSetters[index].uniformiProc = &GlAbstraction::Uniform4iv;
437         mImpl->uniformSetters[index].type         = UniformSetter::Type::INT;
438         break;
439       }
440       case GLType::INT:
441       {
442         mImpl->uniformSetters[index].uniformiProc = &GlAbstraction::Uniform1iv;
443         mImpl->uniformSetters[index].type         = UniformSetter::Type::INT;
444         break;
445       }
446       case GLType::BOOL:
447       case GLType::BOOL_VEC2:
448       case GLType::BOOL_VEC3:
449       case GLType::BOOL_VEC4:
450       case GLType::FLOAT:
451       {
452         mImpl->uniformSetters[index].uniformfProc = &GlAbstraction::Uniform1fv;
453         mImpl->uniformSetters[index].type         = UniformSetter::Type::FLOAT;
454         break;
455       }
456       case GLType::FLOAT_MAT2:
457       {
458         mImpl->uniformSetters[index].uniformMatrixProc = &GlAbstraction::UniformMatrix2fv;
459         mImpl->uniformSetters[index].type              = UniformSetter::Type::MATRIX;
460         break;
461       }
462       case GLType::FLOAT_MAT3:
463       {
464         mImpl->uniformSetters[index].uniformMatrixProc = &GlAbstraction::UniformMatrix3fv;
465         mImpl->uniformSetters[index].type              = UniformSetter::Type::MATRIX;
466         break;
467       }
468       case GLType::FLOAT_MAT4:
469       {
470         mImpl->uniformSetters[index].uniformMatrixProc = &GlAbstraction::UniformMatrix4fv;
471         mImpl->uniformSetters[index].type              = UniformSetter::Type::MATRIX;
472         break;
473       }
474       case GLType::SAMPLER_2D:
475       case GLType::SAMPLER_CUBE:
476       default:
477       {
478       }
479     }
480     index++;
481   }
482 }
483
484 Program::~Program()
485 {
486   // Destroy GL resources of implementation. This should happen
487   // only if there's no more pipelines using this program so
488   // it is safe to do it in the destructor
489   if(!mProgram->Release())
490   {
491     mProgram->Destroy();
492   }
493 }
494
495 const GLES::Reflection& Program::GetReflection() const
496 {
497   return mProgram->GetReflection();
498 }
499
500 EglGraphicsController& Program::GetController() const
501 {
502   return GetImplementation()->GetController();
503 }
504
505 const ProgramCreateInfo& Program::GetCreateInfo() const
506 {
507   return GetImplementation()->GetCreateInfo();
508 }
509
510 void Program::DiscardResource()
511 {
512   GetController().DiscardResource(this);
513 }
514
515 }; // namespace Dali::Graphics::GLES