*/
#include "gles-graphics-reflection.h"
+
+#include <dali/integration-api/debug.h>
#include <dali/integration-api/gl-abstraction.h>
#include <dali/integration-api/gl-defines.h>
#include <GLES3/gl3.h>
#include <GLES3/gl31.h>
+#include "gles-graphics-program.h"
+
#include <iostream>
namespace
{
+struct StringSize
+{
+ const char* const mString;
+ const uint32_t mLength;
+
+ template<uint32_t kLength>
+ constexpr StringSize(const char (&string)[kLength])
+ : mString(string),
+ mLength(kLength - 1) // remove terminating null; N.B. there should be no other null.
+ {
+ }
+
+ operator const char*() const
+ {
+ return mString;
+ }
+};
+
+bool operator==(const StringSize& lhs, const char* rhs)
+{
+ return strncmp(lhs.mString, rhs, lhs.mLength) == 0;
+}
+
+const char* const DELIMITERS = " \t\n";
+constexpr StringSize UNIFORM{"uniform"};
+constexpr StringSize SAMPLER_PREFIX{"sampler"};
+constexpr StringSize SAMPLER_TYPES[] = {"2D", "Cube", "ExternalOES"};
+constexpr auto END_SAMPLER_TYPES = SAMPLER_TYPES + std::extent<decltype(SAMPLER_TYPES)>::value;
+
Dali::Graphics::VertexInputAttributeFormat GetVertexAttributeTypeFormat(GLenum type)
{
switch(type)
}
}
-int GetGLDataTypeSize(GLenum type)
+uint32_t GetGLDataTypeSize(GLenum type)
{
// There are many more types than what are covered here, but
// they are not supported in dali.
bool IsSampler(GLenum type)
{
- return type == GL_SAMPLER_2D || type == GL_SAMPLER_3D;
+ return type == GL_SAMPLER_2D || type == GL_SAMPLER_3D || type == GL_SAMPLER_CUBE || type == GL_SAMPLER_EXTERNAL_OES;
}
-bool SortByLocation(Dali::Graphics::UniformInfo a, Dali::Graphics::UniformInfo b)
+bool SortUniformInfoByLocation(Dali::Graphics::UniformInfo a, Dali::Graphics::UniformInfo b)
{
return a.location < b.location;
}
-} // namespace
+bool SortUniformExtraInfoByLocation(Dali::Graphics::GLES::Reflection::UniformExtraInfo a, Dali::Graphics::GLES::Reflection::UniformExtraInfo b)
+{
+ return a.location < b.location;
+}
-namespace Dali
+std::string GetShaderSource(Dali::Graphics::ShaderState shaderState)
{
-namespace Graphics
+ std::vector<uint8_t> data;
+ auto* shader = static_cast<const Dali::Graphics::GLES::Shader*>(shaderState.shader);
+ auto& shaderCreateInfo = shader->GetCreateInfo();
+ data.resize(shaderCreateInfo.sourceSize + 1);
+ std::memcpy(&data[0], shaderCreateInfo.sourceData, shaderCreateInfo.sourceSize);
+ data[shaderCreateInfo.sourceSize] = 0;
+
+ return std::string(reinterpret_cast<char*>(&data[0]));
+}
+
+void ParseShaderSamplers(std::string shaderSource, std::vector<Dali::Graphics::UniformInfo>& uniformOpaques, int& samplerPosition, std::vector<int>& samplerPositions)
{
-namespace GLES
+ if(!shaderSource.empty())
+ {
+ char* shaderStr = strdup(shaderSource.c_str());
+ char* uniform = strstr(shaderStr, UNIFORM);
+
+ while(uniform)
+ {
+ char* outerToken = strtok_r(uniform + UNIFORM.mLength, ";", &uniform);
+
+ char* nextPtr = nullptr;
+ char* token = strtok_r(outerToken, DELIMITERS, &nextPtr);
+ while(token)
+ {
+ if(SAMPLER_PREFIX == token)
+ {
+ token += SAMPLER_PREFIX.mLength;
+ if(std::find(SAMPLER_TYPES, END_SAMPLER_TYPES, token) != END_SAMPLER_TYPES)
+ {
+ bool found(false);
+ token = strtok_r(nullptr, DELIMITERS, &nextPtr);
+
+ for(uint32_t i = 0; i < static_cast<uint32_t>(uniformOpaques.size()); ++i)
+ {
+ if(samplerPositions[i] == -1 &&
+ strncmp(token, uniformOpaques[i].name.c_str(), uniformOpaques[i].name.size()) == 0)
+ {
+ samplerPositions[i] = uniformOpaques[i].offset = samplerPosition++;
+ found = true;
+ break;
+ }
+ }
+
+ if(!found)
+ {
+ DALI_LOG_ERROR("Sampler uniform %s declared but not used in the shader\n", token);
+ }
+ break;
+ }
+ }
+
+ token = strtok_r(nullptr, DELIMITERS, &nextPtr);
+ }
+
+ uniform = strstr(uniform, UNIFORM);
+ }
+ free(shaderStr);
+ }
+}
+
+} // anonymous namespace
+
+namespace Dali::Graphics::GLES
{
-Reflection::Reflection(Graphics::EglGraphicsController& controller)
+Reflection::Reflection(GLES::ProgramImpl& program, Graphics::EglGraphicsController& controller)
: Graphics::Reflection(),
mController(controller),
- mGlProgram(0u)
+ mProgram(program)
{
}
-Reflection::~Reflection()
-{
-}
+Reflection::~Reflection() = default;
void Reflection::BuildVertexAttributeReflection()
{
+ auto glProgram = mProgram.GetGlProgram();
+
int written, size, location, maxLength, nAttribs;
GLenum type;
char* name;
auto gl = mController.GetGL();
+ if(!gl)
+ {
+ // Do nothing during shutdown
+ return;
+ }
- gl->GetProgramiv(mGlProgram, GL_ACTIVE_ATTRIBUTE_MAX_LENGTH, &maxLength);
- gl->GetProgramiv(mGlProgram, GL_ACTIVE_ATTRIBUTES, &nAttribs);
+ gl->GetProgramiv(glProgram, GL_ACTIVE_ATTRIBUTE_MAX_LENGTH, &maxLength);
+ gl->GetProgramiv(glProgram, GL_ACTIVE_ATTRIBUTES, &nAttribs);
mVertexInputAttributes.clear();
mVertexInputAttributes.resize(nAttribs);
+ int maximumLocation = nAttribs - 1;
+
name = new GLchar[maxLength];
for(int i = 0; i < nAttribs; i++)
{
- gl->GetActiveAttrib(mGlProgram, i, maxLength, &written, &size, &type, name);
- location = gl->GetAttribLocation(mGlProgram, name);
+ gl->GetActiveAttrib(glProgram, i, maxLength, &written, &size, &type, name);
+ location = gl->GetAttribLocation(glProgram, name);
- AttributeInfo attributeInfo;
- attributeInfo.location = location;
- attributeInfo.name = name;
- attributeInfo.format = GetVertexAttributeTypeFormat(type);
+ if(location >= 0)
+ {
+ if(maximumLocation < location)
+ {
+ maximumLocation = location;
+ // Increate continer size s.t. we can use maximumLocation as index.
+ mVertexInputAttributes.resize(maximumLocation + 1u);
+ }
- mVertexInputAttributes.insert(mVertexInputAttributes.begin() + location, attributeInfo);
+ AttributeInfo attributeInfo;
+ attributeInfo.location = location;
+ attributeInfo.name = name;
+ attributeInfo.format = GetVertexAttributeTypeFormat(type);
+ mVertexInputAttributes[location] = std::move(attributeInfo);
+ }
}
+
delete[] name;
}
void Reflection::BuildUniformReflection()
{
+ auto glProgram = mProgram.GetGlProgram();
+
int maxLen;
char* name;
int numUniforms = 0;
auto gl = mController.GetGL();
+ if(!gl)
+ {
+ // Do nothing during shutdown
+ return;
+ }
- gl->GetProgramiv(mGlProgram, GL_ACTIVE_UNIFORM_MAX_LENGTH, &maxLen);
- gl->GetProgramiv(mGlProgram, GL_ACTIVE_UNIFORMS, &numUniforms);
+ gl->GetProgramiv(glProgram, GL_ACTIVE_UNIFORM_MAX_LENGTH, &maxLen);
+ gl->GetProgramiv(glProgram, GL_ACTIVE_UNIFORMS, &numUniforms);
mUniformBlocks.clear();
mDefaultUniformBlock.members.clear();
name = new char[maxLen];
- int maxUniformLocations;
- gl->GetProgramiv(mGlProgram, GL_MAX_UNIFORM_LOCATIONS, &maxUniformLocations);
-
- std::vector<int> uniformSize;
- uniformSize.reserve(maxUniformLocations);
+ mStandaloneUniformExtraInfos.clear();
for(int i = 0; i < numUniforms; ++i)
{
- int size;
+ int elementCount;
GLenum type;
int written;
- gl->GetActiveUniform(mGlProgram, i, maxLen, &written, &size, &type, name);
- int location = gl->GetUniformLocation(mGlProgram, name);
- uniformSize[location] = GetGLDataTypeSize(type);
+ gl->GetActiveUniform(glProgram, i, maxLen, &written, &elementCount, &type, name);
+ int location = gl->GetUniformLocation(glProgram, name);
Dali::Graphics::UniformInfo uniformInfo;
- uniformInfo.name = name;
+
+ uniformInfo.name = name;
+ if(elementCount > 1)
+ {
+ auto iter = std::string(uniformInfo.name).find("[", 0);
+ if(iter != std::string::npos)
+ {
+ uniformInfo.name = std::string(name).substr(0, iter);
+ }
+ }
+
uniformInfo.uniformClass = IsSampler(type) ? Dali::Graphics::UniformClass::COMBINED_IMAGE_SAMPLER : Dali::Graphics::UniformClass::UNIFORM;
- uniformInfo.location = IsSampler(type) ? 0 : location;
- uniformInfo.binding = IsSampler(type) ? location : 0;
+ uniformInfo.location = location; //IsSampler(type) ? 0 : location;
+ uniformInfo.binding = 0; // IsSampler(type) ? location : 0;
uniformInfo.bufferIndex = 0;
+ uniformInfo.offset = 0;
if(IsSampler(type))
{
else
{
mDefaultUniformBlock.members.push_back(uniformInfo);
+ mStandaloneUniformExtraInfos.emplace_back(location, GetGLDataTypeSize(type), uniformInfo.offset, elementCount, type);
}
}
// Re-order according to uniform locations.
+
if(mDefaultUniformBlock.members.size() > 1)
{
- std::sort(mDefaultUniformBlock.members.begin(), mDefaultUniformBlock.members.end(), SortByLocation);
+ std::sort(mDefaultUniformBlock.members.begin(), mDefaultUniformBlock.members.end(), SortUniformInfoByLocation);
+ std::sort(mStandaloneUniformExtraInfos.begin(), mStandaloneUniformExtraInfos.end(), SortUniformExtraInfoByLocation);
}
if(mUniformOpaques.size() > 1)
{
- std::sort(mUniformOpaques.begin(), mUniformOpaques.end(), SortByLocation);
+ SortOpaques();
}
// Calculate the uniform offset
for(unsigned int i = 0; i < mDefaultUniformBlock.members.size(); ++i)
{
- mDefaultUniformBlock.members[i].offset = i == 0 ? 0 : mDefaultUniformBlock.members[i - 1].offset + uniformSize[mDefaultUniformBlock.members[i - 1].location];
+ if(i == 0)
+ {
+ mDefaultUniformBlock.members[i].offset = 0;
+ }
+ else
+ {
+ uint32_t previousUniformLocation = mDefaultUniformBlock.members[i - 1].location;
+ auto previousUniform = std::find_if(mStandaloneUniformExtraInfos.begin(), mStandaloneUniformExtraInfos.end(), [&previousUniformLocation](const UniformExtraInfo& iter) { return iter.location == previousUniformLocation; });
+ if(previousUniform != mStandaloneUniformExtraInfos.end())
+ {
+ mDefaultUniformBlock.members[i].offset = mDefaultUniformBlock.members[i - 1].offset + (previousUniform->size * previousUniform->arraySize);
+ mStandaloneUniformExtraInfos[i].offset = mDefaultUniformBlock.members[i].offset;
+ }
+ }
}
- mDefaultUniformBlock.size = mDefaultUniformBlock.members.back().offset + uniformSize[mDefaultUniformBlock.members.back().location];
-
- mUniformBlocks.push_back(mDefaultUniformBlock);
+ if(mDefaultUniformBlock.members.size() > 0)
+ {
+ uint32_t lastUniformLocation = mDefaultUniformBlock.members.back().location;
+ auto lastUniform = std::find_if(mStandaloneUniformExtraInfos.begin(), mStandaloneUniformExtraInfos.end(), [&lastUniformLocation](const UniformExtraInfo& iter) { return iter.location == lastUniformLocation; });
+ if(lastUniform != mStandaloneUniformExtraInfos.end())
+ {
+ mDefaultUniformBlock.size = mDefaultUniformBlock.members.back().offset + (lastUniform->size * lastUniform->arraySize);
+ mUniformBlocks.push_back(mDefaultUniformBlock);
+ }
+ }
+ else
+ {
+ mDefaultUniformBlock.size = 0;
+ }
delete[] name;
}
// TODO: Maybe this is not needed if uniform block is not support by dali shaders?
void Reflection::BuildUniformBlockReflection()
{
- auto gl = mController.GetGL();
+ auto gl = mController.GetGL();
+ auto glProgram = mProgram.GetGlProgram();
+ int numUniformBlocks = 0;
+
+ if(!gl)
+ {
+ // Do nothing during shutdown
+ return;
+ }
- int numUniformBlocks = 0;
- gl->GetProgramiv(mGlProgram, GL_ACTIVE_UNIFORM_BLOCKS, &numUniformBlocks);
+ gl->GetProgramiv(glProgram, GL_ACTIVE_UNIFORM_BLOCKS, &numUniformBlocks);
mUniformBlocks.clear();
mUniformBlocks.resize(numUniformBlocks);
int uniformBlockMaxLength = 0;
- gl->GetProgramiv(mGlProgram, GL_ACTIVE_UNIFORM_BLOCK_MAX_NAME_LENGTH, &uniformBlockMaxLength);
+ gl->GetProgramiv(glProgram, GL_ACTIVE_UNIFORM_BLOCK_MAX_NAME_LENGTH, &uniformBlockMaxLength);
char* uniformBlockName = new char[uniformBlockMaxLength];
for(int i = 0; i < numUniformBlocks; i++)
int length;
int blockBinding;
int blockDataSize;
- gl->GetActiveUniformBlockName(mGlProgram, i, uniformBlockMaxLength, &length, uniformBlockName);
- gl->GetActiveUniformBlockiv(mGlProgram, i, GL_UNIFORM_BLOCK_BINDING, &blockBinding);
- gl->GetActiveUniformBlockiv(mGlProgram, i, GL_UNIFORM_BLOCK_DATA_SIZE, &blockDataSize);
+ gl->GetActiveUniformBlockName(glProgram, i, uniformBlockMaxLength, &length, uniformBlockName);
+ gl->GetActiveUniformBlockiv(glProgram, i, GL_UNIFORM_BLOCK_BINDING, &blockBinding);
+ gl->GetActiveUniformBlockiv(glProgram, i, GL_UNIFORM_BLOCK_DATA_SIZE, &blockDataSize);
Dali::Graphics::UniformBlockInfo uniformBlockInfo;
uniformBlockInfo.name = uniformBlockName;
uniformBlockInfo.binding = blockBinding;
int nUnis;
- gl->GetActiveUniformBlockiv(mGlProgram, i, GL_UNIFORM_BLOCK_ACTIVE_UNIFORMS, &nUnis);
+ gl->GetActiveUniformBlockiv(glProgram, i, GL_UNIFORM_BLOCK_ACTIVE_UNIFORMS, &nUnis);
int* unifIndexes = new GLint[nUnis];
- gl->GetActiveUniformBlockiv(mGlProgram, i, GL_UNIFORM_BLOCK_ACTIVE_UNIFORM_INDICES, unifIndexes);
+ gl->GetActiveUniformBlockiv(glProgram, i, GL_UNIFORM_BLOCK_ACTIVE_UNIFORM_INDICES, unifIndexes);
char* uniformName{};
int maxUniLen;
- gl->GetProgramiv(mGlProgram, GL_ACTIVE_UNIFORM_MAX_LENGTH, &maxUniLen);
+ gl->GetProgramiv(glProgram, GL_ACTIVE_UNIFORM_MAX_LENGTH, &maxUniLen);
for(int unif = 0; unif < nUnis; ++unif)
{
int size;
GLenum type;
- gl->GetActiveUniform(mGlProgram, uniIndex, maxUniLen, &length, &size, &type, uniformName);
- int location = gl->GetUniformLocation(mGlProgram, uniformName);
+ gl->GetActiveUniform(glProgram, uniIndex, maxUniLen, &length, &size, &type, uniformName);
+ int location = gl->GetUniformLocation(glProgram, uniformName);
Dali::Graphics::UniformInfo uniform;
uniform.name = uniformName;
return true;
}
}
- index++;
+ ++index;
}
// check samplers
+ index = 0u;
for(auto&& uniform : mUniformOpaques)
{
if(uniform.name == name)
{
out.uniformClass = Graphics::UniformClass::COMBINED_IMAGE_SAMPLER;
- out.binding = uniform.binding;
+ out.binding = 0;
out.name = name;
- out.offset = 0;
- out.location = uniform.location;
+ out.offset = index; // lexical location in shader
+ out.location = uniform.location; // uniform location mapping
return true;
}
+ ++index;
}
return false;
}
-std::vector<Dali::Graphics::UniformInfo> Reflection::GetSamplers() const
+std::vector<GLenum> Reflection::GetStandaloneUniformTypes() const
+{
+ std::vector<GLenum> retval{};
+ for(auto&& uniform : mStandaloneUniformExtraInfos)
+ {
+ retval.emplace_back(uniform.type);
+ }
+
+ return retval;
+}
+
+const std::vector<Reflection::UniformExtraInfo>& Reflection::GetStandaloneUniformExtraInfo() const
+{
+ return mStandaloneUniformExtraInfos;
+}
+
+const std::vector<Dali::Graphics::UniformInfo>& Reflection::GetSamplers() const
{
return mUniformOpaques;
}
Graphics::ShaderLanguage Reflection::GetLanguage() const
{
+ auto version = Graphics::ShaderLanguage::GLSL_3_2;
+
auto gl = mController.GetGL();
+ if(!gl)
+ {
+ // Do nothing during shutdown
+ return version;
+ }
int majorVersion, minorVersion;
gl->GetIntegerv(GL_MAJOR_VERSION, &majorVersion);
gl->GetIntegerv(GL_MINOR_VERSION, &minorVersion);
- printf("GL Version (integer) : %d.%d\n", majorVersion, minorVersion);
- printf("GLSL Version : %s\n", gl->GetString(GL_SHADING_LANGUAGE_VERSION));
+ DALI_LOG_RELEASE_INFO("GL Version (integer) : %d.%d\n", majorVersion, minorVersion);
+ DALI_LOG_RELEASE_INFO("GLSL Version : %s\n", gl->GetString(GL_SHADING_LANGUAGE_VERSION));
// TODO: the language version is hardcoded for now, but we may use what we get
// from GL_SHADING_LANGUAGE_VERSION?
- return Graphics::ShaderLanguage::GLSL_3_2;
+ return version;
}
-void Reflection::SetGlProgram(uint32_t glProgram)
+void Reflection::SortOpaques()
{
- mGlProgram = glProgram;
+ //Determine declaration order of each sampler
+ auto& programCreateInfo = mProgram.GetCreateInfo();
+
+ std::vector<uint8_t> data;
+ std::string vertShader;
+ std::string fragShader;
+
+ for(auto& shaderState : *programCreateInfo.shaderState)
+ {
+ if(shaderState.pipelineStage == PipelineStage::VERTEX_SHADER)
+ {
+ vertShader = GetShaderSource(shaderState);
+ }
+ else if(shaderState.pipelineStage == PipelineStage::FRAGMENT_SHADER)
+ {
+ fragShader = GetShaderSource(shaderState);
+ }
+ }
+
+ int samplerPosition = 0;
+ std::vector<int> samplerPositions(mUniformOpaques.size(), -1);
+
+ ParseShaderSamplers(vertShader, mUniformOpaques, samplerPosition, samplerPositions);
+ ParseShaderSamplers(fragShader, mUniformOpaques, samplerPosition, samplerPositions);
- BuildVertexAttributeReflection();
- BuildUniformReflection();
+ std::sort(mUniformOpaques.begin(), mUniformOpaques.end(), [](const UniformInfo& a, const UniformInfo& b) { return a.offset < b.offset; });
}
-} // namespace GLES
-} // namespace Graphics
-} // namespace Dali
+} // namespace Dali::Graphics::GLES