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