[Tizen] Enabled sampler arrays in shader
[platform/core/uifw/dali-adaptor.git] / dali / internal / graphics / gles-impl / gles-graphics-reflection.cpp
1 /*
2  * Copyright (c) 2023 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 #if defined(DEBUG_ENABLED)
37 Debug::Filter* gGraphicsReflectionLogFilter = Debug::Filter::New(Debug::NoLogging, false, "LOG_GRAPHICS_REFLECTION");
38 #endif
39
40 struct StringSize
41 {
42   const char* const mString;
43   const uint32_t    mLength;
44
45   template<uint32_t kLength>
46   constexpr StringSize(const char (&string)[kLength])
47   : mString(string),
48     mLength(kLength - 1) // remove terminating null; N.B. there should be no other null.
49   {
50   }
51
52   operator const char*() const
53   {
54     return mString;
55   }
56 };
57
58 bool operator==(const StringSize& lhs, const char* rhs)
59 {
60   return strncmp(lhs.mString, rhs, lhs.mLength) == 0;
61 }
62
63 const char* const    DELIMITERS           = " \t\n";
64 const char* const    DELIMITERS_INC_INDEX = " \t\n[]";
65 constexpr StringSize UNIFORM{"uniform"};
66 constexpr StringSize SAMPLER_PREFIX{"sampler"};
67 constexpr StringSize SAMPLER_TYPES[]   = {"2D", "Cube", "ExternalOES"};
68 constexpr auto       END_SAMPLER_TYPES = SAMPLER_TYPES + std::extent<decltype(SAMPLER_TYPES)>::value;
69
70 Dali::Graphics::VertexInputAttributeFormat GetVertexAttributeTypeFormat(GLenum type)
71 {
72   switch(type)
73   {
74     case GL_FLOAT:
75       return Dali::Graphics::VertexInputAttributeFormat::FLOAT;
76     case GL_FLOAT_VEC2:
77       return Dali::Graphics::VertexInputAttributeFormat::VEC2;
78     case GL_FLOAT_VEC3:
79       return Dali::Graphics::VertexInputAttributeFormat::VEC3;
80     case GL_FLOAT_VEC4:
81       return Dali::Graphics::VertexInputAttributeFormat::VEC4;
82     case GL_INT:
83       return Dali::Graphics::VertexInputAttributeFormat::INTEGER;
84     default:
85       return Dali::Graphics::VertexInputAttributeFormat::UNDEFINED;
86   }
87 }
88
89 uint32_t GetGLDataTypeSize(GLenum type)
90 {
91   // There are many more types than what are covered here, but
92   // they are not supported in dali.
93   switch(type)
94   {
95     case GL_FLOAT: // "float", 1 float, 4 bytes
96       return 4;
97     case GL_FLOAT_VEC2: // "vec2", 2 floats, 8 bytes
98       return 8;
99     case GL_FLOAT_VEC3: // "vec3", 3 floats, 12 bytes
100       return 12;
101     case GL_FLOAT_VEC4: // "vec4", 4 floats, 16 bytes
102       return 16;
103     case GL_INT: // "int", 1 integer, 4 bytes
104       return 4;
105     case GL_FLOAT_MAT2: // "mat2", 4 floats, 16 bytes
106       return 16;
107     case GL_FLOAT_MAT3: // "mat3", 3 vec3, 36 bytes
108       return 36;
109     case GL_FLOAT_MAT4: // "mat4", 4 vec4, 64 bytes
110       return 64;
111     default:
112       return 0;
113   }
114 }
115
116 bool IsSampler(GLenum type)
117 {
118   return type == GL_SAMPLER_2D || type == GL_SAMPLER_3D || type == GL_SAMPLER_CUBE || type == GL_SAMPLER_EXTERNAL_OES;
119 }
120
121 bool SortUniformInfoByLocation(Dali::Graphics::UniformInfo a, Dali::Graphics::UniformInfo b)
122 {
123   return a.location < b.location;
124 }
125
126 bool SortUniformExtraInfoByLocation(Dali::Graphics::GLES::Reflection::UniformExtraInfo a, Dali::Graphics::GLES::Reflection::UniformExtraInfo b)
127 {
128   return a.location < b.location;
129 }
130
131 std::string GetShaderSource(Dali::Graphics::ShaderState shaderState)
132 {
133   std::vector<uint8_t> data;
134   auto*                shader           = static_cast<const Dali::Graphics::GLES::Shader*>(shaderState.shader);
135   auto&                shaderCreateInfo = shader->GetCreateInfo();
136   data.resize(shaderCreateInfo.sourceSize + 1);
137   std::memcpy(&data[0], shaderCreateInfo.sourceData, shaderCreateInfo.sourceSize);
138   data[shaderCreateInfo.sourceSize] = 0;
139
140   return std::string(reinterpret_cast<char*>(&data[0]));
141 }
142
143 void ParseShaderSamplers(std::string shaderSource, std::vector<Dali::Graphics::UniformInfo>& uniformOpaques, int& samplerPosition, std::vector<int>& samplerPositions)
144 {
145   if(!shaderSource.empty())
146   {
147     char* shaderStr = strdup(shaderSource.c_str());
148     char* uniform   = strstr(shaderStr, UNIFORM);
149
150     while(uniform)
151     {
152       // From "uniform" to ";", not ignoring comments.
153       char* outerToken = strtok_r(uniform + UNIFORM.mLength, ";", &uniform);
154
155       char* nextPtr = nullptr;
156       char* token   = strtok_r(outerToken, DELIMITERS, &nextPtr);
157       while(token)
158       {
159         // Ignore any token up to "sampler"
160         if(SAMPLER_PREFIX == token)
161         {
162           token += SAMPLER_PREFIX.mLength;
163           if(std::find(SAMPLER_TYPES, END_SAMPLER_TYPES, token) != END_SAMPLER_TYPES)
164           {
165             bool found(false);
166             // We now are at next token after "samplerxxx" in outerToken token "stream"
167
168             // Does it use array notation?
169             int  arraySize = 0; // 0 = No array
170             auto iter      = std::string(token).find("[", 0);
171             if(iter != std::string::npos)
172             {
173               // Get Array size from source. (Warning, may be higher than GetActiveUniform suggests)
174               iter++;
175               arraySize = int(strtol(token + iter, nullptr, 0));
176             }
177
178             token = strtok_r(nullptr, DELIMITERS_INC_INDEX, &nextPtr); // " ", "\t", "\n", "[", "]"
179
180             for(uint32_t i = 0; i < static_cast<uint32_t>(uniformOpaques.size()); ++i)
181             {
182               if(samplerPositions[i] == -1 &&
183                  strncmp(token, uniformOpaques[i].name.c_str(), uniformOpaques[i].name.size()) == 0)
184               {
185                 // We have found a matching name.
186                 samplerPositions[i] = uniformOpaques[i].offset = samplerPosition;
187                 if(arraySize == 0)
188                 {
189                   ++samplerPosition;
190                 }
191                 else
192                 {
193                   samplerPosition += arraySize;
194                 }
195                 found = true;
196                 break;
197               }
198             }
199
200             if(!found)
201             {
202               DALI_LOG_INFO(gGraphicsReflectionLogFilter, Debug::General, "Sampler uniform %s declared but not used in the shader\n", token);
203             }
204             break;
205           }
206         }
207
208         token = strtok_r(nullptr, DELIMITERS, &nextPtr);
209       }
210
211       uniform = strstr(uniform, UNIFORM);
212     }
213     free(shaderStr);
214   }
215 }
216
217 } // anonymous namespace
218
219 namespace Dali::Graphics::GLES
220 {
221 Reflection::Reflection(GLES::ProgramImpl& program, Graphics::EglGraphicsController& controller)
222 : Graphics::Reflection(),
223   mController(controller),
224   mProgram(program)
225 {
226 }
227
228 Reflection::~Reflection() = default;
229
230 void Reflection::BuildVertexAttributeReflection()
231 {
232   auto glProgram = mProgram.GetGlProgram();
233
234   int    written, size, location, maxLength, nAttribs;
235   GLenum type;
236   char*  name;
237
238   auto gl = mController.GetGL();
239   if(!gl)
240   {
241     // Do nothing during shutdown
242     return;
243   }
244
245   DALI_LOG_INFO(gGraphicsReflectionLogFilter, Debug::General, "Build vertex attribute reflection for glProgram : %u\n", glProgram);
246
247   gl->GetProgramiv(glProgram, GL_ACTIVE_ATTRIBUTE_MAX_LENGTH, &maxLength);
248   gl->GetProgramiv(glProgram, GL_ACTIVE_ATTRIBUTES, &nAttribs);
249
250   mVertexInputAttributes.clear();
251   mVertexInputAttributes.resize(nAttribs);
252
253   int maxLocationValue = nAttribs - 1;
254
255   name = new GLchar[maxLength];
256   for(int i = 0; i < nAttribs; i++)
257   {
258     gl->GetActiveAttrib(glProgram, i, maxLength, &written, &size, &type, name);
259     location = gl->GetAttribLocation(glProgram, name);
260
261     if(location >= 0)
262     {
263       if(maxLocationValue < location)
264       {
265         maxLocationValue = location;
266         mVertexInputAttributes.resize(maxLocationValue + 1u);
267       }
268
269       AttributeInfo attributeInfo;
270       attributeInfo.location = location;
271       attributeInfo.name     = name;
272       attributeInfo.format   = GetVertexAttributeTypeFormat(type);
273       mVertexInputAttributes[location] = std::move(attributeInfo);
274     }
275   }
276
277   delete[] name;
278 }
279
280 void Reflection::BuildUniformReflection()
281 {
282   auto glProgram = mProgram.GetGlProgram();
283
284   int   maxLen;
285   char* name;
286
287   int numUniforms = 0;
288
289   auto gl = mController.GetGL();
290   if(!gl)
291   {
292     // Do nothing during shutdown
293     return;
294   }
295
296   DALI_LOG_INFO(gGraphicsReflectionLogFilter, Debug::General, "Build uniform reflection for glProgram : %u\n", glProgram);
297
298   gl->GetProgramiv(glProgram, GL_ACTIVE_UNIFORM_MAX_LENGTH, &maxLen);
299   gl->GetProgramiv(glProgram, GL_ACTIVE_UNIFORMS, &numUniforms);
300
301   mUniformBlocks.clear();
302   mDefaultUniformBlock.members.clear();
303   mUniformOpaques.clear();
304
305   name = new char[maxLen];
306
307   mStandaloneUniformExtraInfos.clear();
308
309   for(int i = 0; i < numUniforms; ++i)
310   {
311     int    elementCount;
312     GLenum type;
313     int    written;
314     gl->GetActiveUniform(glProgram, i, maxLen, &written, &elementCount, &type, name);
315
316     int location = gl->GetUniformLocation(glProgram, name);
317
318     Dali::Graphics::UniformInfo uniformInfo;
319
320     uniformInfo.name = name;
321     if(elementCount > 1)
322     {
323       // If we have an active uniform that refers to an array, only the first element
324       // is present in this list, and is referenced as "uniform[0]", but the element
325       // count is non-zero to indicate how many uniforms there are in the array.
326
327       // Strip off the array, but store the element count
328       auto iter = std::string(uniformInfo.name).find("[", 0);
329       if(iter != std::string::npos)
330       {
331         uniformInfo.name         = std::string(name).substr(0, iter);
332         uniformInfo.elementCount = elementCount;
333       }
334     }
335     uniformInfo.uniformClass = IsSampler(type) ? Dali::Graphics::UniformClass::COMBINED_IMAGE_SAMPLER : Dali::Graphics::UniformClass::UNIFORM;
336     uniformInfo.location     = location; // GL doesn't guarantee that consecutive array elements have sequential locations. But, we only store location of first element.
337     uniformInfo.binding      = 0;
338     uniformInfo.bufferIndex  = 0;
339     uniformInfo.offset       = 0;
340
341     if(IsSampler(type))
342     {
343       mUniformOpaques.push_back(uniformInfo);
344     }
345     else
346     {
347       mDefaultUniformBlock.members.push_back(uniformInfo);
348       mStandaloneUniformExtraInfos.emplace_back(location, GetGLDataTypeSize(type), uniformInfo.offset, elementCount, type);
349     }
350   }
351
352   // Re-order according to uniform locations.
353
354   if(mDefaultUniformBlock.members.size() > 1)
355   {
356     std::sort(mDefaultUniformBlock.members.begin(), mDefaultUniformBlock.members.end(), SortUniformInfoByLocation);
357     std::sort(mStandaloneUniformExtraInfos.begin(), mStandaloneUniformExtraInfos.end(), SortUniformExtraInfoByLocation);
358   }
359
360   if(mUniformOpaques.size() > 1)
361   {
362     SortOpaques();
363   }
364
365   // Calculate the uniform offset
366   for(unsigned int i = 0; i < mDefaultUniformBlock.members.size(); ++i)
367   {
368     if(i == 0)
369     {
370       mDefaultUniformBlock.members[i].offset = 0;
371     }
372     else
373     {
374       uint32_t previousUniformLocation = mDefaultUniformBlock.members[i - 1].location;
375       auto     previousUniform         = std::find_if(mStandaloneUniformExtraInfos.begin(), mStandaloneUniformExtraInfos.end(), [&previousUniformLocation](const UniformExtraInfo& iter) { return iter.location == previousUniformLocation; });
376       if(previousUniform != mStandaloneUniformExtraInfos.end())
377       {
378         mDefaultUniformBlock.members[i].offset = mDefaultUniformBlock.members[i - 1].offset + (previousUniform->size * previousUniform->arraySize);
379         mStandaloneUniformExtraInfos[i].offset = mDefaultUniformBlock.members[i].offset;
380       }
381     }
382   }
383
384   if(mDefaultUniformBlock.members.size() > 0)
385   {
386     uint32_t lastUniformLocation = mDefaultUniformBlock.members.back().location;
387     auto     lastUniform         = std::find_if(mStandaloneUniformExtraInfos.begin(), mStandaloneUniformExtraInfos.end(), [&lastUniformLocation](const UniformExtraInfo& iter) { return iter.location == lastUniformLocation; });
388     if(lastUniform != mStandaloneUniformExtraInfos.end())
389     {
390       mDefaultUniformBlock.size = mDefaultUniformBlock.members.back().offset + (lastUniform->size * lastUniform->arraySize);
391       mUniformBlocks.push_back(mDefaultUniformBlock);
392     }
393   }
394   else
395   {
396     mDefaultUniformBlock.size = 0;
397   }
398
399   delete[] name;
400 }
401
402 // TODO: Maybe this is not needed if uniform block is not support by dali shaders?
403 void Reflection::BuildUniformBlockReflection()
404 {
405   auto gl               = mController.GetGL();
406   auto glProgram        = mProgram.GetGlProgram();
407   int  numUniformBlocks = 0;
408
409   if(!gl)
410   {
411     // Do nothing during shutdown
412     return;
413   }
414
415   DALI_LOG_INFO(gGraphicsReflectionLogFilter, Debug::General, "Build uniform block reflection for glProgram : %u\n", glProgram);
416
417   gl->GetProgramiv(glProgram, GL_ACTIVE_UNIFORM_BLOCKS, &numUniformBlocks);
418
419   mUniformBlocks.clear();
420   mUniformBlocks.resize(numUniformBlocks);
421
422   int uniformBlockMaxLength = 0;
423   gl->GetProgramiv(glProgram, GL_ACTIVE_UNIFORM_BLOCK_MAX_NAME_LENGTH, &uniformBlockMaxLength);
424
425   char* uniformBlockName = new char[uniformBlockMaxLength];
426   for(int i = 0; i < numUniformBlocks; i++)
427   {
428     int length;
429     int blockBinding;
430     int blockDataSize;
431     gl->GetActiveUniformBlockName(glProgram, i, uniformBlockMaxLength, &length, uniformBlockName);
432     gl->GetActiveUniformBlockiv(glProgram, i, GL_UNIFORM_BLOCK_BINDING, &blockBinding);
433     gl->GetActiveUniformBlockiv(glProgram, i, GL_UNIFORM_BLOCK_DATA_SIZE, &blockDataSize);
434
435     Dali::Graphics::UniformBlockInfo uniformBlockInfo;
436     uniformBlockInfo.name    = uniformBlockName;
437     uniformBlockInfo.size    = blockDataSize;
438     uniformBlockInfo.binding = blockBinding;
439
440     int nUnis;
441     gl->GetActiveUniformBlockiv(glProgram, i, GL_UNIFORM_BLOCK_ACTIVE_UNIFORMS, &nUnis);
442     int* unifIndexes = new GLint[nUnis];
443     gl->GetActiveUniformBlockiv(glProgram, i, GL_UNIFORM_BLOCK_ACTIVE_UNIFORM_INDICES, unifIndexes);
444     char* uniformName{};
445     int   maxUniLen;
446     gl->GetProgramiv(glProgram, GL_ACTIVE_UNIFORM_MAX_LENGTH, &maxUniLen);
447
448     for(int unif = 0; unif < nUnis; ++unif)
449     {
450       int    uniIndex = unifIndexes[unif];
451       int    size;
452       GLenum type;
453
454       gl->GetActiveUniform(glProgram, uniIndex, maxUniLen, &length, &size, &type, uniformName);
455       int location = gl->GetUniformLocation(glProgram, uniformName);
456
457       Dali::Graphics::UniformInfo uniform;
458       uniform.name     = uniformName;
459       uniform.location = location;
460       uniformBlockInfo.members.push_back(uniform);
461     }
462
463     delete[] unifIndexes;
464
465     mUniformBlocks.push_back(uniformBlockInfo);
466   }
467   delete[] uniformBlockName;
468 }
469
470 uint32_t Reflection::GetVertexAttributeLocation(const std::string& name) const
471 {
472   DALI_LOG_INFO(gGraphicsReflectionLogFilter, Debug::Verbose, "name : %s\n", name.c_str());
473   for(auto&& attr : mVertexInputAttributes)
474   {
475     if(attr.name == name)
476     {
477       return attr.location;
478     }
479   }
480   return ERROR_ATTRIBUTE_NOT_FOUND;
481 }
482
483 Dali::Graphics::VertexInputAttributeFormat Reflection::GetVertexAttributeFormat(uint32_t location) const
484 {
485   DALI_LOG_INFO(gGraphicsReflectionLogFilter, Debug::Verbose, "location : %u\n", location);
486   if(location >= mVertexInputAttributes.size())
487   {
488     return Dali::Graphics::VertexInputAttributeFormat::UNDEFINED;
489   }
490
491   return mVertexInputAttributes[location].format;
492 }
493
494 std::string Reflection::GetVertexAttributeName(uint32_t location) const
495 {
496   DALI_LOG_INFO(gGraphicsReflectionLogFilter, Debug::Verbose, "location : %u\n", location);
497   if(location >= mVertexInputAttributes.size())
498   {
499     return std::string();
500   }
501
502   return mVertexInputAttributes[location].name;
503 }
504
505 std::vector<uint32_t> Reflection::GetVertexAttributeLocations() const
506 {
507   std::vector<uint32_t> locations;
508   for(auto&& attr : mVertexInputAttributes)
509   {
510     if(attr.format != Dali::Graphics::VertexInputAttributeFormat::UNDEFINED)
511     {
512       locations.push_back(attr.location);
513     }
514   }
515
516   return locations;
517 }
518
519 uint32_t Reflection::GetUniformBlockCount() const
520 {
521   return mUniformBlocks.size();
522 }
523
524 uint32_t Reflection::GetUniformBlockBinding(uint32_t index) const
525 {
526   return index < mUniformBlocks.size() ? mUniformBlocks[index].binding : 0u;
527 }
528
529 uint32_t Reflection::GetUniformBlockSize(uint32_t index) const
530 {
531   return index < mUniformBlocks.size() ? mUniformBlocks[index].size : 0u;
532 }
533
534 bool Reflection::GetUniformBlock(uint32_t index, Dali::Graphics::UniformBlockInfo& out) const
535 {
536   if(index >= mUniformBlocks.size())
537   {
538     return false;
539   }
540
541   const auto& block = mUniformBlocks[index];
542
543   out.name          = block.name;
544   out.binding       = block.binding;
545   out.descriptorSet = block.descriptorSet;
546   auto membersSize  = block.members.size();
547   out.members.resize(membersSize);
548   out.size = block.size;
549   for(auto i = 0u; i < out.members.size(); ++i)
550   {
551     const auto& memberUniform   = block.members[i];
552     out.members[i].name         = memberUniform.name;
553     out.members[i].binding      = block.binding;
554     out.members[i].uniformClass = Graphics::UniformClass::UNIFORM;
555     out.members[i].offset       = memberUniform.offset;
556     out.members[i].location     = memberUniform.location;
557   }
558
559   return true;
560 }
561
562 std::vector<uint32_t> Reflection::GetUniformBlockLocations() const
563 {
564   std::vector<uint32_t> retval{};
565   for(auto&& ubo : mUniformBlocks)
566   {
567     retval.emplace_back(ubo.binding);
568   }
569   return retval;
570 }
571
572 std::string Reflection::GetUniformBlockName(uint32_t blockIndex) const
573 {
574   if(blockIndex < mUniformBlocks.size())
575   {
576     return mUniformBlocks[blockIndex].name;
577   }
578   else
579   {
580     return std::string();
581   }
582 }
583
584 uint32_t Reflection::GetUniformBlockMemberCount(uint32_t blockIndex) const
585 {
586   if(blockIndex < mUniformBlocks.size())
587   {
588     return static_cast<uint32_t>(mUniformBlocks[blockIndex].members.size());
589   }
590   else
591   {
592     return 0u;
593   }
594 }
595
596 std::string Reflection::GetUniformBlockMemberName(uint32_t blockIndex, uint32_t memberLocation) const
597 {
598   if(blockIndex < mUniformBlocks.size() && memberLocation < mUniformBlocks[blockIndex].members.size())
599   {
600     return mUniformBlocks[blockIndex].members[memberLocation].name;
601   }
602   else
603   {
604     return std::string();
605   }
606 }
607
608 uint32_t Reflection::GetUniformBlockMemberOffset(uint32_t blockIndex, uint32_t memberLocation) const
609 {
610   if(blockIndex < mUniformBlocks.size() && memberLocation < mUniformBlocks[blockIndex].members.size())
611   {
612     return mUniformBlocks[blockIndex].members[memberLocation].offset;
613   }
614   else
615   {
616     return 0u;
617   }
618 }
619
620 bool Reflection::GetNamedUniform(const std::string& name, Dali::Graphics::UniformInfo& out) const
621 {
622   auto index = 0u;
623   for(auto&& ubo : mUniformBlocks)
624   {
625     for(auto&& member : ubo.members)
626     {
627       if(name == member.name || name == (ubo.name + "." + member.name))
628       {
629         out.name         = name;
630         out.location     = member.location;
631         out.binding      = ubo.binding;
632         out.bufferIndex  = index;
633         out.offset       = member.offset;
634         out.uniformClass = Graphics::UniformClass::UNIFORM;
635         return true;
636       }
637     }
638     ++index;
639   }
640
641   // check samplers
642   index = 0u;
643   for(auto&& uniform : mUniformOpaques)
644   {
645     if(uniform.name == name)
646     {
647       out.uniformClass = Graphics::UniformClass::COMBINED_IMAGE_SAMPLER;
648       out.binding      = 0;
649       out.name         = name;
650       out.offset       = index;            // lexical location in shader
651       out.location     = uniform.location; // uniform location mapping
652       return true;
653     }
654     ++index;
655   }
656
657   return false;
658 }
659
660 std::vector<GLenum> Reflection::GetStandaloneUniformTypes() const
661 {
662   std::vector<GLenum> retval{};
663   for(auto&& uniform : mStandaloneUniformExtraInfos)
664   {
665     retval.emplace_back(uniform.type);
666   }
667
668   return retval;
669 }
670
671 const std::vector<Reflection::UniformExtraInfo>& Reflection::GetStandaloneUniformExtraInfo() const
672 {
673   return mStandaloneUniformExtraInfos;
674 }
675
676 const std::vector<Dali::Graphics::UniformInfo>& Reflection::GetSamplers() const
677 {
678   return mUniformOpaques;
679 }
680
681 Graphics::ShaderLanguage Reflection::GetLanguage() const
682 {
683   auto version = Graphics::ShaderLanguage::GLSL_3_2;
684
685   auto gl = mController.GetGL();
686   if(!gl)
687   {
688     // Do nothing during shutdown
689     return version;
690   }
691
692   int majorVersion, minorVersion;
693   gl->GetIntegerv(GL_MAJOR_VERSION, &majorVersion);
694   gl->GetIntegerv(GL_MINOR_VERSION, &minorVersion);
695   DALI_LOG_RELEASE_INFO("GL Version (integer) : %d.%d\n", majorVersion, minorVersion);
696   DALI_LOG_RELEASE_INFO("GLSL Version : %s\n", gl->GetString(GL_SHADING_LANGUAGE_VERSION));
697
698   // TODO: the language version is hardcoded for now, but we may use what we get
699   // from GL_SHADING_LANGUAGE_VERSION?
700   return version;
701 }
702
703 void Reflection::SortOpaques()
704 {
705   //Determine declaration order of each sampler
706   auto& programCreateInfo = mProgram.GetCreateInfo();
707
708   std::vector<uint8_t> data;
709   std::string          vertShader;
710   std::string          fragShader;
711
712   for(auto& shaderState : *programCreateInfo.shaderState)
713   {
714     if(shaderState.pipelineStage == PipelineStage::VERTEX_SHADER)
715     {
716       vertShader = GetShaderSource(shaderState);
717     }
718     else if(shaderState.pipelineStage == PipelineStage::FRAGMENT_SHADER)
719     {
720       fragShader = GetShaderSource(shaderState);
721     }
722   }
723
724   int              samplerPosition = 0;
725   std::vector<int> samplerPositions(mUniformOpaques.size(), -1);
726
727   ParseShaderSamplers(vertShader, mUniformOpaques, samplerPosition, samplerPositions);
728   ParseShaderSamplers(fragShader, mUniformOpaques, samplerPosition, samplerPositions);
729
730   std::sort(mUniformOpaques.begin(), mUniformOpaques.end(), [](const UniformInfo& a, const UniformInfo& b) { return a.offset < b.offset; });
731 }
732
733 } // namespace Dali::Graphics::GLES