stats-gl 3.7.0 → 4.0.0
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 +360 -84
- package/addons/StatsGLNode.js +201 -0
- package/addons/StatsGLNodeWorker.js +198 -0
- package/dist/core.cjs +421 -0
- package/dist/core.cjs.map +1 -0
- package/dist/core.js +421 -0
- package/dist/core.js.map +1 -0
- package/dist/main.cjs +417 -244
- package/dist/main.cjs.map +1 -1
- package/dist/main.js +415 -243
- package/dist/main.js.map +1 -1
- package/dist/panel.cjs +12 -3
- package/dist/panel.cjs.map +1 -1
- package/dist/panel.js +12 -3
- package/dist/panel.js.map +1 -1
- package/dist/panelTexture.cjs +93 -0
- package/dist/panelTexture.cjs.map +1 -0
- package/dist/panelTexture.js +93 -0
- package/dist/panelTexture.js.map +1 -0
- package/dist/profiler.cjs +95 -0
- package/dist/profiler.cjs.map +1 -0
- package/dist/profiler.js +95 -0
- package/dist/profiler.js.map +1 -0
- package/dist/stats-gl.d.ts +335 -72
- package/dist/statsGLNode.cjs +89 -0
- package/dist/statsGLNode.cjs.map +1 -0
- package/dist/statsGLNode.js +89 -0
- package/dist/statsGLNode.js.map +1 -0
- package/dist/textureCapture.cjs +283 -0
- package/dist/textureCapture.cjs.map +1 -0
- package/dist/textureCapture.js +283 -0
- package/dist/textureCapture.js.map +1 -0
- package/lib/core.ts +579 -0
- package/lib/main.ts +514 -403
- package/lib/panel.ts +18 -4
- package/lib/panelTexture.ts +122 -0
- package/lib/profiler.ts +124 -0
- package/lib/statsGLNode.ts +124 -0
- package/lib/textureCapture.ts +403 -0
- package/lib/webgpu.d.ts +190 -0
- package/package.json +6 -4
|
@@ -0,0 +1,403 @@
|
|
|
1
|
+
// Texture capture utilities for WebGPU and WebGL2
|
|
2
|
+
|
|
3
|
+
export interface TextureCaptureSource {
|
|
4
|
+
// WebGL2
|
|
5
|
+
framebuffer?: WebGLFramebuffer;
|
|
6
|
+
width?: number;
|
|
7
|
+
height?: number;
|
|
8
|
+
// WebGPU
|
|
9
|
+
gpuTexture?: GPUTexture;
|
|
10
|
+
// Three.js WebGLRenderTarget
|
|
11
|
+
isWebGLRenderTarget?: boolean;
|
|
12
|
+
// Three.js RenderTarget (WebGPU)
|
|
13
|
+
isRenderTarget?: boolean;
|
|
14
|
+
texture?: any;
|
|
15
|
+
__webglFramebuffer?: WebGLFramebuffer;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
// Default preview dimensions (matches full PANEL size for texture panels)
|
|
19
|
+
const DEFAULT_PREVIEW_WIDTH = 90;
|
|
20
|
+
const DEFAULT_PREVIEW_HEIGHT = 48;
|
|
21
|
+
|
|
22
|
+
// =============================================================================
|
|
23
|
+
// WebGL2 Texture Capture with PBO double-buffering
|
|
24
|
+
// =============================================================================
|
|
25
|
+
|
|
26
|
+
export class TextureCaptureWebGL {
|
|
27
|
+
private gl: WebGL2RenderingContext;
|
|
28
|
+
private previewFbo: WebGLFramebuffer | null = null;
|
|
29
|
+
private previewTexture: WebGLTexture | null = null;
|
|
30
|
+
private pixels: Uint8Array;
|
|
31
|
+
private flippedPixels: Uint8Array;
|
|
32
|
+
private previewWidth: number;
|
|
33
|
+
private previewHeight: number;
|
|
34
|
+
|
|
35
|
+
constructor(gl: WebGL2RenderingContext, width = DEFAULT_PREVIEW_WIDTH, height = DEFAULT_PREVIEW_HEIGHT) {
|
|
36
|
+
this.gl = gl;
|
|
37
|
+
this.previewWidth = width;
|
|
38
|
+
this.previewHeight = height;
|
|
39
|
+
this.pixels = new Uint8Array(width * height * 4);
|
|
40
|
+
this.flippedPixels = new Uint8Array(width * height * 4);
|
|
41
|
+
this.initResources();
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Resize preview dimensions
|
|
46
|
+
*/
|
|
47
|
+
resize(width: number, height: number): void {
|
|
48
|
+
if (width === this.previewWidth && height === this.previewHeight) return;
|
|
49
|
+
|
|
50
|
+
this.previewWidth = width;
|
|
51
|
+
this.previewHeight = height;
|
|
52
|
+
this.pixels = new Uint8Array(width * height * 4);
|
|
53
|
+
this.flippedPixels = new Uint8Array(width * height * 4);
|
|
54
|
+
|
|
55
|
+
// Recreate resources with new dimensions
|
|
56
|
+
this.dispose();
|
|
57
|
+
this.initResources();
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
private initResources(): void {
|
|
61
|
+
const gl = this.gl;
|
|
62
|
+
|
|
63
|
+
// Create preview texture and FBO for downscaling
|
|
64
|
+
this.previewTexture = gl.createTexture();
|
|
65
|
+
gl.bindTexture(gl.TEXTURE_2D, this.previewTexture);
|
|
66
|
+
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA8, this.previewWidth, this.previewHeight, 0, gl.RGBA, gl.UNSIGNED_BYTE, null);
|
|
67
|
+
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
|
|
68
|
+
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
|
|
69
|
+
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
|
|
70
|
+
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
|
|
71
|
+
|
|
72
|
+
this.previewFbo = gl.createFramebuffer();
|
|
73
|
+
gl.bindFramebuffer(gl.FRAMEBUFFER, this.previewFbo);
|
|
74
|
+
gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, this.previewTexture, 0);
|
|
75
|
+
|
|
76
|
+
gl.bindFramebuffer(gl.FRAMEBUFFER, null);
|
|
77
|
+
gl.bindTexture(gl.TEXTURE_2D, null);
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
public async capture(
|
|
81
|
+
source: WebGLFramebuffer | null,
|
|
82
|
+
sourceWidth: number,
|
|
83
|
+
sourceHeight: number,
|
|
84
|
+
_sourceId: string = 'default'
|
|
85
|
+
): Promise<ImageBitmap | null> {
|
|
86
|
+
const gl = this.gl;
|
|
87
|
+
|
|
88
|
+
// Save current state
|
|
89
|
+
const prevReadFbo = gl.getParameter(gl.READ_FRAMEBUFFER_BINDING);
|
|
90
|
+
const prevDrawFbo = gl.getParameter(gl.DRAW_FRAMEBUFFER_BINDING);
|
|
91
|
+
|
|
92
|
+
// Blit source to preview FBO with LINEAR filtering (downscale)
|
|
93
|
+
gl.bindFramebuffer(gl.READ_FRAMEBUFFER, source);
|
|
94
|
+
gl.bindFramebuffer(gl.DRAW_FRAMEBUFFER, this.previewFbo);
|
|
95
|
+
gl.blitFramebuffer(
|
|
96
|
+
0, 0, sourceWidth, sourceHeight,
|
|
97
|
+
0, 0, this.previewWidth, this.previewHeight,
|
|
98
|
+
gl.COLOR_BUFFER_BIT,
|
|
99
|
+
gl.LINEAR
|
|
100
|
+
);
|
|
101
|
+
|
|
102
|
+
// Synchronous read - fine for small preview
|
|
103
|
+
gl.bindFramebuffer(gl.READ_FRAMEBUFFER, this.previewFbo);
|
|
104
|
+
gl.readPixels(0, 0, this.previewWidth, this.previewHeight, gl.RGBA, gl.UNSIGNED_BYTE, this.pixels);
|
|
105
|
+
|
|
106
|
+
// Restore state
|
|
107
|
+
gl.bindFramebuffer(gl.READ_FRAMEBUFFER, prevReadFbo);
|
|
108
|
+
gl.bindFramebuffer(gl.DRAW_FRAMEBUFFER, prevDrawFbo);
|
|
109
|
+
|
|
110
|
+
// Flip Y axis (WebGL has origin at bottom-left)
|
|
111
|
+
const flipped = this.flipY(this.pixels, this.previewWidth, this.previewHeight);
|
|
112
|
+
const imageData = new ImageData(new Uint8ClampedArray(flipped), this.previewWidth, this.previewHeight);
|
|
113
|
+
|
|
114
|
+
return createImageBitmap(imageData);
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
private flipY(pixels: Uint8Array, width: number, height: number): Uint8Array {
|
|
118
|
+
const rowSize = width * 4;
|
|
119
|
+
for (let y = 0; y < height; y++) {
|
|
120
|
+
const srcOffset = y * rowSize;
|
|
121
|
+
const dstOffset = (height - 1 - y) * rowSize;
|
|
122
|
+
this.flippedPixels.set(pixels.subarray(srcOffset, srcOffset + rowSize), dstOffset);
|
|
123
|
+
}
|
|
124
|
+
return this.flippedPixels;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
public removeSource(_sourceId: string): void {
|
|
128
|
+
// No per-source state in sync mode
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
public dispose(): void {
|
|
132
|
+
const gl = this.gl;
|
|
133
|
+
if (this.previewFbo) {
|
|
134
|
+
gl.deleteFramebuffer(this.previewFbo);
|
|
135
|
+
this.previewFbo = null;
|
|
136
|
+
}
|
|
137
|
+
if (this.previewTexture) {
|
|
138
|
+
gl.deleteTexture(this.previewTexture);
|
|
139
|
+
this.previewTexture = null;
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
// =============================================================================
|
|
145
|
+
// WebGPU Texture Capture with blit pipeline and staging buffer
|
|
146
|
+
// =============================================================================
|
|
147
|
+
|
|
148
|
+
export class TextureCaptureWebGPU {
|
|
149
|
+
private device: GPUDevice;
|
|
150
|
+
private previewTexture: GPUTexture | null = null;
|
|
151
|
+
private stagingBuffer: GPUBuffer | null = null;
|
|
152
|
+
private blitPipeline: GPURenderPipeline | null = null;
|
|
153
|
+
private sampler: GPUSampler | null = null;
|
|
154
|
+
private bindGroupLayout: GPUBindGroupLayout | null = null;
|
|
155
|
+
private initialized = false;
|
|
156
|
+
private previewWidth: number;
|
|
157
|
+
private previewHeight: number;
|
|
158
|
+
private pixelsBuffer: Uint8ClampedArray;
|
|
159
|
+
|
|
160
|
+
constructor(device: GPUDevice, width = DEFAULT_PREVIEW_WIDTH, height = DEFAULT_PREVIEW_HEIGHT) {
|
|
161
|
+
this.device = device;
|
|
162
|
+
this.previewWidth = width;
|
|
163
|
+
this.previewHeight = height;
|
|
164
|
+
this.pixelsBuffer = new Uint8ClampedArray(width * height * 4);
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
/**
|
|
168
|
+
* Resize preview dimensions
|
|
169
|
+
*/
|
|
170
|
+
resize(width: number, height: number): void {
|
|
171
|
+
if (width === this.previewWidth && height === this.previewHeight) return;
|
|
172
|
+
|
|
173
|
+
this.previewWidth = width;
|
|
174
|
+
this.previewHeight = height;
|
|
175
|
+
this.pixelsBuffer = new Uint8ClampedArray(width * height * 4);
|
|
176
|
+
|
|
177
|
+
// Dispose texture and buffer (they need new dimensions)
|
|
178
|
+
if (this.previewTexture) this.previewTexture.destroy();
|
|
179
|
+
if (this.stagingBuffer) this.stagingBuffer.destroy();
|
|
180
|
+
this.previewTexture = null;
|
|
181
|
+
this.stagingBuffer = null;
|
|
182
|
+
|
|
183
|
+
// Recreate on next capture
|
|
184
|
+
if (this.initialized) {
|
|
185
|
+
this.createSizeResources();
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
private createSizeResources(): void {
|
|
190
|
+
const device = this.device;
|
|
191
|
+
|
|
192
|
+
// Create preview texture
|
|
193
|
+
this.previewTexture = device.createTexture({
|
|
194
|
+
size: { width: this.previewWidth, height: this.previewHeight },
|
|
195
|
+
format: 'rgba8unorm',
|
|
196
|
+
usage: GPUTextureUsage.RENDER_ATTACHMENT | GPUTextureUsage.COPY_SRC
|
|
197
|
+
});
|
|
198
|
+
|
|
199
|
+
// Create staging buffer for readback
|
|
200
|
+
const bytesPerRow = Math.ceil(this.previewWidth * 4 / 256) * 256;
|
|
201
|
+
this.stagingBuffer = device.createBuffer({
|
|
202
|
+
size: bytesPerRow * this.previewHeight,
|
|
203
|
+
usage: GPUBufferUsage.COPY_DST | GPUBufferUsage.MAP_READ
|
|
204
|
+
});
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
private async initResources(): Promise<void> {
|
|
208
|
+
if (this.initialized) return;
|
|
209
|
+
|
|
210
|
+
const device = this.device;
|
|
211
|
+
|
|
212
|
+
this.createSizeResources();
|
|
213
|
+
|
|
214
|
+
// Create sampler
|
|
215
|
+
this.sampler = device.createSampler({
|
|
216
|
+
minFilter: 'linear',
|
|
217
|
+
magFilter: 'linear'
|
|
218
|
+
});
|
|
219
|
+
|
|
220
|
+
// Create blit shader
|
|
221
|
+
const shaderModule = device.createShaderModule({
|
|
222
|
+
code: `
|
|
223
|
+
@group(0) @binding(0) var texSampler: sampler;
|
|
224
|
+
@group(0) @binding(1) var texInput: texture_2d<f32>;
|
|
225
|
+
|
|
226
|
+
struct VertexOutput {
|
|
227
|
+
@builtin(position) position: vec4f,
|
|
228
|
+
@location(0) uv: vec2f
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
@vertex
|
|
232
|
+
fn vertexMain(@builtin(vertex_index) vertexIndex: u32) -> VertexOutput {
|
|
233
|
+
var positions = array<vec2f, 3>(
|
|
234
|
+
vec2f(-1.0, -1.0),
|
|
235
|
+
vec2f(3.0, -1.0),
|
|
236
|
+
vec2f(-1.0, 3.0)
|
|
237
|
+
);
|
|
238
|
+
var uvs = array<vec2f, 3>(
|
|
239
|
+
vec2f(0.0, 1.0),
|
|
240
|
+
vec2f(2.0, 1.0),
|
|
241
|
+
vec2f(0.0, -1.0)
|
|
242
|
+
);
|
|
243
|
+
|
|
244
|
+
var output: VertexOutput;
|
|
245
|
+
output.position = vec4f(positions[vertexIndex], 0.0, 1.0);
|
|
246
|
+
output.uv = uvs[vertexIndex];
|
|
247
|
+
return output;
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
@fragment
|
|
251
|
+
fn fragmentMain(@location(0) uv: vec2f) -> @location(0) vec4f {
|
|
252
|
+
return textureSample(texInput, texSampler, uv);
|
|
253
|
+
}
|
|
254
|
+
`
|
|
255
|
+
});
|
|
256
|
+
|
|
257
|
+
// Create bind group layout
|
|
258
|
+
this.bindGroupLayout = device.createBindGroupLayout({
|
|
259
|
+
entries: [
|
|
260
|
+
{ binding: 0, visibility: GPUShaderStage.FRAGMENT, sampler: { type: 'filtering' } },
|
|
261
|
+
{ binding: 1, visibility: GPUShaderStage.FRAGMENT, texture: { sampleType: 'float' } }
|
|
262
|
+
]
|
|
263
|
+
});
|
|
264
|
+
|
|
265
|
+
// Create pipeline
|
|
266
|
+
this.blitPipeline = device.createRenderPipeline({
|
|
267
|
+
layout: device.createPipelineLayout({ bindGroupLayouts: [this.bindGroupLayout] }),
|
|
268
|
+
vertex: {
|
|
269
|
+
module: shaderModule,
|
|
270
|
+
entryPoint: 'vertexMain'
|
|
271
|
+
},
|
|
272
|
+
fragment: {
|
|
273
|
+
module: shaderModule,
|
|
274
|
+
entryPoint: 'fragmentMain',
|
|
275
|
+
targets: [{ format: 'rgba8unorm' }]
|
|
276
|
+
},
|
|
277
|
+
primitive: { topology: 'triangle-list' }
|
|
278
|
+
});
|
|
279
|
+
|
|
280
|
+
this.initialized = true;
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
public async capture(source: GPUTexture): Promise<ImageBitmap | null> {
|
|
284
|
+
await this.initResources();
|
|
285
|
+
|
|
286
|
+
if (!this.previewTexture || !this.stagingBuffer || !this.blitPipeline || !this.sampler || !this.bindGroupLayout) {
|
|
287
|
+
return null;
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
const device = this.device;
|
|
291
|
+
|
|
292
|
+
// Create bind group for source texture
|
|
293
|
+
const bindGroup = device.createBindGroup({
|
|
294
|
+
layout: this.bindGroupLayout,
|
|
295
|
+
entries: [
|
|
296
|
+
{ binding: 0, resource: this.sampler },
|
|
297
|
+
{ binding: 1, resource: source.createView() }
|
|
298
|
+
]
|
|
299
|
+
});
|
|
300
|
+
|
|
301
|
+
// Blit source to preview texture
|
|
302
|
+
const commandEncoder = device.createCommandEncoder();
|
|
303
|
+
|
|
304
|
+
const renderPass = commandEncoder.beginRenderPass({
|
|
305
|
+
colorAttachments: [{
|
|
306
|
+
view: this.previewTexture.createView(),
|
|
307
|
+
loadOp: 'clear',
|
|
308
|
+
storeOp: 'store',
|
|
309
|
+
clearValue: { r: 0, g: 0, b: 0, a: 1 }
|
|
310
|
+
}]
|
|
311
|
+
});
|
|
312
|
+
|
|
313
|
+
renderPass.setPipeline(this.blitPipeline);
|
|
314
|
+
renderPass.setBindGroup(0, bindGroup);
|
|
315
|
+
renderPass.draw(3);
|
|
316
|
+
renderPass.end();
|
|
317
|
+
|
|
318
|
+
// Copy to staging buffer
|
|
319
|
+
const bytesPerRow = Math.ceil(this.previewWidth * 4 / 256) * 256;
|
|
320
|
+
commandEncoder.copyTextureToBuffer(
|
|
321
|
+
{ texture: this.previewTexture },
|
|
322
|
+
{ buffer: this.stagingBuffer, bytesPerRow },
|
|
323
|
+
{ width: this.previewWidth, height: this.previewHeight }
|
|
324
|
+
);
|
|
325
|
+
|
|
326
|
+
device.queue.submit([commandEncoder.finish()]);
|
|
327
|
+
|
|
328
|
+
// Map and read staging buffer
|
|
329
|
+
await this.stagingBuffer.mapAsync(GPUMapMode.READ);
|
|
330
|
+
const data = new Uint8Array(this.stagingBuffer.getMappedRange());
|
|
331
|
+
|
|
332
|
+
// Copy data (accounting for row alignment) into pre-allocated buffer
|
|
333
|
+
for (let y = 0; y < this.previewHeight; y++) {
|
|
334
|
+
const srcOffset = y * bytesPerRow;
|
|
335
|
+
const dstOffset = y * this.previewWidth * 4;
|
|
336
|
+
this.pixelsBuffer.set(data.subarray(srcOffset, srcOffset + this.previewWidth * 4), dstOffset);
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
this.stagingBuffer.unmap();
|
|
340
|
+
|
|
341
|
+
// ImageData needs its own Uint8ClampedArray - create from pre-allocated buffer
|
|
342
|
+
const imageData = new ImageData(new Uint8ClampedArray(this.pixelsBuffer), this.previewWidth, this.previewHeight);
|
|
343
|
+
return createImageBitmap(imageData);
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
public dispose(): void {
|
|
347
|
+
if (this.previewTexture) this.previewTexture.destroy();
|
|
348
|
+
if (this.stagingBuffer) this.stagingBuffer.destroy();
|
|
349
|
+
this.previewTexture = null;
|
|
350
|
+
this.stagingBuffer = null;
|
|
351
|
+
this.blitPipeline = null;
|
|
352
|
+
this.sampler = null;
|
|
353
|
+
this.bindGroupLayout = null;
|
|
354
|
+
this.initialized = false;
|
|
355
|
+
}
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
// =============================================================================
|
|
359
|
+
// Three.js helper to extract native handles
|
|
360
|
+
// =============================================================================
|
|
361
|
+
|
|
362
|
+
export interface ThreeTextureSource {
|
|
363
|
+
// WebGLRenderTarget
|
|
364
|
+
isWebGLRenderTarget?: boolean;
|
|
365
|
+
__webglFramebuffer?: WebGLFramebuffer;
|
|
366
|
+
width?: number;
|
|
367
|
+
height?: number;
|
|
368
|
+
// WebGPU RenderTarget
|
|
369
|
+
isRenderTarget?: boolean;
|
|
370
|
+
texture?: { isTexture?: boolean };
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
export interface ThreeRendererBackend {
|
|
374
|
+
device?: GPUDevice;
|
|
375
|
+
get?: (texture: any) => { texture?: GPUTexture };
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
export function extractWebGLSource(
|
|
379
|
+
target: ThreeTextureSource,
|
|
380
|
+
gl: WebGL2RenderingContext
|
|
381
|
+
): { framebuffer: WebGLFramebuffer; width: number; height: number } | null {
|
|
382
|
+
if (target.isWebGLRenderTarget && target.__webglFramebuffer) {
|
|
383
|
+
return {
|
|
384
|
+
framebuffer: target.__webglFramebuffer,
|
|
385
|
+
width: target.width || 1,
|
|
386
|
+
height: target.height || 1
|
|
387
|
+
};
|
|
388
|
+
}
|
|
389
|
+
return null;
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
export function extractWebGPUSource(
|
|
393
|
+
target: ThreeTextureSource,
|
|
394
|
+
backend: ThreeRendererBackend
|
|
395
|
+
): GPUTexture | null {
|
|
396
|
+
if (target.isRenderTarget && target.texture && backend.get) {
|
|
397
|
+
const textureData = backend.get(target.texture);
|
|
398
|
+
return textureData?.texture || null;
|
|
399
|
+
}
|
|
400
|
+
return null;
|
|
401
|
+
}
|
|
402
|
+
|
|
403
|
+
export { DEFAULT_PREVIEW_WIDTH, DEFAULT_PREVIEW_HEIGHT };
|
package/lib/webgpu.d.ts
ADDED
|
@@ -0,0 +1,190 @@
|
|
|
1
|
+
// WebGPU type declarations for stats-gl
|
|
2
|
+
// These are minimal declarations for the types used in texture capture and timestamp queries
|
|
3
|
+
|
|
4
|
+
interface GPUDevice {
|
|
5
|
+
createTexture(descriptor: GPUTextureDescriptor): GPUTexture;
|
|
6
|
+
createBuffer(descriptor: GPUBufferDescriptor): GPUBuffer;
|
|
7
|
+
createSampler(descriptor?: GPUSamplerDescriptor): GPUSampler;
|
|
8
|
+
createShaderModule(descriptor: GPUShaderModuleDescriptor): GPUShaderModule;
|
|
9
|
+
createBindGroupLayout(descriptor: GPUBindGroupLayoutDescriptor): GPUBindGroupLayout;
|
|
10
|
+
createPipelineLayout(descriptor: GPUPipelineLayoutDescriptor): GPUPipelineLayout;
|
|
11
|
+
createRenderPipeline(descriptor: GPURenderPipelineDescriptor): GPURenderPipeline;
|
|
12
|
+
createBindGroup(descriptor: GPUBindGroupDescriptor): GPUBindGroup;
|
|
13
|
+
createCommandEncoder(): GPUCommandEncoder;
|
|
14
|
+
createQuerySet(descriptor: GPUQuerySetDescriptor): GPUQuerySet;
|
|
15
|
+
queue: GPUQueue;
|
|
16
|
+
features: GPUSupportedFeatures;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
interface GPUSupportedFeatures {
|
|
20
|
+
has(feature: string): boolean;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
interface GPUQuerySet {
|
|
24
|
+
destroy(): void;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
interface GPUQuerySetDescriptor {
|
|
28
|
+
type: string;
|
|
29
|
+
count: number;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
interface GPUTexture {
|
|
33
|
+
createView(): GPUTextureView;
|
|
34
|
+
destroy(): void;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
interface GPUTextureView {}
|
|
38
|
+
|
|
39
|
+
interface GPUBuffer {
|
|
40
|
+
mapAsync(mode: number): Promise<void>;
|
|
41
|
+
getMappedRange(): ArrayBuffer;
|
|
42
|
+
unmap(): void;
|
|
43
|
+
destroy(): void;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
interface GPUSampler {}
|
|
47
|
+
|
|
48
|
+
interface GPUShaderModule {}
|
|
49
|
+
|
|
50
|
+
interface GPUBindGroupLayout {}
|
|
51
|
+
|
|
52
|
+
interface GPUPipelineLayout {}
|
|
53
|
+
|
|
54
|
+
interface GPURenderPipeline {}
|
|
55
|
+
|
|
56
|
+
interface GPUBindGroup {}
|
|
57
|
+
|
|
58
|
+
interface GPUQueue {
|
|
59
|
+
submit(commandBuffers: GPUCommandBuffer[]): void;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
interface GPUCommandEncoder {
|
|
63
|
+
beginRenderPass(descriptor: GPURenderPassDescriptor): GPURenderPassEncoder;
|
|
64
|
+
copyTextureToBuffer(source: GPUImageCopyTexture, destination: GPUImageCopyBuffer, copySize: GPUExtent3D): void;
|
|
65
|
+
copyBufferToBuffer(source: GPUBuffer, sourceOffset: number, destination: GPUBuffer, destinationOffset: number, size: number): void;
|
|
66
|
+
resolveQuerySet(querySet: GPUQuerySet, firstQuery: number, queryCount: number, destination: GPUBuffer, destinationOffset: number): void;
|
|
67
|
+
finish(): GPUCommandBuffer;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
interface GPURenderPassEncoder {
|
|
71
|
+
setPipeline(pipeline: GPURenderPipeline): void;
|
|
72
|
+
setBindGroup(index: number, bindGroup: GPUBindGroup): void;
|
|
73
|
+
draw(vertexCount: number): void;
|
|
74
|
+
end(): void;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
interface GPUCommandBuffer {}
|
|
78
|
+
|
|
79
|
+
interface GPUTextureDescriptor {
|
|
80
|
+
size: { width: number; height: number };
|
|
81
|
+
format: string;
|
|
82
|
+
usage: number;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
interface GPUBufferDescriptor {
|
|
86
|
+
size: number;
|
|
87
|
+
usage: number;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
interface GPUSamplerDescriptor {
|
|
91
|
+
minFilter?: string;
|
|
92
|
+
magFilter?: string;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
interface GPUShaderModuleDescriptor {
|
|
96
|
+
code: string;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
interface GPUBindGroupLayoutDescriptor {
|
|
100
|
+
entries: GPUBindGroupLayoutEntry[];
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
interface GPUBindGroupLayoutEntry {
|
|
104
|
+
binding: number;
|
|
105
|
+
visibility: number;
|
|
106
|
+
sampler?: { type: string };
|
|
107
|
+
texture?: { sampleType: string };
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
interface GPUPipelineLayoutDescriptor {
|
|
111
|
+
bindGroupLayouts: GPUBindGroupLayout[];
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
interface GPURenderPipelineDescriptor {
|
|
115
|
+
layout: GPUPipelineLayout;
|
|
116
|
+
vertex: {
|
|
117
|
+
module: GPUShaderModule;
|
|
118
|
+
entryPoint: string;
|
|
119
|
+
};
|
|
120
|
+
fragment: {
|
|
121
|
+
module: GPUShaderModule;
|
|
122
|
+
entryPoint: string;
|
|
123
|
+
targets: { format: string }[];
|
|
124
|
+
};
|
|
125
|
+
primitive: {
|
|
126
|
+
topology: string;
|
|
127
|
+
};
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
interface GPUBindGroupDescriptor {
|
|
131
|
+
layout: GPUBindGroupLayout;
|
|
132
|
+
entries: GPUBindGroupEntry[];
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
interface GPUBindGroupEntry {
|
|
136
|
+
binding: number;
|
|
137
|
+
resource: GPUSampler | GPUTextureView;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
interface GPURenderPassDescriptor {
|
|
141
|
+
colorAttachments: GPURenderPassColorAttachment[];
|
|
142
|
+
timestampWrites?: GPURenderPassTimestampWrites;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
interface GPURenderPassTimestampWrites {
|
|
146
|
+
querySet: GPUQuerySet;
|
|
147
|
+
beginningOfPassWriteIndex?: number;
|
|
148
|
+
endOfPassWriteIndex?: number;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
interface GPURenderPassColorAttachment {
|
|
152
|
+
view: GPUTextureView;
|
|
153
|
+
loadOp: string;
|
|
154
|
+
storeOp: string;
|
|
155
|
+
clearValue: { r: number; g: number; b: number; a: number };
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
interface GPUImageCopyTexture {
|
|
159
|
+
texture: GPUTexture;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
interface GPUImageCopyBuffer {
|
|
163
|
+
buffer: GPUBuffer;
|
|
164
|
+
bytesPerRow: number;
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
interface GPUExtent3D {
|
|
168
|
+
width: number;
|
|
169
|
+
height: number;
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
declare const GPUTextureUsage: {
|
|
173
|
+
RENDER_ATTACHMENT: number;
|
|
174
|
+
COPY_SRC: number;
|
|
175
|
+
};
|
|
176
|
+
|
|
177
|
+
declare const GPUBufferUsage: {
|
|
178
|
+
COPY_DST: number;
|
|
179
|
+
COPY_SRC: number;
|
|
180
|
+
MAP_READ: number;
|
|
181
|
+
QUERY_RESOLVE: number;
|
|
182
|
+
};
|
|
183
|
+
|
|
184
|
+
declare const GPUShaderStage: {
|
|
185
|
+
FRAGMENT: number;
|
|
186
|
+
};
|
|
187
|
+
|
|
188
|
+
declare const GPUMapMode: {
|
|
189
|
+
READ: number;
|
|
190
|
+
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "stats-gl",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "4.0.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"author": "Renaud ROHLINGER (https://github.com/RenaudRohlinger)",
|
|
6
6
|
"homepage": "https://github.com/RenaudRohlinger/stats-gl",
|
|
@@ -8,17 +8,19 @@
|
|
|
8
8
|
"license": "MIT",
|
|
9
9
|
"files": [
|
|
10
10
|
"dist/*",
|
|
11
|
-
"lib/*"
|
|
11
|
+
"lib/*",
|
|
12
|
+
"addons/*"
|
|
12
13
|
],
|
|
13
14
|
"types": "./dist/stats-gl.d.ts",
|
|
14
15
|
"main": "./dist/main.cjs",
|
|
15
16
|
"module": "./dist/main.js",
|
|
16
17
|
"exports": {
|
|
17
|
-
|
|
18
|
+
".": {
|
|
18
19
|
"types": "./dist/stats-gl.d.ts",
|
|
19
20
|
"require": "./dist/main.cjs",
|
|
20
21
|
"import": "./dist/main.js"
|
|
21
|
-
}
|
|
22
|
+
},
|
|
23
|
+
"./addons/*": "./addons/*"
|
|
22
24
|
},
|
|
23
25
|
"sideEffects": false,
|
|
24
26
|
"scripts": {
|