Переглянути джерело

support ignoring defines for shader variants

Alexander Rose 3 роки тому
батько
коміт
472866d8ec
3 змінених файлів з 48 додано та 14 видалено
  1. 1 0
      CHANGELOG.md
  2. 41 13
      src/mol-gl/shader-code.ts
  3. 6 1
      src/mol-gl/webgl/resources.ts

+ 1 - 0
CHANGELOG.md

@@ -28,6 +28,7 @@ Note that since we don't clearly distinguish between a public and private interf
     - Support specifying variants when creating graphics render-items
     - Change double-side shader param from define to uniform
     - Remove dMarkerType shader define (use uMarker as needed)
+    - Support to ignore defines depending on the shader variant
 
 ## [v3.0.0-dev.5] - 2021-12-16
 

+ 41 - 13
src/mol-gl/shader-code.ts

@@ -23,6 +23,7 @@ export interface ShaderExtensions {
 }
 
 type FragOutTypes = { [k in number]: 'vec4' | 'ivec4' }
+type IgnoreDefine = (name: string, variant: string, defines: ShaderDefines) => boolean
 
 export interface ShaderCode {
     readonly id: number
@@ -32,6 +33,7 @@ export interface ShaderCode {
     readonly extensions: ShaderExtensions
     /** Fragment shader output type only applicable for webgl2 */
     readonly outTypes: FragOutTypes
+    readonly ignoreDefine?: IgnoreDefine
 }
 
 import { apply_fog } from './shader/chunks/apply-fog.glsl';
@@ -143,35 +145,56 @@ 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 };
+export function ShaderCode(name: string, vert: string, frag: string, extensions: ShaderExtensions = {}, outTypes: FragOutTypes = {}, ignoreDefine?: IgnoreDefine): ShaderCode {
+    return { id: shaderCodeId(), name, vert: addIncludes(vert), frag: addIncludes(frag), extensions, outTypes, ignoreDefine };
 }
 
 // Note: `drawBuffers` need to be 'optional' for wboit
 
+function ignoreDefine(name: string, variant: string, defines: ShaderDefines): boolean {
+    if (variant.startsWith('color')) {
+        if (name === 'dLightCount') {
+            return !!defines.dIgnoreLight?.ref.value;
+        }
+    } else {
+        return [
+            'dColorType', 'dUsePalette',
+            'dLightCount',
+            'dOverpaintType', 'dOverpaint',
+            'dSubstanceType', 'dSubstance',
+        ].includes(name);
+    }
+    return false;
+};
+
+function ignoreDefineUnlit(name: string, variant: string, defines: ShaderDefines): boolean {
+    if (name === 'dLightCount') return true;
+    return ignoreDefine(name, variant, defines);
+};
+
 import { points_vert } from './shader/points.vert';
 import { points_frag } from './shader/points.frag';
-export const PointsShaderCode = ShaderCode('points', points_vert, points_frag, { drawBuffers: 'optional' });
+export const PointsShaderCode = ShaderCode('points', points_vert, points_frag, { drawBuffers: 'optional' }, {}, ignoreDefineUnlit);
 
 import { spheres_vert } from './shader/spheres.vert';
 import { spheres_frag } from './shader/spheres.frag';
-export const SpheresShaderCode = ShaderCode('spheres', spheres_vert, spheres_frag, { fragDepth: 'required', drawBuffers: 'optional' });
+export const SpheresShaderCode = ShaderCode('spheres', spheres_vert, spheres_frag, { fragDepth: 'required', drawBuffers: 'optional' }, {}, ignoreDefine);
 
 import { cylinders_vert } from './shader/cylinders.vert';
 import { cylinders_frag } from './shader/cylinders.frag';
-export const CylindersShaderCode = ShaderCode('cylinders', cylinders_vert, cylinders_frag, { fragDepth: 'required', drawBuffers: 'optional' });
+export const CylindersShaderCode = ShaderCode('cylinders', cylinders_vert, cylinders_frag, { fragDepth: 'required', drawBuffers: 'optional' }, {}, ignoreDefine);
 
 import { text_vert } from './shader/text.vert';
 import { text_frag } from './shader/text.frag';
-export const TextShaderCode = ShaderCode('text', text_vert, text_frag, { drawBuffers: 'optional' });
+export const TextShaderCode = ShaderCode('text', text_vert, text_frag, { drawBuffers: 'optional' }, {}, ignoreDefineUnlit);
 
 import { lines_vert } from './shader/lines.vert';
 import { lines_frag } from './shader/lines.frag';
-export const LinesShaderCode = ShaderCode('lines', lines_vert, lines_frag, { drawBuffers: 'optional' });
+export const LinesShaderCode = ShaderCode('lines', lines_vert, lines_frag, { drawBuffers: 'optional' }, {}, ignoreDefineUnlit);
 
 import { mesh_vert } from './shader/mesh.vert';
 import { mesh_frag } from './shader/mesh.frag';
-export const MeshShaderCode = ShaderCode('mesh', mesh_vert, mesh_frag, { drawBuffers: 'optional' });
+export const MeshShaderCode = ShaderCode('mesh', mesh_vert, mesh_frag, { drawBuffers: 'optional' }, {}, ignoreDefine);
 
 import { directVolume_vert } from './shader/direct-volume.vert';
 import { directVolume_frag } from './shader/direct-volume.frag';
@@ -179,7 +202,7 @@ export const DirectVolumeShaderCode = ShaderCode('direct-volume', directVolume_v
 
 import { image_vert } from './shader/image.vert';
 import { image_frag } from './shader/image.frag';
-export const ImageShaderCode = ShaderCode('image', image_vert, image_frag, { drawBuffers: 'optional' });
+export const ImageShaderCode = ShaderCode('image', image_vert, image_frag, { drawBuffers: 'optional' }, {}, ignoreDefineUnlit);
 
 //
 
@@ -187,10 +210,14 @@ export type ShaderDefines = {
     [k: string]: ValueCell<DefineType>
 }
 
-function getDefinesCode(defines: ShaderDefines) {
+function getDefinesCode(defines: ShaderDefines, ignore?: IgnoreDefine) {
     if (defines === undefined) return '';
+    const variant = (defines.dRenderVariant?.ref.value || '') as string;
+
     const lines = [];
     for (const name in defines) {
+        if (ignore?.(name, variant, defines)) continue;
+
         const define = defines[name];
         const v = define.ref.value;
         if (v !== undefined) {
@@ -288,7 +315,8 @@ function transformGlsl300Frag(frag: string) {
 }
 
 export function addShaderDefines(gl: GLRenderingContext, extensions: WebGLExtensions, defines: ShaderDefines, shaders: ShaderCode): ShaderCode {
-    const header = getDefinesCode(defines);
+    const vertHeader = getDefinesCode(defines, shaders.ignoreDefine);
+    const fragHeader = getDefinesCode(defines, shaders.ignoreDefine);
     const vertPrefix = isWebGL2(gl) ? glsl300VertPrefix : '';
     const fragPrefix = isWebGL2(gl)
         ? getGlsl300FragPrefix(gl, extensions, shaders.extensions, shaders.outTypes)
@@ -297,8 +325,8 @@ export function addShaderDefines(gl: GLRenderingContext, extensions: WebGLExtens
     return {
         id: shaderCodeId(),
         name: shaders.name,
-        vert: `${vertPrefix}${header}${preprocess(shaders.vert, defines)}`,
-        frag: `${fragPrefix}${header}${preprocess(frag, defines)}`,
+        vert: `${vertPrefix}${vertHeader}${preprocess(shaders.vert, defines)}`,
+        frag: `${fragPrefix}${fragHeader}${preprocess(frag, defines)}`,
         extensions: shaders.extensions,
         outTypes: shaders.outTypes
     };

+ 6 - 1
src/mol-gl/webgl/resources.ts

@@ -105,7 +105,12 @@ export function createResources(gl: GLRenderingContext, state: WebGLState, stats
     const programCache = createReferenceCache(
         (props: ProgramProps) => {
             const array = [props.shaderCode.id];
-            Object.keys(props.defineValues).forEach(k => array.push(hashString(k), defineValueHash(props.defineValues[k].ref.value)));
+            const variant = (props.defineValues.dRenderVariant?.ref.value || '') as string;
+            Object.keys(props.defineValues).forEach(k => {
+                if (!props.shaderCode.ignoreDefine?.(k, variant, props.defineValues)) {
+                    array.push(hashString(k), defineValueHash(props.defineValues[k].ref.value));
+                }
+            });
             return hashFnv32a(array).toString();
         },
         (props: ProgramProps) => wrap('program', createProgram(gl, state, extensions, getShader, props)),