Skip to content

Commit

Permalink
fix: [#3215] Check shader complexity to avoid crash on certain hardwa…
Browse files Browse the repository at this point in the history
…re (#3216)

Closes #3215

## Changes:

- Tests shader complexity starting with max texture slots
  • Loading branch information
eonarheim authored Sep 23, 2024
1 parent ed052ee commit f506da4
Show file tree
Hide file tree
Showing 3 changed files with 47 additions and 1 deletion.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
5 changes: 4 additions & 1 deletion src/engine/Graphics/Context/image-renderer/image-renderer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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';

Expand Down Expand Up @@ -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({
Expand Down
42 changes: 42 additions & 0 deletions src/engine/Graphics/Context/webgl-util.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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) | 0;
}
} while (!canCompile);
return numIfs;
}

0 comments on commit f506da4

Please sign in to comment.