2 * Copyright (c) 2021 Samsung Electronics Co., Ltd.
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
18 #include "gles-graphics-reflection.h"
20 #include <dali/integration-api/debug.h>
21 #include <dali/integration-api/gl-abstraction.h>
22 #include <dali/integration-api/gl-defines.h>
25 #include "egl-graphics-controller.h"
27 #include <GLES3/gl3.h>
28 #include <GLES3/gl31.h>
30 #include "gles-graphics-program.h"
36 Dali::Graphics::VertexInputAttributeFormat GetVertexAttributeTypeFormat(GLenum type)
41 return Dali::Graphics::VertexInputAttributeFormat::FLOAT;
43 return Dali::Graphics::VertexInputAttributeFormat::VEC2;
45 return Dali::Graphics::VertexInputAttributeFormat::VEC3;
47 return Dali::Graphics::VertexInputAttributeFormat::VEC4;
49 return Dali::Graphics::VertexInputAttributeFormat::INTEGER;
51 return Dali::Graphics::VertexInputAttributeFormat::UNDEFINED;
55 uint32_t GetGLDataTypeSize(GLenum type)
57 // There are many more types than what are covered here, but
58 // they are not supported in dali.
61 case GL_FLOAT: // "float", 1 float, 4 bytes
63 case GL_FLOAT_VEC2: // "vec2", 2 floats, 8 bytes
65 case GL_FLOAT_VEC3: // "vec3", 3 floats, 12 bytes
67 case GL_FLOAT_VEC4: // "vec4", 4 floats, 16 bytes
69 case GL_INT: // "int", 1 integer, 4 bytes
71 case GL_FLOAT_MAT2: // "mat2", 4 floats, 16 bytes
73 case GL_FLOAT_MAT3: // "mat3", 3 vec3, 36 bytes
75 case GL_FLOAT_MAT4: // "mat4", 4 vec4, 64 bytes
82 bool IsSampler(GLenum type)
84 return type == GL_SAMPLER_2D || type == GL_SAMPLER_3D || type == GL_SAMPLER_CUBE || type == GL_SAMPLER_EXTERNAL_OES;
87 bool SortUniformInfoByLocation(Dali::Graphics::UniformInfo a, Dali::Graphics::UniformInfo b)
89 return a.location < b.location;
92 bool SortUniformExtraInfoByLocation(Dali::Graphics::GLES::Reflection::UniformExtraInfo a, Dali::Graphics::GLES::Reflection::UniformExtraInfo b)
94 return a.location < b.location;
99 const char* const mString;
100 const uint32_t mLength;
102 template<uint32_t kLength>
103 constexpr StringSize(const char (&string)[kLength])
105 mLength(kLength - 1) // remove terminating null; N.B. there should be no other null.
109 operator const char*() const
115 bool operator==(const StringSize& lhs, const char* rhs)
117 return strncmp(lhs.mString, rhs, lhs.mLength) == 0;
120 const char* const DELIMITERS = " \t\n";
121 constexpr StringSize UNIFORM{"uniform"};
122 constexpr StringSize SAMPLER_PREFIX{"sampler"};
123 constexpr StringSize SAMPLER_TYPES[] = {"2D", "Cube", "ExternalOES"};
124 constexpr auto END_SAMPLER_TYPES = SAMPLER_TYPES + std::extent<decltype(SAMPLER_TYPES)>::value;
126 } // anonymous namespace
128 namespace Dali::Graphics::GLES
130 Reflection::Reflection(GLES::ProgramImpl& program, Graphics::EglGraphicsController& controller)
131 : Graphics::Reflection(),
132 mController(controller),
137 Reflection::~Reflection() = default;
139 void Reflection::BuildVertexAttributeReflection()
141 auto glProgram = mProgram.GetGlProgram();
143 int written, size, location, maxLength, nAttribs;
147 auto gl = mController.GetGL();
150 // Do nothing during shutdown
154 gl->GetProgramiv(glProgram, GL_ACTIVE_ATTRIBUTE_MAX_LENGTH, &maxLength);
155 gl->GetProgramiv(glProgram, GL_ACTIVE_ATTRIBUTES, &nAttribs);
157 mVertexInputAttributes.clear();
158 mVertexInputAttributes.resize(nAttribs);
160 name = new GLchar[maxLength];
161 for(int i = 0; i < nAttribs; i++)
163 gl->GetActiveAttrib(glProgram, i, maxLength, &written, &size, &type, name);
164 location = gl->GetAttribLocation(glProgram, name);
168 AttributeInfo attributeInfo;
169 attributeInfo.location = location;
170 attributeInfo.name = name;
171 attributeInfo.format = GetVertexAttributeTypeFormat(type);
172 mVertexInputAttributes.insert(mVertexInputAttributes.begin() + location, attributeInfo);
178 void Reflection::BuildUniformReflection()
180 auto glProgram = mProgram.GetGlProgram();
187 auto gl = mController.GetGL();
190 // Do nothing during shutdown
194 gl->GetProgramiv(glProgram, GL_ACTIVE_UNIFORM_MAX_LENGTH, &maxLen);
195 gl->GetProgramiv(glProgram, GL_ACTIVE_UNIFORMS, &numUniforms);
197 mUniformBlocks.clear();
198 mDefaultUniformBlock.members.clear();
199 mUniformOpaques.clear();
201 name = new char[maxLen];
203 mStandaloneUniformExtraInfos.clear();
205 for(int i = 0; i < numUniforms; ++i)
210 gl->GetActiveUniform(glProgram, i, maxLen, &written, &elementCount, &type, name);
211 int location = gl->GetUniformLocation(glProgram, name);
213 Dali::Graphics::UniformInfo uniformInfo;
215 uniformInfo.name = name;
218 auto iter = std::string(uniformInfo.name).find("[", 0);
219 if(iter != std::string::npos)
221 uniformInfo.name = std::string(name).substr(0, iter);
225 uniformInfo.uniformClass = IsSampler(type) ? Dali::Graphics::UniformClass::COMBINED_IMAGE_SAMPLER : Dali::Graphics::UniformClass::UNIFORM;
226 uniformInfo.location = location; //IsSampler(type) ? 0 : location;
227 uniformInfo.binding = 0; // IsSampler(type) ? location : 0;
228 uniformInfo.bufferIndex = 0;
229 uniformInfo.offset = 0;
233 mUniformOpaques.push_back(uniformInfo);
237 mDefaultUniformBlock.members.push_back(uniformInfo);
238 mStandaloneUniformExtraInfos.emplace_back(location, GetGLDataTypeSize(type), uniformInfo.offset, elementCount, type);
242 // Re-order according to uniform locations.
244 if(mDefaultUniformBlock.members.size() > 1)
246 std::sort(mDefaultUniformBlock.members.begin(), mDefaultUniformBlock.members.end(), SortUniformInfoByLocation);
247 std::sort(mStandaloneUniformExtraInfos.begin(), mStandaloneUniformExtraInfos.end(), SortUniformExtraInfoByLocation);
250 if(mUniformOpaques.size() > 1)
255 // Calculate the uniform offset
256 for(unsigned int i = 0; i < mDefaultUniformBlock.members.size(); ++i)
260 mDefaultUniformBlock.members[i].offset = 0;
264 uint32_t previousUniformLocation = mDefaultUniformBlock.members[i - 1].location;
265 auto previousUniform = std::find_if(mStandaloneUniformExtraInfos.begin(), mStandaloneUniformExtraInfos.end(), [&previousUniformLocation](const UniformExtraInfo& iter) { return iter.location == previousUniformLocation; });
266 if(previousUniform != mStandaloneUniformExtraInfos.end())
268 mDefaultUniformBlock.members[i].offset = mDefaultUniformBlock.members[i - 1].offset + (previousUniform->size * previousUniform->arraySize);
269 mStandaloneUniformExtraInfos[i].offset = mDefaultUniformBlock.members[i].offset;
274 if(mDefaultUniformBlock.members.size() > 0)
276 uint32_t lastUniformLocation = mDefaultUniformBlock.members.back().location;
277 auto lastUniform = std::find_if(mStandaloneUniformExtraInfos.begin(), mStandaloneUniformExtraInfos.end(), [&lastUniformLocation](const UniformExtraInfo& iter) { return iter.location == lastUniformLocation; });
278 if(lastUniform != mStandaloneUniformExtraInfos.end())
280 mDefaultUniformBlock.size = mDefaultUniformBlock.members.back().offset + (lastUniform->size * lastUniform->arraySize);
281 mUniformBlocks.push_back(mDefaultUniformBlock);
286 mDefaultUniformBlock.size = 0;
292 // TODO: Maybe this is not needed if uniform block is not support by dali shaders?
293 void Reflection::BuildUniformBlockReflection()
295 auto gl = mController.GetGL();
296 auto glProgram = mProgram.GetGlProgram();
297 int numUniformBlocks = 0;
301 // Do nothing during shutdown
305 gl->GetProgramiv(glProgram, GL_ACTIVE_UNIFORM_BLOCKS, &numUniformBlocks);
307 mUniformBlocks.clear();
308 mUniformBlocks.resize(numUniformBlocks);
310 int uniformBlockMaxLength = 0;
311 gl->GetProgramiv(glProgram, GL_ACTIVE_UNIFORM_BLOCK_MAX_NAME_LENGTH, &uniformBlockMaxLength);
313 char* uniformBlockName = new char[uniformBlockMaxLength];
314 for(int i = 0; i < numUniformBlocks; i++)
319 gl->GetActiveUniformBlockName(glProgram, i, uniformBlockMaxLength, &length, uniformBlockName);
320 gl->GetActiveUniformBlockiv(glProgram, i, GL_UNIFORM_BLOCK_BINDING, &blockBinding);
321 gl->GetActiveUniformBlockiv(glProgram, i, GL_UNIFORM_BLOCK_DATA_SIZE, &blockDataSize);
323 Dali::Graphics::UniformBlockInfo uniformBlockInfo;
324 uniformBlockInfo.name = uniformBlockName;
325 uniformBlockInfo.size = blockDataSize;
326 uniformBlockInfo.binding = blockBinding;
329 gl->GetActiveUniformBlockiv(glProgram, i, GL_UNIFORM_BLOCK_ACTIVE_UNIFORMS, &nUnis);
330 int* unifIndexes = new GLint[nUnis];
331 gl->GetActiveUniformBlockiv(glProgram, i, GL_UNIFORM_BLOCK_ACTIVE_UNIFORM_INDICES, unifIndexes);
334 gl->GetProgramiv(glProgram, GL_ACTIVE_UNIFORM_MAX_LENGTH, &maxUniLen);
336 for(int unif = 0; unif < nUnis; ++unif)
338 int uniIndex = unifIndexes[unif];
342 gl->GetActiveUniform(glProgram, uniIndex, maxUniLen, &length, &size, &type, uniformName);
343 int location = gl->GetUniformLocation(glProgram, uniformName);
345 Dali::Graphics::UniformInfo uniform;
346 uniform.name = uniformName;
347 uniform.location = location;
348 uniformBlockInfo.members.push_back(uniform);
351 delete[] unifIndexes;
353 mUniformBlocks.push_back(uniformBlockInfo);
355 delete[] uniformBlockName;
358 uint32_t Reflection::GetVertexAttributeLocation(const std::string& name) const
360 for(auto&& attr : mVertexInputAttributes)
362 if(attr.name == name)
364 return attr.location;
367 return ERROR_ATTRIBUTE_NOT_FOUND;
370 Dali::Graphics::VertexInputAttributeFormat Reflection::GetVertexAttributeFormat(uint32_t location) const
372 if(location >= mVertexInputAttributes.size())
374 return Dali::Graphics::VertexInputAttributeFormat::UNDEFINED;
377 return mVertexInputAttributes[location].format;
380 std::string Reflection::GetVertexAttributeName(uint32_t location) const
382 if(location >= mVertexInputAttributes.size())
384 return std::string();
387 return mVertexInputAttributes[location].name;
390 std::vector<uint32_t> Reflection::GetVertexAttributeLocations() const
392 std::vector<uint32_t> locations;
393 for(auto&& attr : mVertexInputAttributes)
395 if(attr.format != Dali::Graphics::VertexInputAttributeFormat::UNDEFINED)
397 locations.push_back(attr.location);
404 uint32_t Reflection::GetUniformBlockCount() const
406 return mUniformBlocks.size();
409 uint32_t Reflection::GetUniformBlockBinding(uint32_t index) const
411 return index < mUniformBlocks.size() ? mUniformBlocks[index].binding : 0u;
414 uint32_t Reflection::GetUniformBlockSize(uint32_t index) const
416 return index < mUniformBlocks.size() ? mUniformBlocks[index].size : 0u;
419 bool Reflection::GetUniformBlock(uint32_t index, Dali::Graphics::UniformBlockInfo& out) const
421 if(index >= mUniformBlocks.size())
426 const auto& block = mUniformBlocks[index];
428 out.name = block.name;
429 out.binding = block.binding;
430 out.descriptorSet = block.descriptorSet;
431 auto membersSize = block.members.size();
432 out.members.resize(membersSize);
433 out.size = block.size;
434 for(auto i = 0u; i < out.members.size(); ++i)
436 const auto& memberUniform = block.members[i];
437 out.members[i].name = memberUniform.name;
438 out.members[i].binding = block.binding;
439 out.members[i].uniformClass = Graphics::UniformClass::UNIFORM;
440 out.members[i].offset = memberUniform.offset;
441 out.members[i].location = memberUniform.location;
447 std::vector<uint32_t> Reflection::GetUniformBlockLocations() const
449 std::vector<uint32_t> retval{};
450 for(auto&& ubo : mUniformBlocks)
452 retval.emplace_back(ubo.binding);
457 std::string Reflection::GetUniformBlockName(uint32_t blockIndex) const
459 if(blockIndex < mUniformBlocks.size())
461 return mUniformBlocks[blockIndex].name;
465 return std::string();
469 uint32_t Reflection::GetUniformBlockMemberCount(uint32_t blockIndex) const
471 if(blockIndex < mUniformBlocks.size())
473 return static_cast<uint32_t>(mUniformBlocks[blockIndex].members.size());
481 std::string Reflection::GetUniformBlockMemberName(uint32_t blockIndex, uint32_t memberLocation) const
483 if(blockIndex < mUniformBlocks.size() && memberLocation < mUniformBlocks[blockIndex].members.size())
485 return mUniformBlocks[blockIndex].members[memberLocation].name;
489 return std::string();
493 uint32_t Reflection::GetUniformBlockMemberOffset(uint32_t blockIndex, uint32_t memberLocation) const
495 if(blockIndex < mUniformBlocks.size() && memberLocation < mUniformBlocks[blockIndex].members.size())
497 return mUniformBlocks[blockIndex].members[memberLocation].offset;
505 bool Reflection::GetNamedUniform(const std::string& name, Dali::Graphics::UniformInfo& out) const
508 for(auto&& ubo : mUniformBlocks)
510 for(auto&& member : ubo.members)
512 if(name == member.name || name == (ubo.name + "." + member.name))
515 out.location = member.location;
516 out.binding = ubo.binding;
517 out.bufferIndex = index;
518 out.offset = member.offset;
519 out.uniformClass = Graphics::UniformClass::UNIFORM;
528 for(auto&& uniform : mUniformOpaques)
530 if(uniform.name == name)
532 out.uniformClass = Graphics::UniformClass::COMBINED_IMAGE_SAMPLER;
535 out.offset = index; // lexical location in shader
536 out.location = uniform.location; // uniform location mapping
545 std::vector<GLenum> Reflection::GetStandaloneUniformTypes() const
547 std::vector<GLenum> retval{};
548 for(auto&& uniform : mStandaloneUniformExtraInfos)
550 retval.emplace_back(uniform.type);
556 const std::vector<Reflection::UniformExtraInfo>& Reflection::GetStandaloneUniformExtraInfo() const
558 return mStandaloneUniformExtraInfos;
561 const std::vector<Dali::Graphics::UniformInfo>& Reflection::GetSamplers() const
563 return mUniformOpaques;
566 Graphics::ShaderLanguage Reflection::GetLanguage() const
568 auto version = Graphics::ShaderLanguage::GLSL_3_2;
570 auto gl = mController.GetGL();
573 // Do nothing during shutdown
577 int majorVersion, minorVersion;
578 gl->GetIntegerv(GL_MAJOR_VERSION, &majorVersion);
579 gl->GetIntegerv(GL_MINOR_VERSION, &minorVersion);
580 DALI_LOG_RELEASE_INFO("GL Version (integer) : %d.%d\n", majorVersion, minorVersion);
581 DALI_LOG_RELEASE_INFO("GLSL Version : %s\n", gl->GetString(GL_SHADING_LANGUAGE_VERSION));
583 // TODO: the language version is hardcoded for now, but we may use what we get
584 // from GL_SHADING_LANGUAGE_VERSION?
588 void Reflection::SortOpaques()
590 //Determine declaration order of each sampler
591 auto& programCreateInfo = mProgram.GetCreateInfo();
593 std::vector<uint8_t> data;
594 std::string fragShader;
596 for(auto& shaderState : *programCreateInfo.shaderState)
598 if(shaderState.pipelineStage == PipelineStage::FRAGMENT_SHADER)
600 auto* shader = static_cast<const GLES::Shader*>(shaderState.shader);
601 auto& shaderCreateInfo = shader->GetCreateInfo();
602 data.resize(shaderCreateInfo.sourceSize + 1);
603 std::memcpy(&data[0], shaderCreateInfo.sourceData, shaderCreateInfo.sourceSize);
604 data[shaderCreateInfo.sourceSize] = 0;
605 fragShader = std::string(reinterpret_cast<char*>(&data[0]));
610 if(!fragShader.empty())
612 char* shaderStr = strdup(fragShader.c_str());
613 char* uniform = strstr(shaderStr, UNIFORM);
614 int samplerPosition = 0;
615 std::vector<int> samplerPositions(mUniformOpaques.size(), -1);
619 char* outerToken = strtok_r(uniform + UNIFORM.mLength, ";", &uniform);
621 char* nextPtr = nullptr;
622 char* token = strtok_r(outerToken, DELIMITERS, &nextPtr);
625 if(SAMPLER_PREFIX == token)
627 token += SAMPLER_PREFIX.mLength;
628 if(std::find(SAMPLER_TYPES, END_SAMPLER_TYPES, token) != END_SAMPLER_TYPES)
631 token = strtok_r(nullptr, DELIMITERS, &nextPtr);
633 for(uint32_t i = 0; i < static_cast<uint32_t>(mUniformOpaques.size()); ++i)
635 if(samplerPositions[i] == -1 &&
636 strncmp(token, mUniformOpaques[i].name.c_str(), mUniformOpaques[i].name.size()) == 0)
638 samplerPositions[i] = mUniformOpaques[i].offset = samplerPosition++;
646 DALI_LOG_ERROR("Sampler uniform %s declared but not used in the shader\n", token);
652 token = strtok_r(nullptr, DELIMITERS, &nextPtr);
655 uniform = strstr(uniform, UNIFORM);
659 std::sort(mUniformOpaques.begin(), mUniformOpaques.end(), [](const UniformInfo& a, const UniformInfo& b) { return a.offset < b.offset; });
662 } // namespace Dali::Graphics::GLES