@aethervtt/shard-gpu-webgl2 0.0.0-stage → 0.2.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/LICENSE +21 -0
- package/README.md +2 -2
- package/dist/binding.d.ts +32 -0
- package/dist/binding.js +81 -0
- package/dist/cache.d.ts +73 -0
- package/dist/cache.js +184 -0
- package/dist/commands.d.ts +101 -0
- package/dist/commands.js +391 -0
- package/dist/constants.d.ts +41 -0
- package/dist/constants.js +38 -0
- package/dist/copies.d.ts +61 -0
- package/dist/copies.js +629 -0
- package/dist/device.d.ts +168 -0
- package/dist/device.js +401 -0
- package/dist/errors.d.ts +8 -0
- package/dist/errors.js +18 -0
- package/dist/fake-gl.d.ts +338 -0
- package/dist/fake-gl.js +980 -0
- package/dist/fbo.d.ts +30 -0
- package/dist/fbo.js +142 -0
- package/dist/formats.d.ts +25 -0
- package/dist/formats.js +106 -0
- package/dist/gl.d.ts +216 -0
- package/dist/gl.js +232 -0
- package/dist/gpu.d.ts +58 -0
- package/dist/gpu.js +215 -0
- package/dist/index.d.ts +8 -0
- package/dist/index.js +42 -0
- package/dist/naga.d.ts +37 -0
- package/dist/naga.js +99 -0
- package/dist/pipeline.d.ts +113 -0
- package/dist/pipeline.js +294 -0
- package/dist/present.d.ts +18 -0
- package/dist/present.js +108 -0
- package/dist/queries.d.ts +41 -0
- package/dist/queries.js +110 -0
- package/dist/queue.d.ts +13 -0
- package/dist/queue.js +50 -0
- package/dist/readback.d.ts +17 -0
- package/dist/readback.js +104 -0
- package/dist/replay.d.ts +78 -0
- package/dist/replay.js +678 -0
- package/dist/resources.d.ts +96 -0
- package/dist/resources.js +355 -0
- package/dist/state.d.ts +43 -0
- package/dist/state.js +169 -0
- package/package.json +36 -4
- package/wasm/shard_naga.wasm +0 -0
package/dist/gl.js
ADDED
|
@@ -0,0 +1,232 @@
|
|
|
1
|
+
const GL = {
|
|
2
|
+
// Buffers
|
|
3
|
+
ARRAY_BUFFER: 34962,
|
|
4
|
+
ELEMENT_ARRAY_BUFFER: 34963,
|
|
5
|
+
UNIFORM_BUFFER: 35345,
|
|
6
|
+
COPY_READ_BUFFER: 36662,
|
|
7
|
+
COPY_WRITE_BUFFER: 36663,
|
|
8
|
+
PIXEL_PACK_BUFFER: 35051,
|
|
9
|
+
PIXEL_UNPACK_BUFFER: 35052,
|
|
10
|
+
STATIC_DRAW: 35044,
|
|
11
|
+
DYNAMIC_DRAW: 35048,
|
|
12
|
+
STREAM_READ: 35041,
|
|
13
|
+
DYNAMIC_READ: 35049,
|
|
14
|
+
// Types
|
|
15
|
+
BYTE: 5120,
|
|
16
|
+
UNSIGNED_BYTE: 5121,
|
|
17
|
+
SHORT: 5122,
|
|
18
|
+
UNSIGNED_SHORT: 5123,
|
|
19
|
+
INT: 5124,
|
|
20
|
+
UNSIGNED_INT: 5125,
|
|
21
|
+
FLOAT: 5126,
|
|
22
|
+
HALF_FLOAT: 5131,
|
|
23
|
+
UNSIGNED_INT_2_10_10_10_REV: 33640,
|
|
24
|
+
UNSIGNED_INT_10F_11F_11F_REV: 35899,
|
|
25
|
+
UNSIGNED_INT_24_8: 34042,
|
|
26
|
+
FLOAT_32_UNSIGNED_INT_24_8_REV: 36269,
|
|
27
|
+
// Formats
|
|
28
|
+
RED: 6403,
|
|
29
|
+
RG: 33319,
|
|
30
|
+
RGB: 6407,
|
|
31
|
+
RGBA: 6408,
|
|
32
|
+
RED_INTEGER: 36244,
|
|
33
|
+
RG_INTEGER: 33320,
|
|
34
|
+
RGBA_INTEGER: 36249,
|
|
35
|
+
DEPTH_COMPONENT: 6402,
|
|
36
|
+
DEPTH_STENCIL: 34041,
|
|
37
|
+
STENCIL_INDEX8: 36168,
|
|
38
|
+
// Internal formats
|
|
39
|
+
R8: 33321,
|
|
40
|
+
RG8: 33323,
|
|
41
|
+
RGBA8: 32856,
|
|
42
|
+
SRGB8_ALPHA8: 35907,
|
|
43
|
+
RGB10_A2: 32857,
|
|
44
|
+
R16F: 33325,
|
|
45
|
+
RG16F: 33327,
|
|
46
|
+
RGBA16F: 34842,
|
|
47
|
+
R32F: 33326,
|
|
48
|
+
RG32F: 33328,
|
|
49
|
+
RGBA32F: 34836,
|
|
50
|
+
R11F_G11F_B10F: 35898,
|
|
51
|
+
R8UI: 33330,
|
|
52
|
+
RGBA8UI: 36220,
|
|
53
|
+
R16UI: 33332,
|
|
54
|
+
R32UI: 33334,
|
|
55
|
+
RG32UI: 33340,
|
|
56
|
+
RGBA32UI: 36208,
|
|
57
|
+
DEPTH_COMPONENT16: 33189,
|
|
58
|
+
DEPTH_COMPONENT24: 33190,
|
|
59
|
+
DEPTH_COMPONENT32F: 36012,
|
|
60
|
+
DEPTH24_STENCIL8: 35056,
|
|
61
|
+
DEPTH32F_STENCIL8: 36013,
|
|
62
|
+
// Textures
|
|
63
|
+
TEXTURE_2D: 3553,
|
|
64
|
+
TEXTURE_2D_ARRAY: 35866,
|
|
65
|
+
TEXTURE_3D: 32879,
|
|
66
|
+
TEXTURE_CUBE_MAP: 34067,
|
|
67
|
+
TEXTURE_CUBE_MAP_POSITIVE_X: 34069,
|
|
68
|
+
TEXTURE0: 33984,
|
|
69
|
+
TEXTURE_BASE_LEVEL: 33084,
|
|
70
|
+
TEXTURE_MAX_LEVEL: 33085,
|
|
71
|
+
TEXTURE_MIN_FILTER: 10241,
|
|
72
|
+
TEXTURE_MAG_FILTER: 10240,
|
|
73
|
+
TEXTURE_WRAP_S: 10242,
|
|
74
|
+
TEXTURE_WRAP_T: 10243,
|
|
75
|
+
TEXTURE_WRAP_R: 32882,
|
|
76
|
+
TEXTURE_MIN_LOD: 33082,
|
|
77
|
+
TEXTURE_MAX_LOD: 33083,
|
|
78
|
+
TEXTURE_COMPARE_MODE: 34892,
|
|
79
|
+
TEXTURE_COMPARE_FUNC: 34893,
|
|
80
|
+
COMPARE_REF_TO_TEXTURE: 34894,
|
|
81
|
+
NONE: 0,
|
|
82
|
+
NEAREST: 9728,
|
|
83
|
+
LINEAR: 9729,
|
|
84
|
+
NEAREST_MIPMAP_NEAREST: 9984,
|
|
85
|
+
LINEAR_MIPMAP_NEAREST: 9985,
|
|
86
|
+
NEAREST_MIPMAP_LINEAR: 9986,
|
|
87
|
+
LINEAR_MIPMAP_LINEAR: 9987,
|
|
88
|
+
REPEAT: 10497,
|
|
89
|
+
CLAMP_TO_EDGE: 33071,
|
|
90
|
+
MIRRORED_REPEAT: 33648,
|
|
91
|
+
TEXTURE_MAX_ANISOTROPY_EXT: 34046,
|
|
92
|
+
MAX_TEXTURE_MAX_ANISOTROPY_EXT: 34047,
|
|
93
|
+
UNPACK_ALIGNMENT: 3317,
|
|
94
|
+
PACK_ALIGNMENT: 3333,
|
|
95
|
+
UNPACK_ROW_LENGTH: 3314,
|
|
96
|
+
UNPACK_IMAGE_HEIGHT: 32878,
|
|
97
|
+
UNPACK_SKIP_ROWS: 3315,
|
|
98
|
+
UNPACK_SKIP_PIXELS: 3316,
|
|
99
|
+
UNPACK_SKIP_IMAGES: 32877,
|
|
100
|
+
UNPACK_FLIP_Y_WEBGL: 37440,
|
|
101
|
+
UNPACK_PREMULTIPLY_ALPHA_WEBGL: 37441,
|
|
102
|
+
UNPACK_COLORSPACE_CONVERSION_WEBGL: 37443,
|
|
103
|
+
PACK_ROW_LENGTH: 3330,
|
|
104
|
+
// Framebuffers
|
|
105
|
+
FRAMEBUFFER: 36160,
|
|
106
|
+
READ_FRAMEBUFFER: 36008,
|
|
107
|
+
DRAW_FRAMEBUFFER: 36009,
|
|
108
|
+
RENDERBUFFER: 36161,
|
|
109
|
+
COLOR_ATTACHMENT0: 36064,
|
|
110
|
+
DEPTH_ATTACHMENT: 36096,
|
|
111
|
+
STENCIL_ATTACHMENT: 36128,
|
|
112
|
+
DEPTH_STENCIL_ATTACHMENT: 33306,
|
|
113
|
+
FRAMEBUFFER_COMPLETE: 36053,
|
|
114
|
+
COLOR_BUFFER_BIT: 16384,
|
|
115
|
+
DEPTH_BUFFER_BIT: 256,
|
|
116
|
+
STENCIL_BUFFER_BIT: 1024,
|
|
117
|
+
COLOR: 6144,
|
|
118
|
+
DEPTH: 6145,
|
|
119
|
+
STENCIL: 6146,
|
|
120
|
+
BACK: 1029,
|
|
121
|
+
SAMPLES: 32937,
|
|
122
|
+
// State
|
|
123
|
+
BLEND: 3042,
|
|
124
|
+
DITHER: 3024,
|
|
125
|
+
CULL_FACE: 2884,
|
|
126
|
+
DEPTH_TEST: 2929,
|
|
127
|
+
STENCIL_TEST: 2960,
|
|
128
|
+
SCISSOR_TEST: 3089,
|
|
129
|
+
POLYGON_OFFSET_FILL: 32823,
|
|
130
|
+
RASTERIZER_DISCARD: 35977,
|
|
131
|
+
FRONT: 1028,
|
|
132
|
+
FRONT_AND_BACK: 1032,
|
|
133
|
+
CW: 2304,
|
|
134
|
+
CCW: 2305,
|
|
135
|
+
NEVER: 512,
|
|
136
|
+
LESS: 513,
|
|
137
|
+
EQUAL: 514,
|
|
138
|
+
LEQUAL: 515,
|
|
139
|
+
GREATER: 516,
|
|
140
|
+
NOTEQUAL: 517,
|
|
141
|
+
GEQUAL: 518,
|
|
142
|
+
ALWAYS: 519,
|
|
143
|
+
KEEP: 7680,
|
|
144
|
+
ZERO: 0,
|
|
145
|
+
ONE: 1,
|
|
146
|
+
REPLACE: 7681,
|
|
147
|
+
INCR: 7682,
|
|
148
|
+
DECR: 7683,
|
|
149
|
+
INVERT: 5386,
|
|
150
|
+
INCR_WRAP: 34055,
|
|
151
|
+
DECR_WRAP: 34056,
|
|
152
|
+
SRC_COLOR: 768,
|
|
153
|
+
ONE_MINUS_SRC_COLOR: 769,
|
|
154
|
+
SRC_ALPHA: 770,
|
|
155
|
+
ONE_MINUS_SRC_ALPHA: 771,
|
|
156
|
+
DST_ALPHA: 772,
|
|
157
|
+
ONE_MINUS_DST_ALPHA: 773,
|
|
158
|
+
DST_COLOR: 774,
|
|
159
|
+
ONE_MINUS_DST_COLOR: 775,
|
|
160
|
+
SRC_ALPHA_SATURATE: 776,
|
|
161
|
+
CONSTANT_COLOR: 32769,
|
|
162
|
+
ONE_MINUS_CONSTANT_COLOR: 32770,
|
|
163
|
+
FUNC_ADD: 32774,
|
|
164
|
+
FUNC_SUBTRACT: 32778,
|
|
165
|
+
FUNC_REVERSE_SUBTRACT: 32779,
|
|
166
|
+
MIN: 32775,
|
|
167
|
+
MAX: 32776,
|
|
168
|
+
// Drawing
|
|
169
|
+
TRIANGLES: 4,
|
|
170
|
+
TRIANGLE_STRIP: 5,
|
|
171
|
+
LINES: 1,
|
|
172
|
+
LINE_STRIP: 3,
|
|
173
|
+
POINTS: 0,
|
|
174
|
+
// Shaders and programs
|
|
175
|
+
VERTEX_SHADER: 35633,
|
|
176
|
+
FRAGMENT_SHADER: 35632,
|
|
177
|
+
COMPILE_STATUS: 35713,
|
|
178
|
+
LINK_STATUS: 35714,
|
|
179
|
+
UNIFORM_BLOCK_DATA_SIZE: 35392,
|
|
180
|
+
COMPLETION_STATUS_KHR: 37297,
|
|
181
|
+
// Sync
|
|
182
|
+
SYNC_GPU_COMMANDS_COMPLETE: 37143,
|
|
183
|
+
SYNC_STATUS: 37140,
|
|
184
|
+
SIGNALED: 37145,
|
|
185
|
+
ALREADY_SIGNALED: 37146,
|
|
186
|
+
CONDITION_SATISFIED: 37148,
|
|
187
|
+
TIMEOUT_EXPIRED: 37147,
|
|
188
|
+
WAIT_FAILED: 37149,
|
|
189
|
+
// Limits
|
|
190
|
+
MAX_TEXTURE_SIZE: 3379,
|
|
191
|
+
MAX_3D_TEXTURE_SIZE: 32883,
|
|
192
|
+
MAX_ARRAY_TEXTURE_LAYERS: 35071,
|
|
193
|
+
MAX_CUBE_MAP_TEXTURE_SIZE: 34076,
|
|
194
|
+
MAX_TEXTURE_IMAGE_UNITS: 34930,
|
|
195
|
+
MAX_VERTEX_TEXTURE_IMAGE_UNITS: 35660,
|
|
196
|
+
MAX_COMBINED_TEXTURE_IMAGE_UNITS: 35661,
|
|
197
|
+
MAX_UNIFORM_BLOCK_SIZE: 35376,
|
|
198
|
+
MAX_VERTEX_UNIFORM_BLOCKS: 35371,
|
|
199
|
+
MAX_FRAGMENT_UNIFORM_BLOCKS: 35373,
|
|
200
|
+
MAX_COMBINED_UNIFORM_BLOCKS: 35374,
|
|
201
|
+
MAX_UNIFORM_BUFFER_BINDINGS: 35375,
|
|
202
|
+
UNIFORM_BUFFER_OFFSET_ALIGNMENT: 35380,
|
|
203
|
+
MAX_DRAW_BUFFERS: 34852,
|
|
204
|
+
MAX_COLOR_ATTACHMENTS: 36063,
|
|
205
|
+
MAX_VERTEX_ATTRIBS: 34921,
|
|
206
|
+
MAX_VARYING_COMPONENTS: 35659,
|
|
207
|
+
MAX_SAMPLES: 36183,
|
|
208
|
+
MAX_RENDERBUFFER_SIZE: 34024,
|
|
209
|
+
MAX_VERTEX_UNIFORM_VECTORS: 36347,
|
|
210
|
+
MAX_ELEMENT_INDEX: 36203,
|
|
211
|
+
// Errors
|
|
212
|
+
NO_ERROR: 0,
|
|
213
|
+
INVALID_ENUM: 1280,
|
|
214
|
+
INVALID_VALUE: 1281,
|
|
215
|
+
INVALID_OPERATION: 1282,
|
|
216
|
+
OUT_OF_MEMORY: 1285,
|
|
217
|
+
INVALID_FRAMEBUFFER_OPERATION: 1286,
|
|
218
|
+
CONTEXT_LOST_WEBGL: 37442,
|
|
219
|
+
// Debug info (WEBGL_debug_renderer_info)
|
|
220
|
+
UNMASKED_VENDOR_WEBGL: 37445,
|
|
221
|
+
UNMASKED_RENDERER_WEBGL: 37446,
|
|
222
|
+
VENDOR: 7936,
|
|
223
|
+
RENDERER: 7937
|
|
224
|
+
};
|
|
225
|
+
const CLIP = {
|
|
226
|
+
LOWER_LEFT_EXT: 36001,
|
|
227
|
+
ZERO_TO_ONE_EXT: 37727
|
|
228
|
+
};
|
|
229
|
+
export {
|
|
230
|
+
CLIP,
|
|
231
|
+
GL
|
|
232
|
+
};
|
package/dist/gpu.d.ts
ADDED
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import { type BakedTranslations } from './cache.js';
|
|
2
|
+
import { type Webgl2AdapterInfo, Webgl2Device } from './device.js';
|
|
3
|
+
import type { Naga } from './naga.js';
|
|
4
|
+
export interface Webgl2GpuOptions {
|
|
5
|
+
/**
|
|
6
|
+
* The canvas whose context the device uses: it presents straight into it. Omitted, a detached
|
|
7
|
+
* canvas, and every surface is drawn onto from it.
|
|
8
|
+
*/
|
|
9
|
+
canvas?: HTMLCanvasElement | OffscreenCanvas;
|
|
10
|
+
/** A context to use as it is (tests pass a fake one). */
|
|
11
|
+
context?: WebGL2RenderingContext;
|
|
12
|
+
/**
|
|
13
|
+
* 'minimum' holds the device to WebGL2's floor whatever the GPU has: no clip control, 16 texture
|
|
14
|
+
* units, 2048 texels, 4 draw buffers, no float filtering, no compression.
|
|
15
|
+
*/
|
|
16
|
+
profile?: 'native' | 'minimum';
|
|
17
|
+
/** Checks GL errors after every submit. A round trip to the GPU process: for dev and tests. */
|
|
18
|
+
checkErrors?: boolean;
|
|
19
|
+
/**
|
|
20
|
+
* A baked translation set (`shard shaders bake`), fetched on the first pipeline: with every
|
|
21
|
+
* shader in it, naga never loads.
|
|
22
|
+
*/
|
|
23
|
+
shaders?: string | URL | BakedTranslations;
|
|
24
|
+
/** Keeps translations in IndexedDB across sessions. Default true where there is IndexedDB. */
|
|
25
|
+
persist?: boolean;
|
|
26
|
+
/** Loads naga (tests count the loads). */
|
|
27
|
+
naga?: () => Promise<Naga>;
|
|
28
|
+
}
|
|
29
|
+
export interface Webgl2Gpu {
|
|
30
|
+
requestAdapter(options?: GPURequestAdapterOptions): Promise<Webgl2Adapter | null>;
|
|
31
|
+
getPreferredCanvasFormat(): GPUTextureFormat;
|
|
32
|
+
readonly wgslLanguageFeatures: ReadonlySet<string>;
|
|
33
|
+
/** Why the last requestAdapter found none: 'no-webgl2', 'context-lost' or 'no-float-render-targets'. */
|
|
34
|
+
readonly unavailable: string | undefined;
|
|
35
|
+
}
|
|
36
|
+
/** A WebGPU entry point over WebGL2 (0064). Installs the `GPU*` flag globals the engine reads. */
|
|
37
|
+
export declare function createWebgl2Gpu(options?: Webgl2GpuOptions): Webgl2Gpu;
|
|
38
|
+
/** Why WebGL2 can't run the baseline tier here, or undefined when it can. */
|
|
39
|
+
export declare function webgl2Unavailable(gl: WebGL2RenderingContext | null): string | undefined;
|
|
40
|
+
interface Opened {
|
|
41
|
+
gl: WebGL2RenderingContext;
|
|
42
|
+
canvas: HTMLCanvasElement | OffscreenCanvas | undefined;
|
|
43
|
+
owns: boolean;
|
|
44
|
+
}
|
|
45
|
+
export declare class Webgl2Adapter {
|
|
46
|
+
readonly features: ReadonlySet<string>;
|
|
47
|
+
readonly limits: Readonly<Record<string, number>>;
|
|
48
|
+
readonly info: Webgl2AdapterInfo;
|
|
49
|
+
readonly isFallbackAdapter = false;
|
|
50
|
+
readonly featureLevel = "compatibility";
|
|
51
|
+
private readonly caps;
|
|
52
|
+
private readonly extensions;
|
|
53
|
+
private readonly options;
|
|
54
|
+
private opened;
|
|
55
|
+
constructor(opened: Opened, options: Webgl2GpuOptions);
|
|
56
|
+
requestDevice(descriptor?: GPUDeviceDescriptor): Promise<Webgl2Device>;
|
|
57
|
+
}
|
|
58
|
+
export {};
|
package/dist/gpu.js
ADDED
|
@@ -0,0 +1,215 @@
|
|
|
1
|
+
import { Translator } from "./cache.js";
|
|
2
|
+
import { installGpuConstants } from "./constants.js";
|
|
3
|
+
import {
|
|
4
|
+
Webgl2Device
|
|
5
|
+
} from "./device.js";
|
|
6
|
+
import { GL } from "./gl.js";
|
|
7
|
+
function createWebgl2Gpu(options = {}) {
|
|
8
|
+
installGpuConstants();
|
|
9
|
+
let unavailable;
|
|
10
|
+
return {
|
|
11
|
+
wgslLanguageFeatures: /* @__PURE__ */ new Set(),
|
|
12
|
+
get unavailable() {
|
|
13
|
+
return unavailable;
|
|
14
|
+
},
|
|
15
|
+
getPreferredCanvasFormat: () => "rgba8unorm",
|
|
16
|
+
requestAdapter(request) {
|
|
17
|
+
const opened = openContext(options, request?.powerPreference);
|
|
18
|
+
unavailable = typeof opened === "string" ? opened : void 0;
|
|
19
|
+
return Promise.resolve(typeof opened === "string" ? null : new Webgl2Adapter(opened, options));
|
|
20
|
+
}
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
function webgl2Unavailable(gl) {
|
|
24
|
+
if (!gl) return "no-webgl2";
|
|
25
|
+
if (gl.isContextLost()) return "context-lost";
|
|
26
|
+
if (!gl.getExtension("EXT_color_buffer_float")) return "no-float-render-targets";
|
|
27
|
+
return void 0;
|
|
28
|
+
}
|
|
29
|
+
function openContext(options, powerPreference) {
|
|
30
|
+
if (options.context) {
|
|
31
|
+
const why2 = webgl2Unavailable(options.context);
|
|
32
|
+
if (why2) return why2;
|
|
33
|
+
const canvas2 = options.canvas ?? options.context.canvas;
|
|
34
|
+
return { gl: options.context, canvas: canvas2, owns: false };
|
|
35
|
+
}
|
|
36
|
+
const canvas = options.canvas ?? detachedCanvas();
|
|
37
|
+
if (!canvas) return "no-webgl2";
|
|
38
|
+
const gl = canvas.getContext("webgl2", {
|
|
39
|
+
alpha: true,
|
|
40
|
+
antialias: false,
|
|
41
|
+
depth: false,
|
|
42
|
+
stencil: false,
|
|
43
|
+
premultipliedAlpha: true,
|
|
44
|
+
preserveDrawingBuffer: false,
|
|
45
|
+
powerPreference: powerPreference === "low-power" ? "low-power" : "high-performance"
|
|
46
|
+
});
|
|
47
|
+
const why = webgl2Unavailable(gl);
|
|
48
|
+
if (why) return why;
|
|
49
|
+
return { gl, canvas, owns: !options.canvas };
|
|
50
|
+
}
|
|
51
|
+
function detachedCanvas() {
|
|
52
|
+
const doc = globalThis.document;
|
|
53
|
+
if (doc) return doc.createElement("canvas");
|
|
54
|
+
if (typeof OffscreenCanvas !== "undefined") return new OffscreenCanvas(1, 1);
|
|
55
|
+
return void 0;
|
|
56
|
+
}
|
|
57
|
+
class Webgl2Adapter {
|
|
58
|
+
features;
|
|
59
|
+
limits;
|
|
60
|
+
info;
|
|
61
|
+
isFallbackAdapter = false;
|
|
62
|
+
featureLevel = "compatibility";
|
|
63
|
+
caps;
|
|
64
|
+
extensions;
|
|
65
|
+
options;
|
|
66
|
+
opened;
|
|
67
|
+
constructor(opened, options) {
|
|
68
|
+
this.opened = opened;
|
|
69
|
+
this.options = options;
|
|
70
|
+
const { caps, extensions } = capsOf(opened.gl, options.profile ?? "native");
|
|
71
|
+
this.caps = caps;
|
|
72
|
+
this.extensions = extensions;
|
|
73
|
+
this.features = featuresOf(opened.gl, caps, extensions.timer !== null);
|
|
74
|
+
this.limits = limitsOf(caps);
|
|
75
|
+
this.info = infoOf(opened.gl);
|
|
76
|
+
}
|
|
77
|
+
requestDevice(descriptor = {}) {
|
|
78
|
+
const missing = [...descriptor.requiredFeatures ?? []].filter((f) => !this.features.has(f));
|
|
79
|
+
if (missing.length > 0) {
|
|
80
|
+
return Promise.reject(new TypeError(`WebGL2 doesn't offer ${missing.join(", ")}`));
|
|
81
|
+
}
|
|
82
|
+
const opened = this.opened;
|
|
83
|
+
if (!opened) return Promise.reject(new Error("This adapter has already made its device"));
|
|
84
|
+
this.opened = void 0;
|
|
85
|
+
const caps = this.caps;
|
|
86
|
+
const device = new Webgl2Device(opened.gl, caps, {
|
|
87
|
+
label: descriptor.label,
|
|
88
|
+
canvas: opened.canvas,
|
|
89
|
+
ownsContext: opened.owns,
|
|
90
|
+
checkErrors: this.options.checkErrors === true,
|
|
91
|
+
features: new Set(descriptor.requiredFeatures ?? []),
|
|
92
|
+
limits: this.limits,
|
|
93
|
+
info: this.info,
|
|
94
|
+
translator: new Translator({
|
|
95
|
+
clipControl: caps.clipControl,
|
|
96
|
+
baked: this.options.shaders,
|
|
97
|
+
persist: this.options.persist,
|
|
98
|
+
naga: this.options.naga
|
|
99
|
+
}),
|
|
100
|
+
extensions: this.extensions
|
|
101
|
+
});
|
|
102
|
+
return Promise.resolve(device);
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
function capsOf(gl, profile) {
|
|
106
|
+
const minimum = profile === "minimum";
|
|
107
|
+
const ext = (name) => minimum ? null : gl.getExtension(name);
|
|
108
|
+
const p = (e) => gl.getParameter(e);
|
|
109
|
+
const anisotropic = ext("EXT_texture_filter_anisotropic");
|
|
110
|
+
const parallel = gl.getExtension("KHR_parallel_shader_compile");
|
|
111
|
+
const clipControl = ext("EXT_clip_control");
|
|
112
|
+
const floatBlend = gl.getExtension("EXT_float_blend");
|
|
113
|
+
const floatLinear = ext("OES_texture_float_linear");
|
|
114
|
+
const indexed = ext("OES_draw_buffers_indexed");
|
|
115
|
+
const lose = gl.getExtension("WEBGL_lose_context");
|
|
116
|
+
const timer = ext("EXT_disjoint_timer_query_webgl2");
|
|
117
|
+
const bc = ext("WEBGL_compressed_texture_s3tc") !== null && ext("WEBGL_compressed_texture_s3tc_srgb") !== null && ext("EXT_texture_compression_rgtc") !== null && ext("EXT_texture_compression_bptc") !== null;
|
|
118
|
+
const caps = {
|
|
119
|
+
maxSamples: minimum ? Math.min(4, p(GL.MAX_SAMPLES)) : p(GL.MAX_SAMPLES),
|
|
120
|
+
anisotropy: anisotropic ? p(GL.MAX_TEXTURE_MAX_ANISOTROPY_EXT) : 1,
|
|
121
|
+
parallelCompile: parallel !== null,
|
|
122
|
+
textureUnits: minimum ? 16 : p(GL.MAX_TEXTURE_IMAGE_UNITS),
|
|
123
|
+
vertexTextureUnits: minimum ? 16 : p(GL.MAX_VERTEX_TEXTURE_IMAGE_UNITS),
|
|
124
|
+
combinedUnits: minimum ? 32 : p(GL.MAX_COMBINED_TEXTURE_IMAGE_UNITS),
|
|
125
|
+
clipControl: clipControl !== null,
|
|
126
|
+
floatBlend: floatBlend !== null,
|
|
127
|
+
floatLinear: floatLinear !== null,
|
|
128
|
+
maxTextureSize: minimum ? 2048 : p(GL.MAX_TEXTURE_SIZE),
|
|
129
|
+
max3dTextureSize: minimum ? 256 : p(GL.MAX_3D_TEXTURE_SIZE),
|
|
130
|
+
maxArrayLayers: minimum ? 256 : p(GL.MAX_ARRAY_TEXTURE_LAYERS),
|
|
131
|
+
maxCubeSize: minimum ? 2048 : p(GL.MAX_CUBE_MAP_TEXTURE_SIZE),
|
|
132
|
+
maxDrawBuffers: minimum ? 4 : Math.min(p(GL.MAX_DRAW_BUFFERS), p(GL.MAX_COLOR_ATTACHMENTS)),
|
|
133
|
+
maxAttributes: minimum ? 16 : p(GL.MAX_VERTEX_ATTRIBS),
|
|
134
|
+
maxVaryings: minimum ? 15 : Math.floor(p(GL.MAX_VARYING_COMPONENTS) / 4),
|
|
135
|
+
uniformBlockSize: minimum ? 16384 : p(GL.MAX_UNIFORM_BLOCK_SIZE),
|
|
136
|
+
uniformBlocks: minimum ? 12 : Math.min(p(GL.MAX_VERTEX_UNIFORM_BLOCKS), p(GL.MAX_FRAGMENT_UNIFORM_BLOCKS)),
|
|
137
|
+
uniformBindings: minimum ? 24 : p(GL.MAX_UNIFORM_BUFFER_BINDINGS),
|
|
138
|
+
uniformAlignment: p(GL.UNIFORM_BUFFER_OFFSET_ALIGNMENT),
|
|
139
|
+
compression: {
|
|
140
|
+
bc,
|
|
141
|
+
astc: ext("WEBGL_compressed_texture_astc") !== null,
|
|
142
|
+
etc2: ext("WEBGL_compressed_texture_etc") !== null
|
|
143
|
+
}
|
|
144
|
+
};
|
|
145
|
+
return { caps, extensions: { clipControl, indexed, lose, timer } };
|
|
146
|
+
}
|
|
147
|
+
function featuresOf(gl, caps, timer) {
|
|
148
|
+
const features = /* @__PURE__ */ new Set(["depth32float-stencil8"]);
|
|
149
|
+
if (timer) features.add("timestamp-query");
|
|
150
|
+
if (caps.compression.bc) features.add("texture-compression-bc");
|
|
151
|
+
if (caps.compression.astc) features.add("texture-compression-astc");
|
|
152
|
+
if (caps.compression.etc2) features.add("texture-compression-etc2");
|
|
153
|
+
if (caps.floatLinear) features.add("float32-filterable");
|
|
154
|
+
if (caps.floatBlend) features.add("float32-blendable");
|
|
155
|
+
const samples = gl.getInternalformatParameter(
|
|
156
|
+
GL.RENDERBUFFER,
|
|
157
|
+
GL.R11F_G11F_B10F,
|
|
158
|
+
GL.SAMPLES
|
|
159
|
+
);
|
|
160
|
+
if (samples && samples.length > 0 && Math.max(...samples) >= 4)
|
|
161
|
+
features.add("rg11b10ufloat-renderable");
|
|
162
|
+
return features;
|
|
163
|
+
}
|
|
164
|
+
function limitsOf(caps) {
|
|
165
|
+
const sampled = Math.min(caps.textureUnits, caps.vertexTextureUnits);
|
|
166
|
+
return {
|
|
167
|
+
maxTextureDimension1D: caps.maxTextureSize,
|
|
168
|
+
maxTextureDimension2D: caps.maxTextureSize,
|
|
169
|
+
maxTextureDimension3D: caps.max3dTextureSize,
|
|
170
|
+
maxTextureArrayLayers: caps.maxArrayLayers,
|
|
171
|
+
maxBindGroups: 4,
|
|
172
|
+
maxBindGroupsPlusVertexBuffers: 24,
|
|
173
|
+
maxBindingsPerBindGroup: 1e3,
|
|
174
|
+
maxDynamicUniformBuffersPerPipelineLayout: 8,
|
|
175
|
+
maxDynamicStorageBuffersPerPipelineLayout: 0,
|
|
176
|
+
maxSampledTexturesPerShaderStage: sampled,
|
|
177
|
+
maxSamplersPerShaderStage: sampled,
|
|
178
|
+
maxStorageBuffersPerShaderStage: 0,
|
|
179
|
+
maxStorageBuffersInVertexStage: 0,
|
|
180
|
+
maxStorageBuffersInFragmentStage: 0,
|
|
181
|
+
maxStorageTexturesPerShaderStage: 0,
|
|
182
|
+
maxStorageTexturesInVertexStage: 0,
|
|
183
|
+
maxStorageTexturesInFragmentStage: 0,
|
|
184
|
+
maxUniformBuffersPerShaderStage: caps.uniformBlocks,
|
|
185
|
+
maxUniformBufferBindingSize: caps.uniformBlockSize,
|
|
186
|
+
maxStorageBufferBindingSize: 0,
|
|
187
|
+
minUniformBufferOffsetAlignment: Math.max(256, caps.uniformAlignment),
|
|
188
|
+
minStorageBufferOffsetAlignment: 256,
|
|
189
|
+
maxVertexBuffers: 8,
|
|
190
|
+
maxBufferSize: 256 * 1024 * 1024,
|
|
191
|
+
maxVertexAttributes: caps.maxAttributes,
|
|
192
|
+
// WebGL's vertexAttribPointer stride limit.
|
|
193
|
+
maxVertexBufferArrayStride: 255,
|
|
194
|
+
maxInterStageShaderVariables: caps.maxVaryings,
|
|
195
|
+
maxColorAttachments: caps.maxDrawBuffers,
|
|
196
|
+
maxColorAttachmentBytesPerSample: 32,
|
|
197
|
+
maxComputeWorkgroupStorageSize: 0,
|
|
198
|
+
maxComputeInvocationsPerWorkgroup: 0,
|
|
199
|
+
maxComputeWorkgroupSizeX: 0,
|
|
200
|
+
maxComputeWorkgroupSizeY: 0,
|
|
201
|
+
maxComputeWorkgroupSizeZ: 0,
|
|
202
|
+
maxComputeWorkgroupsPerDimension: 0
|
|
203
|
+
};
|
|
204
|
+
}
|
|
205
|
+
function infoOf(gl) {
|
|
206
|
+
const debug = gl.getExtension("WEBGL_debug_renderer_info");
|
|
207
|
+
const vendor = String(gl.getParameter(debug ? GL.UNMASKED_VENDOR_WEBGL : GL.VENDOR) ?? "");
|
|
208
|
+
const renderer = String(gl.getParameter(debug ? GL.UNMASKED_RENDERER_WEBGL : GL.RENDERER) ?? "");
|
|
209
|
+
return { vendor, architecture: "", device: renderer, description: `WebGL2: ${renderer}` };
|
|
210
|
+
}
|
|
211
|
+
export {
|
|
212
|
+
Webgl2Adapter,
|
|
213
|
+
createWebgl2Gpu,
|
|
214
|
+
webgl2Unavailable
|
|
215
|
+
};
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export { type BakedTranslations, NAGA_VERSION, SHIM_VERSION, type ShaderCacheStats, Translator, type TranslatorOptions, translationKey, } from './cache.js';
|
|
2
|
+
export { BufferUsage, ColorWrite, installGpuConstants, MapMode, ShaderStage, TextureUsage, } from './constants.js';
|
|
3
|
+
export type { Webgl2AdapterInfo, Webgl2Caps, Webgl2Device } from './device.js';
|
|
4
|
+
export { unsupported } from './errors.js';
|
|
5
|
+
export { createWebgl2Gpu, type Webgl2Adapter, type Webgl2Gpu, type Webgl2GpuOptions, webgl2Unavailable, } from './gpu.js';
|
|
6
|
+
export { type GlslStage, type GlslTranslation, loadNaga, type Naga, type TranslateOptions, } from './naga.js';
|
|
7
|
+
export { entryPointOf } from './pipeline.js';
|
|
8
|
+
export { canvasContext, type Webgl2CanvasContext } from './present.js';
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import {
|
|
2
|
+
NAGA_VERSION,
|
|
3
|
+
SHIM_VERSION,
|
|
4
|
+
Translator,
|
|
5
|
+
translationKey
|
|
6
|
+
} from "./cache.js";
|
|
7
|
+
import {
|
|
8
|
+
BufferUsage,
|
|
9
|
+
ColorWrite,
|
|
10
|
+
installGpuConstants,
|
|
11
|
+
MapMode,
|
|
12
|
+
ShaderStage,
|
|
13
|
+
TextureUsage
|
|
14
|
+
} from "./constants.js";
|
|
15
|
+
import { unsupported } from "./errors.js";
|
|
16
|
+
import {
|
|
17
|
+
createWebgl2Gpu,
|
|
18
|
+
webgl2Unavailable
|
|
19
|
+
} from "./gpu.js";
|
|
20
|
+
import {
|
|
21
|
+
loadNaga
|
|
22
|
+
} from "./naga.js";
|
|
23
|
+
import { entryPointOf } from "./pipeline.js";
|
|
24
|
+
import { canvasContext } from "./present.js";
|
|
25
|
+
export {
|
|
26
|
+
BufferUsage,
|
|
27
|
+
ColorWrite,
|
|
28
|
+
MapMode,
|
|
29
|
+
NAGA_VERSION,
|
|
30
|
+
SHIM_VERSION,
|
|
31
|
+
ShaderStage,
|
|
32
|
+
TextureUsage,
|
|
33
|
+
Translator,
|
|
34
|
+
canvasContext,
|
|
35
|
+
createWebgl2Gpu,
|
|
36
|
+
entryPointOf,
|
|
37
|
+
installGpuConstants,
|
|
38
|
+
loadNaga,
|
|
39
|
+
translationKey,
|
|
40
|
+
unsupported,
|
|
41
|
+
webgl2Unavailable
|
|
42
|
+
};
|
package/dist/naga.d.ts
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
export type GlslStage = 'vertex' | 'fragment';
|
|
2
|
+
export interface GlslTranslation {
|
|
3
|
+
glsl: string;
|
|
4
|
+
/** Combined sampler uniforms: the texture binding, and the sampler's (null for `texelFetch`). */
|
|
5
|
+
textures: {
|
|
6
|
+
name: string;
|
|
7
|
+
group: number;
|
|
8
|
+
binding: number;
|
|
9
|
+
sampler: [number, number] | null;
|
|
10
|
+
}[];
|
|
11
|
+
/** Uniform blocks by block name. */
|
|
12
|
+
uniforms: {
|
|
13
|
+
name: string;
|
|
14
|
+
group: number;
|
|
15
|
+
binding: number;
|
|
16
|
+
}[];
|
|
17
|
+
varyings: {
|
|
18
|
+
name: string;
|
|
19
|
+
location: number;
|
|
20
|
+
}[];
|
|
21
|
+
/** Uses `naga_vs_first_instance`, the uniform standing in for the draw's first instance. */
|
|
22
|
+
firstInstance: boolean;
|
|
23
|
+
}
|
|
24
|
+
export interface TranslateOptions {
|
|
25
|
+
/**
|
|
26
|
+
* `EXT_clip_control` sets depth to [0, 1] as WebGPU has it: only y is flipped. Without it,
|
|
27
|
+
* naga maps z to [-1, 1] too (the same depth values, less precision far away).
|
|
28
|
+
*/
|
|
29
|
+
clipControl: boolean;
|
|
30
|
+
}
|
|
31
|
+
export interface Naga {
|
|
32
|
+
/** naga's release: part of every translation's cache key. */
|
|
33
|
+
readonly version: string;
|
|
34
|
+
translate(wgsl: string, entry: string, stage: GlslStage, options: TranslateOptions): GlslTranslation;
|
|
35
|
+
}
|
|
36
|
+
/** Loads naga once. Rejects with `gpu-webgl2/naga-load-failed` if the module can't be fetched. */
|
|
37
|
+
export declare function loadNaga(): Promise<Naga>;
|
package/dist/naga.js
ADDED
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
import { ShardError } from "@aethervtt/shard-core";
|
|
2
|
+
const ADJUST_COORDINATE_SPACE = 1;
|
|
3
|
+
const Z_REMAP = "gl_Position.yz = vec2(-gl_Position.y, gl_Position.z * 2.0 - gl_Position.w);";
|
|
4
|
+
const Y_FLIP = "gl_Position.y = -gl_Position.y;";
|
|
5
|
+
let loading;
|
|
6
|
+
function loadNaga() {
|
|
7
|
+
loading ??= (async () => {
|
|
8
|
+
const module = await compileNaga();
|
|
9
|
+
return nagaFrom(module);
|
|
10
|
+
})();
|
|
11
|
+
loading.catch(() => {
|
|
12
|
+
loading = void 0;
|
|
13
|
+
});
|
|
14
|
+
return loading;
|
|
15
|
+
}
|
|
16
|
+
async function compileNaga() {
|
|
17
|
+
const url = new URL("../wasm/shard_naga.wasm", import.meta.url);
|
|
18
|
+
try {
|
|
19
|
+
if (url.protocol === "file:") {
|
|
20
|
+
const { readFile } = await import("node:fs/promises");
|
|
21
|
+
const data = await readFile(url);
|
|
22
|
+
return await WebAssembly.compile(
|
|
23
|
+
new Uint8Array(data.buffer, data.byteOffset, data.byteLength)
|
|
24
|
+
);
|
|
25
|
+
}
|
|
26
|
+
const response = await fetch(url);
|
|
27
|
+
if (!response.ok) throw new Error(`HTTP ${response.status}`);
|
|
28
|
+
return await WebAssembly.compileStreaming(response);
|
|
29
|
+
} catch (cause) {
|
|
30
|
+
throw new ShardError(
|
|
31
|
+
"gpu-webgl2/naga-load-failed",
|
|
32
|
+
"Couldn't load naga, the shader translator",
|
|
33
|
+
{
|
|
34
|
+
cause,
|
|
35
|
+
path: url.href,
|
|
36
|
+
hint: "packages/gpu-webgl2/wasm must be served with the app (rebuild with `pnpm build:wasm`)."
|
|
37
|
+
}
|
|
38
|
+
);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
function nagaFrom(module) {
|
|
42
|
+
let exports = instantiate(module);
|
|
43
|
+
const decoder = new TextDecoder();
|
|
44
|
+
const encoder = new TextEncoder();
|
|
45
|
+
const read = () => decoder.decode(
|
|
46
|
+
new Uint8Array(exports.memory.buffer, exports.result_ptr(), exports.result_len())
|
|
47
|
+
);
|
|
48
|
+
exports.version();
|
|
49
|
+
const version = read();
|
|
50
|
+
return {
|
|
51
|
+
version,
|
|
52
|
+
translate(wgsl, entry, stage, options) {
|
|
53
|
+
const src = encoder.encode(wgsl);
|
|
54
|
+
const name = encoder.encode(entry);
|
|
55
|
+
let status;
|
|
56
|
+
let json;
|
|
57
|
+
try {
|
|
58
|
+
const srcPtr = exports.alloc(src.length);
|
|
59
|
+
const namePtr = exports.alloc(name.length);
|
|
60
|
+
new Uint8Array(exports.memory.buffer, srcPtr, src.length).set(src);
|
|
61
|
+
new Uint8Array(exports.memory.buffer, namePtr, name.length).set(name);
|
|
62
|
+
status = exports.translate(
|
|
63
|
+
srcPtr,
|
|
64
|
+
src.length,
|
|
65
|
+
namePtr,
|
|
66
|
+
name.length,
|
|
67
|
+
stage === "vertex" ? 0 : 1,
|
|
68
|
+
ADJUST_COORDINATE_SPACE
|
|
69
|
+
);
|
|
70
|
+
json = read();
|
|
71
|
+
exports.dealloc(srcPtr, src.length);
|
|
72
|
+
exports.dealloc(namePtr, name.length);
|
|
73
|
+
} catch (cause) {
|
|
74
|
+
exports = instantiate(module);
|
|
75
|
+
throw new ShardError("gpu-webgl2/naga-crashed", `naga crashed translating ${entry}`, {
|
|
76
|
+
cause,
|
|
77
|
+
hint: "Report the shader: naga should return an error, not crash."
|
|
78
|
+
});
|
|
79
|
+
}
|
|
80
|
+
const result = JSON.parse(json);
|
|
81
|
+
if (status !== 0 || "error" in result) {
|
|
82
|
+
throw new ShardError(
|
|
83
|
+
"gpu-webgl2/translate",
|
|
84
|
+
`WGSL \u2192 GLSL failed for ${entry}: ${result.error}`
|
|
85
|
+
);
|
|
86
|
+
}
|
|
87
|
+
if (options.clipControl && stage === "vertex") {
|
|
88
|
+
result.glsl = result.glsl.replaceAll(Z_REMAP, Y_FLIP);
|
|
89
|
+
}
|
|
90
|
+
return result;
|
|
91
|
+
}
|
|
92
|
+
};
|
|
93
|
+
}
|
|
94
|
+
function instantiate(module) {
|
|
95
|
+
return new WebAssembly.Instance(module, {}).exports;
|
|
96
|
+
}
|
|
97
|
+
export {
|
|
98
|
+
loadNaga
|
|
99
|
+
};
|