From ebf64404beda0916c3682c437fd866f37c37a09b Mon Sep 17 00:00:00 2001 From: Alexander Rose <alexander.rose@weirdbyte.de> Date: Sat, 6 Nov 2021 14:55:23 -0700 Subject: [PATCH] add loop unrolling glsl support --- src/mol-gl/shader-code.ts | 30 ++++++++++++++++++-- src/mol-gl/shader/chunks/common-clip.glsl.ts | 4 ++- 2 files changed, 30 insertions(+), 4 deletions(-) diff --git a/src/mol-gl/shader-code.ts b/src/mol-gl/shader-code.ts index 63836245a..5e7c10475 100644 --- a/src/mol-gl/shader-code.ts +++ b/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 }; diff --git a/src/mol-gl/shader/chunks/common-clip.glsl.ts b/src/mol-gl/shader/chunks/common-clip.glsl.ts index f38c78a1e..5bca9dec1 100644 --- a/src/mol-gl/shader/chunks/common-clip.glsl.ts +++ b/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 -- GitLab