Skip to content

Commit c72c558

Browse files
committed
change luma shader validation logic for raster tile layer
Signed-off-by: Ihor Dykhta <dikhta.igor@gmail.com>
1 parent 1cae110 commit c72c558

5 files changed

Lines changed: 70 additions & 45 deletions

File tree

src/deckgl-layers/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@
4141
"@luma.gl/constants": "^9.2.6",
4242
"@luma.gl/core": "^9.2.6",
4343
"@luma.gl/engine": "^9.2.6",
44+
"@luma.gl/webgl": "^9.2.6",
4445
"@mapbox/geo-viewport": "^0.4.1",
4546
"@mapbox/vector-tile": "^1.3.1",
4647
"@math.gl/web-mercator": "^4.1.0",
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
// SPDX-License-Identifier: MIT
2+
// Copyright contributors to the kepler.gl project
3+
4+
// @ts-nocheck
5+
6+
/**
7+
* Patch luma.gl 9's WEBGLRenderPipeline to tolerate mixed-sampler-type
8+
* validation errors in _getLinkStatus().
9+
*
10+
* WebGL2's validateProgram checks that sampler uniforms of different types
11+
* (sampler2D, usampler2D, isampler2D) are not assigned to the same texture
12+
* unit. Before any draw call the default texture unit for all samplers is 0,
13+
* so programs that mix sampler types (e.g. raster band data as usampler2D +
14+
* colormap as sampler2D) always fail validation even though the program linked
15+
* successfully and will work correctly once texture units are assigned at draw
16+
* time.
17+
*
18+
* luma.gl calls validateProgram inside _getLinkStatus() immediately after
19+
* linkProgram, before any texture units can be assigned. This patch keeps the
20+
* full validateProgram call but ignores only the known false-positive about
21+
* mixed sampler types. All other validation errors are still reported.
22+
*/
23+
24+
import {WEBGLRenderPipeline} from '@luma.gl/webgl';
25+
26+
const MIXED_SAMPLER_RE = /different type[s]? use the same sampler location/i;
27+
28+
let _patched = false;
29+
30+
export function patchPipelineValidation(): void {
31+
if (_patched) return;
32+
_patched = true;
33+
34+
if (!WEBGLRenderPipeline?.prototype?._getLinkStatus) {
35+
return;
36+
}
37+
38+
WEBGLRenderPipeline.prototype._getLinkStatus = function () {
39+
const {gl} = this.device;
40+
const linked = gl.getProgramParameter(this.handle, 0x8b82 /* LINK_STATUS */);
41+
if (!linked) {
42+
this.linkStatus = 'error';
43+
return 'link-error';
44+
}
45+
46+
gl.validateProgram(this.handle);
47+
const validated = gl.getProgramParameter(this.handle, 0x8b83 /* VALIDATE_STATUS */);
48+
if (!validated) {
49+
const infoLog = gl.getProgramInfoLog(this.handle) || '';
50+
if (!MIXED_SAMPLER_RE.test(infoLog)) {
51+
// Real validation error — report it
52+
this.linkStatus = 'error';
53+
return 'validation-error';
54+
}
55+
// Mixed sampler types sharing default texture unit 0 before draw-time
56+
// binding — this is a false positive, ignore it.
57+
}
58+
59+
this.linkStatus = 'success';
60+
return 'success';
61+
};
62+
}

src/deckgl-layers/src/raster/raster-layer/raster-layer.ts

Lines changed: 3 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,9 @@ import {
1616
import {loadImages} from '../images';
1717
import type {RasterLayerAddedProps, ImageState} from '../types';
1818
import {modulesEqual} from '../util';
19+
import {patchPipelineValidation} from '../pipeline-validation-patch';
20+
21+
patchPipelineValidation();
1922

2023
const defaultProps = {
2124
...BitmapLayer.defaultProps,
@@ -33,36 +36,9 @@ export default class RasterLayer extends BitmapLayer<RasterLayerAddedProps> {
3336
initializeState(): void {
3437
ensureRasterHooksRegistered();
3538
this.setState({images: {}});
36-
this._patchValidateProgram();
3739
super.initializeState();
3840
}
3941

40-
/**
41-
* Skip gl.validateProgram for this WebGL context.
42-
* WebGL2 validateProgram fails with "Two textures of different types use the
43-
* same sampler location" when sampler2D and usampler2D uniforms both default
44-
* to texture unit 0 before any bindings are set. This is a false positive —
45-
* proper texture units are assigned at draw time. Link errors and shader
46-
* compilation errors are still caught without validateProgram.
47-
*/
48-
_patchValidateProgram(): void {
49-
const gl = this.context.device?.gl;
50-
if (gl && !gl.__validateProgramPatched) {
51-
gl.__validateProgramPatched = true;
52-
const origGetProgramParameter = gl.getProgramParameter.bind(gl);
53-
gl.validateProgram = function () {
54-
// no op
55-
};
56-
gl.getProgramParameter = function (program: WebGLProgram, pname: number) {
57-
if (pname === 0x8b83) {
58-
// GL_VALIDATE_STATUS — always return true since we skip validation
59-
return true;
60-
}
61-
return origGetProgramParameter(program, pname);
62-
};
63-
}
64-
}
65-
6642
draw(_opts: {shaderModuleProps: any}): void {
6743
const {model, images, coordinateConversion, bounds} = this.state;
6844
const {desaturate, transparentColor, tintColor, moduleProps} = this.props;

src/deckgl-layers/src/raster/raster-mesh-layer/raster-mesh-layer.ts

Lines changed: 3 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,9 @@ import {
1919
import {loadImages} from '../images';
2020
import type {RasterLayerAddedProps, ImageState} from '../types';
2121
import {modulesEqual} from '../util';
22+
import {patchPipelineValidation} from '../pipeline-validation-patch';
23+
24+
patchPipelineValidation();
2225

2326
type Mesh = SimpleMeshLayerProps['mesh'];
2427

@@ -65,27 +68,9 @@ export default class RasterMeshLayer extends SimpleMeshLayer<any, RasterLayerAdd
6568
initializeState(): void {
6669
ensureRasterHooksRegistered();
6770
this.setState({images: {}});
68-
this._patchValidateProgram();
6971
super.initializeState();
7072
}
7173

72-
_patchValidateProgram(): void {
73-
const gl = this.context.device?.gl;
74-
if (gl && !gl.__validateProgramPatched) {
75-
gl.__validateProgramPatched = true;
76-
const origGetProgramParameter = gl.getProgramParameter.bind(gl);
77-
gl.validateProgram = function () {
78-
// no op
79-
};
80-
gl.getProgramParameter = function (program: WebGLProgram, pname: number) {
81-
if (pname === 0x8b83) {
82-
return true;
83-
}
84-
return origGetProgramParameter(program, pname);
85-
};
86-
}
87-
}
88-
8974
getShaders(): any {
9075
const {modules = []} = this.props;
9176

yarn.lock

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5153,6 +5153,7 @@ __metadata:
51535153
"@luma.gl/constants": "npm:^9.2.6"
51545154
"@luma.gl/core": "npm:^9.2.6"
51555155
"@luma.gl/engine": "npm:^9.2.6"
5156+
"@luma.gl/webgl": "npm:^9.2.6"
51565157
"@mapbox/geo-viewport": "npm:^0.4.1"
51575158
"@mapbox/vector-tile": "npm:^1.3.1"
51585159
"@math.gl/web-mercator": "npm:^4.1.0"

0 commit comments

Comments
 (0)