Added DS-5 Streamline tracing support
[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
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->GetImplementation()->Compile())
152     {
153       gl->AttachShader(program, shader->GetImplementation()->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   if(!gl)
262   {
263     return; // Early out if no GL found
264   }
265
266   // Set uniforms
267   int  index    = 0;
268   auto cachePtr = reinterpret_cast<char*>(mImpl->uniformData.data());
269   for(const auto& info : extraInfos)
270   {
271     auto& setter = mImpl->uniformSetters[index++];
272     auto  offset = info.offset;
273     if(!memcmp4(&cachePtr[offset], &ptr[offset], info.size * info.arraySize))
274     {
275       switch(setter.type)
276       {
277         case UniformSetter::Type::FLOAT:
278         {
279           (gl->*(setter.uniformfProc))(info.location, info.arraySize, reinterpret_cast<const float*>(&ptr[offset]));
280           break;
281         }
282         case UniformSetter::Type::INT:
283         {
284           (gl->*(setter.uniformiProc))(info.location, info.arraySize, reinterpret_cast<const int*>(&ptr[offset]));
285           break;
286         }
287         case UniformSetter::Type::MATRIX:
288         {
289           (gl->*(setter.uniformMatrixProc))(info.location, info.arraySize, GL_FALSE, reinterpret_cast<const float*>(&ptr[offset]));
290           break;
291         }
292         case UniformSetter::Type::UNDEFINED:
293         {
294         }
295       }
296     }
297   }
298   // Update caches
299   memmove(mImpl->uniformData.data(), ptr, mImpl->uniformData.size());
300 }
301
302 void ProgramImpl::BuildStandaloneUniformCache()
303 {
304   const auto& reflection = GetReflection();
305   const auto& extraInfos = reflection.GetStandaloneUniformExtraInfo();
306
307   // Prepare pointers to the uniform setter calls
308   mImpl->uniformSetters.resize(extraInfos.size());
309   int index = 0;
310   for(const auto& info : extraInfos)
311   {
312     auto type                         = GLTypeConversion(info.type).type;
313     mImpl->uniformSetters[index].type = UniformSetter::Type::UNDEFINED;
314     switch(type)
315     {
316       case GLType::FLOAT_VEC2:
317       {
318         mImpl->uniformSetters[index].uniformfProc = &GlAbstraction::Uniform2fv;
319         mImpl->uniformSetters[index].type         = UniformSetter::Type::FLOAT;
320         break;
321       }
322       case GLType::FLOAT_VEC3:
323       {
324         mImpl->uniformSetters[index].uniformfProc = &GlAbstraction::Uniform3fv;
325         mImpl->uniformSetters[index].type         = UniformSetter::Type::FLOAT;
326         break;
327       }
328       case GLType::FLOAT_VEC4:
329       {
330         mImpl->uniformSetters[index].uniformfProc = &GlAbstraction::Uniform4fv;
331         mImpl->uniformSetters[index].type         = UniformSetter::Type::FLOAT;
332         break;
333       }
334       case GLType::INT_VEC2:
335       {
336         mImpl->uniformSetters[index].uniformiProc = &GlAbstraction::Uniform2iv;
337         mImpl->uniformSetters[index].type         = UniformSetter::Type::INT;
338         break;
339       }
340       case GLType::INT_VEC3:
341       {
342         mImpl->uniformSetters[index].uniformiProc = &GlAbstraction::Uniform3iv;
343         mImpl->uniformSetters[index].type         = UniformSetter::Type::INT;
344         break;
345       }
346       case GLType::INT_VEC4:
347       {
348         mImpl->uniformSetters[index].uniformiProc = &GlAbstraction::Uniform4iv;
349         mImpl->uniformSetters[index].type         = UniformSetter::Type::INT;
350         break;
351       }
352       case GLType::INT:
353       {
354         mImpl->uniformSetters[index].uniformiProc = &GlAbstraction::Uniform1iv;
355         mImpl->uniformSetters[index].type         = UniformSetter::Type::INT;
356         break;
357       }
358       case GLType::BOOL:
359       case GLType::BOOL_VEC2:
360       case GLType::BOOL_VEC3:
361       case GLType::BOOL_VEC4:
362       case GLType::FLOAT:
363       {
364         mImpl->uniformSetters[index].uniformfProc = &GlAbstraction::Uniform1fv;
365         mImpl->uniformSetters[index].type         = UniformSetter::Type::FLOAT;
366         break;
367       }
368       case GLType::FLOAT_MAT2:
369       {
370         mImpl->uniformSetters[index].uniformMatrixProc = &GlAbstraction::UniformMatrix2fv;
371         mImpl->uniformSetters[index].type              = UniformSetter::Type::MATRIX;
372         break;
373       }
374       case GLType::FLOAT_MAT3:
375       {
376         mImpl->uniformSetters[index].uniformMatrixProc = &GlAbstraction::UniformMatrix3fv;
377         mImpl->uniformSetters[index].type              = UniformSetter::Type::MATRIX;
378         break;
379       }
380       case GLType::FLOAT_MAT4:
381       {
382         mImpl->uniformSetters[index].uniformMatrixProc = &GlAbstraction::UniformMatrix4fv;
383         mImpl->uniformSetters[index].type              = UniformSetter::Type::MATRIX;
384         break;
385       }
386       case GLType::SAMPLER_2D:
387       case GLType::SAMPLER_CUBE:
388       default:
389       {
390       }
391     }
392     index++;
393   }
394 }
395
396 Program::~Program()
397 {
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())
402   {
403     mProgram->Destroy();
404   }
405 }
406
407 const GLES::Reflection& Program::GetReflection() const
408 {
409   return mProgram->GetReflection();
410 }
411
412 EglGraphicsController& Program::GetController() const
413 {
414   return GetImplementation()->GetController();
415 }
416
417 const ProgramCreateInfo& Program::GetCreateInfo() const
418 {
419   return GetImplementation()->GetCreateInfo();
420 }
421
422 void Program::DiscardResource()
423 {
424   GetController().DiscardResource(this);
425 }
426
427 }; // namespace Dali::Graphics::GLES