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"
19 #include <dali/integration-api/gl-abstraction.h>
20 #include <dali/integration-api/gl-defines.h>
23 #include "egl-graphics-controller.h"
25 #include <GLES3/gl3.h>
26 #include <GLES3/gl31.h>
28 #include "gles-graphics-program.h"
34 Dali::Graphics::VertexInputAttributeFormat GetVertexAttributeTypeFormat(GLenum type)
39 return Dali::Graphics::VertexInputAttributeFormat::FLOAT;
41 return Dali::Graphics::VertexInputAttributeFormat::VEC2;
43 return Dali::Graphics::VertexInputAttributeFormat::VEC3;
45 return Dali::Graphics::VertexInputAttributeFormat::VEC4;
47 return Dali::Graphics::VertexInputAttributeFormat::INTEGER;
49 return Dali::Graphics::VertexInputAttributeFormat::UNDEFINED;
53 uint32_t GetGLDataTypeSize(GLenum type)
55 // There are many more types than what are covered here, but
56 // they are not supported in dali.
59 case GL_FLOAT: // "float", 1 float, 4 bytes
61 case GL_FLOAT_VEC2: // "vec2", 2 floats, 8 bytes
63 case GL_FLOAT_VEC3: // "vec3", 3 floats, 12 bytes
65 case GL_FLOAT_VEC4: // "vec4", 4 floats, 16 bytes
67 case GL_INT: // "int", 1 integer, 4 bytes
69 case GL_FLOAT_MAT2: // "mat2", 4 floats, 16 bytes
71 case GL_FLOAT_MAT3: // "mat3", 3 vec3, 36 bytes
73 case GL_FLOAT_MAT4: // "mat4", 4 vec4, 64 bytes
80 bool IsSampler(GLenum type)
82 return type == GL_SAMPLER_2D || type == GL_SAMPLER_3D || type == GL_SAMPLER_CUBE || type == GL_SAMPLER_EXTERNAL_OES;
85 bool SortUniformInfoByLocation(Dali::Graphics::UniformInfo a, Dali::Graphics::UniformInfo b)
87 return a.location < b.location;
90 bool SortUniformExtraInfoByLocation(Dali::Graphics::GLES::Reflection::UniformExtraInfo a, Dali::Graphics::GLES::Reflection::UniformExtraInfo b)
92 return a.location < b.location;
97 namespace Dali::Graphics::GLES
99 Reflection::Reflection(GLES::ProgramImpl& program, Graphics::EglGraphicsController& controller)
100 : Graphics::Reflection(),
101 mController(controller),
106 Reflection::~Reflection() = default;
108 void Reflection::BuildVertexAttributeReflection()
110 auto glProgram = mProgram.GetGlProgram();
112 int written, size, location, maxLength, nAttribs;
116 auto gl = mController.GetGL();
118 gl->GetProgramiv(glProgram, GL_ACTIVE_ATTRIBUTE_MAX_LENGTH, &maxLength);
119 gl->GetProgramiv(glProgram, GL_ACTIVE_ATTRIBUTES, &nAttribs);
121 mVertexInputAttributes.clear();
122 mVertexInputAttributes.resize(nAttribs);
124 name = new GLchar[maxLength];
125 for(int i = 0; i < nAttribs; i++)
127 gl->GetActiveAttrib(glProgram, i, maxLength, &written, &size, &type, name);
128 location = gl->GetAttribLocation(glProgram, name);
132 AttributeInfo attributeInfo;
133 attributeInfo.location = location;
134 attributeInfo.name = name;
135 attributeInfo.format = GetVertexAttributeTypeFormat(type);
136 mVertexInputAttributes.insert(mVertexInputAttributes.begin() + location, attributeInfo);
142 void Reflection::BuildUniformReflection()
144 auto glProgram = mProgram.GetGlProgram();
151 auto gl = mController.GetGL();
153 gl->GetProgramiv(glProgram, GL_ACTIVE_UNIFORM_MAX_LENGTH, &maxLen);
154 gl->GetProgramiv(glProgram, GL_ACTIVE_UNIFORMS, &numUniforms);
156 mUniformBlocks.clear();
157 mDefaultUniformBlock.members.clear();
158 mUniformOpaques.clear();
160 name = new char[maxLen];
162 mStandaloneUniformExtraInfos.clear();
164 for(int i = 0; i < numUniforms; ++i)
169 gl->GetActiveUniform(glProgram, i, maxLen, &written, &elementCount, &type, name);
170 int location = gl->GetUniformLocation(glProgram, name);
172 Dali::Graphics::UniformInfo uniformInfo;
174 uniformInfo.name = name;
177 auto iter = std::string(uniformInfo.name).find("[", 0);
178 if(iter != std::string::npos)
180 uniformInfo.name = std::string(name).substr(0, iter);
184 uniformInfo.uniformClass = IsSampler(type) ? Dali::Graphics::UniformClass::COMBINED_IMAGE_SAMPLER : Dali::Graphics::UniformClass::UNIFORM;
185 uniformInfo.location = IsSampler(type) ? 0 : location;
186 uniformInfo.binding = IsSampler(type) ? location : 0;
187 uniformInfo.bufferIndex = 0;
191 mUniformOpaques.push_back(uniformInfo);
195 mDefaultUniformBlock.members.push_back(uniformInfo);
196 mStandaloneUniformExtraInfos.emplace_back(location, GetGLDataTypeSize(type), uniformInfo.offset, elementCount, type);
200 // Re-order according to uniform locations.
202 if(mDefaultUniformBlock.members.size() > 1)
204 std::sort(mDefaultUniformBlock.members.begin(), mDefaultUniformBlock.members.end(), SortUniformInfoByLocation);
205 std::sort(mStandaloneUniformExtraInfos.begin(), mStandaloneUniformExtraInfos.end(), SortUniformExtraInfoByLocation);
208 if(mUniformOpaques.size() > 1)
210 std::sort(mUniformOpaques.begin(), mUniformOpaques.end(), SortUniformInfoByLocation);
213 // Calculate the uniform offset
214 for(unsigned int i = 0; i < mDefaultUniformBlock.members.size(); ++i)
218 mDefaultUniformBlock.members[i].offset = 0;
222 uint32_t previousUniformLocation = mDefaultUniformBlock.members[i - 1].location;
223 auto previousUniform = std::find_if(mStandaloneUniformExtraInfos.begin(), mStandaloneUniformExtraInfos.end(), [&previousUniformLocation](const UniformExtraInfo& iter) { return iter.location == previousUniformLocation; });
224 if(previousUniform != mStandaloneUniformExtraInfos.end())
226 mDefaultUniformBlock.members[i].offset = mDefaultUniformBlock.members[i - 1].offset + (previousUniform->size * previousUniform->arraySize);
227 mStandaloneUniformExtraInfos[i].offset = mDefaultUniformBlock.members[i].offset;
232 if(mDefaultUniformBlock.members.size() > 0)
234 uint32_t lastUniformLocation = mDefaultUniformBlock.members.back().location;
235 auto lastUniform = std::find_if(mStandaloneUniformExtraInfos.begin(), mStandaloneUniformExtraInfos.end(), [&lastUniformLocation](const UniformExtraInfo& iter) { return iter.location == lastUniformLocation; });
236 if(lastUniform != mStandaloneUniformExtraInfos.end())
238 mDefaultUniformBlock.size = mDefaultUniformBlock.members.back().offset + (lastUniform->size * lastUniform->arraySize);
239 mUniformBlocks.push_back(mDefaultUniformBlock);
244 mDefaultUniformBlock.size = 0;
250 // TODO: Maybe this is not needed if uniform block is not support by dali shaders?
251 void Reflection::BuildUniformBlockReflection()
253 auto gl = mController.GetGL();
254 auto glProgram = mProgram.GetGlProgram();
255 int numUniformBlocks = 0;
256 gl->GetProgramiv(glProgram, GL_ACTIVE_UNIFORM_BLOCKS, &numUniformBlocks);
258 mUniformBlocks.clear();
259 mUniformBlocks.resize(numUniformBlocks);
261 int uniformBlockMaxLength = 0;
262 gl->GetProgramiv(glProgram, GL_ACTIVE_UNIFORM_BLOCK_MAX_NAME_LENGTH, &uniformBlockMaxLength);
264 char* uniformBlockName = new char[uniformBlockMaxLength];
265 for(int i = 0; i < numUniformBlocks; i++)
270 gl->GetActiveUniformBlockName(glProgram, i, uniformBlockMaxLength, &length, uniformBlockName);
271 gl->GetActiveUniformBlockiv(glProgram, i, GL_UNIFORM_BLOCK_BINDING, &blockBinding);
272 gl->GetActiveUniformBlockiv(glProgram, i, GL_UNIFORM_BLOCK_DATA_SIZE, &blockDataSize);
274 Dali::Graphics::UniformBlockInfo uniformBlockInfo;
275 uniformBlockInfo.name = uniformBlockName;
276 uniformBlockInfo.size = blockDataSize;
277 uniformBlockInfo.binding = blockBinding;
280 gl->GetActiveUniformBlockiv(glProgram, i, GL_UNIFORM_BLOCK_ACTIVE_UNIFORMS, &nUnis);
281 int* unifIndexes = new GLint[nUnis];
282 gl->GetActiveUniformBlockiv(glProgram, i, GL_UNIFORM_BLOCK_ACTIVE_UNIFORM_INDICES, unifIndexes);
285 gl->GetProgramiv(glProgram, GL_ACTIVE_UNIFORM_MAX_LENGTH, &maxUniLen);
287 for(int unif = 0; unif < nUnis; ++unif)
289 int uniIndex = unifIndexes[unif];
293 gl->GetActiveUniform(glProgram, uniIndex, maxUniLen, &length, &size, &type, uniformName);
294 int location = gl->GetUniformLocation(glProgram, uniformName);
296 Dali::Graphics::UniformInfo uniform;
297 uniform.name = uniformName;
298 uniform.location = location;
299 uniformBlockInfo.members.push_back(uniform);
302 delete[] unifIndexes;
304 mUniformBlocks.push_back(uniformBlockInfo);
306 delete[] uniformBlockName;
309 uint32_t Reflection::GetVertexAttributeLocation(const std::string& name) const
311 for(auto&& attr : mVertexInputAttributes)
313 if(attr.name == name)
315 return attr.location;
318 return ERROR_ATTRIBUTE_NOT_FOUND;
321 Dali::Graphics::VertexInputAttributeFormat Reflection::GetVertexAttributeFormat(uint32_t location) const
323 if(location >= mVertexInputAttributes.size())
325 return Dali::Graphics::VertexInputAttributeFormat::UNDEFINED;
328 return mVertexInputAttributes[location].format;
331 std::string Reflection::GetVertexAttributeName(uint32_t location) const
333 if(location >= mVertexInputAttributes.size())
335 return std::string();
338 return mVertexInputAttributes[location].name;
341 std::vector<uint32_t> Reflection::GetVertexAttributeLocations() const
343 std::vector<uint32_t> locations;
344 for(auto&& attr : mVertexInputAttributes)
346 if(attr.format != Dali::Graphics::VertexInputAttributeFormat::UNDEFINED)
348 locations.push_back(attr.location);
355 uint32_t Reflection::GetUniformBlockCount() const
357 return mUniformBlocks.size();
360 uint32_t Reflection::GetUniformBlockBinding(uint32_t index) const
362 return index < mUniformBlocks.size() ? mUniformBlocks[index].binding : 0u;
365 uint32_t Reflection::GetUniformBlockSize(uint32_t index) const
367 return index < mUniformBlocks.size() ? mUniformBlocks[index].size : 0u;
370 bool Reflection::GetUniformBlock(uint32_t index, Dali::Graphics::UniformBlockInfo& out) const
372 if(index >= mUniformBlocks.size())
377 const auto& block = mUniformBlocks[index];
379 out.name = block.name;
380 out.binding = block.binding;
381 out.descriptorSet = block.descriptorSet;
382 auto membersSize = block.members.size();
383 out.members.resize(membersSize);
384 out.size = block.size;
385 for(auto i = 0u; i < out.members.size(); ++i)
387 const auto& memberUniform = block.members[i];
388 out.members[i].name = memberUniform.name;
389 out.members[i].binding = block.binding;
390 out.members[i].uniformClass = Graphics::UniformClass::UNIFORM;
391 out.members[i].offset = memberUniform.offset;
392 out.members[i].location = memberUniform.location;
398 std::vector<uint32_t> Reflection::GetUniformBlockLocations() const
400 std::vector<uint32_t> retval{};
401 for(auto&& ubo : mUniformBlocks)
403 retval.emplace_back(ubo.binding);
408 std::string Reflection::GetUniformBlockName(uint32_t blockIndex) const
410 if(blockIndex < mUniformBlocks.size())
412 return mUniformBlocks[blockIndex].name;
416 return std::string();
420 uint32_t Reflection::GetUniformBlockMemberCount(uint32_t blockIndex) const
422 if(blockIndex < mUniformBlocks.size())
424 return static_cast<uint32_t>(mUniformBlocks[blockIndex].members.size());
432 std::string Reflection::GetUniformBlockMemberName(uint32_t blockIndex, uint32_t memberLocation) const
434 if(blockIndex < mUniformBlocks.size() && memberLocation < mUniformBlocks[blockIndex].members.size())
436 return mUniformBlocks[blockIndex].members[memberLocation].name;
440 return std::string();
444 uint32_t Reflection::GetUniformBlockMemberOffset(uint32_t blockIndex, uint32_t memberLocation) const
446 if(blockIndex < mUniformBlocks.size() && memberLocation < mUniformBlocks[blockIndex].members.size())
448 return mUniformBlocks[blockIndex].members[memberLocation].offset;
456 bool Reflection::GetNamedUniform(const std::string& name, Dali::Graphics::UniformInfo& out) const
459 for(auto&& ubo : mUniformBlocks)
461 for(auto&& member : ubo.members)
463 if(name == member.name || name == (ubo.name + "." + member.name))
466 out.location = member.location;
467 out.binding = ubo.binding;
468 out.bufferIndex = index;
469 out.offset = member.offset;
470 out.uniformClass = Graphics::UniformClass::UNIFORM;
478 for(auto&& uniform : mUniformOpaques)
480 if(uniform.name == name)
482 out.uniformClass = Graphics::UniformClass::COMBINED_IMAGE_SAMPLER;
483 out.binding = uniform.binding;
486 out.location = uniform.location;
494 std::vector<GLenum> Reflection::GetStandaloneUniformTypes() const
496 std::vector<GLenum> retval{};
497 for(auto&& uniform : mStandaloneUniformExtraInfos)
499 retval.emplace_back(uniform.type);
505 const std::vector<Reflection::UniformExtraInfo>& Reflection::GetStandaloneUniformExtraInfo() const
507 return mStandaloneUniformExtraInfos;
510 std::vector<Dali::Graphics::UniformInfo> Reflection::GetSamplers() const
512 return mUniformOpaques;
515 Graphics::ShaderLanguage Reflection::GetLanguage() const
517 auto gl = mController.GetGL();
519 int majorVersion, minorVersion;
520 gl->GetIntegerv(GL_MAJOR_VERSION, &majorVersion);
521 gl->GetIntegerv(GL_MINOR_VERSION, &minorVersion);
522 printf("GL Version (integer) : %d.%d\n", majorVersion, minorVersion);
523 printf("GLSL Version : %s\n", gl->GetString(GL_SHADING_LANGUAGE_VERSION));
525 // TODO: the language version is hardcoded for now, but we may use what we get
526 // from GL_SHADING_LANGUAGE_VERSION?
527 return Graphics::ShaderLanguage::GLSL_3_2;
530 } // namespace Dali::Graphics::GLES