[Bf-blender-cvs] [fdda05bf15c] temp-gpu-push-constants: [WIP] GPU: Push Constants.

Jeroen Bakker noreply at git.blender.org
Wed Jun 30 17:11:36 CEST 2021


Commit: fdda05bf15c12f07ec1b6d813e4e12a0f7a89255
Author: Jeroen Bakker
Date:   Wed Jun 30 17:10:47 2021 +0200
Branches: temp-gpu-push-constants
https://developer.blender.org/rBfdda05bf15c12f07ec1b6d813e4e12a0f7a89255

[WIP] GPU: Push Constants.

See T89553 for more details.

===================================================================

M	source/blender/gpu/CMakeLists.txt
M	source/blender/gpu/opengl/gl_shader.cc
M	source/blender/gpu/opengl/gl_shader.hh
A	source/blender/gpu/opengl/gl_shader_converter.cc
A	source/blender/gpu/opengl/gl_shader_converter.hh
A	source/blender/gpu/tests/gpu_shader_push_constants_test.cc

===================================================================

diff --git a/source/blender/gpu/CMakeLists.txt b/source/blender/gpu/CMakeLists.txt
index abb7330d292..ba3a23f2641 100644
--- a/source/blender/gpu/CMakeLists.txt
+++ b/source/blender/gpu/CMakeLists.txt
@@ -104,6 +104,7 @@ set(SRC
   opengl/gl_query.cc
   opengl/gl_shader.cc
   opengl/gl_shader_log.cc
+  opengl/gl_shader_converter.cc
   opengl/gl_shader_interface.cc
   opengl/gl_state.cc
   opengl/gl_texture.cc
@@ -399,6 +400,7 @@ if(WITH_GTESTS)
 
       tests/gpu_index_buffer_test.cc
       tests/gpu_shader_builtin_test.cc
+      tests/gpu_shader_push_constants_test.cc
       tests/gpu_shader_test.cc
 
       tests/gpu_testing.hh
diff --git a/source/blender/gpu/opengl/gl_shader.cc b/source/blender/gpu/opengl/gl_shader.cc
index 66a1bd5ceb7..78544035416 100644
--- a/source/blender/gpu/opengl/gl_shader.cc
+++ b/source/blender/gpu/opengl/gl_shader.cc
@@ -148,6 +148,11 @@ GLuint GLShader::create_shader_stage(GLenum gl_stage, MutableSpan<const char *>
 
   /* Patch the shader code using the first source slot. */
   sources[0] = glsl_patch_get(gl_stage);
+  converter_.patch(sources);
+  if (converter_.has_error()) {
+    compilation_failed_ = true;
+    return 0;
+  }
 
   glShaderSource(shader, sources.size(), sources.data(), nullptr);
   glCompileShader(shader);
@@ -228,6 +233,10 @@ bool GLShader::finalize()
 
   interface = new GLShaderInterface(shader_program_);
 
+  /* Only patched sources are only freed when shader compilation and linking succeeds for
+   * debugging. */
+  converter_.free();
+
   return true;
 }
 
diff --git a/source/blender/gpu/opengl/gl_shader.hh b/source/blender/gpu/opengl/gl_shader.hh
index 770bc29747e..76919b6b803 100644
--- a/source/blender/gpu/opengl/gl_shader.hh
+++ b/source/blender/gpu/opengl/gl_shader.hh
@@ -29,6 +29,8 @@
 
 #include "gpu_shader_private.hh"
 
+#include "gl_shader_converter.hh"
+
 namespace blender {
 namespace gpu {
 
@@ -48,6 +50,7 @@ class GLShader : public Shader {
   bool compilation_failed_ = false;
 
   eGPUShaderTFBType transform_feedback_type_ = GPU_SHADER_TFB_NONE;
+  GLShaderConverter converter_;
 
  public:
   GLShader(const char *name);
diff --git a/source/blender/gpu/opengl/gl_shader_converter.cc b/source/blender/gpu/opengl/gl_shader_converter.cc
new file mode 100644
index 00000000000..c2f06b74e31
--- /dev/null
+++ b/source/blender/gpu/opengl/gl_shader_converter.cc
@@ -0,0 +1,110 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2021 Blender Foundation.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup gpu
+ *
+ * Parse/convert GLSL source from Vulkan GLSL to OpenGL GLSL.
+ */
+
+#include "gl_shader_converter.hh"
+
+namespace blender::gpu {
+
+void GLShaderConverter::patch(MutableSpan<const char *> sources)
+{
+  for (int i = 0; i < sources.size(); i++) {
+    std::string patched_source = patch(sources[i]);
+    patched_sources_.append(patched_source);
+    sources[i] = patched_sources_.last().c_str();
+  }
+}
+
+bool GLShaderConverter::has_error() const
+{
+  return status != GLShaderConverterState::Ok;
+}
+
+void GLShaderConverter::free()
+{
+  patched_sources_.clear();
+}
+
+std::string GLShaderConverter::patch(StringRef src)
+{
+  std::string result = patch_push_constants(src);
+  return result;
+}
+
+StringRef GLShaderConverter::skip_whitespace(StringRef ref)
+{
+  static constexpr StringRef WHITESPACES = " \t\n\v\f\r";
+
+  size_t skip = ref.find_first_not_of(WHITESPACES);
+  if (skip == blender::StringRef::not_found) {
+    return ref;
+  }
+  return ref.drop_prefix(skip);
+}
+
+StringRef GLShaderConverter::extract_name(StringRef src)
+{
+  static constexpr StringRef VALID_CHARS =
+      "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01232456789_";
+  StringRef result = src;
+
+  size_t skip = result.find_first_not_of(VALID_CHARS);
+  BLI_assert(skip != StringRef::not_found);
+  return result.substr(0, skip);
+}
+
+std::string GLShaderConverter::patch_push_constants(StringRef src)
+{
+  static constexpr StringRef LAYOUT_PUSH_CONSTANTS = "layout(push_constant)";
+  static constexpr StringRef LAYOUT_STD140 = "layout(std140)";
+
+  size_t pos = src.find(LAYOUT_PUSH_CONSTANTS);
+  if (pos == StringRef::not_found) {
+    return src;
+  }
+  std::stringstream result;
+  result << src.substr(0, pos);
+  result << LAYOUT_STD140;
+  result << src.substr(pos + LAYOUT_PUSH_CONSTANTS.size());
+
+  StringRef name = src.substr(pos + LAYOUT_PUSH_CONSTANTS.size());
+  name = skip_whitespace(name);
+  name = name.drop_known_prefix("uniform");
+  name = skip_whitespace(name);
+  name = extract_name(name);
+
+  if (push_constants.name.empty()) {
+    push_constants.name = name;
+  }
+  else {
+    /* Push constant name must be the same across all stages. */
+    if (push_constants.name != name) {
+      status = GLShaderConverterState::NOT_MATCHING_PUSH_CONSTANT_NAME;
+    }
+  }
+
+  return patch_push_constants(result.str());
+}
+
+}  // namespace blender::gpu
diff --git a/source/blender/gpu/opengl/gl_shader_converter.hh b/source/blender/gpu/opengl/gl_shader_converter.hh
new file mode 100644
index 00000000000..0ba58cccf4c
--- /dev/null
+++ b/source/blender/gpu/opengl/gl_shader_converter.hh
@@ -0,0 +1,61 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2021 Blender Foundation.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup gpu
+ */
+
+#pragma once
+
+#include "BLI_string_ref.hh"
+#include "BLI_vector.hh"
+
+namespace blender::gpu {
+
+enum class GLShaderConverterState {
+  Ok,
+  NOT_MATCHING_PUSH_CONSTANT_NAME,
+};
+class GLShaderConverter {
+ public:
+  struct {
+    std::string name;
+  } push_constants;
+  GLShaderConverterState status = GLShaderConverterState::Ok;
+
+ private:
+  Vector<std::string> patched_sources_;
+
+ public:
+  void patch(MutableSpan<const char *> sources);
+  bool has_error() const;
+  void free();
+
+ private:
+  std::string patch(StringRef src);
+  bool is_valid_name_char(const char c) const;
+  StringRef skip_whitespace(StringRef src);
+
+  StringRef extract_name(StringRef src);
+  std::string patch_push_constants(StringRef src);
+
+  MEM_CXX_CLASS_ALLOC_FUNCS("GLShaderConverter");
+};
+
+}  // namespace blender::gpu
diff --git a/source/blender/gpu/tests/gpu_shader_push_constants_test.cc b/source/blender/gpu/tests/gpu_shader_push_constants_test.cc
new file mode 100644
index 00000000000..dca6810068b
--- /dev/null
+++ b/source/blender/gpu/tests/gpu_shader_push_constants_test.cc
@@ -0,0 +1,227 @@
+/* Apache License, Version 2.0 */
+
+#include "testing/testing.h"
+
+#include "GPU_shader.h"
+
+#include "gpu_testing.hh"
+
+namespace blender::gpu::tests {
+
+static void test_gpu_shader_push_constants()
+{
+  const char *vert_glsl = R"(
+
+uniform mat4 ModelViewProjectionMatrix;
+in vec3 pos;
+
+void main() {
+  vec4 pos_4d = vec4(pos, 1.0);
+  gl_Position = ModelViewProjectionMatrix * pos_4d;
+}
+
+)";
+
+  const char *frag_glsl = R"(
+
+layout(push_constant) uniform PushConstants {
+    vec4 color;
+};
+
+out vec4 fragColor;
+
+void main()
+{
+  fragColor = color;
+}
+
+)";
+
+  GPUShader *shader = GPU_shader_create(
+      vert_glsl, frag_glsl, nullptr, nullptr, nullptr, "test_gpu_shader_push_constants");
+  EXPECT_NE(shader, nullptr);
+
+  GPU_shader_free(shader);
+}
+GPU_TEST(gpu_shader_push_constants)
+
+static void test_gpu_shader_push_constants_2_definitions()
+{
+  const char *vert_glsl = R"(
+
+uniform mat4 ModelViewProjectionMatrix;
+in vec3 pos;
+
+void main() {
+  vec4 pos_4d = vec4(pos, 1.0);
+  gl_Position = ModelViewProjectionMatrix * pos_4d;
+}
+
+)";
+
+  const char *frag_glsl = R"(
+
+#ifdef NEW
+layout(push_constant) uniform PushConstants {
+    vec4 color;
+};
+#else 
+layout(push_constant) uniform PushConstants {
+    vec4 color;
+};
+#endif
+
+out vec4 fragColor;
+
+void main()
+{
+  fragColor = color;
+}
+
+)";
+
+  GPUShader *shader = GPU_shader_create(
+      vert_glsl, frag_glsl, nullptr, nullptr, nullptr, "gpu_shader_push_constants_2_definitions");
+  EXPECT_NE(shader, nullptr);
+
+  GPU_shader_free(shader);
+}
+GPU_TEST(gpu_shader_push_constants_2_definitions)
+
+static void test_gpu_shader_push_constants_2_stages()
+{
+  const char *vert_glsl = R"(
+
+uniform mat4 ModelViewProjectionMatrix;
+in vec3 pos;
+
+layout(push_constant) uniform PushConstants {
+    vec4 color;
+};
+
+void main() {
+  vec4 pos_4d = vec4(pos, 1.0);
+  gl_Position = ModelViewProjectionMatrix * pos_4d;
+}
+
+)";
+
+  const char *frag_glsl = R"(
+
+layout(push_constant) uniform PushConstants {
+    vec4 color;
+};
+
+out vec4 fragColor;
+
+void main()
+{
+  fragColor = color;
+}
+
+)";
+
+  GPUShader *shader = GPU_shader_create(
+      vert_glsl, frag_glsl, nullptr, nullptr, nullptr, "test_gpu_shader_push_constants_2_stages");
+  EXPECT_NE(shader, nullptr);
+
+  GPU_shader_free(shader);
+}
+GPU_TEST(gpu_shader_push_constant

@@ Diff output truncated at 10240 characters. @@



More information about the Bf-blender-cvs mailing list