@flighthq/render-gl 0.5.1-next.1069.554a2ac → 0.5.1-next.1201.9b49dee
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/README.md +2 -2
- package/dist/contract.d.ts +1 -3
- package/dist/contract.d.ts.map +1 -1
- package/dist/contract.js +1 -3
- package/dist/contract.js.map +1 -1
- package/dist/enableGlRenderStateGuards.js +2 -2
- package/dist/enableGlRenderStateGuards.js.map +1 -1
- package/dist/glCubeRenderTarget.d.ts +5 -5
- package/dist/glCubeRenderTarget.d.ts.map +1 -1
- package/dist/glCubeRenderTarget.js +16 -13
- package/dist/glCubeRenderTarget.js.map +1 -1
- package/dist/glFullscreenPass.d.ts +4 -3
- package/dist/glFullscreenPass.d.ts.map +1 -1
- package/dist/glFullscreenPass.js +152 -23
- package/dist/glFullscreenPass.js.map +1 -1
- package/dist/glLinearToSrgbPass.d.ts +2 -2
- package/dist/glLinearToSrgbPass.d.ts.map +1 -1
- package/dist/glLinearToSrgbPass.js.map +1 -1
- package/dist/glPresentRenderTarget.d.ts +2 -2
- package/dist/glPresentRenderTarget.d.ts.map +1 -1
- package/dist/glPresentRenderTarget.js.map +1 -1
- package/dist/glReadback.d.ts +2 -2
- package/dist/glReadback.d.ts.map +1 -1
- package/dist/glReadback.js +1 -1
- package/dist/glReadback.js.map +1 -1
- package/dist/glRenderPass.d.ts +6 -3
- package/dist/glRenderPass.d.ts.map +1 -1
- package/dist/glRenderPass.js +105 -86
- package/dist/glRenderPass.js.map +1 -1
- package/dist/glRenderState.d.ts +1 -2
- package/dist/glRenderState.d.ts.map +1 -1
- package/dist/glRenderState.js +53 -46
- package/dist/glRenderState.js.map +1 -1
- package/dist/glRenderTarget.d.ts +17 -16
- package/dist/glRenderTarget.d.ts.map +1 -1
- package/dist/glRenderTarget.js +38 -26
- package/dist/glRenderTarget.js.map +1 -1
- package/dist/glRenderTargetPool.d.ts +9 -9
- package/dist/glRenderTargetPool.d.ts.map +1 -1
- package/dist/glRenderTargetPool.js +10 -12
- package/dist/glRenderTargetPool.js.map +1 -1
- package/dist/glRenderTexture.d.ts +2 -2
- package/dist/glRenderTexture.d.ts.map +1 -1
- package/dist/glRenderTexture.js +11 -13
- package/dist/glRenderTexture.js.map +1 -1
- package/dist/glRenderTexturePool.js +3 -5
- package/dist/glRenderTexturePool.js.map +1 -1
- package/dist/glSkinPaletteTexture.js +8 -2
- package/dist/glSkinPaletteTexture.js.map +1 -1
- package/dist/glTestHelper.d.ts +0 -1
- package/dist/glTestHelper.d.ts.map +1 -1
- package/dist/glTestHelper.js +0 -1
- package/dist/glTestHelper.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/package.json +11 -11
- package/src/enableGlRenderStateGuards.test.ts +2 -4
- package/src/glContext.test.ts +3 -52
- package/src/glCubeRenderTarget.test.ts +10 -8
- package/src/glDraw.test.ts +4 -16
- package/src/glFullscreenPass.test.ts +145 -41
- package/src/glLinearToSrgbPass.test.ts +8 -5
- package/src/glPresentRenderTarget.test.ts +3 -5
- package/src/glReadback.test.ts +3 -3
- package/src/glRenderPass.test.ts +228 -55
- package/src/glRenderState.test.ts +106 -165
- package/src/glRenderTarget.test.ts +134 -99
- package/src/glRenderTargetPool.test.ts +69 -76
- package/src/glRenderTexture.test.ts +58 -31
- package/src/glSkinPaletteTexture.test.ts +9 -0
- package/src/glTextureResolver.test.ts +5 -1
- package/dist/glBackground.d.ts +0 -3
- package/dist/glBackground.d.ts.map +0 -1
- package/dist/glBackground.js +0 -19
- package/dist/glBackground.js.map +0 -1
- package/dist/glContext.d.ts +0 -3
- package/dist/glContext.d.ts.map +0 -1
- package/dist/glContext.js +0 -16
- package/dist/glContext.js.map +0 -1
- package/src/glBackground.test.ts +0 -68
|
@@ -6,18 +6,19 @@ import { EntityRuntimeKey } from '@flighthq/types/contract';
|
|
|
6
6
|
import { beginGlRenderPass, endGlRenderPass } from './glRenderPass';
|
|
7
7
|
import { getGlRenderStateRuntime } from './glRenderState';
|
|
8
8
|
import {
|
|
9
|
-
|
|
9
|
+
createGlScreenRenderTarget,
|
|
10
|
+
createGlTextureRenderTarget,
|
|
10
11
|
declareGlRenderTargetColorSpace,
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
12
|
+
destroyGlTextureRenderTarget,
|
|
13
|
+
drawGlTextureRenderTargetResult,
|
|
14
|
+
explainGlTextureRenderTarget,
|
|
15
|
+
initializeGlTextureRenderTarget,
|
|
15
16
|
isGlRenderTargetFormatSupported,
|
|
16
|
-
|
|
17
|
-
|
|
17
|
+
resizeGlTextureRenderTarget,
|
|
18
|
+
resolveGlTextureRenderTarget,
|
|
18
19
|
resolveGlRenderTargetAxes,
|
|
19
20
|
} from './glRenderTarget';
|
|
20
|
-
import { createGlState } from './glTestHelper';
|
|
21
|
+
import { createGlState, makeGL } from './glTestHelper';
|
|
21
22
|
|
|
22
23
|
function makeState() {
|
|
23
24
|
const { state: _state, gl: _gl } = createGlState();
|
|
@@ -44,38 +45,66 @@ function makeState() {
|
|
|
44
45
|
return { state, gl };
|
|
45
46
|
}
|
|
46
47
|
|
|
47
|
-
describe('
|
|
48
|
+
describe('createGlScreenRenderTarget', () => {
|
|
49
|
+
it('returns a target with framebuffer null', () => {
|
|
50
|
+
const gl = makeGL(320, 240);
|
|
51
|
+
const target = createGlScreenRenderTarget(gl);
|
|
52
|
+
expect(target.framebuffer).toBeNull();
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
it('reads dimensions from drawingBufferWidth and drawingBufferHeight', () => {
|
|
56
|
+
const gl = makeGL(320, 240);
|
|
57
|
+
const target = createGlScreenRenderTarget(gl);
|
|
58
|
+
expect(target.width).toBe(320);
|
|
59
|
+
expect(target.height).toBe(240);
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
it('returns an Entity-backed target', () => {
|
|
63
|
+
const gl = makeGL();
|
|
64
|
+
const target = createGlScreenRenderTarget(gl);
|
|
65
|
+
expect(Object.hasOwn(target, EntityRuntimeKey)).toBe(true);
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
it('sets colorAttachments to 1 and colorSpace to srgb', () => {
|
|
69
|
+
const gl = makeGL();
|
|
70
|
+
const target = createGlScreenRenderTarget(gl);
|
|
71
|
+
expect(target.colorAttachments).toBe(1);
|
|
72
|
+
expect(target.colorSpace).toBe('srgb');
|
|
73
|
+
});
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
describe('createGlTextureRenderTarget', () => {
|
|
48
77
|
it('returns a render target with the requested dimensions', () => {
|
|
49
78
|
const { state } = makeState();
|
|
50
|
-
const target =
|
|
79
|
+
const target = createGlTextureRenderTarget(state, { width: 128, height: 64 });
|
|
51
80
|
expect(target.width).toBe(128);
|
|
52
81
|
expect(target.height).toBe(64);
|
|
53
82
|
});
|
|
54
83
|
|
|
55
84
|
it('returns an Entity-backed render target', () => {
|
|
56
85
|
const { state } = makeState();
|
|
57
|
-
const target =
|
|
86
|
+
const target = createGlTextureRenderTarget(state, { width: 128, height: 64 });
|
|
58
87
|
expect(Object.hasOwn(target, EntityRuntimeKey)).toBe(true);
|
|
59
88
|
expect(target[EntityRuntimeKey]).toBeUndefined();
|
|
60
89
|
});
|
|
61
90
|
|
|
62
91
|
it('enforces a minimum size of 1', () => {
|
|
63
92
|
const { state } = makeState();
|
|
64
|
-
const target =
|
|
93
|
+
const target = createGlTextureRenderTarget(state, { width: 0, height: 0 });
|
|
65
94
|
expect(target.width).toBe(1);
|
|
66
95
|
expect(target.height).toBe(1);
|
|
67
96
|
});
|
|
68
97
|
|
|
69
98
|
it('ceils fractional dimensions', () => {
|
|
70
99
|
const { state } = makeState();
|
|
71
|
-
const target =
|
|
100
|
+
const target = createGlTextureRenderTarget(state, { width: 10.3, height: 20.9 });
|
|
72
101
|
expect(target.width).toBe(11);
|
|
73
102
|
expect(target.height).toBe(21);
|
|
74
103
|
});
|
|
75
104
|
|
|
76
105
|
it('calls createFramebuffer and createTexture', () => {
|
|
77
106
|
const { state, gl } = makeState();
|
|
78
|
-
|
|
107
|
+
createGlTextureRenderTarget(state, { width: 64, height: 64 });
|
|
79
108
|
expect(vi.mocked(gl.createFramebuffer)).toHaveBeenCalled();
|
|
80
109
|
expect(vi.mocked(gl.createTexture)).toHaveBeenCalled();
|
|
81
110
|
});
|
|
@@ -84,26 +113,26 @@ describe('createGlRenderTarget', () => {
|
|
|
84
113
|
const { state } = makeState();
|
|
85
114
|
const runtime = getGlRenderStateRuntime(state);
|
|
86
115
|
runtime.context.currentTextureRealization = { straightAlpha: false, texture: {} as WebGLTexture };
|
|
87
|
-
|
|
116
|
+
createGlTextureRenderTarget(state, { width: 32, height: 32 });
|
|
88
117
|
expect(runtime.context.currentTextureRealization).toBeNull();
|
|
89
118
|
});
|
|
90
119
|
|
|
91
120
|
it("defaults colorSpace to 'srgb' when the descriptor omits it", () => {
|
|
92
121
|
const { state } = makeState();
|
|
93
|
-
const target =
|
|
122
|
+
const target = createGlTextureRenderTarget(state, { width: 32, height: 32 });
|
|
94
123
|
expect(target.colorSpace).toBe('srgb');
|
|
95
124
|
});
|
|
96
125
|
|
|
97
126
|
it('honors an explicit colorSpace', () => {
|
|
98
127
|
const { state } = makeState();
|
|
99
|
-
const target =
|
|
128
|
+
const target = createGlTextureRenderTarget(state, { width: 32, height: 32, colorSpace: 'linear' });
|
|
100
129
|
expect(target.colorSpace).toBe('linear');
|
|
101
130
|
});
|
|
102
131
|
|
|
103
132
|
it('retains canonical requested axes separately from effective storage', () => {
|
|
104
133
|
const { state, gl } = makeState();
|
|
105
134
|
vi.mocked(gl.getParameter).mockImplementation((parameter) => (parameter === gl.MAX_SAMPLES ? 4 : null));
|
|
106
|
-
const target =
|
|
135
|
+
const target = createGlTextureRenderTarget(state, {
|
|
107
136
|
width: 32,
|
|
108
137
|
height: 16,
|
|
109
138
|
colorAttachments: 2,
|
|
@@ -134,7 +163,7 @@ describe('createGlRenderTarget', () => {
|
|
|
134
163
|
(gl as unknown as { getExtension: (n: string) => unknown }).getExtension = (name: string) =>
|
|
135
164
|
name === 'EXT_color_buffer_float' ? null : {};
|
|
136
165
|
for (const format of ['rgba16f', 'rgba32f'] as const) {
|
|
137
|
-
const target =
|
|
166
|
+
const target = createGlTextureRenderTarget(state, { width: 32, height: 32, format }, 'preferred');
|
|
138
167
|
expect(target.format).toBe('rgba8');
|
|
139
168
|
expect(target.colorFormats).toEqual(['rgba8']);
|
|
140
169
|
}
|
|
@@ -143,7 +172,7 @@ describe('createGlRenderTarget', () => {
|
|
|
143
172
|
it('keeps a float format when EXT_color_buffer_float is available', () => {
|
|
144
173
|
const { state, gl } = makeState();
|
|
145
174
|
(gl as unknown as { getExtension: (n: string) => unknown }).getExtension = () => ({});
|
|
146
|
-
const target =
|
|
175
|
+
const target = createGlTextureRenderTarget(state, { width: 32, height: 32, format: 'rgba16f' });
|
|
147
176
|
expect(target.format).toBe('rgba16f');
|
|
148
177
|
});
|
|
149
178
|
|
|
@@ -153,7 +182,7 @@ describe('createGlRenderTarget', () => {
|
|
|
153
182
|
name === 'EXT_color_buffer_float' ? null : {};
|
|
154
183
|
vi.clearAllMocks();
|
|
155
184
|
|
|
156
|
-
const target =
|
|
185
|
+
const target = createGlTextureRenderTarget(state, { width: 32, height: 32, format: 'rgba32f' }, 'required');
|
|
157
186
|
|
|
158
187
|
expect(target).toBeNull();
|
|
159
188
|
expect(gl.createFramebuffer).not.toHaveBeenCalled();
|
|
@@ -165,7 +194,7 @@ describe('createGlRenderTarget', () => {
|
|
|
165
194
|
(gl as unknown as { getExtension: (n: string) => unknown }).getExtension = (name: string) =>
|
|
166
195
|
name === 'EXT_color_buffer_float' ? null : {};
|
|
167
196
|
|
|
168
|
-
const target =
|
|
197
|
+
const target = createGlTextureRenderTarget(
|
|
169
198
|
state,
|
|
170
199
|
{
|
|
171
200
|
width: 32,
|
|
@@ -183,13 +212,13 @@ describe('createGlRenderTarget', () => {
|
|
|
183
212
|
describe('declareGlRenderTargetColorSpace', () => {
|
|
184
213
|
it('stamps the currently bound target and returns true', () => {
|
|
185
214
|
const { state } = makeState();
|
|
186
|
-
const target =
|
|
215
|
+
const target = createGlTextureRenderTarget(state, { width: 64, height: 48 });
|
|
187
216
|
expect(target.colorSpace).toBe('srgb');
|
|
188
|
-
beginGlRenderPass(state, target);
|
|
217
|
+
const pass = beginGlRenderPass(state, target);
|
|
189
218
|
expect(declareGlRenderTargetColorSpace(state, 'linear')).toBe(true);
|
|
190
219
|
expect(target.colorSpace).toBe('linear');
|
|
191
220
|
expect(target.requestedAxes.colorSpace).toBe('linear');
|
|
192
|
-
endGlRenderPass(
|
|
221
|
+
endGlRenderPass(pass);
|
|
193
222
|
});
|
|
194
223
|
|
|
195
224
|
it('returns false when no target is bound (rendering to the canvas)', () => {
|
|
@@ -199,62 +228,68 @@ describe('declareGlRenderTargetColorSpace', () => {
|
|
|
199
228
|
|
|
200
229
|
it('is restored to the outer target when a nested target ends', () => {
|
|
201
230
|
const { state } = makeState();
|
|
202
|
-
const outer =
|
|
203
|
-
const inner =
|
|
204
|
-
beginGlRenderPass(state, outer);
|
|
205
|
-
beginGlRenderPass(state, inner);
|
|
231
|
+
const outer = createGlTextureRenderTarget(state, { width: 64, height: 48 });
|
|
232
|
+
const inner = createGlTextureRenderTarget(state, { width: 32, height: 32 });
|
|
233
|
+
const outerPass = beginGlRenderPass(state, outer);
|
|
234
|
+
const innerPass = beginGlRenderPass(state, inner);
|
|
206
235
|
declareGlRenderTargetColorSpace(state, 'linear');
|
|
207
236
|
expect(inner.colorSpace).toBe('linear');
|
|
208
|
-
endGlRenderPass(
|
|
237
|
+
endGlRenderPass(innerPass);
|
|
209
238
|
// Back on `outer`: a declare now stamps it, not the popped inner target.
|
|
210
239
|
declareGlRenderTargetColorSpace(state, 'linear');
|
|
211
240
|
expect(outer.colorSpace).toBe('linear');
|
|
212
|
-
endGlRenderPass(
|
|
241
|
+
endGlRenderPass(outerPass);
|
|
213
242
|
});
|
|
214
243
|
});
|
|
215
244
|
|
|
216
|
-
describe('
|
|
245
|
+
describe('destroyGlTextureRenderTarget', () => {
|
|
217
246
|
it('deletes the framebuffer and texture', () => {
|
|
218
247
|
const { state, gl } = makeState();
|
|
219
|
-
const target =
|
|
248
|
+
const target = createGlTextureRenderTarget(state, { width: 32, height: 32 });
|
|
220
249
|
const { framebuffer, texture } = target;
|
|
221
250
|
|
|
222
|
-
|
|
251
|
+
destroyGlTextureRenderTarget(target);
|
|
223
252
|
|
|
224
253
|
expect(vi.mocked(gl.deleteFramebuffer)).toHaveBeenCalledWith(framebuffer);
|
|
225
254
|
expect(vi.mocked(gl.deleteTexture)).toHaveBeenCalledWith(texture);
|
|
226
255
|
});
|
|
227
256
|
});
|
|
228
257
|
|
|
229
|
-
describe('
|
|
258
|
+
describe('drawGlTextureRenderTargetResult', () => {
|
|
230
259
|
it('is a no-op when target dimensions are zero', () => {
|
|
231
260
|
const { state, gl } = makeState();
|
|
261
|
+
const screenTarget = createGlScreenRenderTarget(gl);
|
|
262
|
+
const pass = beginGlRenderPass(state, screenTarget);
|
|
232
263
|
const node = getOrCreateRenderProxy2D(state, createDisplayObject());
|
|
233
|
-
const target =
|
|
264
|
+
const target = createGlTextureRenderTarget(state, { width: 1, height: 1 });
|
|
234
265
|
target.width = 0;
|
|
235
266
|
vi.clearAllMocks();
|
|
236
267
|
|
|
237
|
-
|
|
268
|
+
drawGlTextureRenderTargetResult(pass, node, target, createMatrix());
|
|
238
269
|
|
|
239
270
|
expect(vi.mocked(gl.bindTexture)).not.toHaveBeenCalled();
|
|
240
271
|
});
|
|
241
272
|
|
|
242
273
|
it('composites a valid target without throwing', () => {
|
|
243
|
-
const { state } = makeState();
|
|
274
|
+
const { state, gl } = makeState();
|
|
275
|
+
const screenTarget = createGlScreenRenderTarget(gl);
|
|
276
|
+
const pass = beginGlRenderPass(state, screenTarget);
|
|
244
277
|
const node = getOrCreateRenderProxy2D(state, createDisplayObject());
|
|
245
278
|
node.alpha = 1;
|
|
246
|
-
const target =
|
|
279
|
+
const target = createGlTextureRenderTarget(state, { width: 64, height: 48 });
|
|
247
280
|
|
|
248
|
-
expect(() =>
|
|
281
|
+
expect(() => drawGlTextureRenderTargetResult(pass, node, target, createMatrix())).not.toThrow();
|
|
249
282
|
});
|
|
250
283
|
|
|
251
284
|
it('binds the target texture', () => {
|
|
252
285
|
const { state, gl } = makeState();
|
|
286
|
+
const screenTarget = createGlScreenRenderTarget(gl);
|
|
287
|
+
const pass = beginGlRenderPass(state, screenTarget);
|
|
253
288
|
const node = getOrCreateRenderProxy2D(state, createDisplayObject());
|
|
254
|
-
const target =
|
|
289
|
+
const target = createGlTextureRenderTarget(state, { width: 64, height: 48 });
|
|
255
290
|
vi.clearAllMocks();
|
|
256
291
|
|
|
257
|
-
|
|
292
|
+
drawGlTextureRenderTargetResult(pass, node, target, createMatrix());
|
|
258
293
|
|
|
259
294
|
expect(vi.mocked(gl.bindTexture)).toHaveBeenCalledWith(
|
|
260
295
|
(gl as unknown as { TEXTURE_2D: number }).TEXTURE_2D,
|
|
@@ -263,13 +298,13 @@ describe('drawGlRenderTargetResult', () => {
|
|
|
263
298
|
});
|
|
264
299
|
});
|
|
265
300
|
|
|
266
|
-
describe('
|
|
301
|
+
describe('explainGlTextureRenderTarget', () => {
|
|
267
302
|
it('reports every GL capability substitution without losing the request', () => {
|
|
268
303
|
const { state, gl } = makeState();
|
|
269
304
|
vi.mocked(gl.getParameter).mockImplementation((parameter) => (parameter === gl.MAX_SAMPLES ? 4 : null));
|
|
270
305
|
(gl as unknown as { getExtension: (name: string) => unknown }).getExtension = (name: string) =>
|
|
271
306
|
name === 'EXT_color_buffer_float' ? null : {};
|
|
272
|
-
const target =
|
|
307
|
+
const target = createGlTextureRenderTarget(state, {
|
|
273
308
|
width: 32,
|
|
274
309
|
height: 16,
|
|
275
310
|
format: 'rgba16f',
|
|
@@ -277,7 +312,7 @@ describe('explainGlRenderTarget', () => {
|
|
|
277
312
|
depth: 'depth-stencil-sampled',
|
|
278
313
|
});
|
|
279
314
|
|
|
280
|
-
expect(
|
|
315
|
+
expect(explainGlTextureRenderTarget(target).differences).toEqual([
|
|
281
316
|
{ axis: 'format', effective: 'rgba8', requested: 'rgba16f' },
|
|
282
317
|
{ axis: 'colorFormats', effective: ['rgba8'], requested: ['rgba16f'] },
|
|
283
318
|
{ axis: 'sampleCount', effective: 4, requested: 8 },
|
|
@@ -287,14 +322,14 @@ describe('explainGlRenderTarget', () => {
|
|
|
287
322
|
|
|
288
323
|
it('reports no differences when GL realizes every requested axis', () => {
|
|
289
324
|
const { state } = makeState();
|
|
290
|
-
const target =
|
|
291
|
-
expect(
|
|
325
|
+
const target = createGlTextureRenderTarget(state, { width: 32, height: 16 });
|
|
326
|
+
expect(explainGlTextureRenderTarget(target).differences).toEqual([]);
|
|
292
327
|
});
|
|
293
328
|
});
|
|
294
329
|
|
|
295
|
-
describe('
|
|
296
|
-
it('is the construction initializer of
|
|
297
|
-
expect(typeof
|
|
330
|
+
describe('initializeGlTextureRenderTarget', () => {
|
|
331
|
+
it('is the construction initializer of createGlTextureRenderTarget', () => {
|
|
332
|
+
expect(typeof initializeGlTextureRenderTarget).toBe('function');
|
|
298
333
|
});
|
|
299
334
|
});
|
|
300
335
|
|
|
@@ -320,12 +355,12 @@ describe('isGlRenderTargetFormatSupported', () => {
|
|
|
320
355
|
});
|
|
321
356
|
});
|
|
322
357
|
|
|
323
|
-
describe('
|
|
358
|
+
describe('resizeGlTextureRenderTarget', () => {
|
|
324
359
|
it('updates the target dimensions', () => {
|
|
325
360
|
const { state } = makeState();
|
|
326
|
-
const target =
|
|
361
|
+
const target = createGlTextureRenderTarget(state, { width: 64, height: 64 });
|
|
327
362
|
|
|
328
|
-
|
|
363
|
+
resizeGlTextureRenderTarget(state, target, 256, 128);
|
|
329
364
|
|
|
330
365
|
expect(target.width).toBe(256);
|
|
331
366
|
expect(target.height).toBe(128);
|
|
@@ -333,9 +368,9 @@ describe('resizeGlRenderTarget', () => {
|
|
|
333
368
|
|
|
334
369
|
it('enforces a minimum size of 1', () => {
|
|
335
370
|
const { state } = makeState();
|
|
336
|
-
const target =
|
|
371
|
+
const target = createGlTextureRenderTarget(state, { width: 64, height: 64 });
|
|
337
372
|
|
|
338
|
-
|
|
373
|
+
resizeGlTextureRenderTarget(state, target, 0, 0);
|
|
339
374
|
|
|
340
375
|
expect(target.width).toBe(1);
|
|
341
376
|
expect(target.height).toBe(1);
|
|
@@ -343,10 +378,10 @@ describe('resizeGlRenderTarget', () => {
|
|
|
343
378
|
|
|
344
379
|
it('reallocates the texture storage', () => {
|
|
345
380
|
const { state, gl } = makeState();
|
|
346
|
-
const target =
|
|
381
|
+
const target = createGlTextureRenderTarget(state, { width: 64, height: 64 });
|
|
347
382
|
vi.clearAllMocks();
|
|
348
383
|
|
|
349
|
-
|
|
384
|
+
resizeGlTextureRenderTarget(state, target, 128, 128);
|
|
350
385
|
|
|
351
386
|
expect(vi.mocked(gl.bindTexture)).toHaveBeenCalledWith(
|
|
352
387
|
(gl as unknown as { TEXTURE_2D: number }).TEXTURE_2D,
|
|
@@ -357,12 +392,12 @@ describe('resizeGlRenderTarget', () => {
|
|
|
357
392
|
|
|
358
393
|
it('restores the tracked framebuffer after reallocating storage', () => {
|
|
359
394
|
const { state, gl } = makeState();
|
|
360
|
-
const target =
|
|
395
|
+
const target = createGlTextureRenderTarget(state, { width: 64, height: 64 });
|
|
361
396
|
const previous = { name: 'previous-framebuffer' } as unknown as WebGLFramebuffer;
|
|
362
397
|
getGlRenderStateRuntime(state).currentFramebuffer = previous;
|
|
363
398
|
vi.clearAllMocks();
|
|
364
399
|
|
|
365
|
-
|
|
400
|
+
resizeGlTextureRenderTarget(state, target, 128, 96);
|
|
366
401
|
|
|
367
402
|
expect(vi.mocked(gl.bindFramebuffer)).toHaveBeenLastCalledWith(gl.FRAMEBUFFER, previous);
|
|
368
403
|
expect(getGlRenderStateRuntime(state).currentFramebuffer).toBe(previous);
|
|
@@ -371,7 +406,7 @@ describe('resizeGlRenderTarget', () => {
|
|
|
371
406
|
it('preserves heterogeneous color formats and sampled depth across resize', () => {
|
|
372
407
|
const { state, gl } = makeState();
|
|
373
408
|
(gl as unknown as { getExtension: (name: string) => unknown }).getExtension = () => ({});
|
|
374
|
-
const target =
|
|
409
|
+
const target = createGlTextureRenderTarget(state, {
|
|
375
410
|
width: 64,
|
|
376
411
|
height: 64,
|
|
377
412
|
colorAttachments: 2,
|
|
@@ -380,7 +415,7 @@ describe('resizeGlRenderTarget', () => {
|
|
|
380
415
|
});
|
|
381
416
|
vi.clearAllMocks();
|
|
382
417
|
|
|
383
|
-
|
|
418
|
+
resizeGlTextureRenderTarget(state, target, 128, 96);
|
|
384
419
|
|
|
385
420
|
expect(target.colorAttachments).toBe(2);
|
|
386
421
|
expect(target.colorFormats).toEqual(['rgba8', 'rgba32f']);
|
|
@@ -394,34 +429,61 @@ describe('resizeGlRenderTarget', () => {
|
|
|
394
429
|
});
|
|
395
430
|
});
|
|
396
431
|
|
|
397
|
-
describe('
|
|
432
|
+
describe('resolveGlRenderTargetAxes', () => {
|
|
433
|
+
it('queries effective axes without allocating target storage', () => {
|
|
434
|
+
const { state, gl } = makeState();
|
|
435
|
+
vi.mocked(gl.getParameter).mockImplementation((parameter) => (parameter === gl.MAX_SAMPLES ? 2 : null));
|
|
436
|
+
vi.clearAllMocks();
|
|
437
|
+
|
|
438
|
+
const axes = resolveGlRenderTargetAxes(state, { width: 32, height: 16, sampleCount: 4 });
|
|
439
|
+
|
|
440
|
+
expect(axes.sampleCount).toBe(2);
|
|
441
|
+
expect(gl.createFramebuffer).not.toHaveBeenCalled();
|
|
442
|
+
expect(gl.createTexture).not.toHaveBeenCalled();
|
|
443
|
+
});
|
|
444
|
+
|
|
445
|
+
it('applies preferred fallback and required refusal without allocating storage', () => {
|
|
446
|
+
const { state, gl } = makeState();
|
|
447
|
+
(gl as unknown as { getExtension: (name: string) => unknown }).getExtension = () => null;
|
|
448
|
+
vi.clearAllMocks();
|
|
449
|
+
|
|
450
|
+
expect(resolveGlRenderTargetAxes(state, { width: 32, height: 16, format: 'rgba32f' }, 'preferred')).toMatchObject({
|
|
451
|
+
format: 'rgba8',
|
|
452
|
+
colorFormats: ['rgba8'],
|
|
453
|
+
});
|
|
454
|
+
expect(resolveGlRenderTargetAxes(state, { width: 32, height: 16, format: 'rgba32f' }, 'required')).toBeNull();
|
|
455
|
+
expect(gl.createFramebuffer).not.toHaveBeenCalled();
|
|
456
|
+
expect(gl.createTexture).not.toHaveBeenCalled();
|
|
457
|
+
});
|
|
458
|
+
});
|
|
459
|
+
describe('resolveGlTextureRenderTarget', () => {
|
|
398
460
|
it('is a no-op for a single-sample target', () => {
|
|
399
461
|
const { state, gl } = makeState();
|
|
400
|
-
const target =
|
|
462
|
+
const target = createGlTextureRenderTarget(state, { width: 64, height: 48 });
|
|
401
463
|
expect(target.sampleCount).toBe(1);
|
|
402
464
|
vi.clearAllMocks();
|
|
403
465
|
|
|
404
|
-
|
|
466
|
+
resolveGlTextureRenderTarget(state, target);
|
|
405
467
|
|
|
406
468
|
expect(vi.mocked(gl.bindFramebuffer)).not.toHaveBeenCalled();
|
|
407
469
|
});
|
|
408
470
|
|
|
409
471
|
it('is a no-op when the target has no resolve framebuffer', () => {
|
|
410
472
|
const { state, gl } = makeState();
|
|
411
|
-
const target =
|
|
473
|
+
const target = createGlTextureRenderTarget(state, { width: 64, height: 48 });
|
|
412
474
|
// Force the MSAA sample-count gate open but leave resolveFramebuffer null.
|
|
413
475
|
target.sampleCount = 4;
|
|
414
476
|
target.resolveFramebuffer = null;
|
|
415
477
|
vi.clearAllMocks();
|
|
416
478
|
|
|
417
|
-
|
|
479
|
+
resolveGlTextureRenderTarget(state, target);
|
|
418
480
|
|
|
419
481
|
expect(vi.mocked(gl.bindFramebuffer)).not.toHaveBeenCalled();
|
|
420
482
|
});
|
|
421
483
|
|
|
422
484
|
it('blits each color attachment and flushes for an MSAA target', () => {
|
|
423
485
|
const { state, gl } = makeState();
|
|
424
|
-
const target =
|
|
486
|
+
const target = createGlTextureRenderTarget(state, { width: 64, height: 48 });
|
|
425
487
|
target.sampleCount = 4;
|
|
426
488
|
target.resolveFramebuffer = {} as WebGLFramebuffer;
|
|
427
489
|
// Two color attachments resolve as two separate blits.
|
|
@@ -443,7 +505,7 @@ describe('resolveGlRenderTarget', () => {
|
|
|
443
505
|
flush,
|
|
444
506
|
});
|
|
445
507
|
|
|
446
|
-
|
|
508
|
+
resolveGlTextureRenderTarget(state, target);
|
|
447
509
|
|
|
448
510
|
expect(blit).toHaveBeenCalledTimes(2);
|
|
449
511
|
expect(readBuffer).toHaveBeenCalledTimes(2);
|
|
@@ -452,7 +514,7 @@ describe('resolveGlRenderTarget', () => {
|
|
|
452
514
|
|
|
453
515
|
it('disables an active scissor for the storage-wide resolve and restores it afterward', () => {
|
|
454
516
|
const { state, gl } = makeState();
|
|
455
|
-
const target =
|
|
517
|
+
const target = createGlTextureRenderTarget(state, { width: 64, height: 48 });
|
|
456
518
|
target.sampleCount = 4;
|
|
457
519
|
target.resolveFramebuffer = {} as WebGLFramebuffer;
|
|
458
520
|
const runtime = getGlRenderStateRuntime(state);
|
|
@@ -470,7 +532,7 @@ describe('resolveGlRenderTarget', () => {
|
|
|
470
532
|
flush: vi.fn(),
|
|
471
533
|
});
|
|
472
534
|
|
|
473
|
-
|
|
535
|
+
resolveGlTextureRenderTarget(state, target);
|
|
474
536
|
|
|
475
537
|
expect(gl.disable).toHaveBeenCalledWith(gl.SCISSOR_TEST);
|
|
476
538
|
expect(vi.mocked(gl.disable).mock.invocationCallOrder.at(-1)).toBeLessThan(blit.mock.invocationCallOrder[0]);
|
|
@@ -480,7 +542,7 @@ describe('resolveGlRenderTarget', () => {
|
|
|
480
542
|
|
|
481
543
|
it('restores framebuffer and scissor state when an MSAA blit throws', () => {
|
|
482
544
|
const { state, gl } = makeState();
|
|
483
|
-
const target =
|
|
545
|
+
const target = createGlTextureRenderTarget(state, { width: 64, height: 48 });
|
|
484
546
|
target.sampleCount = 4;
|
|
485
547
|
target.resolveFramebuffer = { id: 'resolve' } as unknown as WebGLFramebuffer;
|
|
486
548
|
const runtime = getGlRenderStateRuntime(state);
|
|
@@ -501,37 +563,10 @@ describe('resolveGlRenderTarget', () => {
|
|
|
501
563
|
flush: vi.fn(),
|
|
502
564
|
});
|
|
503
565
|
|
|
504
|
-
expect(() =>
|
|
566
|
+
expect(() => resolveGlTextureRenderTarget(state, target)).toThrow('blit failed');
|
|
505
567
|
expect(gl.bindFramebuffer).toHaveBeenCalledWith(gl.READ_FRAMEBUFFER, enclosingFramebuffer);
|
|
506
568
|
expect(gl.bindFramebuffer).toHaveBeenLastCalledWith(gl.DRAW_FRAMEBUFFER, enclosingFramebuffer);
|
|
507
569
|
expect(gl.enable).toHaveBeenLastCalledWith(gl.SCISSOR_TEST);
|
|
508
570
|
expect(gl.scissor).toHaveBeenLastCalledWith(3, 4, 16, 12);
|
|
509
571
|
});
|
|
510
572
|
});
|
|
511
|
-
describe('resolveGlRenderTargetAxes', () => {
|
|
512
|
-
it('queries effective axes without allocating target storage', () => {
|
|
513
|
-
const { state, gl } = makeState();
|
|
514
|
-
vi.mocked(gl.getParameter).mockImplementation((parameter) => (parameter === gl.MAX_SAMPLES ? 2 : null));
|
|
515
|
-
vi.clearAllMocks();
|
|
516
|
-
|
|
517
|
-
const axes = resolveGlRenderTargetAxes(state, { width: 32, height: 16, sampleCount: 4 });
|
|
518
|
-
|
|
519
|
-
expect(axes.sampleCount).toBe(2);
|
|
520
|
-
expect(gl.createFramebuffer).not.toHaveBeenCalled();
|
|
521
|
-
expect(gl.createTexture).not.toHaveBeenCalled();
|
|
522
|
-
});
|
|
523
|
-
|
|
524
|
-
it('applies preferred fallback and required refusal without allocating storage', () => {
|
|
525
|
-
const { state, gl } = makeState();
|
|
526
|
-
(gl as unknown as { getExtension: (name: string) => unknown }).getExtension = () => null;
|
|
527
|
-
vi.clearAllMocks();
|
|
528
|
-
|
|
529
|
-
expect(resolveGlRenderTargetAxes(state, { width: 32, height: 16, format: 'rgba32f' }, 'preferred')).toMatchObject({
|
|
530
|
-
format: 'rgba8',
|
|
531
|
-
colorFormats: ['rgba8'],
|
|
532
|
-
});
|
|
533
|
-
expect(resolveGlRenderTargetAxes(state, { width: 32, height: 16, format: 'rgba32f' }, 'required')).toBeNull();
|
|
534
|
-
expect(gl.createFramebuffer).not.toHaveBeenCalled();
|
|
535
|
-
expect(gl.createTexture).not.toHaveBeenCalled();
|
|
536
|
-
});
|
|
537
|
-
});
|