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