Shader Parser and SPIRV generator changes 26/320626/3
authorAdam Bialogonski <adam.b@samsung.com>
Tue, 19 Nov 2024 15:35:12 +0000 (15:35 +0000)
committerAdam Bialogonski <adam.b@samsung.com>
Wed, 20 Nov 2024 09:10:27 +0000 (09:10 +0000)
- Assigning locations to in/out between stages when type is larger than 4 floats (mat2, mat3, mat4)
Example:

Vertex shader:
out (location=0) highp mat3 vMatrix;
out (location=3) highp float vNumber; // Location must be 3 not 1!

Fragment shader:
in (location=0) highp mat3 vMatrix;
in (location=3) highp float vNumber; // Location must be 3 not 1!

This patch doesn't deal with arrays and doesn't deal with input attributes in
vertex shader. It only resolves problem of default PBR shader.

- SPIRVGenerator::Generate() sates 'valid' flag correctly now (false on error)

Change-Id: I19ee9ac639baf30ef988a43c06ad6295f042c424

automated-tests/resources/shaders/inout-locations.frag [new file with mode: 0644]
automated-tests/resources/shaders/inout-locations.frag.processed [new file with mode: 0644]
automated-tests/resources/shaders/inout-locations.vert [new file with mode: 0644]
automated-tests/resources/shaders/inout-locations.vert.processed [new file with mode: 0644]
automated-tests/src/dali-egl-graphics/utc-Dali-GraphicsShaderParser.cpp
dali/internal/graphics/common/shader-parser.cpp
dali/internal/graphics/vulkan-impl/vulkan-spirv.cpp

diff --git a/automated-tests/resources/shaders/inout-locations.frag b/automated-tests/resources/shaders/inout-locations.frag
new file mode 100644 (file)
index 0000000..2fd9aba
--- /dev/null
@@ -0,0 +1,27 @@
+//@version 100
+
+// Some amazing uniform block
+UNIFORM_BLOCK FragBlock// another breaking comment
+{
+  UNIFORM lowp vec4 uColor;// This is color (used to cause a parsing error!)
+};
+
+// Input coords
+INPUT mediump vec2 vTexCoord;
+INPUT mediump vec2 vTexCoord2;
+INPUT highp mat3 vMatrix;
+
+UNIFORM sampler2D sTexture;// Sampler two-dimensional
+UNIFORM samplerCube sTextureCube;// Cube sampler for fun
+
+void main()
+{
+
+  // Using GLSL100 semantics
+  vec4 skyboxColor = textureCube(sTextureCube, vec3(0,0,0));
+
+  // Using modern semantics
+  vec4 skyboxColor2 = TEXTURE_CUBE(sTextureCube, vec3(0,0,0));
+
+  gl_FragColor = TEXTURE(sTexture, vTexCoord) * uColor;
+}
diff --git a/automated-tests/resources/shaders/inout-locations.frag.processed b/automated-tests/resources/shaders/inout-locations.frag.processed
new file mode 100644 (file)
index 0000000..12bb98d
--- /dev/null
@@ -0,0 +1,38 @@
+#version 430
+//@version 100
+#define TEXTURE texture
+#define TEXTURE_CUBE texture
+#define TEXTURE_LOD textureLod
+#define TEXTURE_CUBE_LOD textureLod
+#define textureCube texture
+#define texture2D texture
+#define texture2DLod textureLod
+#define textureCubeLod textureLod
+
+// Some amazing uniform block
+layout(set=0, binding=1, std140) uniform FragBlock// another breaking comment
+{
+ lowp vec4 uColor;// This is color (used to cause a parsing error!)
+};
+
+// Input coords
+layout(location = 0) in mediump vec2 vTexCoord;
+layout(location = 4) in mediump vec2 vTexCoord2;
+layout(location = 1) in highp mat3 vMatrix;
+
+layout(binding = 2) uniform sampler2D sTexture;// Sampler two-dimensional
+layout(binding = 3) uniform samplerCube sTextureCube;// Cube sampler for fun
+
+#define gl_FragColor _glFragColor
+layout(location=0) out mediump vec4 _glFragColor;
+void main()
+{
+
+  // Using GLSL100 semantics
+  vec4 skyboxColor = textureCube(sTextureCube, vec3(0,0,0));
+
+  // Using modern semantics
+  vec4 skyboxColor2 = TEXTURE_CUBE(sTextureCube, vec3(0,0,0));
+
+  gl_FragColor = TEXTURE(sTexture, vTexCoord) * uColor;
+}
diff --git a/automated-tests/resources/shaders/inout-locations.vert b/automated-tests/resources/shaders/inout-locations.vert
new file mode 100644 (file)
index 0000000..4b2885c
--- /dev/null
@@ -0,0 +1,24 @@
+//@version 100
+
+INPUT mediump vec2 aPosition;// This is postion
+INPUT mediump vec2 aTexCoord;/// This is texcort
+OUTPUT mediump vec2 vTexCoord;// some output
+OUTPUT highp mat3 vMatrix;
+OUTPUT medium vec2 vTexCoord2;// other output
+
+// Some vertex block
+UNIFORM_BLOCK VertBlock//block comment
+{
+  UNIFORM highp mat4 uMvpMatrix;//comment0
+  UNIFORM highp vec3 uSize;//comment1
+};
+
+// Main function
+void main()
+{
+
+  // Compute position
+  gl_Position = uMvpMatrix * vec4(aPosition * uSize.xy, 0.0, 1.0);
+
+  vTexCoord = aPosition + vec2(0.5);// and set up tex coord
+}
diff --git a/automated-tests/resources/shaders/inout-locations.vert.processed b/automated-tests/resources/shaders/inout-locations.vert.processed
new file mode 100644 (file)
index 0000000..6f9374f
--- /dev/null
@@ -0,0 +1,33 @@
+#version 430
+//@version 100
+#define TEXTURE texture
+#define TEXTURE_CUBE texture
+#define TEXTURE_LOD textureLod
+#define TEXTURE_CUBE_LOD textureLod
+#define textureCube texture
+#define texture2D texture
+#define texture2DLod textureLod
+#define textureCubeLod textureLod
+
+layout(location = 0) in mediump vec2 aPosition;// This is postion
+layout(location = 1) in mediump vec2 aTexCoord;/// This is texcort
+layout(location=0) out mediump vec2 vTexCoord;// some output
+layout(location=1) out highp mat3 vMatrix;
+layout(location=4) out medium vec2 vTexCoord2;// other output
+
+// Some vertex block
+layout(set=0, binding=0, std140) uniform VertBlock//block comment
+{
+ highp mat4 uMvpMatrix;//comment0
+ highp vec3 uSize;//comment1
+};
+
+// Main function
+void main()
+{
+
+  // Compute position
+  gl_Position = uMvpMatrix * vec4(aPosition * uSize.xy, 0.0, 1.0);
+
+  vTexCoord = aPosition + vec2(0.5);// and set up tex coord
+}
index cf7b44100d643180d165dd672746fe073b00f40d..5150f94e74a37834942db1ecc62f90150a12c239 100644 (file)
@@ -671,4 +671,35 @@ int UtcParserSingleLineCommentStrip(void)
     DALI_TEST_EQUALS(cmp, true, TEST_LOCATION);
   }
   END_TEST;
+}
+
+int UtcParserInOutLocation0(void)
+{
+  tet_infoline("UtcParserInOutLocation0 - Tests In/Out locations for longer types");
+
+  auto vertexShader   = LoadTextFile(TEST_RESOURCE_DIR "/shaders/inout-locations.vert");
+  auto fragmentShader = LoadTextFile(TEST_RESOURCE_DIR "/shaders/inout-locations.frag");
+
+  std::vector<std::string> outStrings;
+
+  Internal::ShaderParser::ShaderParserInfo parseInfo{};
+  parseInfo.vertexShaderCode            = &vertexShader;
+  parseInfo.fragmentShaderCode          = &fragmentShader;
+  parseInfo.vertexShaderLegacyVersion   = 0;
+  parseInfo.fragmentShaderLegacyVersion = 0;
+  parseInfo.language                    = Internal::ShaderParser::OutputLanguage::SPIRV_GLSL;
+  parseInfo.outputVersion               = 0;
+  Parse(parseInfo, outStrings);
+
+  auto& outVertexShader   = outStrings[0];
+  auto& outFragmentShader = outStrings[1];
+  {
+    bool cmp = CompareFileWithString(TEST_RESOURCE_DIR "/shaders/inout-locations.vert.processed", outVertexShader);
+    DALI_TEST_EQUALS(cmp, true, TEST_LOCATION);
+  }
+  {
+    bool cmp = CompareFileWithString(TEST_RESOURCE_DIR "/shaders/inout-locations.frag.processed", outFragmentShader);
+    DALI_TEST_EQUALS(cmp, true, TEST_LOCATION);
+  }
+  END_TEST;
 }
\ No newline at end of file
index be1ec371d917d7e86123e6d252707ca66028ee78..6bbde1d3e967b717f8e7f66a7a2e2009ff64a239 100644 (file)
@@ -21,6 +21,8 @@
 
 namespace
 {
+const std::vector<std::string> MATRIX_DATA_TYPE_TOKENS{"mat3", "mat4", "mat2"};
+
 inline bool IsWordChar(const char c)
 {
   return ('A' <= c && c <= 'Z') ||
@@ -118,6 +120,42 @@ std::string_view GetToken(CodeLine& line, int i)
   return std::string_view(&line.line[line.tokens[i].first], line.tokens[i].second);
 }
 
+/**
+ * Function is looking for any token from the given list.
+ *
+ * @return return -1 if no token found, or index of token that has been found first
+ */
+int HasAnyToken(CodeLine& line, const std::vector<std::string>& tokens)
+{
+  for(const auto& token : line.tokens)
+  {
+    uint32_t i   = 0;
+    auto     str = std::string_view(&line.line[token.first], token.second);
+    for(const auto& token2 : tokens)
+    {
+      if(str == token2)
+      {
+        return i;
+      }
+      ++i;
+    }
+  }
+  return -1;
+}
+
+bool HasToken(CodeLine& line, std::string_view tokenToFind)
+{
+  for(const auto& token : line.tokens)
+  {
+    auto str = std::string_view(&line.line[token.first], token.second);
+    if(str == tokenToFind)
+    {
+      return true;
+    }
+  }
+  return false;
+}
+
 void TokenizeSource(Program& program, ShaderStage stage, std::istream& ss)
 {
   Shader* output{nullptr};
@@ -524,8 +562,21 @@ void LinkProgram(Program& program)
 
     if(isOutputToken)
     {
-      auto varname              = GetToken(line, -1);
-      program.varyings[varname] = location++;
+      auto varname = GetToken(line, -1);
+
+      // The location depends on type, anything larger than vec4 (4 floats)
+      // will require adjusting the location, otherwise the location override error
+      // will occur.
+      auto locationsUsed = 1;
+      auto tokenIndex    = HasAnyToken(line, MATRIX_DATA_TYPE_TOKENS);
+      if(tokenIndex >= 0)
+      {
+        // get last character which indicates how many vec4-sizes the type uses
+        locationsUsed = int(std::string_view(MATRIX_DATA_TYPE_TOKENS[tokenIndex]).back()) - '0';
+      }
+
+      program.varyings[varname] = location;
+      location += locationsUsed;
     }
   }
   // Verify
index 54228c0e2f999b228298799f14110a66d837cea6..5a72a810f8e52a0af1b81bdc1652359c322686fd 100644 (file)
@@ -39,7 +39,7 @@ SPIRVGenerator::SPIRVGenerator(Dali::Graphics::Vulkan::SPIRVGeneratorInfo genera
   // Using new to inject internal data visible only within implementation
   mGeneratorInfo.extraInfo = new SPIRVGeneratorExtraInfo;
 
-  mGeneratorInfo.extraInfo->valid = true;
+  mGeneratorInfo.extraInfo->valid = false;
 
   switch(mGeneratorInfo.pipelineStage)
   {
@@ -137,9 +137,14 @@ void SPIRVGenerator::Generate()
   mBinary.resize(size);
   glslang_program_SPIRV_get(program, mBinary.data());
 
+  mGeneratorInfo.extraInfo->valid = true;
+
   const char* spirv_messages = glslang_program_SPIRV_get_messages(program);
   if(spirv_messages)
+  {
     DALI_LOG_ERROR("%s\b", spirv_messages);
+    mGeneratorInfo.extraInfo->valid = false;
+  }
 
   glslang_program_delete(program);
   glslang_finalize_process();