[Tizen] Enabled sampler arrays in shader
[platform/core/uifw/dali-adaptor.git] / dali / internal / graphics / gles-impl / gles-graphics-reflection.cpp
index 05a803d..76f305a 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2021 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2023 Samsung Electronics Co., Ltd.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
 
 namespace
 {
+#if defined(DEBUG_ENABLED)
+Debug::Filter* gGraphicsReflectionLogFilter = Debug::Filter::New(Debug::NoLogging, false, "LOG_GRAPHICS_REFLECTION");
+#endif
+
+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";
+const char* const    DELIMITERS_INC_INDEX = " \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)
@@ -94,34 +128,91 @@ bool SortUniformExtraInfoByLocation(Dali::Graphics::GLES::Reflection::UniformExt
   return a.location < b.location;
 }
 
-struct StringSize
+std::string GetShaderSource(Dali::Graphics::ShaderState shaderState)
 {
-  const char* const mString;
-  const uint32_t    mLength;
+  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;
 
-  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.
-  {
-  }
+  return std::string(reinterpret_cast<char*>(&data[0]));
+}
 
-  operator const char*() const
+void ParseShaderSamplers(std::string shaderSource, std::vector<Dali::Graphics::UniformInfo>& uniformOpaques, int& samplerPosition, std::vector<int>& samplerPositions)
+{
+  if(!shaderSource.empty())
   {
-    return mString;
-  }
-};
+    char* shaderStr = strdup(shaderSource.c_str());
+    char* uniform   = strstr(shaderStr, UNIFORM);
 
-bool operator==(const StringSize& lhs, const char* rhs)
-{
-  return strncmp(lhs.mString, rhs, lhs.mLength) == 0;
-}
+    while(uniform)
+    {
+      // From "uniform" to ";", not ignoring comments.
+      char* outerToken = strtok_r(uniform + UNIFORM.mLength, ";", &uniform);
 
-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;
+      char* nextPtr = nullptr;
+      char* token   = strtok_r(outerToken, DELIMITERS, &nextPtr);
+      while(token)
+      {
+        // Ignore any token up to "sampler"
+        if(SAMPLER_PREFIX == token)
+        {
+          token += SAMPLER_PREFIX.mLength;
+          if(std::find(SAMPLER_TYPES, END_SAMPLER_TYPES, token) != END_SAMPLER_TYPES)
+          {
+            bool found(false);
+            // We now are at next token after "samplerxxx" in outerToken token "stream"
+
+            // Does it use array notation?
+            int  arraySize = 0; // 0 = No array
+            auto iter      = std::string(token).find("[", 0);
+            if(iter != std::string::npos)
+            {
+              // Get Array size from source. (Warning, may be higher than GetActiveUniform suggests)
+              iter++;
+              arraySize = int(strtol(token + iter, nullptr, 0));
+            }
+
+            token = strtok_r(nullptr, DELIMITERS_INC_INDEX, &nextPtr); // " ", "\t", "\n", "[", "]"
+
+            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)
+              {
+                // We have found a matching name.
+                samplerPositions[i] = uniformOpaques[i].offset = samplerPosition;
+                if(arraySize == 0)
+                {
+                  ++samplerPosition;
+                }
+                else
+                {
+                  samplerPosition += arraySize;
+                }
+                found = true;
+                break;
+              }
+            }
+
+            if(!found)
+            {
+              DALI_LOG_INFO(gGraphicsReflectionLogFilter, Debug::General, "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
 
@@ -151,12 +242,16 @@ void Reflection::BuildVertexAttributeReflection()
     return;
   }
 
+  DALI_LOG_INFO(gGraphicsReflectionLogFilter, Debug::General, "Build vertex attribute reflection for glProgram : %u\n", glProgram);
+
   gl->GetProgramiv(glProgram, GL_ACTIVE_ATTRIBUTE_MAX_LENGTH, &maxLength);
   gl->GetProgramiv(glProgram, GL_ACTIVE_ATTRIBUTES, &nAttribs);
 
   mVertexInputAttributes.clear();
   mVertexInputAttributes.resize(nAttribs);
 
+  int maxLocationValue = nAttribs - 1;
+
   name = new GLchar[maxLength];
   for(int i = 0; i < nAttribs; i++)
   {
@@ -165,13 +260,20 @@ void Reflection::BuildVertexAttributeReflection()
 
     if(location >= 0)
     {
+      if(maxLocationValue < location)
+      {
+        maxLocationValue = location;
+        mVertexInputAttributes.resize(maxLocationValue + 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;
 }
 
@@ -191,6 +293,8 @@ void Reflection::BuildUniformReflection()
     return;
   }
 
+  DALI_LOG_INFO(gGraphicsReflectionLogFilter, Debug::General, "Build uniform reflection for glProgram : %u\n", glProgram);
+
   gl->GetProgramiv(glProgram, GL_ACTIVE_UNIFORM_MAX_LENGTH, &maxLen);
   gl->GetProgramiv(glProgram, GL_ACTIVE_UNIFORMS, &numUniforms);
 
@@ -208,6 +312,7 @@ void Reflection::BuildUniformReflection()
     GLenum type;
     int    written;
     gl->GetActiveUniform(glProgram, i, maxLen, &written, &elementCount, &type, name);
+
     int location = gl->GetUniformLocation(glProgram, name);
 
     Dali::Graphics::UniformInfo uniformInfo;
@@ -215,16 +320,21 @@ void Reflection::BuildUniformReflection()
     uniformInfo.name = name;
     if(elementCount > 1)
     {
+      // If we have an active uniform that refers to an array, only the first element
+      // is present in this list, and is referenced as "uniform[0]", but the element
+      // count is non-zero to indicate how many uniforms there are in the array.
+
+      // Strip off the array, but store the element count
       auto iter = std::string(uniformInfo.name).find("[", 0);
       if(iter != std::string::npos)
       {
-        uniformInfo.name = std::string(name).substr(0, iter);
+        uniformInfo.name         = std::string(name).substr(0, iter);
+        uniformInfo.elementCount = elementCount;
       }
     }
-
     uniformInfo.uniformClass = IsSampler(type) ? Dali::Graphics::UniformClass::COMBINED_IMAGE_SAMPLER : Dali::Graphics::UniformClass::UNIFORM;
-    uniformInfo.location     = location; //IsSampler(type) ? 0 : location;
-    uniformInfo.binding      = 0;        // IsSampler(type) ? location : 0;
+    uniformInfo.location     = location; // GL doesn't guarantee that consecutive array elements have sequential locations. But, we only store location of first element.
+    uniformInfo.binding      = 0;
     uniformInfo.bufferIndex  = 0;
     uniformInfo.offset       = 0;
 
@@ -302,6 +412,8 @@ void Reflection::BuildUniformBlockReflection()
     return;
   }
 
+  DALI_LOG_INFO(gGraphicsReflectionLogFilter, Debug::General, "Build uniform block reflection for glProgram : %u\n", glProgram);
+
   gl->GetProgramiv(glProgram, GL_ACTIVE_UNIFORM_BLOCKS, &numUniformBlocks);
 
   mUniformBlocks.clear();
@@ -357,6 +469,7 @@ void Reflection::BuildUniformBlockReflection()
 
 uint32_t Reflection::GetVertexAttributeLocation(const std::string& name) const
 {
+  DALI_LOG_INFO(gGraphicsReflectionLogFilter, Debug::Verbose, "name : %s\n", name.c_str());
   for(auto&& attr : mVertexInputAttributes)
   {
     if(attr.name == name)
@@ -369,6 +482,7 @@ uint32_t Reflection::GetVertexAttributeLocation(const std::string& name) const
 
 Dali::Graphics::VertexInputAttributeFormat Reflection::GetVertexAttributeFormat(uint32_t location) const
 {
+  DALI_LOG_INFO(gGraphicsReflectionLogFilter, Debug::Verbose, "location : %u\n", location);
   if(location >= mVertexInputAttributes.size())
   {
     return Dali::Graphics::VertexInputAttributeFormat::UNDEFINED;
@@ -379,6 +493,7 @@ Dali::Graphics::VertexInputAttributeFormat Reflection::GetVertexAttributeFormat(
 
 std::string Reflection::GetVertexAttributeName(uint32_t location) const
 {
+  DALI_LOG_INFO(gGraphicsReflectionLogFilter, Debug::Verbose, "location : %u\n", location);
   if(location >= mVertexInputAttributes.size())
   {
     return std::string();
@@ -591,71 +706,27 @@ void Reflection::SortOpaques()
   auto& programCreateInfo = mProgram.GetCreateInfo();
 
   std::vector<uint8_t> data;
+  std::string          vertShader;
   std::string          fragShader;
 
   for(auto& shaderState : *programCreateInfo.shaderState)
   {
-    if(shaderState.pipelineStage == PipelineStage::FRAGMENT_SHADER)
+    if(shaderState.pipelineStage == PipelineStage::VERTEX_SHADER)
     {
-      auto* shader           = static_cast<const 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;
-      fragShader                        = std::string(reinterpret_cast<char*>(&data[0]));
-      break;
+      vertShader = GetShaderSource(shaderState);
     }
-  }
-
-  if(!fragShader.empty())
-  {
-    char*            shaderStr       = strdup(fragShader.c_str());
-    char*            uniform         = strstr(shaderStr, UNIFORM);
-    int              samplerPosition = 0;
-    std::vector<int> samplerPositions(mUniformOpaques.size(), -1);
-
-    while(uniform)
+    else if(shaderState.pipelineStage == PipelineStage::FRAGMENT_SHADER)
     {
-      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>(mUniformOpaques.size()); ++i)
-            {
-              if(samplerPositions[i] == -1 &&
-                 strncmp(token, mUniformOpaques[i].name.c_str(), mUniformOpaques[i].name.size()) == 0)
-              {
-                samplerPositions[i] = mUniformOpaques[i].offset = samplerPosition++;
-                found                                           = true;
-                break;
-              }
-            }
+      fragShader = GetShaderSource(shaderState);
+    }
+  }
 
-            if(!found)
-            {
-              DALI_LOG_ERROR("Sampler uniform %s declared but not used in the shader\n", token);
-            }
-            break;
-          }
-        }
+  int              samplerPosition = 0;
+  std::vector<int> samplerPositions(mUniformOpaques.size(), -1);
 
-        token = strtok_r(nullptr, DELIMITERS, &nextPtr);
-      }
+  ParseShaderSamplers(vertShader, mUniformOpaques, samplerPosition, samplerPositions);
+  ParseShaderSamplers(fragShader, mUniformOpaques, samplerPosition, samplerPositions);
 
-      uniform = strstr(uniform, UNIFORM);
-    }
-    free(shaderStr);
-  }
   std::sort(mUniformOpaques.begin(), mUniformOpaques.end(), [](const UniformInfo& a, const UniformInfo& b) { return a.offset < b.offset; });
 }