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