@flighthq/render-gl 0.3.1-next.733.f1845ac → 0.3.1-next.780.12e6944
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/enableGlRenderStateGuards.d.ts.map +1 -1
- package/dist/enableGlRenderStateGuards.js +12 -3
- package/dist/enableGlRenderStateGuards.js.map +1 -1
- package/dist/glRenderStateBracket.d.ts.map +1 -1
- package/dist/glRenderStateBracket.js +54 -0
- package/dist/glRenderStateBracket.js.map +1 -1
- package/package.json +11 -11
- package/src/enableGlRenderStateGuards.test.ts +10 -0
- package/src/glRenderState.test.ts +9 -1
- package/src/glRenderStateBracket.test.ts +170 -0
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"enableGlRenderStateGuards.d.ts","sourceRoot":"","sources":["../src/enableGlRenderStateGuards.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"enableGlRenderStateGuards.d.ts","sourceRoot":"","sources":["../src/enableGlRenderStateGuards.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,aAAa,EAA2B,MAAM,0BAA0B,CAAC;AAKvF,wBAAgB,6BAA6B,CAAC,KAAK,EAAE,aAAa,GAAG,OAAO,CAG3E;AAKD,wBAAgB,yBAAyB,CAAC,KAAK,EAAE,aAAa,GAAG,IAAI,CAUpE"}
|
|
@@ -1,15 +1,24 @@
|
|
|
1
1
|
import { logOnce } from '@flighthq/log/contract';
|
|
2
|
+
import { createSlotTable } from '@flighthq/registry/contract';
|
|
2
3
|
import { getRenderStateRuntime } from '@flighthq/render/contract';
|
|
3
|
-
import { LogLevel } from '@flighthq/types/contract';
|
|
4
|
+
import { LogLevel, RegistryEntryState } from '@flighthq/types/contract';
|
|
4
5
|
import { getGlRenderStateRuntime } from './glRenderState';
|
|
5
6
|
export function areGlRenderStateGuardsEnabled(state) {
|
|
6
|
-
|
|
7
|
+
const entry = getRenderStateRuntime(state).registries.renderRootGuard?.entry;
|
|
8
|
+
return entry?.state === RegistryEntryState.Bound && entry.value === warnOnSecondRenderRoot;
|
|
7
9
|
}
|
|
8
10
|
// Installs the GL pipeline-policy guard. A render state derives proxy transforms relative to one root;
|
|
9
11
|
// preparing another root on that state can reuse stale relative transforms. Give each independently
|
|
10
12
|
// rendered root its own createGlOffscreenRenderState-derived state.
|
|
11
13
|
export function enableGlRenderStateGuards(state) {
|
|
12
|
-
getRenderStateRuntime(state)
|
|
14
|
+
const runtime = getRenderStateRuntime(state);
|
|
15
|
+
const table = runtime.registries.renderRootGuard ?? createSlotTable('RenderRootGuard', 'Disabled');
|
|
16
|
+
if (table.entry?.state !== RegistryEntryState.Bound || table.entry.value !== warnOnSecondRenderRoot) {
|
|
17
|
+
runtime.registries.renderRootGuard = {
|
|
18
|
+
...table,
|
|
19
|
+
entry: { state: RegistryEntryState.Bound, value: warnOnSecondRenderRoot },
|
|
20
|
+
};
|
|
21
|
+
}
|
|
13
22
|
getGlRenderStateRuntime(state).bindingCacheGuard = warnOnForeignGlBinding;
|
|
14
23
|
}
|
|
15
24
|
// render-gl skips a redundant `useProgram` by trusting its cached binding slot, which is sound only
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"enableGlRenderStateGuards.js","sourceRoot":"","sources":["../src/enableGlRenderStateGuards.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,wBAAwB,CAAC;AACjD,OAAO,EAAE,qBAAqB,EAAE,MAAM,2BAA2B,CAAC;AAElE,OAAO,EAAE,QAAQ,EAAE,MAAM,0BAA0B,CAAC;
|
|
1
|
+
{"version":3,"file":"enableGlRenderStateGuards.js","sourceRoot":"","sources":["../src/enableGlRenderStateGuards.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,wBAAwB,CAAC;AACjD,OAAO,EAAE,eAAe,EAAE,MAAM,6BAA6B,CAAC;AAC9D,OAAO,EAAE,qBAAqB,EAAE,MAAM,2BAA2B,CAAC;AAElE,OAAO,EAAE,QAAQ,EAAE,kBAAkB,EAAE,MAAM,0BAA0B,CAAC;AAExE,OAAO,EAAE,uBAAuB,EAAE,MAAM,iBAAiB,CAAC;AAE1D,MAAM,UAAU,6BAA6B,CAAC,KAAoB;IAChE,MAAM,KAAK,GAAG,qBAAqB,CAAC,KAAK,CAAC,CAAC,UAAU,CAAC,eAAe,EAAE,KAAK,CAAC;IAC7E,OAAO,KAAK,EAAE,KAAK,KAAK,kBAAkB,CAAC,KAAK,IAAI,KAAK,CAAC,KAAK,KAAK,sBAAsB,CAAC;AAC7F,CAAC;AAED,uGAAuG;AACvG,oGAAoG;AACpG,oEAAoE;AACpE,MAAM,UAAU,yBAAyB,CAAC,KAAoB;IAC5D,MAAM,OAAO,GAAG,qBAAqB,CAAC,KAAK,CAAC,CAAC;IAC7C,MAAM,KAAK,GAAG,OAAO,CAAC,UAAU,CAAC,eAAe,IAAI,eAAe,CAAC,iBAAiB,EAAE,UAAU,CAAC,CAAC;IACnG,IAAI,KAAK,CAAC,KAAK,EAAE,KAAK,KAAK,kBAAkB,CAAC,KAAK,IAAI,KAAK,CAAC,KAAK,CAAC,KAAK,KAAK,sBAAsB,EAAE,CAAC;QACpG,OAAO,CAAC,UAAU,CAAC,eAAe,GAAG;YACnC,GAAG,KAAK;YACR,KAAK,EAAE,EAAE,KAAK,EAAE,kBAAkB,CAAC,KAAK,EAAE,KAAK,EAAE,sBAAsB,EAAE;SAC1E,CAAC;IACJ,CAAC;IACD,uBAAuB,CAAC,KAAK,CAAC,CAAC,iBAAiB,GAAG,sBAAsB,CAAC;AAC5E,CAAC;AAED,oGAAoG;AACpG,qGAAqG;AACrG,wGAAwG;AACxG,mFAAmF;AACnF,EAAE;AACF,oGAAoG;AACpG,qGAAqG;AACrG,uGAAuG;AACvG,uDAAuD;AACvD,SAAS,sBAAsB,CAAC,KAAoB,EAAE,eAA6B;IACjF,MAAM,MAAM,GAAG,KAAK,CAAC,EAAE,CAAC,YAAY,CAAC,KAAK,CAAC,EAAE,CAAC,eAAe,CAAwB,CAAC;IACtF,IAAI,MAAM,KAAK,eAAe;QAAE,OAAO;IACvC,OAAO,CACL,8BAA8B,EAC9B,QAAQ,CAAC,IAAI,EACb;QACE,OAAO,EACL,mGAAmG;YACnG,iGAAiG;YACjG,8FAA8F;QAChG,KAAK;KACN,EACD,WAAW,CACZ,CAAC;AACJ,CAAC;AAED,SAAS,sBAAsB,CAAC,KAAkB,EAAE,IAAgB;IAClE,MAAM,OAAO,GAAG,KAAsB,CAAC;IACvC,MAAM,QAAQ,GAAG,WAAW,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;IAC1C,IAAI,QAAQ,KAAK,SAAS,EAAE,CAAC;QAC3B,WAAW,CAAC,GAAG,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC;QAC/B,OAAO;IACT,CAAC;IACD,IAAI,QAAQ,KAAK,IAAI;QAAE,OAAO;IAC9B,OAAO,CACL,oCAAoC,EACpC,QAAQ,CAAC,IAAI,EACb;QACE,SAAS,EAAE,QAAQ;QACnB,OAAO,EACL,kJAAkJ;QACpJ,IAAI;QACJ,KAAK;KACN,EACD,WAAW,CACZ,CAAC;AACJ,CAAC;AAED,MAAM,WAAW,GAAG,IAAI,OAAO,EAA6B,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"glRenderStateBracket.d.ts","sourceRoot":"","sources":["../src/glRenderStateBracket.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAwB,MAAM,0BAA0B,CAAC;
|
|
1
|
+
{"version":3,"file":"glRenderStateBracket.d.ts","sourceRoot":"","sources":["../src/glRenderStateBracket.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAwB,MAAM,0BAA0B,CAAC;AA6DpF,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,aAAa,GAAG,IAAI,CAmE3D;AAKD,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,aAAa,GAAG,IAAI,CAmE5D;AAKD,wBAAgB,iBAAiB,CAAC,CAAC,EAAE,KAAK,EAAE,aAAa,EAAE,QAAQ,EAAE,MAAM,CAAC,GAAG,CAAC,CAO/E"}
|
|
@@ -13,6 +13,26 @@ export function popGlRenderState(state) {
|
|
|
13
13
|
gl.depthFunc(saved.depthFunc);
|
|
14
14
|
restoreGlCapability(gl, gl.CULL_FACE, saved.cullFace);
|
|
15
15
|
gl.cullFace(saved.cullFaceMode);
|
|
16
|
+
// The 3D mesh path selects a front face per draw from the model determinant, so this is state
|
|
17
|
+
// Flight mutates and must hand back exactly as the host left it — a host context set to CW would
|
|
18
|
+
// otherwise get CCW returned.
|
|
19
|
+
gl.frontFace(saved.frontFace);
|
|
20
|
+
// The 2D clip system rasterizes stencil masks, and its own capture/restore inside glRenderPass is
|
|
21
|
+
// scoped to FLIGHT's mask nesting — it captures only when Flight already has a clip active, and its
|
|
22
|
+
// null path disables the test outright. That is correct for Flight's own nesting and says nothing
|
|
23
|
+
// about the host: a caller that had STENCIL_TEST enabled would otherwise get it switched off by any
|
|
24
|
+
// Flight render. This is the host-facing half.
|
|
25
|
+
//
|
|
26
|
+
// Restored per face, because the unsuffixed setters write FRONT_AND_BACK: restoring both faces from
|
|
27
|
+
// the front's saved values would silently overwrite the back face of a host using two-sided stencil,
|
|
28
|
+
// which is the case stencilOpSeparate exists for and the one Flight's own clip pass writes.
|
|
29
|
+
restoreGlCapability(gl, gl.STENCIL_TEST, saved.stencilTest);
|
|
30
|
+
gl.stencilMaskSeparate(gl.FRONT, saved.stencilWriteMask);
|
|
31
|
+
gl.stencilMaskSeparate(gl.BACK, saved.stencilBackWriteMask);
|
|
32
|
+
gl.stencilFuncSeparate(gl.FRONT, saved.stencilFunc, saved.stencilRef, saved.stencilValueMask);
|
|
33
|
+
gl.stencilFuncSeparate(gl.BACK, saved.stencilBackFunc, saved.stencilBackRef, saved.stencilBackValueMask);
|
|
34
|
+
gl.stencilOpSeparate(gl.FRONT, saved.stencilFail, saved.stencilPassDepthFail, saved.stencilPassDepthPass);
|
|
35
|
+
gl.stencilOpSeparate(gl.BACK, saved.stencilBackFail, saved.stencilBackPassDepthFail, saved.stencilBackPassDepthPass);
|
|
16
36
|
restoreGlCapability(gl, gl.BLEND, saved.blend);
|
|
17
37
|
gl.blendFuncSeparate(saved.blendSrcRgb, saved.blendDstRgb, saved.blendSrcAlpha, saved.blendDstAlpha);
|
|
18
38
|
gl.blendEquationSeparate(saved.blendEquationRgb, saved.blendEquationAlpha);
|
|
@@ -24,6 +44,13 @@ export function popGlRenderState(state) {
|
|
|
24
44
|
gl.bindTexture(gl.TEXTURE_2D, saved.texture2DByUnit[i]);
|
|
25
45
|
}
|
|
26
46
|
gl.activeTexture(saved.activeTexture);
|
|
47
|
+
// Pixel-write and upload state Flight sets and never puts back on its own: the 2D clip pass masks
|
|
48
|
+
// colour while it rasterizes coverage, the background/velocity passes set a clear colour, and every
|
|
49
|
+
// texture upload sets the premultiply flag. Each is context-wide, so a host that never called them
|
|
50
|
+
// would otherwise inherit Flight's last value.
|
|
51
|
+
gl.colorMask(saved.colorMask[0], saved.colorMask[1], saved.colorMask[2], saved.colorMask[3]);
|
|
52
|
+
gl.clearColor(saved.clearColor[0], saved.clearColor[1], saved.clearColor[2], saved.clearColor[3]);
|
|
53
|
+
gl.pixelStorei(gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, saved.unpackPremultiplyAlpha);
|
|
27
54
|
restoreGlCapability(gl, gl.SCISSOR_TEST, saved.scissorTest);
|
|
28
55
|
gl.scissor(saved.scissorBox[0], saved.scissorBox[1], saved.scissorBox[2], saved.scissorBox[3]);
|
|
29
56
|
gl.viewport(saved.viewport[0], saved.viewport[1], saved.viewport[2], saved.viewport[3]);
|
|
@@ -65,8 +92,26 @@ export function pushGlRenderState(state) {
|
|
|
65
92
|
blendEquationRgb: gl.getParameter(gl.BLEND_EQUATION_RGB),
|
|
66
93
|
blendSrcAlpha: gl.getParameter(gl.BLEND_SRC_ALPHA),
|
|
67
94
|
blendSrcRgb: gl.getParameter(gl.BLEND_SRC_RGB),
|
|
95
|
+
clearColor: readGlBox(gl, gl.COLOR_CLEAR_VALUE),
|
|
96
|
+
colorMask: readGlBooleanQuad(gl, gl.COLOR_WRITEMASK),
|
|
68
97
|
cullFace: gl.isEnabled(gl.CULL_FACE),
|
|
69
98
|
cullFaceMode: gl.getParameter(gl.CULL_FACE_MODE),
|
|
99
|
+
frontFace: gl.getParameter(gl.FRONT_FACE),
|
|
100
|
+
stencilBackFail: gl.getParameter(gl.STENCIL_BACK_FAIL),
|
|
101
|
+
stencilBackFunc: gl.getParameter(gl.STENCIL_BACK_FUNC),
|
|
102
|
+
stencilBackPassDepthFail: gl.getParameter(gl.STENCIL_BACK_PASS_DEPTH_FAIL),
|
|
103
|
+
stencilBackPassDepthPass: gl.getParameter(gl.STENCIL_BACK_PASS_DEPTH_PASS),
|
|
104
|
+
stencilBackRef: gl.getParameter(gl.STENCIL_BACK_REF),
|
|
105
|
+
stencilBackValueMask: gl.getParameter(gl.STENCIL_BACK_VALUE_MASK),
|
|
106
|
+
stencilBackWriteMask: gl.getParameter(gl.STENCIL_BACK_WRITEMASK),
|
|
107
|
+
stencilFail: gl.getParameter(gl.STENCIL_FAIL),
|
|
108
|
+
stencilFunc: gl.getParameter(gl.STENCIL_FUNC),
|
|
109
|
+
stencilPassDepthFail: gl.getParameter(gl.STENCIL_PASS_DEPTH_FAIL),
|
|
110
|
+
stencilPassDepthPass: gl.getParameter(gl.STENCIL_PASS_DEPTH_PASS),
|
|
111
|
+
stencilRef: gl.getParameter(gl.STENCIL_REF),
|
|
112
|
+
stencilTest: gl.isEnabled(gl.STENCIL_TEST),
|
|
113
|
+
stencilValueMask: gl.getParameter(gl.STENCIL_VALUE_MASK),
|
|
114
|
+
stencilWriteMask: gl.getParameter(gl.STENCIL_WRITEMASK),
|
|
70
115
|
currentFramebuffer: runtime.currentFramebuffer,
|
|
71
116
|
currentBlendMode: runtime.currentBlendMode,
|
|
72
117
|
currentRenderTarget: runtime.currentRenderTarget,
|
|
@@ -83,6 +128,7 @@ export function pushGlRenderState(state) {
|
|
|
83
128
|
scissorBox: readGlBox(gl, gl.SCISSOR_BOX),
|
|
84
129
|
scissorTest: gl.isEnabled(gl.SCISSOR_TEST),
|
|
85
130
|
texture2DByUnit,
|
|
131
|
+
unpackPremultiplyAlpha: gl.getParameter(gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL),
|
|
86
132
|
vertexArray: gl.getParameter(gl.VERTEX_ARRAY_BINDING),
|
|
87
133
|
viewport: readGlBox(gl, gl.VIEWPORT),
|
|
88
134
|
});
|
|
@@ -99,6 +145,14 @@ export function withGlRenderState(state, callback) {
|
|
|
99
145
|
popGlRenderState(state);
|
|
100
146
|
}
|
|
101
147
|
}
|
|
148
|
+
function readGlBooleanQuad(gl, parameter) {
|
|
149
|
+
const value = gl.getParameter(parameter);
|
|
150
|
+
// As readGlBox: browsers always return four values for COLOR_WRITEMASK. All-enabled is the GL
|
|
151
|
+
// default and the conservative sentinel for a partial mock — it can never mask a host's writes off.
|
|
152
|
+
if (value === null || value === undefined)
|
|
153
|
+
return [true, true, true, true];
|
|
154
|
+
return [value[0], value[1], value[2], value[3]];
|
|
155
|
+
}
|
|
102
156
|
function readGlBox(gl, parameter) {
|
|
103
157
|
const value = gl.getParameter(parameter);
|
|
104
158
|
// Lightweight test contexts may omit inert query state. Browsers always return four values for
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"glRenderStateBracket.js","sourceRoot":"","sources":["../src/glRenderStateBracket.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,uBAAuB,EAAE,MAAM,iBAAiB,CAAC;
|
|
1
|
+
{"version":3,"file":"glRenderStateBracket.js","sourceRoot":"","sources":["../src/glRenderStateBracket.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@flighthq/render-gl",
|
|
3
|
-
"version": "0.3.1-next.
|
|
3
|
+
"version": "0.3.1-next.780.12e6944",
|
|
4
4
|
"author": "Joshua Granick and other contributors",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
@@ -38,16 +38,16 @@
|
|
|
38
38
|
"clean:dist": "tsx ../../scripts/clean-package-dist.ts"
|
|
39
39
|
},
|
|
40
40
|
"dependencies": {
|
|
41
|
-
"@flighthq/color": "0.3.1-next.
|
|
42
|
-
"@flighthq/entity": "0.3.1-next.
|
|
43
|
-
"@flighthq/log": "0.3.1-next.
|
|
44
|
-
"@flighthq/scene2d": "0.3.1-next.
|
|
45
|
-
"@flighthq/geometry": "0.3.1-next.
|
|
46
|
-
"@flighthq/render": "0.3.1-next.
|
|
47
|
-
"@flighthq/registry": "0.3.1-next.
|
|
48
|
-
"@flighthq/signals": "0.3.1-next.
|
|
49
|
-
"@flighthq/texture": "0.3.1-next.
|
|
50
|
-
"@flighthq/types": "0.3.1-next.
|
|
41
|
+
"@flighthq/color": "0.3.1-next.780.12e6944",
|
|
42
|
+
"@flighthq/entity": "0.3.1-next.780.12e6944",
|
|
43
|
+
"@flighthq/log": "0.3.1-next.780.12e6944",
|
|
44
|
+
"@flighthq/scene2d": "0.3.1-next.780.12e6944",
|
|
45
|
+
"@flighthq/geometry": "0.3.1-next.780.12e6944",
|
|
46
|
+
"@flighthq/render": "0.3.1-next.780.12e6944",
|
|
47
|
+
"@flighthq/registry": "0.3.1-next.780.12e6944",
|
|
48
|
+
"@flighthq/signals": "0.3.1-next.780.12e6944",
|
|
49
|
+
"@flighthq/texture": "0.3.1-next.780.12e6944",
|
|
50
|
+
"@flighthq/types": "0.3.1-next.780.12e6944"
|
|
51
51
|
},
|
|
52
52
|
"devDependencies": {
|
|
53
53
|
"typescript": "^5.3.0"
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import { setLogSink } from '@flighthq/log/contract';
|
|
2
|
+
import { getRenderStateRuntime } from '@flighthq/render/contract';
|
|
2
3
|
import type { LogEntry } from '@flighthq/types/contract';
|
|
4
|
+
import { RegistryEntryState } from '@flighthq/types/contract';
|
|
3
5
|
|
|
4
6
|
import { areGlRenderStateGuardsEnabled, enableGlRenderStateGuards } from './enableGlRenderStateGuards';
|
|
5
7
|
import { useGlProgram } from './glDraw';
|
|
@@ -25,8 +27,16 @@ describe('enableGlRenderStateGuards', () => {
|
|
|
25
27
|
it('installs the state-local multiple-root guard idempotently', () => {
|
|
26
28
|
const state = createState();
|
|
27
29
|
enableGlRenderStateGuards(state);
|
|
30
|
+
const table = getRenderStateRuntime(state).registries.renderRootGuard;
|
|
31
|
+
expect(table).toMatchObject({
|
|
32
|
+
entry: { state: RegistryEntryState.Bound },
|
|
33
|
+
onMiss: 'Disabled',
|
|
34
|
+
registry: 'RenderRootGuard',
|
|
35
|
+
shape: 'slot',
|
|
36
|
+
});
|
|
28
37
|
enableGlRenderStateGuards(state);
|
|
29
38
|
expect(areGlRenderStateGuardsEnabled(state)).toBe(true);
|
|
39
|
+
expect(getRenderStateRuntime(state).registries.renderRootGuard).toBe(table);
|
|
30
40
|
});
|
|
31
41
|
});
|
|
32
42
|
|
|
@@ -23,7 +23,7 @@ import type {
|
|
|
23
23
|
} from '@flighthq/types/contract';
|
|
24
24
|
import { BlendMode, RegistryEntryState } from '@flighthq/types/contract';
|
|
25
25
|
|
|
26
|
-
import { enableGlRenderStateGuards } from './enableGlRenderStateGuards';
|
|
26
|
+
import { areGlRenderStateGuardsEnabled, enableGlRenderStateGuards } from './enableGlRenderStateGuards';
|
|
27
27
|
import { registerGlCompressedTextureDecoder, registerGlCompressedTextureUpload } from './glCompressedTexture';
|
|
28
28
|
import { isBlendModeSupported, registerGlBlendMode } from './glDraw';
|
|
29
29
|
import { registerGlMaterialRenderer } from './glMaterialRegistry';
|
|
@@ -160,6 +160,7 @@ describe('createGlOffscreenRenderState', () => {
|
|
|
160
160
|
registerGlTextureResolver(screen, 'acme.Texture', textureResolver);
|
|
161
161
|
enableColorAdjustments(screen);
|
|
162
162
|
enableColorAdjustmentGuards(screen);
|
|
163
|
+
enableGlRenderStateGuards(screen);
|
|
163
164
|
getGlRenderStateRuntime(screen).registries.renderEffects = withRegistryTableEntry(
|
|
164
165
|
getGlRenderStateRuntime(screen).registries.renderEffects,
|
|
165
166
|
'acme.Effect',
|
|
@@ -221,6 +222,13 @@ describe('createGlOffscreenRenderState', () => {
|
|
|
221
222
|
expect(getColorAdjustmentUnsupportedGuard(screen)).toBeNull();
|
|
222
223
|
expect(offscreenRuntime.registries.colorAdjustmentUnsupportedGuard).toBe(sharedUnsupportedGuard);
|
|
223
224
|
expect(getColorAdjustmentUnsupportedGuard(offscreen)).not.toBeNull();
|
|
225
|
+
expect(offscreenRuntime.registries.renderRootGuard).toBe(screenRuntime.registries.renderRootGuard);
|
|
226
|
+
expect(areGlRenderStateGuardsEnabled(offscreen)).toBe(true);
|
|
227
|
+
const sharedRenderRootGuard = offscreenRuntime.registries.renderRootGuard;
|
|
228
|
+
screenRuntime.registries.renderRootGuard = undefined;
|
|
229
|
+
expect(screenRuntime.registries.renderRootGuard).toBeUndefined();
|
|
230
|
+
expect(offscreenRuntime.registries.renderRootGuard).toBe(sharedRenderRootGuard);
|
|
231
|
+
expect(areGlRenderStateGuardsEnabled(offscreen)).toBe(true);
|
|
224
232
|
expect(offscreenRuntime.registries.compressedTextureDecoder).toBe(
|
|
225
233
|
screenRuntime.registries.compressedTextureDecoder,
|
|
226
234
|
);
|
|
@@ -23,6 +23,9 @@ type TestGlState = {
|
|
|
23
23
|
blendSrcRgb: number;
|
|
24
24
|
cullFace: boolean;
|
|
25
25
|
cullFaceMode: number;
|
|
26
|
+
frontFace: number;
|
|
27
|
+
stencilTest: boolean;
|
|
28
|
+
stencilWriteMask: number;
|
|
26
29
|
currentRenderTarget: GlRenderTarget | null;
|
|
27
30
|
depthFunc: number;
|
|
28
31
|
depthMask: boolean;
|
|
@@ -58,6 +61,9 @@ const OUTER_STATE: TestGlState = {
|
|
|
58
61
|
blendSrcRgb: 1,
|
|
59
62
|
cullFace: false,
|
|
60
63
|
cullFaceMode: 0x0405,
|
|
64
|
+
frontFace: 0x0900, // GL_CW — a host that does not use Flight's default
|
|
65
|
+
stencilTest: true, // enabled on purpose: a fixture that starts disabled cannot tell 'restored' from 'left off'
|
|
66
|
+
stencilWriteMask: 0x0f,
|
|
61
67
|
currentRenderTarget: { name: 'outer-target' } as unknown as GlRenderTarget,
|
|
62
68
|
depthFunc: 0x0203,
|
|
63
69
|
depthMask: false,
|
|
@@ -86,6 +92,9 @@ const MIDDLE_STATE: TestGlState = {
|
|
|
86
92
|
blendSrcRgb: 1,
|
|
87
93
|
cullFace: true,
|
|
88
94
|
cullFaceMode: 0x0404,
|
|
95
|
+
frontFace: 0x0901, // GL_CCW
|
|
96
|
+
stencilTest: false,
|
|
97
|
+
stencilWriteMask: 0xff,
|
|
89
98
|
currentRenderTarget: { name: 'middle-target' } as unknown as GlRenderTarget,
|
|
90
99
|
depthFunc: 0x0201,
|
|
91
100
|
depthMask: true,
|
|
@@ -136,6 +145,57 @@ describe('popGlRenderState', () => {
|
|
|
136
145
|
expectTestGlState(fixture, OUTER_STATE);
|
|
137
146
|
});
|
|
138
147
|
|
|
148
|
+
it('restores a two-sided stencil configuration without collapsing the back face onto the front', () => {
|
|
149
|
+
const fixture = createStatefulGl();
|
|
150
|
+
const gl = fixture.gl;
|
|
151
|
+
applyTestGlState(fixture, OUTER_STATE);
|
|
152
|
+
// A host driving two-sided stencil — the case stencilOpSeparate exists for. Every back-face value
|
|
153
|
+
// differs from its front counterpart, so a restore that writes both faces from the front's saved
|
|
154
|
+
// values cannot pass by coincidence: it would report the front correct and the back overwritten.
|
|
155
|
+
gl.stencilOpSeparate(gl.FRONT, 0x1e00, 0x1e00, 0x1e01); // KEEP, KEEP, REPLACE
|
|
156
|
+
gl.stencilOpSeparate(gl.BACK, 0x1e02, 0x1e03, 0x150a); // INCR, DECR, INVERT
|
|
157
|
+
gl.stencilFuncSeparate(gl.FRONT, 0x0201, 1, 0xf0); // LESS
|
|
158
|
+
gl.stencilFuncSeparate(gl.BACK, 0x0204, 2, 0x0f); // GREATER
|
|
159
|
+
gl.stencilMaskSeparate(gl.FRONT, 0xaa);
|
|
160
|
+
gl.stencilMaskSeparate(gl.BACK, 0x55);
|
|
161
|
+
const host = new Map(fixture.parameters);
|
|
162
|
+
pushGlRenderState(fixture.state);
|
|
163
|
+
|
|
164
|
+
// What Flight's own 2D clip pass writes: separate wrap ops per face, then a symmetric gate.
|
|
165
|
+
gl.stencilOpSeparate(gl.FRONT, 0x1e00, 0x1e00, 0x8507); // INCR_WRAP
|
|
166
|
+
gl.stencilOpSeparate(gl.BACK, 0x1e00, 0x1e00, 0x8508); // DECR_WRAP
|
|
167
|
+
gl.stencilFunc(0x0207, 0, 0xff); // ALWAYS, both faces
|
|
168
|
+
gl.stencilMask(0xff);
|
|
169
|
+
popGlRenderState(fixture.state);
|
|
170
|
+
|
|
171
|
+
for (const parameter of TWO_SIDED_STENCIL_PARAMETERS) {
|
|
172
|
+
expect([parameter, fixture.parameters.get(gl[parameter])]).toEqual([parameter, host.get(gl[parameter])]);
|
|
173
|
+
}
|
|
174
|
+
});
|
|
175
|
+
|
|
176
|
+
it('restores colour-write, clear-colour, and upload-premultiply state Flight leaves behind', () => {
|
|
177
|
+
const fixture = createStatefulGl();
|
|
178
|
+
const gl = fixture.gl;
|
|
179
|
+
applyTestGlState(fixture, OUTER_STATE);
|
|
180
|
+
// A host whose own settings all differ from both the GL defaults and from what Flight will set,
|
|
181
|
+
// so neither 'never restored' nor 'reset to the default' can pass as restoration.
|
|
182
|
+
gl.colorMask(true, false, true, false);
|
|
183
|
+
gl.clearColor(0.25, 0.5, 0.75, 1);
|
|
184
|
+
gl.pixelStorei(gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, false);
|
|
185
|
+
pushGlRenderState(fixture.state);
|
|
186
|
+
|
|
187
|
+
// What Flight's own passes do: mask colour off while rasterizing clip coverage, clear a target,
|
|
188
|
+
// and premultiply a texture upload. None of these puts the previous value back.
|
|
189
|
+
gl.colorMask(false, false, false, false);
|
|
190
|
+
gl.clearColor(0, 0, 0, 0);
|
|
191
|
+
gl.pixelStorei(gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, true);
|
|
192
|
+
popGlRenderState(fixture.state);
|
|
193
|
+
|
|
194
|
+
expect(fixture.parameters.get(gl.COLOR_WRITEMASK)).toEqual([true, false, true, false]);
|
|
195
|
+
expect(fixture.parameters.get(gl.COLOR_CLEAR_VALUE)).toEqual([0.25, 0.5, 0.75, 1]);
|
|
196
|
+
expect(fixture.parameters.get(gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL)).toBe(false);
|
|
197
|
+
});
|
|
198
|
+
|
|
139
199
|
it('restores a non-active texture unit binding', () => {
|
|
140
200
|
const fixture = createStatefulGl();
|
|
141
201
|
applyTestGlState(fixture, OUTER_STATE);
|
|
@@ -207,6 +267,9 @@ function applyTestGlState(fixture: StatefulGl, values: Readonly<TestGlState>): v
|
|
|
207
267
|
gl.depthFunc(values.depthFunc);
|
|
208
268
|
setCapability(gl, gl.CULL_FACE, values.cullFace);
|
|
209
269
|
gl.cullFace(values.cullFaceMode);
|
|
270
|
+
gl.frontFace(values.frontFace);
|
|
271
|
+
setCapability(gl, gl.STENCIL_TEST, values.stencilTest);
|
|
272
|
+
gl.stencilMask(values.stencilWriteMask);
|
|
210
273
|
setCapability(gl, gl.BLEND, values.blend);
|
|
211
274
|
gl.blendFuncSeparate(values.blendSrcRgb, values.blendDstRgb, values.blendSrcAlpha, values.blendDstAlpha);
|
|
212
275
|
gl.blendEquationSeparate(values.blendEquationRgb, values.blendEquationAlpha);
|
|
@@ -244,6 +307,27 @@ function createStatefulGl(): StatefulGl & ReturnType<typeof createGlState> {
|
|
|
244
307
|
DEPTH_FUNC: 0x0b74,
|
|
245
308
|
DEPTH_WRITEMASK: 0x0b72,
|
|
246
309
|
FRAMEBUFFER_BINDING: 0x8ca6,
|
|
310
|
+
FRONT_FACE: 0x0b46,
|
|
311
|
+
BACK: 0x0405,
|
|
312
|
+
COLOR_CLEAR_VALUE: 0x0c22,
|
|
313
|
+
COLOR_WRITEMASK: 0x0c23,
|
|
314
|
+
UNPACK_PREMULTIPLY_ALPHA_WEBGL: 0x9241,
|
|
315
|
+
FRONT: 0x0404,
|
|
316
|
+
STENCIL_BACK_FAIL: 0x8801,
|
|
317
|
+
STENCIL_BACK_FUNC: 0x8800,
|
|
318
|
+
STENCIL_BACK_PASS_DEPTH_FAIL: 0x8802,
|
|
319
|
+
STENCIL_BACK_PASS_DEPTH_PASS: 0x8803,
|
|
320
|
+
STENCIL_BACK_REF: 0x8ca3,
|
|
321
|
+
STENCIL_BACK_VALUE_MASK: 0x8ca4,
|
|
322
|
+
STENCIL_BACK_WRITEMASK: 0x8ca5,
|
|
323
|
+
STENCIL_FAIL: 0x0b94,
|
|
324
|
+
STENCIL_FUNC: 0x0b92,
|
|
325
|
+
STENCIL_PASS_DEPTH_FAIL: 0x0b95,
|
|
326
|
+
STENCIL_PASS_DEPTH_PASS: 0x0b96,
|
|
327
|
+
STENCIL_REF: 0x0b97,
|
|
328
|
+
STENCIL_TEST: 0x0b90,
|
|
329
|
+
STENCIL_VALUE_MASK: 0x0b93,
|
|
330
|
+
STENCIL_WRITEMASK: 0x0b98,
|
|
247
331
|
SCISSOR_BOX: 0x0c10,
|
|
248
332
|
TEXTURE_BINDING_2D: 0x8069,
|
|
249
333
|
VERTEX_ARRAY_BINDING: 0x85b5,
|
|
@@ -271,6 +355,65 @@ function createStatefulGl(): StatefulGl & ReturnType<typeof createGlState> {
|
|
|
271
355
|
(gl.cullFace as ReturnType<typeof vi.fn>).mockImplementation((value: number) =>
|
|
272
356
|
parameters.set(gl.CULL_FACE_MODE, value),
|
|
273
357
|
);
|
|
358
|
+
(gl.frontFace as ReturnType<typeof vi.fn>).mockImplementation((value: number) =>
|
|
359
|
+
parameters.set(gl.FRONT_FACE, value),
|
|
360
|
+
);
|
|
361
|
+
(gl.colorMask as ReturnType<typeof vi.fn>).mockImplementation((r: boolean, g: boolean, b: boolean, a: boolean) =>
|
|
362
|
+
parameters.set(gl.COLOR_WRITEMASK, [r, g, b, a]),
|
|
363
|
+
);
|
|
364
|
+
(gl.clearColor as ReturnType<typeof vi.fn>).mockImplementation((r: number, g: number, b: number, a: number) =>
|
|
365
|
+
parameters.set(gl.COLOR_CLEAR_VALUE, [r, g, b, a]),
|
|
366
|
+
);
|
|
367
|
+
(gl.pixelStorei as ReturnType<typeof vi.fn>).mockImplementation((parameter: number, value: unknown) =>
|
|
368
|
+
parameters.set(parameter, value),
|
|
369
|
+
);
|
|
370
|
+
// Stencil is two-faced state: the unsuffixed setters write FRONT_AND_BACK while the Separate ones
|
|
371
|
+
// write only the named face. That rule was measured against a real WebGL2 context rather than assumed
|
|
372
|
+
// here — a fake cannot be the oracle for the API it fakes. `null` is the unsuffixed, both-faces form.
|
|
373
|
+
const writeStencilMask = (face: number | null, value: number): void => {
|
|
374
|
+
if (face !== gl.BACK) parameters.set(gl.STENCIL_WRITEMASK, value);
|
|
375
|
+
if (face !== gl.FRONT) parameters.set(gl.STENCIL_BACK_WRITEMASK, value);
|
|
376
|
+
};
|
|
377
|
+
const writeStencilFunc = (face: number | null, func: number, ref: number, mask: number): void => {
|
|
378
|
+
if (face !== gl.BACK) {
|
|
379
|
+
parameters.set(gl.STENCIL_FUNC, func);
|
|
380
|
+
parameters.set(gl.STENCIL_REF, ref);
|
|
381
|
+
parameters.set(gl.STENCIL_VALUE_MASK, mask);
|
|
382
|
+
}
|
|
383
|
+
if (face !== gl.FRONT) {
|
|
384
|
+
parameters.set(gl.STENCIL_BACK_FUNC, func);
|
|
385
|
+
parameters.set(gl.STENCIL_BACK_REF, ref);
|
|
386
|
+
parameters.set(gl.STENCIL_BACK_VALUE_MASK, mask);
|
|
387
|
+
}
|
|
388
|
+
};
|
|
389
|
+
const writeStencilOp = (face: number | null, fail: number, depthFail: number, depthPass: number): void => {
|
|
390
|
+
if (face !== gl.BACK) {
|
|
391
|
+
parameters.set(gl.STENCIL_FAIL, fail);
|
|
392
|
+
parameters.set(gl.STENCIL_PASS_DEPTH_FAIL, depthFail);
|
|
393
|
+
parameters.set(gl.STENCIL_PASS_DEPTH_PASS, depthPass);
|
|
394
|
+
}
|
|
395
|
+
if (face !== gl.FRONT) {
|
|
396
|
+
parameters.set(gl.STENCIL_BACK_FAIL, fail);
|
|
397
|
+
parameters.set(gl.STENCIL_BACK_PASS_DEPTH_FAIL, depthFail);
|
|
398
|
+
parameters.set(gl.STENCIL_BACK_PASS_DEPTH_PASS, depthPass);
|
|
399
|
+
}
|
|
400
|
+
};
|
|
401
|
+
(gl.stencilMask as ReturnType<typeof vi.fn>).mockImplementation((value: number) => writeStencilMask(null, value));
|
|
402
|
+
(gl.stencilMaskSeparate as ReturnType<typeof vi.fn>).mockImplementation((face: number, value: number) =>
|
|
403
|
+
writeStencilMask(face, value),
|
|
404
|
+
);
|
|
405
|
+
(gl.stencilFunc as ReturnType<typeof vi.fn>).mockImplementation((func: number, ref: number, mask: number) =>
|
|
406
|
+
writeStencilFunc(null, func, ref, mask),
|
|
407
|
+
);
|
|
408
|
+
(gl.stencilFuncSeparate as ReturnType<typeof vi.fn>).mockImplementation(
|
|
409
|
+
(face: number, func: number, ref: number, mask: number) => writeStencilFunc(face, func, ref, mask),
|
|
410
|
+
);
|
|
411
|
+
(gl.stencilOp as ReturnType<typeof vi.fn>).mockImplementation((fail: number, dFail: number, dPass: number) =>
|
|
412
|
+
writeStencilOp(null, fail, dFail, dPass),
|
|
413
|
+
);
|
|
414
|
+
(gl.stencilOpSeparate as ReturnType<typeof vi.fn>).mockImplementation(
|
|
415
|
+
(face: number, fail: number, dFail: number, dPass: number) => writeStencilOp(face, fail, dFail, dPass),
|
|
416
|
+
);
|
|
274
417
|
(gl.blendFuncSeparate as ReturnType<typeof vi.fn>).mockImplementation(
|
|
275
418
|
(srcRgb: number, dstRgb: number, srcAlpha: number, dstAlpha: number) => {
|
|
276
419
|
parameters.set(gl.BLEND_SRC_RGB, srcRgb);
|
|
@@ -315,6 +458,14 @@ function expectTestGlState(fixture: StatefulGl, expected: Readonly<TestGlState>)
|
|
|
315
458
|
expect(parameters.get(gl.DEPTH_FUNC)).toBe(expected.depthFunc);
|
|
316
459
|
expect(gl.isEnabled(gl.CULL_FACE)).toBe(expected.cullFace);
|
|
317
460
|
expect(parameters.get(gl.CULL_FACE_MODE)).toBe(expected.cullFaceMode);
|
|
461
|
+
// The 3D mesh path picks a front face per draw from the model determinant, so this is state Flight
|
|
462
|
+
// mutates and must hand back untouched — a host set to CW must not get CCW returned.
|
|
463
|
+
expect(parameters.get(gl.FRONT_FACE)).toBe(expected.frontFace);
|
|
464
|
+
// Flight's 2D clip system rasterizes stencil masks; its internal restore is scoped to Flight's own
|
|
465
|
+
// nesting and disables the test outright when Flight had no clip, so the host-facing preservation
|
|
466
|
+
// has to happen here. The outer fixture starts ENABLED so 'restored' is distinguishable from 'left off'.
|
|
467
|
+
expect(gl.isEnabled(gl.STENCIL_TEST)).toBe(expected.stencilTest);
|
|
468
|
+
expect(parameters.get(gl.STENCIL_WRITEMASK)).toBe(expected.stencilWriteMask);
|
|
318
469
|
expect(gl.isEnabled(gl.BLEND)).toBe(expected.blend);
|
|
319
470
|
expect(parameters.get(gl.BLEND_SRC_RGB)).toBe(expected.blendSrcRgb);
|
|
320
471
|
expect(parameters.get(gl.BLEND_DST_RGB)).toBe(expected.blendDstRgb);
|
|
@@ -347,3 +498,22 @@ function setCapability(gl: WebGL2RenderingContext, capability: number, enabled:
|
|
|
347
498
|
gl.disable(capability);
|
|
348
499
|
}
|
|
349
500
|
}
|
|
501
|
+
|
|
502
|
+
// Both faces of every stencil parameter the bracket saves. Naming them here rather than asserting a
|
|
503
|
+
// handful keeps the list checkable against the saved-state fields by eye.
|
|
504
|
+
const TWO_SIDED_STENCIL_PARAMETERS = [
|
|
505
|
+
'STENCIL_FAIL',
|
|
506
|
+
'STENCIL_BACK_FAIL',
|
|
507
|
+
'STENCIL_PASS_DEPTH_FAIL',
|
|
508
|
+
'STENCIL_BACK_PASS_DEPTH_FAIL',
|
|
509
|
+
'STENCIL_PASS_DEPTH_PASS',
|
|
510
|
+
'STENCIL_BACK_PASS_DEPTH_PASS',
|
|
511
|
+
'STENCIL_FUNC',
|
|
512
|
+
'STENCIL_BACK_FUNC',
|
|
513
|
+
'STENCIL_REF',
|
|
514
|
+
'STENCIL_BACK_REF',
|
|
515
|
+
'STENCIL_VALUE_MASK',
|
|
516
|
+
'STENCIL_BACK_VALUE_MASK',
|
|
517
|
+
'STENCIL_WRITEMASK',
|
|
518
|
+
'STENCIL_BACK_WRITEMASK',
|
|
519
|
+
] as const;
|