Fix attribute cache bug
[platform/core/uifw/dali-adaptor.git] / dali / internal / graphics / gles-impl / gles-graphics-reflection.cpp
index 43420ad..d25ec1d 100644 (file)
@@ -16,6 +16,8 @@
  */
 
 #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>
 
 
 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)
@@ -92,7 +123,70 @@ bool SortUniformExtraInfoByLocation(Dali::Graphics::GLES::Reflection::UniformExt
   return a.location < b.location;
 }
 
-} // namespace
+std::string GetShaderSource(Dali::Graphics::ShaderState shaderState)
+{
+  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)
+{
+  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
 {
@@ -114,6 +208,11 @@ void Reflection::BuildVertexAttributeReflection()
   char*  name;
 
   auto gl = mController.GetGL();
+  if(!gl)
+  {
+    // Do nothing during shutdown
+    return;
+  }
 
   gl->GetProgramiv(glProgram, GL_ACTIVE_ATTRIBUTE_MAX_LENGTH, &maxLength);
   gl->GetProgramiv(glProgram, GL_ACTIVE_ATTRIBUTES, &nAttribs);
@@ -121,6 +220,8 @@ void Reflection::BuildVertexAttributeReflection()
   mVertexInputAttributes.clear();
   mVertexInputAttributes.resize(nAttribs);
 
+  int maximumLocation = nAttribs - 1;
+
   name = new GLchar[maxLength];
   for(int i = 0; i < nAttribs; i++)
   {
@@ -129,13 +230,21 @@ void Reflection::BuildVertexAttributeReflection()
 
     if(location >= 0)
     {
+      if(maximumLocation < location)
+      {
+        maximumLocation = location;
+        // Increate continer size s.t. we can use maximumLocation as index.
+        mVertexInputAttributes.resize(maximumLocation + 1u);
+      }
+
       AttributeInfo attributeInfo;
       attributeInfo.location = location;
       attributeInfo.name     = name;
       attributeInfo.format   = GetVertexAttributeTypeFormat(type);
-      mVertexInputAttributes.insert(mVertexInputAttributes.begin() + location, attributeInfo);
+      mVertexInputAttributes[location] = std::move(attributeInfo);
     }
   }
+
   delete[] name;
 }
 
@@ -149,6 +258,11 @@ void Reflection::BuildUniformReflection()
   int numUniforms = 0;
 
   auto gl = mController.GetGL();
+  if(!gl)
+  {
+    // Do nothing during shutdown
+    return;
+  }
 
   gl->GetProgramiv(glProgram, GL_ACTIVE_UNIFORM_MAX_LENGTH, &maxLen);
   gl->GetProgramiv(glProgram, GL_ACTIVE_UNIFORMS, &numUniforms);
@@ -182,9 +296,10 @@ void Reflection::BuildUniformReflection()
     }
 
     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))
     {
@@ -207,7 +322,7 @@ void Reflection::BuildUniformReflection()
 
   if(mUniformOpaques.size() > 1)
   {
-    std::sort(mUniformOpaques.begin(), mUniformOpaques.end(), SortUniformInfoByLocation);
+    SortOpaques();
   }
 
   // Calculate the uniform offset
@@ -219,19 +334,25 @@ void Reflection::BuildUniformReflection()
     }
     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; });
-      mDefaultUniformBlock.members[i].offset = mDefaultUniformBlock.members[i - 1].offset + (previousUniform->size * previousUniform->arraySize);
-      mStandaloneUniformExtraInfos[i].offset = mDefaultUniformBlock.members[i].offset;
+      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;
+      }
     }
   }
 
   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; });
-  mDefaultUniformBlock.size    = mDefaultUniformBlock.members.back().offset + (lastUniform->size * lastUniform->arraySize);
-  mUniformBlocks.push_back(mDefaultUniformBlock);
+    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
   {
@@ -247,6 +368,13 @@ void Reflection::BuildUniformBlockReflection()
   auto gl               = mController.GetGL();
   auto glProgram        = mProgram.GetGlProgram();
   int  numUniformBlocks = 0;
+
+  if(!gl)
+  {
+    // Do nothing during shutdown
+    return;
+  }
+
   gl->GetProgramiv(glProgram, GL_ACTIVE_UNIFORM_BLOCKS, &numUniformBlocks);
 
   mUniformBlocks.clear();
@@ -465,21 +593,23 @@ bool Reflection::GetNamedUniform(const std::string& name, Dali::Graphics::Unifor
         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;
@@ -501,24 +631,61 @@ const std::vector<Reflection::UniformExtraInfo>& Reflection::GetStandaloneUnifor
   return mStandaloneUniformExtraInfos;
 }
 
-std::vector<Dali::Graphics::UniformInfo> Reflection::GetSamplers() const
+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::SortOpaques()
+{
+  //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);
+
+  std::sort(mUniformOpaques.begin(), mUniformOpaques.end(), [](const UniformInfo& a, const UniformInfo& b) { return a.offset < b.offset; });
 }
 
 } // namespace Dali::Graphics::GLES