Browse Source

add loop unrolling glsl support

Alexander Rose 3 years ago
parent
commit
ebf64404be
2 changed files with 30 additions and 4 deletions
  1. 27 3
      src/mol-gl/shader-code.ts
  2. 3 1
      src/mol-gl/shader/chunks/common-clip.glsl.ts

+ 27 - 3
src/mol-gl/shader-code.ts

@@ -101,7 +101,8 @@ const ShaderChunks: { [k: string]: string } = {
     wboit_write
 };
 
-const reInclude = /^(?!\/\/)\s*#include\s+(\S+)/gmi;
+const reInclude = /^(?!\/\/)\s*#include\s+(\S+)/gm;
+const reUnrollLoop = /#pragma unroll_loop_start\s+for\s*\(\s*int\s+i\s*=\s*(\d+)\s*;\s*i\s*<\s*(\d+)\s*;\s*\+\+i\s*\s*\)\s*{([\s\S]+?)}\s+#pragma unroll_loop_end/g;
 const reSingleLineComment = /[ \t]*\/\/.*\n/g;
 const reMultiLineComment = /[ \t]*\/\*[\s\S]*?\*\//g;
 const reMultipleLinebreaks = /\n{2,}/g;
@@ -119,6 +120,29 @@ function addIncludes(text: string) {
         .replace(reMultipleLinebreaks, '\n');
 }
 
+function unrollLoops(str: string) {
+    return str.replace(reUnrollLoop, loopReplacer);
+}
+
+function loopReplacer(match: string, start: string, end: string, snippet: string) {
+    let out = '';
+    for (let i = parseInt(start); i < parseInt(end); ++i) {
+        out += snippet
+            .replace(/\[\s*i\s*\]/g, `[${i}]`)
+            .replace(/UNROLLED_LOOP_INDEX/g, `${i}`);
+    }
+    return out;
+}
+
+function replaceCounts(str: string, defines: ShaderDefines) {
+    if (defines.dClipObjectCount) str = str.replace(/dClipObjectCount/g, `${defines.dClipObjectCount.ref.value}`);
+    return str;
+}
+
+function preprocess(str: string, defines: ShaderDefines) {
+    return unrollLoops(replaceCounts(str, defines));
+}
+
 export function ShaderCode(name: string, vert: string, frag: string, extensions: ShaderExtensions = {}, outTypes: FragOutTypes = {}): ShaderCode {
     return { id: shaderCodeId(), name, vert: addIncludes(vert), frag: addIncludes(frag), extensions, outTypes };
 }
@@ -278,8 +302,8 @@ export function addShaderDefines(gl: GLRenderingContext, extensions: WebGLExtens
     return {
         id: shaderCodeId(),
         name: shaders.name,
-        vert: `${vertPrefix}${header}${shaders.vert}`,
-        frag: `${fragPrefix}${header}${frag}`,
+        vert: `${vertPrefix}${header}${preprocess(shaders.vert, defines)}`,
+        frag: `${fragPrefix}${header}${preprocess(frag, defines)}`,
         extensions: shaders.extensions,
         outTypes: shaders.outTypes
     };

+ 3 - 1
src/mol-gl/shader/chunks/common-clip.glsl.ts

@@ -89,8 +89,9 @@ export const common_clip = `
 
     // flag is a bit-flag for clip-objects to ignore (note, object ids start at 1 not 0)
     bool clipTest(vec4 sphere, int flag) {
+        #pragma unroll_loop_start
         for (int i = 0; i < dClipObjectCount; ++i) {
-            if (flag == 0 || hasBit(flag, i + 1)) {
+            if (flag == 0 || hasBit(flag, UNROLLED_LOOP_INDEX + 1)) {
                 // TODO take sphere radius into account?
                 bool test = getSignedDistance(sphere.xyz, uClipObjectType[i], uClipObjectPosition[i], uClipObjectRotation[i], uClipObjectScale[i]) <= 0.0;
                 if ((!uClipObjectInvert[i] && test) || (uClipObjectInvert[i] && !test)) {
@@ -98,6 +99,7 @@ export const common_clip = `
                 }
             }
         }
+        #pragma unroll_loop_end
         return false;
     }
 #endif