From 672a6b11fc17838eb8a195c3c09f8bb85884ec1e Mon Sep 17 00:00:00 2001
From: m0dB <m0dB@mixxx.org>
Date: Mon, 9 Dec 2024 17:00:52 +0100
Subject: [PATCH] rendergraph opengl with shaders

---
 CMakeLists.txt                                |  2 +-
 res/shaders/rendergraph/CMakeLists.txt        | 53 +++++++++++++++
 res/shaders/rendergraph/README.md             | 29 ++++++++
 .../rendergraph/generate_shaders_gl.pl        | 68 +++++++++++++++++++
 .../rendergraph/generated_shaders_gl.cmake    | 13 ++++
 res/shaders/rendergraph/pattern.frag          |  9 +++
 res/shaders/rendergraph/pattern.frag.gl       | 11 +++
 res/shaders/rendergraph/pattern.vert          | 15 ++++
 res/shaders/rendergraph/pattern.vert.gl       | 19 ++++++
 res/shaders/rendergraph/rgb.frag              |  8 +++
 res/shaders/rendergraph/rgb.frag.gl           |  9 +++
 res/shaders/rendergraph/rgb.vert              | 15 ++++
 res/shaders/rendergraph/rgb.vert.gl           | 19 ++++++
 res/shaders/rendergraph/rgba.frag             |  8 +++
 res/shaders/rendergraph/rgba.frag.gl          |  9 +++
 res/shaders/rendergraph/rgba.vert             | 15 ++++
 res/shaders/rendergraph/rgba.vert.gl          | 19 ++++++
 res/shaders/rendergraph/texture.frag          |  9 +++
 res/shaders/rendergraph/texture.frag.gl       | 11 +++
 res/shaders/rendergraph/texture.vert          | 15 ++++
 res/shaders/rendergraph/texture.vert.gl       | 19 ++++++
 res/shaders/rendergraph/unicolor.frag         | 13 ++++
 res/shaders/rendergraph/unicolor.frag.gl      | 15 ++++
 res/shaders/rendergraph/unicolor.vert         | 13 ++++
 res/shaders/rendergraph/unicolor.vert.gl      | 17 +++++
 src/rendergraph/CMakeLists.txt                |  2 +-
 26 files changed, 433 insertions(+), 2 deletions(-)
 create mode 100644 res/shaders/rendergraph/CMakeLists.txt
 create mode 100644 res/shaders/rendergraph/README.md
 create mode 100755 res/shaders/rendergraph/generate_shaders_gl.pl
 create mode 100644 res/shaders/rendergraph/generated_shaders_gl.cmake
 create mode 100644 res/shaders/rendergraph/pattern.frag
 create mode 100644 res/shaders/rendergraph/pattern.frag.gl
 create mode 100644 res/shaders/rendergraph/pattern.vert
 create mode 100644 res/shaders/rendergraph/pattern.vert.gl
 create mode 100644 res/shaders/rendergraph/rgb.frag
 create mode 100644 res/shaders/rendergraph/rgb.frag.gl
 create mode 100644 res/shaders/rendergraph/rgb.vert
 create mode 100644 res/shaders/rendergraph/rgb.vert.gl
 create mode 100644 res/shaders/rendergraph/rgba.frag
 create mode 100644 res/shaders/rendergraph/rgba.frag.gl
 create mode 100644 res/shaders/rendergraph/rgba.vert
 create mode 100644 res/shaders/rendergraph/rgba.vert.gl
 create mode 100644 res/shaders/rendergraph/texture.frag
 create mode 100644 res/shaders/rendergraph/texture.frag.gl
 create mode 100644 res/shaders/rendergraph/texture.vert
 create mode 100644 res/shaders/rendergraph/texture.vert.gl
 create mode 100644 res/shaders/rendergraph/unicolor.frag
 create mode 100644 res/shaders/rendergraph/unicolor.frag.gl
 create mode 100644 res/shaders/rendergraph/unicolor.vert
 create mode 100644 res/shaders/rendergraph/unicolor.vert.gl

diff --git a/CMakeLists.txt b/CMakeLists.txt
index f43b5d0dd45d..79de5df5ed00 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -4574,7 +4574,7 @@ if(VINYLCONTROL)
 endif()
 
 # rendergraph
-add_subdirectory(src/rendergraph/opengl)
+add_subdirectory(src/rendergraph)
 target_link_libraries(mixxx-lib PUBLIC rendergraph_gl)
 target_compile_definitions(mixxx-lib PRIVATE rendergraph=rendergraph_gl)
 
diff --git a/res/shaders/rendergraph/CMakeLists.txt b/res/shaders/rendergraph/CMakeLists.txt
new file mode 100644
index 000000000000..42478758f46e
--- /dev/null
+++ b/res/shaders/rendergraph/CMakeLists.txt
@@ -0,0 +1,53 @@
+# included from src/rendergraph/CMakeLists.txt
+
+set(
+  shaders
+  pattern.frag
+  pattern.vert
+  rgb.frag
+  rgb.vert
+  rgba.frag
+  rgba.vert
+  texture.frag
+  texture.vert
+  unicolor.frag
+  unicolor.vert
+)
+
+qt6_add_shaders(rendergraph_sg "shaders-qsb"
+    BATCHABLE
+    PRECOMPILE
+    OPTIMIZED
+    PREFIX
+        /shaders/rendergraph
+    FILES
+        ${shaders}
+)
+
+# USE_QSHADER_FOR_GL is set in src/rendergraph/CMakeLists.txt when Qt >= 6.6
+if(USE_QSHADER_FOR_GL)
+  # Add the .qsb shader bundles; rendergraph::MaterialShader will use
+  # QShader to extract the GLSL shader from the bundle.
+  message(STATUS "Adding qsb shaders to rendergraph_gl")
+  qt6_add_shaders(rendergraph_gl "shaders-qsb"
+        BATCHABLE
+        PRECOMPILE
+        OPTIMIZED
+        PREFIX
+            /shaders/rendergraph
+        FILES
+            ${shaders}
+  )
+else()
+  # Use GLSL shaders extracted from the .qsb shader bundles using
+  # generate_shaders_gl.pl
+  message(STATUS "Adding gl shaders to rendergraph_gl")
+  include(generated_shaders_gl.cmake)
+
+  qt_add_resources(rendergraph_gl "shaders-gl"
+        PREFIX
+            /shaders/rendergraph
+        FILES
+            ${generated_shaders_gl}
+  )
+endif()
diff --git a/res/shaders/rendergraph/README.md b/res/shaders/rendergraph/README.md
new file mode 100644
index 000000000000..31f8a53fff1c
--- /dev/null
+++ b/res/shaders/rendergraph/README.md
@@ -0,0 +1,29 @@
+# rendergraph shaders
+
+The CMakeLists.txt in this folder generates qsb shader bundles from spirv shaders, to
+be used by `rendergraph::MaterialShader`.
+
+## For use with QML / Qt scene graph
+
+The qsb files can be used directly through `QSGShader`. This includes the scenegraph
+implementation of rendergraph.
+
+## For use with OpenGL
+
+Depending on the Qt version, the opengl implementation of `rendergraph::MaterialShader`
+uses either the .qsb shader bundles directly, or the extracted GLSL shaders:
+
+### Qt >= 6.6
+
+The GLSL shaders are extracted programmatically with `QShader` and then used with
+`QOpenGLShader`.
+
+### Qt < 6.6
+
+The GLSL shader have to extracted from the qsb shader bundles to be used by `QOpenGLShader`.
+This can be done using the script `generate_shaders_gl.pl`. To use this script, make sure
+that the qsb and spirv commands are in your path. qsb is part of Qt. spirv is part of the
+Vulkan SDK and can be downloaded from <https://vulkan.org>
+
+The script also generates the file ```generated_shaders_gl.cmake``` which sets a cmake
+variable containing a list of all GLSL shaders, used by the CMakeLists.txt in this folder.
diff --git a/res/shaders/rendergraph/generate_shaders_gl.pl b/res/shaders/rendergraph/generate_shaders_gl.pl
new file mode 100755
index 000000000000..c528eb947475
--- /dev/null
+++ b/res/shaders/rendergraph/generate_shaders_gl.pl
@@ -0,0 +1,68 @@
+#!/usr/bin/perl
+
+my @files = (glob("*.vert"),glob("*.frag"));
+
+open(GENERATED,">generated_shaders_gl.cmake");
+print(GENERATED "set(generated_shaders_gl\n");
+for $file (@files)
+{
+    system("qsb","--glsl","120",$file,"-o","/tmp/$$-$file.qsb");
+    open(INFILE,"qsb --dump /tmp/$$-$file.qsb|");
+    open(OUTFILE,">$file.gl");
+    $ok = 0;
+    $comment_added = 0;
+    print "Generating $file.gl from $file\n";
+    while (<INFILE>)
+    {
+        if ($in_shader_block == 2)
+        {
+            if (m/^\*\*/)
+            {
+                $in_shader_block = 0;
+                $ok = 1;
+            }
+            else
+            {
+                if (!$comment_added)
+                {
+                    if (!m/^#/)
+                    {
+                        print(OUTFILE "//// GENERATED - EDITS WILL BE OVERWRITTEN\n");
+                        $comment_added = 1;
+                    }
+                }
+                print OUTFILE "$_";
+            }
+        }
+        elsif ($in_shader_block == 1)
+        {
+            chomp($_);
+            if ($_ eq "Contents:")
+            {
+                $in_shader_block = 2;
+            }
+        }
+        else
+        {
+            chomp($_);
+            if ($_ eq "Shader 1: GLSL 120 [Standard]")
+            {
+                $in_shader_block = 1;
+            }
+        }
+    }
+    close INFILE;
+    close OUTFILE;
+    if($ok)
+    {
+        print(GENERATED "    $file.gl\n");
+    }
+    else
+    {
+        print STDERR "Failed to generated $file.gl";
+        unlink("$file.gl")
+    }
+    unlink("/tmp/$$-$file.qsb");
+}
+print(GENERATED ")\n");
+close GENERATED;
diff --git a/res/shaders/rendergraph/generated_shaders_gl.cmake b/res/shaders/rendergraph/generated_shaders_gl.cmake
new file mode 100644
index 000000000000..f3f89002e51c
--- /dev/null
+++ b/res/shaders/rendergraph/generated_shaders_gl.cmake
@@ -0,0 +1,13 @@
+set(
+  generated_shaders_gl
+  pattern.vert.gl
+  rgb.vert.gl
+  rgba.vert.gl
+  texture.vert.gl
+  unicolor.vert.gl
+  pattern.frag.gl
+  rgb.frag.gl
+  rgba.frag.gl
+  texture.frag.gl
+  unicolor.frag.gl
+)
diff --git a/res/shaders/rendergraph/pattern.frag b/res/shaders/rendergraph/pattern.frag
new file mode 100644
index 000000000000..5aa3d1556b1e
--- /dev/null
+++ b/res/shaders/rendergraph/pattern.frag
@@ -0,0 +1,9 @@
+#version 440
+
+layout(binding = 1) uniform sampler2D texture1;
+layout(location = 0) in vec2 vTexcoord;
+layout(location = 0) out vec4 fragColor;
+
+void main() {
+    fragColor = texture(texture1, fract(vTexcoord));
+}
diff --git a/res/shaders/rendergraph/pattern.frag.gl b/res/shaders/rendergraph/pattern.frag.gl
new file mode 100644
index 000000000000..376c71668ba4
--- /dev/null
+++ b/res/shaders/rendergraph/pattern.frag.gl
@@ -0,0 +1,11 @@
+#version 120
+//// GENERATED - EDITS WILL BE OVERWRITTEN
+
+uniform sampler2D texture1;
+
+varying vec2 vTexcoord;
+
+void main()
+{
+    gl_FragData[0] = texture2D(texture1, fract(vTexcoord));
+}
diff --git a/res/shaders/rendergraph/pattern.vert b/res/shaders/rendergraph/pattern.vert
new file mode 100644
index 000000000000..07b3d7f1f3ba
--- /dev/null
+++ b/res/shaders/rendergraph/pattern.vert
@@ -0,0 +1,15 @@
+#version 440
+
+layout(std140, binding = 0) uniform buf {
+    mat4 matrix;
+}
+ubuf;
+
+layout(location = 0) in vec4 position;
+layout(location = 1) in vec2 texcoord;
+layout(location = 0) out vec2 vTexcoord;
+
+void main() {
+    vTexcoord = texcoord;
+    gl_Position = ubuf.matrix * position;
+}
diff --git a/res/shaders/rendergraph/pattern.vert.gl b/res/shaders/rendergraph/pattern.vert.gl
new file mode 100644
index 000000000000..a3d58014be32
--- /dev/null
+++ b/res/shaders/rendergraph/pattern.vert.gl
@@ -0,0 +1,19 @@
+#version 120
+//// GENERATED - EDITS WILL BE OVERWRITTEN
+
+struct buf
+{
+    mat4 matrix;
+};
+
+uniform buf ubuf;
+
+varying vec2 vTexcoord;
+attribute vec2 texcoord;
+attribute vec4 position;
+
+void main()
+{
+    vTexcoord = texcoord;
+    gl_Position = ubuf.matrix * position;
+}
diff --git a/res/shaders/rendergraph/rgb.frag b/res/shaders/rendergraph/rgb.frag
new file mode 100644
index 000000000000..0a808489f5b2
--- /dev/null
+++ b/res/shaders/rendergraph/rgb.frag
@@ -0,0 +1,8 @@
+#version 440
+
+layout(location = 0) in vec3 vColor;
+layout(location = 0) out vec4 fragColor;
+
+void main() {
+    fragColor = vec4(vColor, 1.0);
+}
diff --git a/res/shaders/rendergraph/rgb.frag.gl b/res/shaders/rendergraph/rgb.frag.gl
new file mode 100644
index 000000000000..b8a61f8682f9
--- /dev/null
+++ b/res/shaders/rendergraph/rgb.frag.gl
@@ -0,0 +1,9 @@
+#version 120
+//// GENERATED - EDITS WILL BE OVERWRITTEN
+
+varying vec3 vColor;
+
+void main()
+{
+    gl_FragData[0] = vec4(vColor, 1.0);
+}
diff --git a/res/shaders/rendergraph/rgb.vert b/res/shaders/rendergraph/rgb.vert
new file mode 100644
index 000000000000..6568d01f187c
--- /dev/null
+++ b/res/shaders/rendergraph/rgb.vert
@@ -0,0 +1,15 @@
+#version 440
+
+layout(std140, binding = 0) uniform buf {
+    mat4 matrix;
+}
+ubuf;
+
+layout(location = 0) in vec4 position;
+layout(location = 1) in vec3 color;
+layout(location = 0) out vec3 vColor;
+
+void main() {
+    vColor = color;
+    gl_Position = ubuf.matrix * position;
+}
diff --git a/res/shaders/rendergraph/rgb.vert.gl b/res/shaders/rendergraph/rgb.vert.gl
new file mode 100644
index 000000000000..53e86e4501cc
--- /dev/null
+++ b/res/shaders/rendergraph/rgb.vert.gl
@@ -0,0 +1,19 @@
+#version 120
+//// GENERATED - EDITS WILL BE OVERWRITTEN
+
+struct buf
+{
+    mat4 matrix;
+};
+
+uniform buf ubuf;
+
+varying vec3 vColor;
+attribute vec3 color;
+attribute vec4 position;
+
+void main()
+{
+    vColor = color;
+    gl_Position = ubuf.matrix * position;
+}
diff --git a/res/shaders/rendergraph/rgba.frag b/res/shaders/rendergraph/rgba.frag
new file mode 100644
index 000000000000..5cf90a770eae
--- /dev/null
+++ b/res/shaders/rendergraph/rgba.frag
@@ -0,0 +1,8 @@
+#version 440
+
+layout(location = 0) in vec4 vColor;
+layout(location = 0) out vec4 fragColor;
+
+void main() {
+    fragColor = vec4(vColor.xyz * vColor.w, vColor.w); // premultiple alpha
+}
diff --git a/res/shaders/rendergraph/rgba.frag.gl b/res/shaders/rendergraph/rgba.frag.gl
new file mode 100644
index 000000000000..a831457b9681
--- /dev/null
+++ b/res/shaders/rendergraph/rgba.frag.gl
@@ -0,0 +1,9 @@
+#version 120
+//// GENERATED - EDITS WILL BE OVERWRITTEN
+
+varying vec4 vColor;
+
+void main()
+{
+    gl_FragData[0] = vec4(vColor.xyz * vColor.w, vColor.w);
+}
diff --git a/res/shaders/rendergraph/rgba.vert b/res/shaders/rendergraph/rgba.vert
new file mode 100644
index 000000000000..d5ce8b2d9db6
--- /dev/null
+++ b/res/shaders/rendergraph/rgba.vert
@@ -0,0 +1,15 @@
+#version 440
+
+layout(std140, binding = 0) uniform buf {
+    mat4 matrix;
+}
+ubuf;
+
+layout(location = 0) in vec4 position;
+layout(location = 1) in vec4 color;
+layout(location = 0) out vec4 vColor;
+
+void main() {
+    vColor = color;
+    gl_Position = ubuf.matrix * position;
+}
diff --git a/res/shaders/rendergraph/rgba.vert.gl b/res/shaders/rendergraph/rgba.vert.gl
new file mode 100644
index 000000000000..df2bcf93236e
--- /dev/null
+++ b/res/shaders/rendergraph/rgba.vert.gl
@@ -0,0 +1,19 @@
+#version 120
+//// GENERATED - EDITS WILL BE OVERWRITTEN
+
+struct buf
+{
+    mat4 matrix;
+};
+
+uniform buf ubuf;
+
+varying vec4 vColor;
+attribute vec4 color;
+attribute vec4 position;
+
+void main()
+{
+    vColor = color;
+    gl_Position = ubuf.matrix * position;
+}
diff --git a/res/shaders/rendergraph/texture.frag b/res/shaders/rendergraph/texture.frag
new file mode 100644
index 000000000000..bbe37bccd69c
--- /dev/null
+++ b/res/shaders/rendergraph/texture.frag
@@ -0,0 +1,9 @@
+#version 440
+
+layout(binding = 1) uniform sampler2D texture1;
+layout(location = 0) in vec2 vTexcoord;
+layout(location = 0) out vec4 fragColor;
+
+void main() {
+    fragColor = texture(texture1, vTexcoord);
+}
diff --git a/res/shaders/rendergraph/texture.frag.gl b/res/shaders/rendergraph/texture.frag.gl
new file mode 100644
index 000000000000..b2d03f1352c6
--- /dev/null
+++ b/res/shaders/rendergraph/texture.frag.gl
@@ -0,0 +1,11 @@
+#version 120
+//// GENERATED - EDITS WILL BE OVERWRITTEN
+
+uniform sampler2D texture1;
+
+varying vec2 vTexcoord;
+
+void main()
+{
+    gl_FragData[0] = texture2D(texture1, vTexcoord);
+}
diff --git a/res/shaders/rendergraph/texture.vert b/res/shaders/rendergraph/texture.vert
new file mode 100644
index 000000000000..07b3d7f1f3ba
--- /dev/null
+++ b/res/shaders/rendergraph/texture.vert
@@ -0,0 +1,15 @@
+#version 440
+
+layout(std140, binding = 0) uniform buf {
+    mat4 matrix;
+}
+ubuf;
+
+layout(location = 0) in vec4 position;
+layout(location = 1) in vec2 texcoord;
+layout(location = 0) out vec2 vTexcoord;
+
+void main() {
+    vTexcoord = texcoord;
+    gl_Position = ubuf.matrix * position;
+}
diff --git a/res/shaders/rendergraph/texture.vert.gl b/res/shaders/rendergraph/texture.vert.gl
new file mode 100644
index 000000000000..a3d58014be32
--- /dev/null
+++ b/res/shaders/rendergraph/texture.vert.gl
@@ -0,0 +1,19 @@
+#version 120
+//// GENERATED - EDITS WILL BE OVERWRITTEN
+
+struct buf
+{
+    mat4 matrix;
+};
+
+uniform buf ubuf;
+
+varying vec2 vTexcoord;
+attribute vec2 texcoord;
+attribute vec4 position;
+
+void main()
+{
+    vTexcoord = texcoord;
+    gl_Position = ubuf.matrix * position;
+}
diff --git a/res/shaders/rendergraph/unicolor.frag b/res/shaders/rendergraph/unicolor.frag
new file mode 100644
index 000000000000..7099bb8f3dd5
--- /dev/null
+++ b/res/shaders/rendergraph/unicolor.frag
@@ -0,0 +1,13 @@
+#version 440
+
+layout(std140, binding = 0) uniform buf {
+    mat4 matrix;
+    vec4 color;
+}
+ubuf;
+
+layout(location = 0) out vec4 fragColor;
+
+void main() {
+    fragColor = vec4(ubuf.color.xyz * ubuf.color.w, ubuf.color.w); // premultiply alpha
+}
diff --git a/res/shaders/rendergraph/unicolor.frag.gl b/res/shaders/rendergraph/unicolor.frag.gl
new file mode 100644
index 000000000000..bfef503120bd
--- /dev/null
+++ b/res/shaders/rendergraph/unicolor.frag.gl
@@ -0,0 +1,15 @@
+#version 120
+//// GENERATED - EDITS WILL BE OVERWRITTEN
+
+struct buf
+{
+    mat4 matrix;
+    vec4 color;
+};
+
+uniform buf ubuf;
+
+void main()
+{
+    gl_FragData[0] = vec4(ubuf.color.xyz * ubuf.color.w, ubuf.color.w);
+}
diff --git a/res/shaders/rendergraph/unicolor.vert b/res/shaders/rendergraph/unicolor.vert
new file mode 100644
index 000000000000..9e268c18fbaa
--- /dev/null
+++ b/res/shaders/rendergraph/unicolor.vert
@@ -0,0 +1,13 @@
+#version 440
+
+layout(std140, binding = 0) uniform buf {
+    mat4 matrix;
+    vec4 color;
+}
+ubuf;
+
+layout(location = 0) in vec4 position;
+
+void main() {
+    gl_Position = ubuf.matrix * position;
+}
diff --git a/res/shaders/rendergraph/unicolor.vert.gl b/res/shaders/rendergraph/unicolor.vert.gl
new file mode 100644
index 000000000000..d126f3dab584
--- /dev/null
+++ b/res/shaders/rendergraph/unicolor.vert.gl
@@ -0,0 +1,17 @@
+#version 120
+//// GENERATED - EDITS WILL BE OVERWRITTEN
+
+struct buf
+{
+    mat4 matrix;
+    vec4 color;
+};
+
+uniform buf ubuf;
+
+attribute vec4 position;
+
+void main()
+{
+    gl_Position = ubuf.matrix * position;
+}
diff --git a/src/rendergraph/CMakeLists.txt b/src/rendergraph/CMakeLists.txt
index 731c47b5122a..6693043d76af 100644
--- a/src/rendergraph/CMakeLists.txt
+++ b/src/rendergraph/CMakeLists.txt
@@ -6,5 +6,5 @@ if(QT_VERSION_MINOR GREATER_EQUAL 6)
 endif()
 
 add_subdirectory(opengl)
-add_subdirectory(scenegraph)
+# add_subdirectory(scenegraph)
 add_subdirectory(../../res/shaders/rendergraph shaders)