From 4e683650c1d203fbd72e7e06d8dc4e032fb58221 Mon Sep 17 00:00:00 2001 From: Erik Onarheim Date: Mon, 23 Sep 2024 08:01:24 -0500 Subject: [PATCH 1/3] fix: [#3215] Check shader complexity to avoid crash --- .../Context/image-renderer/image-renderer.ts | 5 ++- src/engine/Graphics/Context/webgl-util.ts | 42 +++++++++++++++++++ 2 files changed, 46 insertions(+), 1 deletion(-) diff --git a/src/engine/Graphics/Context/image-renderer/image-renderer.ts b/src/engine/Graphics/Context/image-renderer/image-renderer.ts index 6021de77c..1a37fcab1 100644 --- a/src/engine/Graphics/Context/image-renderer/image-renderer.ts +++ b/src/engine/Graphics/Context/image-renderer/image-renderer.ts @@ -11,6 +11,7 @@ import { RendererPlugin } from '../renderer'; import { Shader } from '../shader'; import { VertexBuffer } from '../vertex-buffer'; import { VertexLayout } from '../vertex-layout'; +import { getMaxShaderComplexity } from '../webgl-util'; import frag from './image-renderer.frag.glsl'; import vert from './image-renderer.vert.glsl'; @@ -54,7 +55,9 @@ export class ImageRenderer implements RendererPlugin { this._context = context; // Transform shader source // FIXME: PIXEL 6 complains `ERROR: Expression too complex.` if we use it's reported max texture units, 125 seems to work for now... - this._maxTextures = Math.min(gl.getParameter(gl.MAX_TEXTURE_IMAGE_UNITS), 125); + const maxTexture = gl.getParameter(gl.MAX_TEXTURE_IMAGE_UNITS); + const maxComplexity = getMaxShaderComplexity(gl, maxTexture); + this._maxTextures = Math.min(maxTexture, maxComplexity); const transformedFrag = this._transformFragmentSource(frag, this._maxTextures); // Compile shader this._shader = new Shader({ diff --git a/src/engine/Graphics/Context/webgl-util.ts b/src/engine/Graphics/Context/webgl-util.ts index 5903b12e8..c70679355 100644 --- a/src/engine/Graphics/Context/webgl-util.ts +++ b/src/engine/Graphics/Context/webgl-util.ts @@ -134,3 +134,45 @@ export function getAttributePointerType(gl: WebGLRenderingContext, type: number) return gl.FLOAT; } } + +/** + * + */ +export function getMaxShaderComplexity(gl: WebGL2RenderingContext, numIfs: number): number { + const assembleTestShader = (numIfs: number) => { + const testShader = `#version 300 es + precision mediump float; + out vec4 fragColor; + void main() { + float index = 1.01; + %%complexity%% + }`; + let testComplexity = ''; + for (let i = 0; i < numIfs; i++) { + if (i === 0) { + testComplexity += `if (index <= ${i}.5) {\n`; + } else { + testComplexity += ` else if (index <= ${i}.5) {\n`; + } + + testComplexity += ` fragColor = vec4(1.0);\n`; + testComplexity += ` }\n`; + } + return testShader.replace('%%complexity%%', testComplexity); + }; + + let canCompile = false; + do { + const test = assembleTestShader(numIfs); + + const shader = gl.createShader(gl.FRAGMENT_SHADER)!; + gl.shaderSource(shader, test); + gl.compileShader(shader); + + canCompile = gl.getShaderParameter(shader, gl.COMPILE_STATUS); + if (!canCompile) { + numIfs = numIfs / 2; + } + } while (!canCompile); + return numIfs; +} From 6079b231ea34c3073632ebec24f6637fe4bb271c Mon Sep 17 00:00:00 2001 From: Erik Onarheim Date: Mon, 23 Sep 2024 09:19:30 -0500 Subject: [PATCH 2/3] coerce an integer --- src/engine/Graphics/Context/webgl-util.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/engine/Graphics/Context/webgl-util.ts b/src/engine/Graphics/Context/webgl-util.ts index c70679355..6027059cc 100644 --- a/src/engine/Graphics/Context/webgl-util.ts +++ b/src/engine/Graphics/Context/webgl-util.ts @@ -171,7 +171,7 @@ export function getMaxShaderComplexity(gl: WebGL2RenderingContext, numIfs: numbe canCompile = gl.getShaderParameter(shader, gl.COMPILE_STATUS); if (!canCompile) { - numIfs = numIfs / 2; + numIfs = (numIfs / 2) | 0; } } while (!canCompile); return numIfs; From e2455c064df97a7145ee2e550ee9352757566945 Mon Sep 17 00:00:00 2001 From: Erik Onarheim Date: Mon, 23 Sep 2024 09:35:02 -0500 Subject: [PATCH 3/3] Add changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5b1c910d0..c836953dc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -104,6 +104,7 @@ are doing mtv adjustments during precollision. ### Fixed +- Fixed issue where certain devices that support large numbers of texture slots exhaust the maximum number of if statements (complexity) in the shader. - Fixed issue where `ex.Label` where setting the opacity of caused a multiplicative opacity effect when actor opacity set - Fixed issue where the `ex.Loader` would have a low res logo on small configured resolution sizes - Fixed issue where `ex.Gif` was not parsing certain binary formats correctly