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