@zephyr3d/device 0.2.1 → 0.2.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -1,6 +1,6 @@
1
1
  export { DeviceGPUObjectAddedEvent, DeviceGPUObjectRemovedEvent, DeviceGPUObjectRenameEvent, DeviceLostEvent, DeviceResizeEvent, DeviceRestoreEvent, ShaderType, encodePixel, encodePixelToArray, getTextureFormatBlockHeight, getTextureFormatBlockSize, getTextureFormatBlockWidth, hasAlphaChannel, hasBlueChannel, hasDepthChannel, hasGreenChannel, hasRedChannel, hasStencilChannel, isCompressedTextureFormat, isFloatTextureFormat, isIntegerTextureFormat, isSRGBTextureFormat, isSignedTextureFormat, linearTextureFormatToSRGB } from './base_types.js';
2
2
  export { VertexData } from './vertexdata.js';
3
- export { GPUResourceUsageFlags, MAX_BINDING_GROUPS, MAX_TEXCOORD_INDEX_COUNT, MAX_VERTEX_ATTRIBUTES, VERTEX_ATTRIB_BLEND_INDICES, VERTEX_ATTRIB_BLEND_WEIGHT, VERTEX_ATTRIB_DIFFUSE, VERTEX_ATTRIB_NORMAL, VERTEX_ATTRIB_POSITION, VERTEX_ATTRIB_TANGENT, VERTEX_ATTRIB_TEXCOORD0, VERTEX_ATTRIB_TEXCOORD1, VERTEX_ATTRIB_TEXCOORD2, VERTEX_ATTRIB_TEXCOORD3, VERTEX_ATTRIB_TEXCOORD4, VERTEX_ATTRIB_TEXCOORD5, VERTEX_ATTRIB_TEXCOORD6, VERTEX_ATTRIB_TEXCOORD7, genDefaultName, getVertexAttribByName, getVertexAttribFormat, getVertexAttribName, getVertexBufferAttribType, getVertexBufferAttribTypeBySemantic, getVertexBufferLength, getVertexBufferStride, getVertexFormatSize, makeVertexBufferType, semanticList, semanticToAttrib } from './gpuobject.js';
3
+ export { GPUResourceUsageFlags, MAX_BINDING_GROUPS, MAX_TEXCOORD_INDEX_COUNT, MAX_VERTEX_ATTRIBUTES, VERTEX_ATTRIB_BLEND_INDICES, VERTEX_ATTRIB_BLEND_WEIGHT, VERTEX_ATTRIB_DIFFUSE, VERTEX_ATTRIB_NORMAL, VERTEX_ATTRIB_POSITION, VERTEX_ATTRIB_TANGENT, VERTEX_ATTRIB_TEXCOORD0, VERTEX_ATTRIB_TEXCOORD1, VERTEX_ATTRIB_TEXCOORD2, VERTEX_ATTRIB_TEXCOORD3, VERTEX_ATTRIB_TEXCOORD4, VERTEX_ATTRIB_TEXCOORD5, VERTEX_ATTRIB_TEXCOORD6, VERTEX_ATTRIB_TEXCOORD7, genDefaultName, getVertexAttribByName, getVertexAttribFormat, getVertexAttribName, getVertexBufferAttribType, getVertexBufferAttribTypeBySemantic, getVertexBufferLength, getVertexBufferStride, getVertexFormatComponentCount, getVertexFormatSize, makeVertexBufferType, semanticList, semanticToAttrib } from './gpuobject.js';
4
4
  export { BaseDevice } from './device.js';
5
5
  export { PBShaderExp, Proxiable, getCurrentProgramBuilder, makeConstructor, setCurrentProgramBuilder } from './builder/base.js';
6
6
  export { ASTAddressOf, ASTArrayIndex, ASTAssignment, ASTBinaryFunc, ASTBreak, ASTCallFunction, ASTCast, ASTContinue, ASTDeclareVar, ASTDiscard, ASTDoWhile, ASTExpression, ASTFunction, ASTFunctionParameter, ASTGlobalScope, ASTHash, ASTIf, ASTLValue, ASTLValueArray, ASTLValueDeclare, ASTLValueHash, ASTLValueScalar, ASTNakedScope, ASTPrimitive, ASTRange, ASTReferenceOf, ASTReturn, ASTScalar, ASTScope, ASTSelect, ASTShaderExpConstructor, ASTStructDefine, ASTTouch, ASTUnaryFunc, ASTWhile, DeclareType, ShaderAST, ShaderPrecisionType, builtinVariables, genSamplerName, getBuiltinInputStructInstanceName, getBuiltinInputStructName, getBuiltinOutputStructInstanceName, getBuiltinOutputStructName, getBuiltinParamName, getTextureSampleType } from './builder/ast.js';
package/dist/pool.js ADDED
@@ -0,0 +1,324 @@
1
+ /**
2
+ * ObjectPool class is responsible for managing and reusing textures and framebuffers.
3
+ * @public
4
+ */ class Pool {
5
+ /** @internal */ _memCost;
6
+ /** @internal */ _memCostThreshold;
7
+ /** @internal */ _device;
8
+ /** @internal */ _freeTextures = {};
9
+ /** @internal */ _allocatedTextures = new WeakMap();
10
+ /** @internal */ _autoReleaseTextures = new Set();
11
+ /** @internal */ _freeFramebuffers = {};
12
+ /** @internal */ _allocatedFramebuffers = new WeakMap();
13
+ /** @internal */ _autoReleaseFramebuffers = new Set();
14
+ /**
15
+ * Creates an instance of Pool class
16
+ * @param device - Rendering device
17
+ */ constructor(device, memCostThreshold = 1024 * 1024 * 1024){
18
+ this._device = device;
19
+ this._memCost = 0;
20
+ this._memCostThreshold = memCostThreshold;
21
+ this._freeTextures = {};
22
+ this._allocatedTextures = new WeakMap();
23
+ this._autoReleaseTextures = new Set();
24
+ this._freeFramebuffers = {};
25
+ this._allocatedFramebuffers = new WeakMap();
26
+ this._autoReleaseFramebuffers = new Set();
27
+ this._memCost = 0;
28
+ }
29
+ autoRelease() {
30
+ // auto release objects
31
+ for (const tex of this._autoReleaseTextures){
32
+ this.releaseTexture(tex);
33
+ }
34
+ this._autoReleaseTextures.clear();
35
+ for (const fb of this._autoReleaseFramebuffers){
36
+ this.releaseFrameBuffer(fb);
37
+ }
38
+ this._autoReleaseFramebuffers.clear();
39
+ // Free up video memory if memory usage is greater than specific value
40
+ if (this._memCost >= this._memCostThreshold) {
41
+ this.purge();
42
+ }
43
+ }
44
+ /**
45
+ * Fetch a temporal 2D texture from the object pool.
46
+ * @param autoRelease - Whether the texture should be automatically released at the next frame.
47
+ * @param format - The format of the texture.
48
+ * @param width - The width of the texture.
49
+ * @param height - The height of the texture.
50
+ * @param mipmapping - Whether this texture support mipmapping
51
+ * @returns The fetched Texture2D object.
52
+ */ fetchTemporalTexture2D(autoRelease, format, width, height, mipmapping) {
53
+ const hash = `2d:${format}:${width}:${height}:${mipmapping ? 1 : 0}`;
54
+ let texture = null;
55
+ const list = this._freeTextures[hash];
56
+ if (!list) {
57
+ texture = this._device.createTexture2D(format, width, height, mipmapping ? {} : {
58
+ samplerOptions: {
59
+ mipFilter: 'none'
60
+ }
61
+ });
62
+ this._memCost += texture.memCost;
63
+ } else {
64
+ texture = list.pop();
65
+ if (list.length === 0) {
66
+ delete this._freeTextures[hash];
67
+ }
68
+ }
69
+ this._allocatedTextures.set(texture, {
70
+ hash,
71
+ refcount: 1,
72
+ dispose: false
73
+ });
74
+ if (autoRelease) {
75
+ this._autoReleaseTextures.add(texture);
76
+ }
77
+ return texture;
78
+ }
79
+ /**
80
+ * Fetch a temporal 2D array texture from the object pool.
81
+ * @param autoRelease - Whether the texture should be automatically released at the next frame.
82
+ * @param format - Format of the texture.
83
+ * @param width - Width of the texture.
84
+ * @param height - Height of the texture.
85
+ * @param numLayers - Layer count of the texture
86
+ * @param mipmapping - Whether this texture support mipmapping
87
+ * @returns The fetched Texture2DArray object.
88
+ */ fetchTemporalTexture2DArray(autoRelease, format, width, height, numLayers, mipmapping) {
89
+ const hash = `2darray:${format}:${width}:${height}:${numLayers}:${mipmapping ? 1 : 0}`;
90
+ let texture = null;
91
+ const list = this._freeTextures[hash];
92
+ if (!list) {
93
+ texture = this._device.createTexture2DArray(format, width, height, numLayers, mipmapping ? {} : {
94
+ samplerOptions: {
95
+ mipFilter: 'none'
96
+ }
97
+ });
98
+ this._memCost += texture.memCost;
99
+ } else {
100
+ texture = list.pop();
101
+ if (list.length === 0) {
102
+ delete this._freeTextures[hash];
103
+ }
104
+ }
105
+ this._allocatedTextures.set(texture, {
106
+ hash,
107
+ refcount: 1,
108
+ dispose: false
109
+ });
110
+ if (autoRelease) {
111
+ this._autoReleaseTextures.add(texture);
112
+ }
113
+ return texture;
114
+ }
115
+ /**
116
+ * Fetch a temporal Cube texture from the object pool.
117
+ * @param autoRelease - Whether the texture should be automatically released at the next frame.
118
+ * @param format - Format of the texture.
119
+ * @param size - size of the texture.
120
+ * @param mipmapping - Whether this texture support mipmapping
121
+ * @returns The fetched TextureCube object.
122
+ */ fetchTemporalTextureCube(autoRelease, format, size, mipmapping) {
123
+ const hash = `cube:${format}:${size}:${mipmapping ? 1 : 0}`;
124
+ let texture = null;
125
+ const list = this._freeTextures[hash];
126
+ if (!list) {
127
+ texture = this._device.createCubeTexture(format, size, mipmapping ? {} : {
128
+ samplerOptions: {
129
+ mipFilter: 'none'
130
+ }
131
+ });
132
+ this._memCost += texture.memCost;
133
+ } else {
134
+ texture = list.pop();
135
+ if (list.length === 0) {
136
+ delete this._freeTextures[hash];
137
+ }
138
+ }
139
+ this._allocatedTextures.set(texture, {
140
+ hash,
141
+ refcount: 1,
142
+ dispose: false
143
+ });
144
+ if (autoRelease) {
145
+ this._autoReleaseTextures.add(texture);
146
+ }
147
+ return texture;
148
+ }
149
+ fetchTemporalFramebuffer(autoRelease, width, height, colorTexOrFormat, depthTexOrFormat, mipmapping, sampleCount, ignoreDepthStencil) {
150
+ const colorAttachments = typeof colorTexOrFormat === 'string' ? [
151
+ this.fetchTemporalTexture2D(false, colorTexOrFormat, width, height, mipmapping)
152
+ ] : colorTexOrFormat ? [
153
+ colorTexOrFormat
154
+ ] : null;
155
+ const depthAttachment = typeof depthTexOrFormat === 'string' ? this.fetchTemporalTexture2D(false, depthTexOrFormat, width, height, false) : depthTexOrFormat;
156
+ const fb = this.createTemporalFramebuffer(autoRelease, colorAttachments, depthAttachment, sampleCount, ignoreDepthStencil);
157
+ if (typeof colorTexOrFormat === 'string') {
158
+ this.releaseTexture(colorAttachments[0]);
159
+ }
160
+ if (typeof depthTexOrFormat === 'string') {
161
+ this.releaseTexture(depthAttachment);
162
+ }
163
+ return fb;
164
+ }
165
+ /**
166
+ * Creates a temporal framebuffer from the object pool.
167
+ * @param autoRelease - Whether the framebuffer should be automatically released at the next frame.
168
+ * @param colorAttachments - Array of color attachments for the framebuffer.
169
+ * @param depthAttachment - Depth attachment for the framebuffer.
170
+ * @param sampleCount - The sample count for the framebuffer.
171
+ * @param ignoreDepthStencil - Whether to ignore depth stencil.
172
+ * @returns The fetched FrameBuffer object.
173
+ */ createTemporalFramebuffer(autoRelease, colorAttachments, depthAttachment, sampleCount, ignoreDepthStencil) {
174
+ colorAttachments = colorAttachments ?? [];
175
+ let hash = `${depthAttachment?.uid ?? 0}:${sampleCount ?? 1}:${ignoreDepthStencil ? 1 : 0}`;
176
+ for (const tex of colorAttachments){
177
+ hash += `:${tex.uid}`;
178
+ }
179
+ let fb = null;
180
+ const list = this._freeFramebuffers[hash];
181
+ if (!list) {
182
+ fb = this._device.createFrameBuffer(colorAttachments, depthAttachment, {
183
+ ignoreDepthStencil,
184
+ sampleCount
185
+ });
186
+ } else {
187
+ fb = list.pop();
188
+ if (list.length === 0) {
189
+ delete this._freeFramebuffers[hash];
190
+ }
191
+ }
192
+ // Mark referenced textures
193
+ const info = this._allocatedTextures.get(depthAttachment);
194
+ if (info) {
195
+ info.refcount++;
196
+ }
197
+ for (const tex of colorAttachments){
198
+ const info = this._allocatedTextures.get(tex);
199
+ if (info) {
200
+ info.refcount++;
201
+ }
202
+ }
203
+ this._allocatedFramebuffers.set(fb, hash);
204
+ if (autoRelease) {
205
+ this._autoReleaseFramebuffers.add(fb);
206
+ }
207
+ return fb;
208
+ }
209
+ /**
210
+ * Dispose a texture that is allocated from the object pool.
211
+ * @param texture - The texture to dispose.
212
+ */ disposeTexture(texture) {
213
+ this.safeReleaseTexture(texture, true);
214
+ }
215
+ /**
216
+ * Release a texture back to the object pool.
217
+ * @param texture - The texture to release.
218
+ */ releaseTexture(texture) {
219
+ const info = this._allocatedTextures.get(texture);
220
+ if (!info) {
221
+ console.error(`ObjectPool.releaseTexture(): texture is not allocated from pool`);
222
+ } else {
223
+ this.safeReleaseTexture(texture);
224
+ }
225
+ }
226
+ /**
227
+ * Dispose a framebuffer that is allocated from the object pool.
228
+ * @param fb - The framebuffer to dispose.
229
+ */ disposeFrameBuffer(fb) {
230
+ const hash = this._allocatedFramebuffers.get(fb);
231
+ if (!hash) {
232
+ console.error(`ObjectPool.disposeFrameBuffer(): framebuffer is not allocated from pool`);
233
+ } else {
234
+ this.internalDisposeFrameBuffer(fb);
235
+ fb.dispose();
236
+ }
237
+ }
238
+ /**
239
+ * Release a framebuffer back to the object pool.
240
+ * @param fb - The framebuffer to release.
241
+ */ releaseFrameBuffer(fb) {
242
+ const hash = this._allocatedFramebuffers.get(fb);
243
+ if (!hash) {
244
+ console.error(`ObjectPool.releaseFrameBuffer(): framebuffer is not allocated from pool`);
245
+ } else {
246
+ this.internalDisposeFrameBuffer(fb);
247
+ const list = this._freeFramebuffers[hash];
248
+ if (list) {
249
+ list.push(fb);
250
+ } else {
251
+ this._freeFramebuffers[hash] = [
252
+ fb
253
+ ];
254
+ }
255
+ }
256
+ }
257
+ /**
258
+ * Purge the object pool by disposing all free framebuffers and textures.
259
+ */ purge() {
260
+ for(const k in this._freeFramebuffers){
261
+ const list = this._freeFramebuffers[k];
262
+ if (list) {
263
+ for (const fb of this._freeFramebuffers[k]){
264
+ this.internalDisposeFrameBuffer(fb);
265
+ fb.dispose();
266
+ }
267
+ }
268
+ }
269
+ this._freeFramebuffers = {};
270
+ for(const k in this._freeTextures){
271
+ const list = this._freeTextures[k];
272
+ for (const tex of list){
273
+ this._memCost -= tex.memCost;
274
+ tex.dispose();
275
+ }
276
+ }
277
+ this._freeTextures = {};
278
+ }
279
+ /** @internal */ internalDisposeFrameBuffer(fb) {
280
+ if (fb) {
281
+ // Release attachment textures
282
+ const colorAttachments = fb.getColorAttachments();
283
+ if (colorAttachments) {
284
+ for (const tex of colorAttachments){
285
+ this.safeReleaseTexture(tex);
286
+ }
287
+ }
288
+ const depthAttachment = fb.getDepthAttachment();
289
+ if (depthAttachment) {
290
+ this.safeReleaseTexture(depthAttachment);
291
+ }
292
+ this._allocatedFramebuffers.delete(fb);
293
+ this._autoReleaseFramebuffers.delete(fb);
294
+ }
295
+ }
296
+ /** @internal */ safeReleaseTexture(texture, purge = false) {
297
+ const info = this._allocatedTextures.get(texture);
298
+ if (info) {
299
+ info.refcount--;
300
+ if (info.refcount === 0) {
301
+ this._allocatedTextures.delete(texture);
302
+ this._autoReleaseTextures.delete(texture);
303
+ if (purge || info.dispose) {
304
+ this._memCost -= texture.memCost;
305
+ texture.dispose();
306
+ } else {
307
+ const list = this._freeTextures[info.hash];
308
+ if (list) {
309
+ list.push(texture);
310
+ } else {
311
+ this._freeTextures[info.hash] = [
312
+ texture
313
+ ];
314
+ }
315
+ }
316
+ } else if (purge) {
317
+ info.dispose = true;
318
+ }
319
+ }
320
+ }
321
+ }
322
+
323
+ export { Pool };
324
+ //# sourceMappingURL=pool.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pool.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zephyr3d/device",
3
- "version": "0.2.1",
3
+ "version": "0.2.3",
4
4
  "description": "Device API for zephyr3d",
5
5
  "homepage": "https://github.com/gavinyork/zephyr3d#readme",
6
6
  "type": "module",
@@ -44,7 +44,7 @@
44
44
  "@rollup/plugin-terser": "^0.4.0",
45
45
  "@rollup/pluginutils": "^5.0.2",
46
46
  "@swc/core": "^1.3.62",
47
- "@zephyr3d/base": "^0.1.3",
47
+ "@zephyr3d/base": "^0.1.4",
48
48
  "cross-env": "^7.0.3",
49
49
  "rollup": "^3.15.0",
50
50
  "rollup-plugin-copy": "^3.4.0",
@@ -55,11 +55,11 @@
55
55
  "typescript": "^5.1.3"
56
56
  },
57
57
  "peerDependencies": {
58
- "@zephyr3d/base": "^0.1.3"
58
+ "@zephyr3d/base": "^0.1.4"
59
59
  },
60
60
  "dependencies": {
61
61
  "@types/node": "^18.13.0",
62
- "@webgpu/types": "^0.1.31"
62
+ "@webgpu/types": "^0.1.40"
63
63
  },
64
64
  "scripts": {
65
65
  "clean": "shx rm -rf ./dist .tsbuildinfo",