@geastack/native-webgl-angle 0.1.11 → 0.1.13
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/geatsc-plugin-readback.mjs +46 -0
- package/geatsc-plugin-uniforms.mjs +214 -59
- package/geatsc-plugin-uploads.mjs +7 -2
- package/geatsc-plugin.mjs +919 -68
- package/native/angle_webgl_host.mm +267 -23
- package/native/webgl_readback.h +29 -0
- package/package.json +9 -7
- package/src/inflate.ts +252 -0
- package/src/nativeWebGL.ts +88 -17
- package/src/nativeWebGLHost.ts +28 -2
- package/src/text/atlas-sans.ts +19 -178
- package/src/text/atlas-serif-italic.ts +26 -178
- package/src/text/atlas-serif.ts +22 -178
- package/src/text/native-text-types.ts +28 -0
- package/src/text/native-text.ts +154 -50
- package/src/troika-three-text.ts +49 -4
- package/NOTICE +0 -4
package/src/inflate.ts
ADDED
|
@@ -0,0 +1,252 @@
|
|
|
1
|
+
// Raw DEFLATE (RFC 1951) decoder for data baked into a native binary -- glyph
|
|
2
|
+
// atlases, an app's mesh blobs. Baked data ships as base64 string literals,
|
|
3
|
+
// and compressing it first is what keeps a font or a model kit inside a
|
|
4
|
+
// microcontroller's app partition: zlib's deflate packs a 512 KB alpha atlas to
|
|
5
|
+
// ~40 KB and mesh blobs (flat shading triples every vertex) to a third.
|
|
6
|
+
// Encoders are zlib's own (node:zlib deflateRawSync, Python zlib with wbits=-15).
|
|
7
|
+
|
|
8
|
+
const lengthBase = new Uint16Array([3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31, 35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258])
|
|
9
|
+
const lengthExtra = new Uint8Array([0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0])
|
|
10
|
+
const distanceBase = new Uint16Array([
|
|
11
|
+
1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193, 257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145, 8193, 12289, 16385,
|
|
12
|
+
24577
|
|
13
|
+
])
|
|
14
|
+
const distanceExtra = new Uint8Array([0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 13, 13])
|
|
15
|
+
const codeLengthOrder = new Uint8Array([16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15])
|
|
16
|
+
|
|
17
|
+
// The decoder is plain functions over locals and typed arrays, no class: a
|
|
18
|
+
// native build narrows a function's integer locals to machine integers, but a
|
|
19
|
+
// class's number fields stay doubles, and on a core without a double FPU (the
|
|
20
|
+
// ESP32-S31) every bit read through a field was several soft-float calls --
|
|
21
|
+
// inflating a game's asset kit at boot took over 80 seconds.
|
|
22
|
+
|
|
23
|
+
/** Decoder state: read position, bit buffer, bits held, bytes written. */
|
|
24
|
+
const position = 0
|
|
25
|
+
const bitBuffer = 1
|
|
26
|
+
const bitCount = 2
|
|
27
|
+
const written = 3
|
|
28
|
+
|
|
29
|
+
function bits(state: Int32Array, source: Uint8Array, count: number): number {
|
|
30
|
+
let buffer = state[bitBuffer]
|
|
31
|
+
let have = state[bitCount]
|
|
32
|
+
let at = state[position]
|
|
33
|
+
while (have < count) {
|
|
34
|
+
buffer |= source[at] << have
|
|
35
|
+
at += 1
|
|
36
|
+
have += 8
|
|
37
|
+
}
|
|
38
|
+
state[position] = at
|
|
39
|
+
state[bitBuffer] = buffer >>> count
|
|
40
|
+
state[bitCount] = have - count
|
|
41
|
+
return buffer & ((1 << count) - 1)
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* A canonical Huffman code as puff.c keeps it: `counts` (codes per length,
|
|
46
|
+
* 16 entries) and `symbols` (in code order) built from code lengths.
|
|
47
|
+
*/
|
|
48
|
+
function buildHuffman(counts: Uint16Array, symbols: Uint16Array, lengths: Uint8Array, start: number, count: number): void {
|
|
49
|
+
counts.fill(0)
|
|
50
|
+
for (let i = 0; i < count; i++) counts[lengths[start + i]] += 1
|
|
51
|
+
counts[0] = 0
|
|
52
|
+
const offsets = new Uint16Array(16)
|
|
53
|
+
for (let length = 1; length < 15; length++) offsets[length + 1] = offsets[length] + counts[length]
|
|
54
|
+
for (let i = 0; i < count; i++) {
|
|
55
|
+
const length = lengths[start + i]
|
|
56
|
+
if (length !== 0) {
|
|
57
|
+
symbols[offsets[length]] = i
|
|
58
|
+
offsets[length] += 1
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
function decode(state: Int32Array, source: Uint8Array, counts: Uint16Array, symbols: Uint16Array): number {
|
|
64
|
+
let code = 0
|
|
65
|
+
let first = 0
|
|
66
|
+
let index = 0
|
|
67
|
+
for (let length = 1; length < 16; length++) {
|
|
68
|
+
code |= bits(state, source, 1)
|
|
69
|
+
const count = counts[length]
|
|
70
|
+
if (code - first < count) return symbols[index + code - first]
|
|
71
|
+
index += count
|
|
72
|
+
first = (first + count) << 1
|
|
73
|
+
code <<= 1
|
|
74
|
+
}
|
|
75
|
+
throw new Error('inflate: invalid Huffman code')
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
function stored(state: Int32Array, source: Uint8Array, output: Uint8Array): void {
|
|
79
|
+
state[bitBuffer] = 0
|
|
80
|
+
state[bitCount] = 0
|
|
81
|
+
let at = state[position]
|
|
82
|
+
let out = state[written]
|
|
83
|
+
const length = source[at] | (source[at + 1] << 8)
|
|
84
|
+
at += 4
|
|
85
|
+
for (let i = 0; i < length; i++) {
|
|
86
|
+
output[out] = source[at]
|
|
87
|
+
out += 1
|
|
88
|
+
at += 1
|
|
89
|
+
}
|
|
90
|
+
state[position] = at
|
|
91
|
+
state[written] = out
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
function fixedCodes(literalCounts: Uint16Array, literals: Uint16Array, distanceCounts: Uint16Array, distances: Uint16Array): void {
|
|
95
|
+
const lengths = new Uint8Array(320)
|
|
96
|
+
for (let i = 0; i < 144; i++) lengths[i] = 8
|
|
97
|
+
for (let i = 144; i < 256; i++) lengths[i] = 9
|
|
98
|
+
for (let i = 256; i < 280; i++) lengths[i] = 7
|
|
99
|
+
for (let i = 280; i < 288; i++) lengths[i] = 8
|
|
100
|
+
for (let i = 288; i < 320; i++) lengths[i] = 5
|
|
101
|
+
buildHuffman(literalCounts, literals, lengths, 0, 288)
|
|
102
|
+
buildHuffman(distanceCounts, distances, lengths, 288, 30)
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
function dynamicCodes(
|
|
106
|
+
state: Int32Array,
|
|
107
|
+
source: Uint8Array,
|
|
108
|
+
literalCounts: Uint16Array,
|
|
109
|
+
literals: Uint16Array,
|
|
110
|
+
distanceCounts: Uint16Array,
|
|
111
|
+
distances: Uint16Array
|
|
112
|
+
): void {
|
|
113
|
+
const literalCount = bits(state, source, 5) + 257
|
|
114
|
+
const distanceCount = bits(state, source, 5) + 1
|
|
115
|
+
const codeLengthCount = bits(state, source, 4) + 4
|
|
116
|
+
const lengths = new Uint8Array(320)
|
|
117
|
+
for (let i = 0; i < codeLengthCount; i++) lengths[codeLengthOrder[i]] = bits(state, source, 3)
|
|
118
|
+
buildHuffman(literalCounts, literals, lengths, 0, 19)
|
|
119
|
+
lengths.fill(0)
|
|
120
|
+
let index = 0
|
|
121
|
+
while (index < literalCount + distanceCount) {
|
|
122
|
+
const symbol = decode(state, source, literalCounts, literals)
|
|
123
|
+
if (symbol < 16) {
|
|
124
|
+
lengths[index] = symbol
|
|
125
|
+
index += 1
|
|
126
|
+
continue
|
|
127
|
+
}
|
|
128
|
+
let value = 0
|
|
129
|
+
let repeat = 0
|
|
130
|
+
if (symbol === 16) {
|
|
131
|
+
value = lengths[index - 1]
|
|
132
|
+
repeat = 3 + bits(state, source, 2)
|
|
133
|
+
} else if (symbol === 17) {
|
|
134
|
+
repeat = 3 + bits(state, source, 3)
|
|
135
|
+
} else {
|
|
136
|
+
repeat = 11 + bits(state, source, 7)
|
|
137
|
+
}
|
|
138
|
+
for (let i = 0; i < repeat; i++) {
|
|
139
|
+
lengths[index] = value
|
|
140
|
+
index += 1
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
buildHuffman(literalCounts, literals, lengths, 0, literalCount)
|
|
144
|
+
buildHuffman(distanceCounts, distances, lengths, literalCount, distanceCount)
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
function codes(
|
|
148
|
+
state: Int32Array,
|
|
149
|
+
source: Uint8Array,
|
|
150
|
+
output: Uint8Array,
|
|
151
|
+
literalCounts: Uint16Array,
|
|
152
|
+
literals: Uint16Array,
|
|
153
|
+
distanceCounts: Uint16Array,
|
|
154
|
+
distances: Uint16Array
|
|
155
|
+
): void {
|
|
156
|
+
for (;;) {
|
|
157
|
+
const symbol = decode(state, source, literalCounts, literals)
|
|
158
|
+
if (symbol < 256) {
|
|
159
|
+
const out = state[written]
|
|
160
|
+
output[out] = symbol
|
|
161
|
+
state[written] = out + 1
|
|
162
|
+
continue
|
|
163
|
+
}
|
|
164
|
+
if (symbol === 256) return
|
|
165
|
+
const lengthSymbol = symbol - 257
|
|
166
|
+
const length = lengthBase[lengthSymbol] + bits(state, source, lengthExtra[lengthSymbol])
|
|
167
|
+
const distanceSymbol = decode(state, source, distanceCounts, distances)
|
|
168
|
+
const distance = distanceBase[distanceSymbol] + bits(state, source, distanceExtra[distanceSymbol])
|
|
169
|
+
// A match may overlap its own output, so it copies byte by byte.
|
|
170
|
+
let out = state[written]
|
|
171
|
+
let from = out - distance
|
|
172
|
+
for (let i = 0; i < length; i++) {
|
|
173
|
+
output[out] = output[from]
|
|
174
|
+
out += 1
|
|
175
|
+
from += 1
|
|
176
|
+
}
|
|
177
|
+
state[written] = out
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
/** Inflates a raw DEFLATE stream into exactly `length` bytes. */
|
|
182
|
+
export function inflateRaw(source: Uint8Array, length: number): Uint8Array {
|
|
183
|
+
const output = new Uint8Array(length)
|
|
184
|
+
const state = new Int32Array(4)
|
|
185
|
+
const literalCounts = new Uint16Array(16)
|
|
186
|
+
const literals = new Uint16Array(288)
|
|
187
|
+
const distanceCounts = new Uint16Array(16)
|
|
188
|
+
const distances = new Uint16Array(288)
|
|
189
|
+
let last = 0
|
|
190
|
+
while (last === 0) {
|
|
191
|
+
last = bits(state, source, 1)
|
|
192
|
+
const type = bits(state, source, 2)
|
|
193
|
+
if (type === 0) stored(state, source, output)
|
|
194
|
+
else if (type === 1) {
|
|
195
|
+
fixedCodes(literalCounts, literals, distanceCounts, distances)
|
|
196
|
+
codes(state, source, output, literalCounts, literals, distanceCounts, distances)
|
|
197
|
+
} else if (type === 2) {
|
|
198
|
+
dynamicCodes(state, source, literalCounts, literals, distanceCounts, distances)
|
|
199
|
+
codes(state, source, output, literalCounts, literals, distanceCounts, distances)
|
|
200
|
+
} else throw new Error('inflate: invalid block type')
|
|
201
|
+
}
|
|
202
|
+
if (state[written] !== length) throw new Error('inflate: stream length does not match')
|
|
203
|
+
return output
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
function base64Value(code: number): number {
|
|
207
|
+
if (code >= 65 && code <= 90) return code - 65
|
|
208
|
+
if (code >= 97 && code <= 122) return code - 71
|
|
209
|
+
if (code >= 48 && code <= 57) return code + 4
|
|
210
|
+
if (code === 43) return 62
|
|
211
|
+
if (code === 47) return 63
|
|
212
|
+
return 0
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
/**
|
|
216
|
+
* The bytes base64 string chunks spell. Not atob: the native runtime stores
|
|
217
|
+
* strings as UTF-8, so atob's "binary string" would read bytes >= 0x80 back as
|
|
218
|
+
* Unicode through charCodeAt. Every chunk but the last is a multiple of 4.
|
|
219
|
+
*/
|
|
220
|
+
export function base64Bytes(chunks: string[]): Uint8Array {
|
|
221
|
+
let length = 0
|
|
222
|
+
for (let c = 0; c < chunks.length; c++) {
|
|
223
|
+
const chunk = chunks[c]
|
|
224
|
+
length += (chunk.length / 4) * 3
|
|
225
|
+
if (chunk.length > 0 && chunk.charCodeAt(chunk.length - 1) === 61) length -= 1
|
|
226
|
+
if (chunk.length > 1 && chunk.charCodeAt(chunk.length - 2) === 61) length -= 1
|
|
227
|
+
}
|
|
228
|
+
const bytes = new Uint8Array(length)
|
|
229
|
+
let out = 0
|
|
230
|
+
for (let c = 0; c < chunks.length; c++) {
|
|
231
|
+
const chunk = chunks[c]
|
|
232
|
+
for (let i = 0; i < chunk.length; i += 4) {
|
|
233
|
+
const code2 = chunk.charCodeAt(i + 2)
|
|
234
|
+
const code3 = chunk.charCodeAt(i + 3)
|
|
235
|
+
const v0 = base64Value(chunk.charCodeAt(i))
|
|
236
|
+
const v1 = base64Value(chunk.charCodeAt(i + 1))
|
|
237
|
+
const v2 = base64Value(code2)
|
|
238
|
+
const v3 = base64Value(code3)
|
|
239
|
+
bytes[out] = (v0 << 2) | (v1 >> 4)
|
|
240
|
+
out += 1
|
|
241
|
+
if (code2 !== 61) {
|
|
242
|
+
bytes[out] = ((v1 & 15) << 4) | (v2 >> 2)
|
|
243
|
+
out += 1
|
|
244
|
+
}
|
|
245
|
+
if (code3 !== 61) {
|
|
246
|
+
bytes[out] = ((v2 & 3) << 6) | v3
|
|
247
|
+
out += 1
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
return bytes
|
|
252
|
+
}
|
package/src/nativeWebGL.ts
CHANGED
|
@@ -1,3 +1,7 @@
|
|
|
1
|
+
/** @gea-host-inert Reads scalar arguments, writes GL state only; never calls back into script. */
|
|
2
|
+
declare function threeWebGLCopyTexImage2D(target:number,level:number,internalFormat:number,x:number,y:number,width:number,height:number,border:number):void;
|
|
3
|
+
/** @gea-host-inert Reads scalar arguments, writes GL state only; never calls back into script. */
|
|
4
|
+
declare function threeWebGLCopyTexSubImage2D(target:number,level:number,xoffset:number,yoffset:number,x:number,y:number,width:number,height:number):void;
|
|
1
5
|
/// <reference path="./gea-native-types.d.ts" />
|
|
2
6
|
|
|
3
7
|
import {
|
|
@@ -91,6 +95,7 @@ type NativeHandleKind =
|
|
|
91
95
|
| 'program'
|
|
92
96
|
| 'renderbuffer'
|
|
93
97
|
| 'shader'
|
|
98
|
+
| 'sync'
|
|
94
99
|
| 'texture'
|
|
95
100
|
| 'uniform'
|
|
96
101
|
| 'vertexArray'
|
|
@@ -198,6 +203,27 @@ function typedArrayKind(value: BufferSourceLike): number {
|
|
|
198
203
|
return 1
|
|
199
204
|
}
|
|
200
205
|
|
|
206
|
+
/** @gea-host-inert Reads scalar arguments, writes GL state only; never calls back into script. */
|
|
207
|
+
declare function threeWebGLBlitFramebuffer(sx0:number, sy0:number, sx1:number, sy1:number, dx0:number, dy0:number, dx1:number, dy1:number, mask:number, filter:number): void
|
|
208
|
+
/** @gea-host-inert Reads scalar arguments, writes GL state only; never calls back into script. */
|
|
209
|
+
declare function threeWebGLRenderbufferStorageMultisample(target:number, samples:number, format:number, width:number, height:number): void
|
|
210
|
+
type ReadPixelsDestination = Uint8Array | Uint16Array | Float32Array | Uint32Array | Int32Array | Int16Array | Int8Array
|
|
211
|
+
// Mutates the destination view; deliberately not marked host-inert.
|
|
212
|
+
/** @gea-host-typed-array-element-writes Stores pixels into the destination typed array's elements only; no other property of any object, no callbacks. */
|
|
213
|
+
declare function threeWebGLReadPixels(x: number, y: number, width: number, height: number, format: number, type: number, destination: ReadPixelsDestination, offset: number): void
|
|
214
|
+
// WebGL2 asynchronous readback: into the bound PIXEL_PACK_BUFFER, fenced, then read through getBufferSubData.
|
|
215
|
+
/** @gea-host-inert Reads scalar arguments, writes GL state only; never calls back into script. */
|
|
216
|
+
declare function threeWebGLReadPixelsPack(x: number, y: number, width: number, height: number, format: number, type: number, offset: number): void
|
|
217
|
+
/** @gea-host-inert Creates a GL sync object; never calls back into script. */
|
|
218
|
+
declare function threeWebGLFenceSync(): number
|
|
219
|
+
/** @gea-host-inert Reads scalar arguments, waits on GL state only; never calls back into script. */
|
|
220
|
+
declare function threeWebGLClientWaitSync(sync: number, flags: number, timeout: number): number
|
|
221
|
+
/** @gea-host-inert Reads scalar arguments, writes GL state only; never calls back into script. */
|
|
222
|
+
declare function threeWebGLDeleteSync(sync: number): void
|
|
223
|
+
// Mutates the destination view; deliberately not marked host-inert.
|
|
224
|
+
/** @gea-host-typed-array-element-writes Stores buffer bytes into the destination typed array's elements only; no other property of any object, no callbacks. */
|
|
225
|
+
declare function threeWebGLGetBufferSubData(target: number, srcByteOffset: number, destination: ReadPixelsDestination, dstOffset: number, length: number): void
|
|
226
|
+
|
|
201
227
|
function zeroF32Array(length: number): f32[] {
|
|
202
228
|
const out: f32[] = []
|
|
203
229
|
for (let index = 0; index < length; index++) out.push(0 as f32)
|
|
@@ -246,6 +272,14 @@ declare function threeWebGLTexImage2D(target: number, level: number, internalFor
|
|
|
246
272
|
declare function threeWebGLTexSubImage2D(target: number, level: number, xoffset: number, yoffset: number, width: number, height: number, format: number, type: number, values: BufferSourceLike): void
|
|
247
273
|
/** @gea-host-inert Reads its arguments, writes GL state only; never calls back into script. */
|
|
248
274
|
declare function threeWebGLTexStorage2D(target: number, levels: number, internalFormat: number, width: number, height: number): void
|
|
275
|
+
/** @gea-host-inert Reads its arguments, writes GL state only; never calls back into script. */
|
|
276
|
+
declare function threeWebGLTexImage3D(target: number, level: number, internalFormat: number, width: number, height: number, depth: number, format: number, type: number, values: BufferSourceLike): void
|
|
277
|
+
/** @gea-host-inert Reads its arguments, writes GL state only; never calls back into script. */
|
|
278
|
+
declare function threeWebGLTexSubImage3D(target: number, level: number, xoffset: number, yoffset: number, zoffset: number, width: number, height: number, depth: number, format: number, type: number, values: BufferSourceLike): void
|
|
279
|
+
/** @gea-host-inert Reads its arguments, writes GL state only; never calls back into script. */
|
|
280
|
+
declare function threeWebGLTexStorage3D(target: number, levels: number, internalFormat: number, width: number, height: number, depth: number): void
|
|
281
|
+
/** @gea-host-inert Reads its arguments, writes GL state only; never calls back into script. */
|
|
282
|
+
declare function threeWebGLFramebufferTextureLayer(target: number, attachment: number, texture: number, level: number, layer: number): void
|
|
249
283
|
|
|
250
284
|
// Shader source keyed by the stable native GL handle. A NativeShader instance
|
|
251
285
|
// can be value-copied when it round-trips through a function-return / gcv
|
|
@@ -303,6 +337,9 @@ export interface NativeWebGLContextAttributes {
|
|
|
303
337
|
failIfMajorPerformanceCaveat: boolean
|
|
304
338
|
}
|
|
305
339
|
|
|
340
|
+
// Decoded image boundary. A native host never pretends DOM images have pixels.
|
|
341
|
+
export interface NativeTextureImage { width: number; height: number; data: BufferSourceLike }
|
|
342
|
+
|
|
306
343
|
export class NativeWebGLCanvas {
|
|
307
344
|
width: number
|
|
308
345
|
height: number
|
|
@@ -652,6 +689,10 @@ export class NativeWebGL2RenderingContext {
|
|
|
652
689
|
readonly TIMEOUT_EXPIRED = 0x911B
|
|
653
690
|
readonly CONDITION_SATISFIED = 0x911C
|
|
654
691
|
readonly WAIT_FAILED = 0x911D
|
|
692
|
+
readonly SYNC_GPU_COMMANDS_COMPLETE = 0x9117
|
|
693
|
+
readonly PIXEL_PACK_BUFFER = 0x88EB
|
|
694
|
+
readonly PIXEL_PACK_BUFFER_BINDING = 0x88ED
|
|
695
|
+
readonly STREAM_READ = 0x88E1
|
|
655
696
|
readonly COLOR = 0x1800
|
|
656
697
|
readonly DEPTH_COMPONENT = 0x1902
|
|
657
698
|
readonly ALPHA = 0x1906
|
|
@@ -924,11 +965,14 @@ export class NativeWebGL2RenderingContext {
|
|
|
924
965
|
if (name === this.MAX_RENDERBUFFER_SIZE || name === this.MAX_3D_TEXTURE_SIZE) return 16384
|
|
925
966
|
if (name === this.MAX_ARRAY_TEXTURE_LAYERS) return 2048
|
|
926
967
|
if (name === this.MAX_VERTEX_ATTRIBS) return 16
|
|
927
|
-
|
|
968
|
+
// threejs-rendozer binds up to 32 textures per program (both stages); three checks a program's total against this.
|
|
969
|
+
if (name === this.MAX_TEXTURE_IMAGE_UNITS || name === this.MAX_VERTEX_TEXTURE_IMAGE_UNITS) return 32
|
|
928
970
|
if (name === this.MAX_COMBINED_TEXTURE_IMAGE_UNITS) return 32
|
|
929
971
|
if (name === this.MAX_VERTEX_UNIFORM_VECTORS || name === this.MAX_FRAGMENT_UNIFORM_VECTORS) return 1024
|
|
930
972
|
if (name === this.MAX_VARYING_VECTORS) return 32
|
|
931
|
-
|
|
973
|
+
// threejs-rendozer reports 8 when every multisampled renderbuffer format supports it (and steps down per format).
|
|
974
|
+
if (name === this.MAX_SAMPLES) return 8
|
|
975
|
+
if (name === this.SAMPLES) return 4
|
|
932
976
|
if (name === this.MAX_UNIFORM_BUFFER_BINDINGS) return 24
|
|
933
977
|
if (name === this.DEPTH_BITS) return 24
|
|
934
978
|
if (name === this.STENCIL_BITS) return 8
|
|
@@ -1092,9 +1136,13 @@ export class NativeWebGL2RenderingContext {
|
|
|
1092
1136
|
texParameterf(target: number, pname: number, param: number): void { nativeWebGLTexParameteri(target, pname, param) }
|
|
1093
1137
|
pixelStorei(pname: number, param: number | boolean): void { nativeWebGLPixelStorei(pname, param === true ? 1 : param === false ? 0 : param) }
|
|
1094
1138
|
generateMipmap(target: number): void { nativeWebGLGenerateMipmap(target) }
|
|
1095
|
-
texImage2D(target: number, level: number, internalFormat: number, widthOrFormat: number, heightOrType: number, borderOrSource?: number |
|
|
1139
|
+
texImage2D(target: number, level: number, internalFormat: number, widthOrFormat: number, heightOrType: number, borderOrSource?: number | NativeTextureImage | null, format?: number, type?: number, pixels?: BufferSourceLike | null): void {
|
|
1096
1140
|
if (typeof borderOrSource === 'number' && typeof format === 'number' && typeof type === 'number') {
|
|
1097
|
-
threeWebGLTexImage2D(target, level, internalFormat, widthOrFormat, heightOrType, format, type, pixels
|
|
1141
|
+
threeWebGLTexImage2D(target, level, internalFormat, widthOrFormat, heightOrType, format, type, pixels ?? new Uint8Array(0))
|
|
1142
|
+
} else if (borderOrSource !== null && borderOrSource !== undefined && typeof borderOrSource !== 'number') {
|
|
1143
|
+
threeWebGLTexImage2D(target, level, internalFormat, borderOrSource.width, borderOrSource.height, widthOrFormat, heightOrType, borderOrSource.data)
|
|
1144
|
+
} else {
|
|
1145
|
+
throw new Error(`Native texImage2D requires dimensions and typed pixels, or a decoded NativeTextureImage (target ${target}, level ${level}, internal format ${internalFormat}, source ${borderOrSource === null ? 'null' : typeof borderOrSource})`)
|
|
1098
1146
|
}
|
|
1099
1147
|
}
|
|
1100
1148
|
texSubImage2D(target: number, level: number, xoffset: number, yoffset: number, width: number, height: number, format: number, type: number, pixels: BufferSourceLike): void {
|
|
@@ -1110,9 +1158,15 @@ export class NativeWebGL2RenderingContext {
|
|
|
1110
1158
|
// Three uploads 3D and array textures only from typed `image.data` /
|
|
1111
1159
|
// `mipmap.data` (or `null` to allocate), the same carrier the 2D uploads
|
|
1112
1160
|
// take; no TexImageSource ever reaches these entry points.
|
|
1113
|
-
texImage3D(
|
|
1114
|
-
|
|
1115
|
-
|
|
1161
|
+
texImage3D(target: number, level: number, internalFormat: number, width: number, height: number, depth: number, _border: number, format: number, type: number, source: BufferSourceLike | null): void {
|
|
1162
|
+
threeWebGLTexImage3D(target, level, internalFormat, width, height, depth, format, type, source ?? new Uint8Array(0))
|
|
1163
|
+
}
|
|
1164
|
+
texSubImage3D(target: number, level: number, xoffset: number, yoffset: number, zoffset: number, width: number, height: number, depth: number, format: number, type: number, source: BufferSourceLike): void {
|
|
1165
|
+
threeWebGLTexSubImage3D(target, level, xoffset, yoffset, zoffset, width, height, depth, format, type, source)
|
|
1166
|
+
}
|
|
1167
|
+
texStorage3D(target: number, levels: number, internalFormat: number, width: number, height: number, depth: number): void {
|
|
1168
|
+
threeWebGLTexStorage3D(target, levels, internalFormat, width, height, depth)
|
|
1169
|
+
}
|
|
1116
1170
|
|
|
1117
1171
|
createVertexArray(): NativeHandle { return createHandle('vertexArray', nativeWebGLCreateVertexArray()) }
|
|
1118
1172
|
bindVertexArray(vertexArray: NativeHandle | null): void { nativeWebGLBindVertexArray(nullableNativeHandle(vertexArray)) }
|
|
@@ -1130,12 +1184,14 @@ export class NativeWebGL2RenderingContext {
|
|
|
1130
1184
|
deleteRenderbuffer(renderbuffer: NativeHandle | null): void { nativeWebGLDeleteRenderbuffer(nullableNativeHandle(renderbuffer)) }
|
|
1131
1185
|
renderbufferStorage(target: number, internalFormat: number, width: number, height: number): void { nativeWebGLRenderbufferStorage(target, internalFormat, width, height) }
|
|
1132
1186
|
renderbufferStorageMultisample(target: number, samples: number, internalFormat: number, width: number, height: number): void {
|
|
1133
|
-
|
|
1187
|
+
threeWebGLRenderbufferStorageMultisample(target, samples, internalFormat, width, height)
|
|
1134
1188
|
}
|
|
1135
1189
|
framebufferRenderbuffer(target: number, attachment: number, renderbuffertarget: number, renderbuffer: NativeHandle | null): void {
|
|
1136
1190
|
nativeWebGLFramebufferRenderbuffer(target, attachment, renderbuffertarget, nullableNativeHandle(renderbuffer))
|
|
1137
1191
|
}
|
|
1138
|
-
framebufferTextureLayer(
|
|
1192
|
+
framebufferTextureLayer(target: number, attachment: number, texture: NativeHandle | null, level: number, layer: number): void {
|
|
1193
|
+
threeWebGLFramebufferTextureLayer(target, attachment, nullableNativeHandle(texture), level, layer)
|
|
1194
|
+
}
|
|
1139
1195
|
drawBuffers(buffers: number[]): void { nativeWebGLDrawBuffers(buffers[0] ?? this.COLOR_ATTACHMENT0) }
|
|
1140
1196
|
|
|
1141
1197
|
clearColor(r: number, g: number, b: number, a: number): void { nativeWebGLClearColor(r, g, b, a) }
|
|
@@ -1176,16 +1232,26 @@ export class NativeWebGL2RenderingContext {
|
|
|
1176
1232
|
flush(): void {}
|
|
1177
1233
|
hint(_target: number, _mode: number): void {}
|
|
1178
1234
|
invalidateFramebuffer(_target: number, _attachments: BufferSourceLike): void {}
|
|
1179
|
-
blitFramebuffer(
|
|
1235
|
+
blitFramebuffer(sx0:number, sy0:number, sx1:number, sy1:number, dx0:number, dy0:number, dx1:number, dy1:number, mask:number, filter:number): void { threeWebGLBlitFramebuffer(sx0,sy0,sx1,sy1,dx0,dy0,dx1,dy1,mask,filter) }
|
|
1180
1236
|
readBuffer(_src: number): void {}
|
|
1181
|
-
|
|
1182
|
-
|
|
1183
|
-
|
|
1237
|
+
// WebGL2 also reads into the bound PIXEL_PACK_BUFFER at a byte offset (three's
|
|
1238
|
+
// readRenderTargetPixelsAsync): the GPU copy is recorded without waiting for the GPU.
|
|
1239
|
+
readPixels(x: number, y: number, width: number, height: number, format: number, type: number, destination: ReadPixelsDestination | number, offset = 0): void {
|
|
1240
|
+
if (typeof destination === 'number') {
|
|
1241
|
+
threeWebGLReadPixelsPack(x, y, width, height, format, type, destination)
|
|
1242
|
+
return
|
|
1243
|
+
}
|
|
1244
|
+
threeWebGLReadPixels(x, y, width, height, format, type, destination, offset)
|
|
1245
|
+
}
|
|
1246
|
+
copyTexImage2D(target: number, level: number, internalFormat: number, x: number, y: number, width: number, height: number, border: number): void {threeWebGLCopyTexImage2D(target,level,internalFormat,x,y,width,height,border);}
|
|
1247
|
+
copyTexSubImage2D(target: number, level: number, xoffset: number, yoffset: number, x: number, y: number, width: number, height: number): void {threeWebGLCopyTexSubImage2D(target,level,xoffset,yoffset,x,y,width,height);}
|
|
1184
1248
|
copyTexSubImage3D(_target: number, _level: number, _xoffset: number, _yoffset: number, _zoffset: number, _x: number, _y: number, _width: number, _height: number): void {}
|
|
1185
1249
|
clearBufferiv(_buffer: number, _drawbuffer: number, _values: BufferSourceLike): void {}
|
|
1186
1250
|
clearBufferuiv(_buffer: number, _drawbuffer: number, _values: BufferSourceLike): void {}
|
|
1187
1251
|
getBufferParameter(_target: number, _pname: number): number { return 0 }
|
|
1188
|
-
getBufferSubData(
|
|
1252
|
+
getBufferSubData(target: number, srcByteOffset: number, destination: ReadPixelsDestination, dstOffset = 0, length = 0): void {
|
|
1253
|
+
threeWebGLGetBufferSubData(target, srcByteOffset, destination, dstOffset, length)
|
|
1254
|
+
}
|
|
1189
1255
|
getFramebufferAttachmentParameter(_target: number, _attachment: number, _pname: number): number { return 0 }
|
|
1190
1256
|
getRenderbufferParameter(_target: number, _pname: number): number { return 0 }
|
|
1191
1257
|
getTexParameter(_target: number, _pname: number): number { return 0 }
|
|
@@ -1196,9 +1262,14 @@ export class NativeWebGL2RenderingContext {
|
|
|
1196
1262
|
uniformBlockBinding(_program: NativeProgram | null, _uniformBlockIndex: number, _uniformBlockBinding: number): void {}
|
|
1197
1263
|
bindBufferBase(_target: number, _index: number, _buffer: NativeHandle | null): void {}
|
|
1198
1264
|
bindBufferRange(_target: number, _index: number, _buffer: NativeHandle | null, _offset: number, _size: number): void {}
|
|
1199
|
-
fenceSync(_condition: number, _flags: number):
|
|
1200
|
-
|
|
1201
|
-
|
|
1265
|
+
fenceSync(_condition: number, _flags: number): NativeHandle | null {
|
|
1266
|
+
const sync = threeWebGLFenceSync()
|
|
1267
|
+
return sync ? createHandle('sync', sync) : null
|
|
1268
|
+
}
|
|
1269
|
+
clientWaitSync(sync: NativeHandle | null, flags: number, timeout: number): number {
|
|
1270
|
+
return sync ? threeWebGLClientWaitSync(nativeHandle(sync), flags, timeout) : this.WAIT_FAILED
|
|
1271
|
+
}
|
|
1272
|
+
deleteSync(sync: NativeHandle | null): void { if (sync) threeWebGLDeleteSync(nativeHandle(sync)) }
|
|
1202
1273
|
isBuffer(_buffer: NativeHandle | null): boolean { return true }
|
|
1203
1274
|
isFramebuffer(_framebuffer: NativeHandle | null): boolean { return true }
|
|
1204
1275
|
isProgram(_program: NativeProgram | null): boolean { return true }
|
package/src/nativeWebGLHost.ts
CHANGED
|
@@ -35,6 +35,25 @@ export function nativeWebGLSwap(): void {
|
|
|
35
35
|
threeWebGLSwap()
|
|
36
36
|
}
|
|
37
37
|
|
|
38
|
+
// GPU time-elapsed timers (GL_EXT_disjoint_timer_query): begin returns a timer id (0 when
|
|
39
|
+
// unsupported), end closes the open timer, and result is the elapsed nanoseconds, or -1 while the
|
|
40
|
+
// GPU has not finished it. A timer is released once its result has been read.
|
|
41
|
+
export function nativeWebGLTimerBegin(): number {
|
|
42
|
+
return threeWebGLTimerBegin()
|
|
43
|
+
}
|
|
44
|
+
export function nativeWebGLTimerEnd(): void {
|
|
45
|
+
threeWebGLTimerEnd()
|
|
46
|
+
}
|
|
47
|
+
export function nativeWebGLTimerResult(timer: number): number {
|
|
48
|
+
return threeWebGLTimerResult(timer)
|
|
49
|
+
}
|
|
50
|
+
/** @gea-host-inert Native state only; retains no script references and invokes no script. */
|
|
51
|
+
declare function threeWebGLTimerBegin(): number
|
|
52
|
+
/** @gea-host-inert Native state only; retains no script references and invokes no script. */
|
|
53
|
+
declare function threeWebGLTimerEnd(): void
|
|
54
|
+
/** @gea-host-inert Native state only; retains no script references and invokes no script. */
|
|
55
|
+
declare function threeWebGLTimerResult(timer: number): number
|
|
56
|
+
|
|
38
57
|
export function logNativeWebGL(message: string): void {
|
|
39
58
|
threeAngleSmokeLog(message)
|
|
40
59
|
}
|
|
@@ -148,9 +167,16 @@ export function nativeWebGLDrawElements(mode: number, count: number, type: numbe
|
|
|
148
167
|
export function nativeWebGLDrawArrays(mode: number, first: number, count: number): void { threeWebGLDrawArrays(mode, first, count) }
|
|
149
168
|
export function nativeWebGLGetError(): number { return threeWebGLGetError() }
|
|
150
169
|
|
|
151
|
-
/**
|
|
170
|
+
/**
|
|
171
|
+
* Lifecycle entry: retains/uses the host view and installs native monitors; not an inert call.
|
|
172
|
+
* It writes no property on any script object, which is the narrower contract.
|
|
173
|
+
* @gea-host-no-property-writes
|
|
174
|
+
*/
|
|
152
175
|
declare function threeWebGLAttach(view: NSView, width: number, height: number, devicePixelRatio: number): boolean
|
|
153
|
-
/**
|
|
176
|
+
/**
|
|
177
|
+
* Lifecycle entry: synchronizes host layout and viewport state; keep outside the inert contract.
|
|
178
|
+
* @gea-host-no-property-writes
|
|
179
|
+
*/
|
|
154
180
|
declare function threeWebGLSyncSize(fallbackAspect: number): number
|
|
155
181
|
/** @gea-host-inert Native state only; retains no script references and invokes no script. */
|
|
156
182
|
declare function threeWebGLWidth(): number
|