Ensured GL calls are not made after EGL Shutdown
[platform/core/uifw/dali-adaptor.git] / dali / internal / graphics / gles-impl / gles-graphics-reflection.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
18 #include "gles-graphics-reflection.h"
19
20 #include <dali/integration-api/debug.h>
21 #include <dali/integration-api/gl-abstraction.h>
22 #include <dali/integration-api/gl-defines.h>
23
24 #include <vector>
25 #include "egl-graphics-controller.h"
26
27 #include <GLES3/gl3.h>
28 #include <GLES3/gl31.h>
29
30 #include "gles-graphics-program.h"
31
32 #include <iostream>
33
34 namespace
35 {
36 Dali::Graphics::VertexInputAttributeFormat GetVertexAttributeTypeFormat(GLenum type)
37 {
38   switch(type)
39   {
40     case GL_FLOAT:
41       return Dali::Graphics::VertexInputAttributeFormat::FLOAT;
42     case GL_FLOAT_VEC2:
43       return Dali::Graphics::VertexInputAttributeFormat::VEC2;
44     case GL_FLOAT_VEC3:
45       return Dali::Graphics::VertexInputAttributeFormat::VEC3;
46     case GL_FLOAT_VEC4:
47       return Dali::Graphics::VertexInputAttributeFormat::VEC4;
48     case GL_INT:
49       return Dali::Graphics::VertexInputAttributeFormat::INTEGER;
50     default:
51       return Dali::Graphics::VertexInputAttributeFormat::UNDEFINED;
52   }
53 }
54
55 uint32_t GetGLDataTypeSize(GLenum type)
56 {
57   // There are many more types than what are covered here, but
58   // they are not supported in dali.
59   switch(type)
60   {
61     case GL_FLOAT: // "float", 1 float, 4 bytes
62       return 4;
63     case GL_FLOAT_VEC2: // "vec2", 2 floats, 8 bytes
64       return 8;
65     case GL_FLOAT_VEC3: // "vec3", 3 floats, 12 bytes
66       return 12;
67     case GL_FLOAT_VEC4: // "vec4", 4 floats, 16 bytes
68       return 16;
69     case GL_INT: // "int", 1 integer, 4 bytes
70       return 4;
71     case GL_FLOAT_MAT2: // "mat2", 4 floats, 16 bytes
72       return 16;
73     case GL_FLOAT_MAT3: // "mat3", 3 vec3, 36 bytes
74       return 36;
75     case GL_FLOAT_MAT4: // "mat4", 4 vec4, 64 bytes
76       return 64;
77     default:
78       return 0;
79   }
80 }
81
82 bool IsSampler(GLenum type)
83 {
84   return type == GL_SAMPLER_2D || type == GL_SAMPLER_3D || type == GL_SAMPLER_CUBE || type == GL_SAMPLER_EXTERNAL_OES;
85 }
86
87 bool SortUniformInfoByLocation(Dali::Graphics::UniformInfo a, Dali::Graphics::UniformInfo b)
88 {
89   return a.location < b.location;
90 }
91
92 bool SortUniformExtraInfoByLocation(Dali::Graphics::GLES::Reflection::UniformExtraInfo a, Dali::Graphics::GLES::Reflection::UniformExtraInfo b)
93 {
94   return a.location < b.location;
95 }
96
97 } // namespace
98
99 namespace Dali::Graphics::GLES
100 {
101 Reflection::Reflection(GLES::ProgramImpl& program, Graphics::EglGraphicsController& controller)
102 : Graphics::Reflection(),
103   mController(controller),
104   mProgram(program)
105 {
106 }
107
108 Reflection::~Reflection() = default;
109
110 void Reflection::BuildVertexAttributeReflection()
111 {
112   auto glProgram = mProgram.GetGlProgram();
113
114   int    written, size, location, maxLength, nAttribs;
115   GLenum type;
116   char*  name;
117
118   auto gl = mController.GetGL();
119   if(!gl)
120   {
121     // Do nothing during shutdown
122     return;
123   }
124
125   gl->GetProgramiv(glProgram, GL_ACTIVE_ATTRIBUTE_MAX_LENGTH, &maxLength);
126   gl->GetProgramiv(glProgram, GL_ACTIVE_ATTRIBUTES, &nAttribs);
127
128   mVertexInputAttributes.clear();
129   mVertexInputAttributes.resize(nAttribs);
130
131   name = new GLchar[maxLength];
132   for(int i = 0; i < nAttribs; i++)
133   {
134     gl->GetActiveAttrib(glProgram, i, maxLength, &written, &size, &type, name);
135     location = gl->GetAttribLocation(glProgram, name);
136
137     if(location >= 0)
138     {
139       AttributeInfo attributeInfo;
140       attributeInfo.location = location;
141       attributeInfo.name     = name;
142       attributeInfo.format   = GetVertexAttributeTypeFormat(type);
143       mVertexInputAttributes.insert(mVertexInputAttributes.begin() + location, attributeInfo);
144     }
145   }
146   delete[] name;
147 }
148
149 void Reflection::BuildUniformReflection()
150 {
151   auto glProgram = mProgram.GetGlProgram();
152
153   int   maxLen;
154   char* name;
155
156   int numUniforms = 0;
157
158   auto gl = mController.GetGL();
159   if(!gl)
160   {
161     // Do nothing during shutdown
162     return;
163   }
164
165   gl->GetProgramiv(glProgram, GL_ACTIVE_UNIFORM_MAX_LENGTH, &maxLen);
166   gl->GetProgramiv(glProgram, GL_ACTIVE_UNIFORMS, &numUniforms);
167
168   mUniformBlocks.clear();
169   mDefaultUniformBlock.members.clear();
170   mUniformOpaques.clear();
171
172   name = new char[maxLen];
173
174   mStandaloneUniformExtraInfos.clear();
175
176   for(int i = 0; i < numUniforms; ++i)
177   {
178     int    elementCount;
179     GLenum type;
180     int    written;
181     gl->GetActiveUniform(glProgram, i, maxLen, &written, &elementCount, &type, name);
182     int location = gl->GetUniformLocation(glProgram, name);
183
184     Dali::Graphics::UniformInfo uniformInfo;
185
186     uniformInfo.name = name;
187     if(elementCount > 1)
188     {
189       auto iter = std::string(uniformInfo.name).find("[", 0);
190       if(iter != std::string::npos)
191       {
192         uniformInfo.name = std::string(name).substr(0, iter);
193       }
194     }
195
196     uniformInfo.uniformClass = IsSampler(type) ? Dali::Graphics::UniformClass::COMBINED_IMAGE_SAMPLER : Dali::Graphics::UniformClass::UNIFORM;
197     uniformInfo.location     = IsSampler(type) ? 0 : location;
198     uniformInfo.binding      = IsSampler(type) ? location : 0;
199     uniformInfo.bufferIndex  = 0;
200
201     if(IsSampler(type))
202     {
203       mUniformOpaques.push_back(uniformInfo);
204     }
205     else
206     {
207       mDefaultUniformBlock.members.push_back(uniformInfo);
208       mStandaloneUniformExtraInfos.emplace_back(location, GetGLDataTypeSize(type), uniformInfo.offset, elementCount, type);
209     }
210   }
211
212   // Re-order according to uniform locations.
213
214   if(mDefaultUniformBlock.members.size() > 1)
215   {
216     std::sort(mDefaultUniformBlock.members.begin(), mDefaultUniformBlock.members.end(), SortUniformInfoByLocation);
217     std::sort(mStandaloneUniformExtraInfos.begin(), mStandaloneUniformExtraInfos.end(), SortUniformExtraInfoByLocation);
218   }
219
220   if(mUniformOpaques.size() > 1)
221   {
222     std::sort(mUniformOpaques.begin(), mUniformOpaques.end(), SortUniformInfoByLocation);
223   }
224
225   // Calculate the uniform offset
226   for(unsigned int i = 0; i < mDefaultUniformBlock.members.size(); ++i)
227   {
228     if(i == 0)
229     {
230       mDefaultUniformBlock.members[i].offset = 0;
231     }
232     else
233     {
234       uint32_t previousUniformLocation = mDefaultUniformBlock.members[i - 1].location;
235       auto     previousUniform         = std::find_if(mStandaloneUniformExtraInfos.begin(), mStandaloneUniformExtraInfos.end(), [&previousUniformLocation](const UniformExtraInfo& iter) { return iter.location == previousUniformLocation; });
236       if(previousUniform != mStandaloneUniformExtraInfos.end())
237       {
238         mDefaultUniformBlock.members[i].offset = mDefaultUniformBlock.members[i - 1].offset + (previousUniform->size * previousUniform->arraySize);
239         mStandaloneUniformExtraInfos[i].offset = mDefaultUniformBlock.members[i].offset;
240       }
241     }
242   }
243
244   if(mDefaultUniformBlock.members.size() > 0)
245   {
246     uint32_t lastUniformLocation = mDefaultUniformBlock.members.back().location;
247     auto     lastUniform         = std::find_if(mStandaloneUniformExtraInfos.begin(), mStandaloneUniformExtraInfos.end(), [&lastUniformLocation](const UniformExtraInfo& iter) { return iter.location == lastUniformLocation; });
248     if(lastUniform != mStandaloneUniformExtraInfos.end())
249     {
250       mDefaultUniformBlock.size = mDefaultUniformBlock.members.back().offset + (lastUniform->size * lastUniform->arraySize);
251       mUniformBlocks.push_back(mDefaultUniformBlock);
252     }
253   }
254   else
255   {
256     mDefaultUniformBlock.size = 0;
257   }
258
259   delete[] name;
260 }
261
262 // TODO: Maybe this is not needed if uniform block is not support by dali shaders?
263 void Reflection::BuildUniformBlockReflection()
264 {
265   auto gl               = mController.GetGL();
266   auto glProgram        = mProgram.GetGlProgram();
267   int  numUniformBlocks = 0;
268
269   if(!gl)
270   {
271     // Do nothing during shutdown
272     return;
273   }
274
275   gl->GetProgramiv(glProgram, GL_ACTIVE_UNIFORM_BLOCKS, &numUniformBlocks);
276
277   mUniformBlocks.clear();
278   mUniformBlocks.resize(numUniformBlocks);
279
280   int uniformBlockMaxLength = 0;
281   gl->GetProgramiv(glProgram, GL_ACTIVE_UNIFORM_BLOCK_MAX_NAME_LENGTH, &uniformBlockMaxLength);
282
283   char* uniformBlockName = new char[uniformBlockMaxLength];
284   for(int i = 0; i < numUniformBlocks; i++)
285   {
286     int length;
287     int blockBinding;
288     int blockDataSize;
289     gl->GetActiveUniformBlockName(glProgram, i, uniformBlockMaxLength, &length, uniformBlockName);
290     gl->GetActiveUniformBlockiv(glProgram, i, GL_UNIFORM_BLOCK_BINDING, &blockBinding);
291     gl->GetActiveUniformBlockiv(glProgram, i, GL_UNIFORM_BLOCK_DATA_SIZE, &blockDataSize);
292
293     Dali::Graphics::UniformBlockInfo uniformBlockInfo;
294     uniformBlockInfo.name    = uniformBlockName;
295     uniformBlockInfo.size    = blockDataSize;
296     uniformBlockInfo.binding = blockBinding;
297
298     int nUnis;
299     gl->GetActiveUniformBlockiv(glProgram, i, GL_UNIFORM_BLOCK_ACTIVE_UNIFORMS, &nUnis);
300     int* unifIndexes = new GLint[nUnis];
301     gl->GetActiveUniformBlockiv(glProgram, i, GL_UNIFORM_BLOCK_ACTIVE_UNIFORM_INDICES, unifIndexes);
302     char* uniformName{};
303     int   maxUniLen;
304     gl->GetProgramiv(glProgram, GL_ACTIVE_UNIFORM_MAX_LENGTH, &maxUniLen);
305
306     for(int unif = 0; unif < nUnis; ++unif)
307     {
308       int    uniIndex = unifIndexes[unif];
309       int    size;
310       GLenum type;
311
312       gl->GetActiveUniform(glProgram, uniIndex, maxUniLen, &length, &size, &type, uniformName);
313       int location = gl->GetUniformLocation(glProgram, uniformName);
314
315       Dali::Graphics::UniformInfo uniform;
316       uniform.name     = uniformName;
317       uniform.location = location;
318       uniformBlockInfo.members.push_back(uniform);
319     }
320
321     delete[] unifIndexes;
322
323     mUniformBlocks.push_back(uniformBlockInfo);
324   }
325   delete[] uniformBlockName;
326 }
327
328 uint32_t Reflection::GetVertexAttributeLocation(const std::string& name) const
329 {
330   for(auto&& attr : mVertexInputAttributes)
331   {
332     if(attr.name == name)
333     {
334       return attr.location;
335     }
336   }
337   return ERROR_ATTRIBUTE_NOT_FOUND;
338 }
339
340 Dali::Graphics::VertexInputAttributeFormat Reflection::GetVertexAttributeFormat(uint32_t location) const
341 {
342   if(location >= mVertexInputAttributes.size())
343   {
344     return Dali::Graphics::VertexInputAttributeFormat::UNDEFINED;
345   }
346
347   return mVertexInputAttributes[location].format;
348 }
349
350 std::string Reflection::GetVertexAttributeName(uint32_t location) const
351 {
352   if(location >= mVertexInputAttributes.size())
353   {
354     return std::string();
355   }
356
357   return mVertexInputAttributes[location].name;
358 }
359
360 std::vector<uint32_t> Reflection::GetVertexAttributeLocations() const
361 {
362   std::vector<uint32_t> locations;
363   for(auto&& attr : mVertexInputAttributes)
364   {
365     if(attr.format != Dali::Graphics::VertexInputAttributeFormat::UNDEFINED)
366     {
367       locations.push_back(attr.location);
368     }
369   }
370
371   return locations;
372 }
373
374 uint32_t Reflection::GetUniformBlockCount() const
375 {
376   return mUniformBlocks.size();
377 }
378
379 uint32_t Reflection::GetUniformBlockBinding(uint32_t index) const
380 {
381   return index < mUniformBlocks.size() ? mUniformBlocks[index].binding : 0u;
382 }
383
384 uint32_t Reflection::GetUniformBlockSize(uint32_t index) const
385 {
386   return index < mUniformBlocks.size() ? mUniformBlocks[index].size : 0u;
387 }
388
389 bool Reflection::GetUniformBlock(uint32_t index, Dali::Graphics::UniformBlockInfo& out) const
390 {
391   if(index >= mUniformBlocks.size())
392   {
393     return false;
394   }
395
396   const auto& block = mUniformBlocks[index];
397
398   out.name          = block.name;
399   out.binding       = block.binding;
400   out.descriptorSet = block.descriptorSet;
401   auto membersSize  = block.members.size();
402   out.members.resize(membersSize);
403   out.size = block.size;
404   for(auto i = 0u; i < out.members.size(); ++i)
405   {
406     const auto& memberUniform   = block.members[i];
407     out.members[i].name         = memberUniform.name;
408     out.members[i].binding      = block.binding;
409     out.members[i].uniformClass = Graphics::UniformClass::UNIFORM;
410     out.members[i].offset       = memberUniform.offset;
411     out.members[i].location     = memberUniform.location;
412   }
413
414   return true;
415 }
416
417 std::vector<uint32_t> Reflection::GetUniformBlockLocations() const
418 {
419   std::vector<uint32_t> retval{};
420   for(auto&& ubo : mUniformBlocks)
421   {
422     retval.emplace_back(ubo.binding);
423   }
424   return retval;
425 }
426
427 std::string Reflection::GetUniformBlockName(uint32_t blockIndex) const
428 {
429   if(blockIndex < mUniformBlocks.size())
430   {
431     return mUniformBlocks[blockIndex].name;
432   }
433   else
434   {
435     return std::string();
436   }
437 }
438
439 uint32_t Reflection::GetUniformBlockMemberCount(uint32_t blockIndex) const
440 {
441   if(blockIndex < mUniformBlocks.size())
442   {
443     return static_cast<uint32_t>(mUniformBlocks[blockIndex].members.size());
444   }
445   else
446   {
447     return 0u;
448   }
449 }
450
451 std::string Reflection::GetUniformBlockMemberName(uint32_t blockIndex, uint32_t memberLocation) const
452 {
453   if(blockIndex < mUniformBlocks.size() && memberLocation < mUniformBlocks[blockIndex].members.size())
454   {
455     return mUniformBlocks[blockIndex].members[memberLocation].name;
456   }
457   else
458   {
459     return std::string();
460   }
461 }
462
463 uint32_t Reflection::GetUniformBlockMemberOffset(uint32_t blockIndex, uint32_t memberLocation) const
464 {
465   if(blockIndex < mUniformBlocks.size() && memberLocation < mUniformBlocks[blockIndex].members.size())
466   {
467     return mUniformBlocks[blockIndex].members[memberLocation].offset;
468   }
469   else
470   {
471     return 0u;
472   }
473 }
474
475 bool Reflection::GetNamedUniform(const std::string& name, Dali::Graphics::UniformInfo& out) const
476 {
477   auto index = 0u;
478   for(auto&& ubo : mUniformBlocks)
479   {
480     for(auto&& member : ubo.members)
481     {
482       if(name == member.name || name == (ubo.name + "." + member.name))
483       {
484         out.name         = name;
485         out.location     = member.location;
486         out.binding      = ubo.binding;
487         out.bufferIndex  = index;
488         out.offset       = member.offset;
489         out.uniformClass = Graphics::UniformClass::UNIFORM;
490         return true;
491       }
492     }
493     index++;
494   }
495
496   // check samplers
497   for(auto&& uniform : mUniformOpaques)
498   {
499     if(uniform.name == name)
500     {
501       out.uniformClass = Graphics::UniformClass::COMBINED_IMAGE_SAMPLER;
502       out.binding      = uniform.binding;
503       out.name         = name;
504       out.offset       = 0;
505       out.location     = uniform.location;
506       return true;
507     }
508   }
509
510   return false;
511 }
512
513 std::vector<GLenum> Reflection::GetStandaloneUniformTypes() const
514 {
515   std::vector<GLenum> retval{};
516   for(auto&& uniform : mStandaloneUniformExtraInfos)
517   {
518     retval.emplace_back(uniform.type);
519   }
520
521   return retval;
522 }
523
524 const std::vector<Reflection::UniformExtraInfo>& Reflection::GetStandaloneUniformExtraInfo() const
525 {
526   return mStandaloneUniformExtraInfos;
527 }
528
529 std::vector<Dali::Graphics::UniformInfo> Reflection::GetSamplers() const
530 {
531   return mUniformOpaques;
532 }
533
534 Graphics::ShaderLanguage Reflection::GetLanguage() const
535 {
536   auto version = Graphics::ShaderLanguage::GLSL_3_2;
537
538   auto gl = mController.GetGL();
539   if(!gl)
540   {
541     // Do nothing during shutdown
542     return version;
543   }
544
545   int majorVersion, minorVersion;
546   gl->GetIntegerv(GL_MAJOR_VERSION, &majorVersion);
547   gl->GetIntegerv(GL_MINOR_VERSION, &minorVersion);
548   DALI_LOG_RELEASE_INFO("GL Version (integer) : %d.%d\n", majorVersion, minorVersion);
549   DALI_LOG_RELEASE_INFO("GLSL Version : %s\n", gl->GetString(GL_SHADING_LANGUAGE_VERSION));
550
551   // TODO: the language version is hardcoded for now, but we may use what we get
552   // from GL_SHADING_LANGUAGE_VERSION?
553   return version;
554 }
555
556 } // namespace Dali::Graphics::GLES