@luma.gl/effects 9.3.0-alpha.4 → 9.3.0-alpha.8
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/dist.dev.js +1934 -415
- package/dist/dist.min.js +6 -6
- package/dist/index.cjs +736 -285
- package/dist/index.cjs.map +3 -3
- package/dist/passes/postprocessing/fxaa/fxaa.d.ts +1 -0
- package/dist/passes/postprocessing/fxaa/fxaa.d.ts.map +1 -1
- package/dist/passes/postprocessing/fxaa/fxaa.js +287 -0
- package/dist/passes/postprocessing/fxaa/fxaa.js.map +1 -1
- package/dist/passes/postprocessing/image-adjust-filters/brightnesscontrast.d.ts +1 -1
- package/dist/passes/postprocessing/image-adjust-filters/brightnesscontrast.d.ts.map +1 -1
- package/dist/passes/postprocessing/image-adjust-filters/brightnesscontrast.js +5 -6
- package/dist/passes/postprocessing/image-adjust-filters/brightnesscontrast.js.map +1 -1
- package/dist/passes/postprocessing/image-adjust-filters/denoise.d.ts +2 -2
- package/dist/passes/postprocessing/image-adjust-filters/denoise.d.ts.map +1 -1
- package/dist/passes/postprocessing/image-adjust-filters/denoise.js +32 -24
- package/dist/passes/postprocessing/image-adjust-filters/denoise.js.map +1 -1
- package/dist/passes/postprocessing/image-adjust-filters/huesaturation.d.ts +1 -1
- package/dist/passes/postprocessing/image-adjust-filters/huesaturation.d.ts.map +1 -1
- package/dist/passes/postprocessing/image-adjust-filters/huesaturation.js +25 -32
- package/dist/passes/postprocessing/image-adjust-filters/huesaturation.js.map +1 -1
- package/dist/passes/postprocessing/image-adjust-filters/noise.d.ts +1 -1
- package/dist/passes/postprocessing/image-adjust-filters/noise.d.ts.map +1 -1
- package/dist/passes/postprocessing/image-adjust-filters/noise.js +9 -8
- package/dist/passes/postprocessing/image-adjust-filters/noise.js.map +1 -1
- package/dist/passes/postprocessing/image-adjust-filters/sepia.d.ts +1 -1
- package/dist/passes/postprocessing/image-adjust-filters/sepia.d.ts.map +1 -1
- package/dist/passes/postprocessing/image-adjust-filters/sepia.js +11 -10
- package/dist/passes/postprocessing/image-adjust-filters/sepia.js.map +1 -1
- package/dist/passes/postprocessing/image-adjust-filters/vibrance.d.ts +1 -1
- package/dist/passes/postprocessing/image-adjust-filters/vibrance.js +9 -9
- package/dist/passes/postprocessing/image-adjust-filters/vignette.d.ts +1 -1
- package/dist/passes/postprocessing/image-adjust-filters/vignette.d.ts.map +1 -1
- package/dist/passes/postprocessing/image-adjust-filters/vignette.js +10 -14
- package/dist/passes/postprocessing/image-adjust-filters/vignette.js.map +1 -1
- package/dist/passes/postprocessing/image-blur-filters/tiltshift.d.ts +2 -2
- package/dist/passes/postprocessing/image-blur-filters/tiltshift.d.ts.map +1 -1
- package/dist/passes/postprocessing/image-blur-filters/tiltshift.js +35 -17
- package/dist/passes/postprocessing/image-blur-filters/tiltshift.js.map +1 -1
- package/dist/passes/postprocessing/image-blur-filters/triangleblur.d.ts +2 -2
- package/dist/passes/postprocessing/image-blur-filters/triangleblur.d.ts.map +1 -1
- package/dist/passes/postprocessing/image-blur-filters/triangleblur.js +26 -17
- package/dist/passes/postprocessing/image-blur-filters/triangleblur.js.map +1 -1
- package/dist/passes/postprocessing/image-blur-filters/zoomblur.d.ts +2 -2
- package/dist/passes/postprocessing/image-blur-filters/zoomblur.d.ts.map +1 -1
- package/dist/passes/postprocessing/image-blur-filters/zoomblur.js +21 -12
- package/dist/passes/postprocessing/image-blur-filters/zoomblur.js.map +1 -1
- package/dist/passes/postprocessing/image-fun-filters/colorhalftone.d.ts +1 -1
- package/dist/passes/postprocessing/image-fun-filters/colorhalftone.d.ts.map +1 -1
- package/dist/passes/postprocessing/image-fun-filters/colorhalftone.js +19 -17
- package/dist/passes/postprocessing/image-fun-filters/colorhalftone.js.map +1 -1
- package/dist/passes/postprocessing/image-fun-filters/dotscreen.d.ts +1 -1
- package/dist/passes/postprocessing/image-fun-filters/dotscreen.js +11 -11
- package/dist/passes/postprocessing/image-fun-filters/edgework.d.ts +2 -2
- package/dist/passes/postprocessing/image-fun-filters/edgework.d.ts.map +1 -1
- package/dist/passes/postprocessing/image-fun-filters/edgework.js +84 -13
- package/dist/passes/postprocessing/image-fun-filters/edgework.js.map +1 -1
- package/dist/passes/postprocessing/image-fun-filters/hexagonalpixelate.d.ts +1 -1
- package/dist/passes/postprocessing/image-fun-filters/hexagonalpixelate.d.ts.map +1 -1
- package/dist/passes/postprocessing/image-fun-filters/hexagonalpixelate.js +34 -22
- package/dist/passes/postprocessing/image-fun-filters/hexagonalpixelate.js.map +1 -1
- package/dist/passes/postprocessing/image-fun-filters/ink.d.ts +1 -1
- package/dist/passes/postprocessing/image-fun-filters/ink.d.ts.map +1 -1
- package/dist/passes/postprocessing/image-fun-filters/ink.js +25 -16
- package/dist/passes/postprocessing/image-fun-filters/ink.js.map +1 -1
- package/dist/passes/postprocessing/image-fun-filters/magnify.d.ts +1 -1
- package/dist/passes/postprocessing/image-fun-filters/magnify.d.ts.map +1 -1
- package/dist/passes/postprocessing/image-fun-filters/magnify.js +22 -12
- package/dist/passes/postprocessing/image-fun-filters/magnify.js.map +1 -1
- package/dist/passes/postprocessing/image-warp-filters/bulgepinch.d.ts +3 -3
- package/dist/passes/postprocessing/image-warp-filters/bulgepinch.d.ts.map +1 -1
- package/dist/passes/postprocessing/image-warp-filters/bulgepinch.js +27 -13
- package/dist/passes/postprocessing/image-warp-filters/bulgepinch.js.map +1 -1
- package/dist/passes/postprocessing/image-warp-filters/swirl.d.ts +3 -3
- package/dist/passes/postprocessing/image-warp-filters/swirl.d.ts.map +1 -1
- package/dist/passes/postprocessing/image-warp-filters/swirl.js +20 -15
- package/dist/passes/postprocessing/image-warp-filters/swirl.js.map +1 -1
- package/dist/passes/postprocessing/image-warp-filters/warp.d.ts +1 -1
- package/dist/passes/postprocessing/image-warp-filters/warp.d.ts.map +1 -1
- package/dist/passes/postprocessing/image-warp-filters/warp.js +9 -4
- package/dist/passes/postprocessing/image-warp-filters/warp.js.map +1 -1
- package/package.json +3 -3
- package/src/passes/postprocessing/fxaa/fxaa.ts +288 -0
- package/src/passes/postprocessing/image-adjust-filters/brightnesscontrast.ts +5 -6
- package/src/passes/postprocessing/image-adjust-filters/denoise.ts +34 -26
- package/src/passes/postprocessing/image-adjust-filters/huesaturation.ts +27 -34
- package/src/passes/postprocessing/image-adjust-filters/noise.ts +9 -8
- package/src/passes/postprocessing/image-adjust-filters/sepia.ts +11 -10
- package/src/passes/postprocessing/image-adjust-filters/vibrance.ts +9 -9
- package/src/passes/postprocessing/image-adjust-filters/vignette.ts +10 -14
- package/src/passes/postprocessing/image-blur-filters/tiltshift.ts +37 -19
- package/src/passes/postprocessing/image-blur-filters/triangleblur.ts +26 -17
- package/src/passes/postprocessing/image-blur-filters/zoomblur.ts +22 -13
- package/src/passes/postprocessing/image-fun-filters/colorhalftone.ts +19 -17
- package/src/passes/postprocessing/image-fun-filters/dotscreen.ts +11 -11
- package/src/passes/postprocessing/image-fun-filters/edgework.ts +85 -14
- package/src/passes/postprocessing/image-fun-filters/hexagonalpixelate.ts +38 -26
- package/src/passes/postprocessing/image-fun-filters/ink.ts +25 -16
- package/src/passes/postprocessing/image-fun-filters/magnify.ts +22 -12
- package/src/passes/postprocessing/image-warp-filters/bulgepinch.ts +27 -13
- package/src/passes/postprocessing/image-warp-filters/swirl.ts +20 -15
- package/src/passes/postprocessing/image-warp-filters/warp.ts +9 -4
package/dist/dist.dev.js
CHANGED
|
@@ -66,44 +66,48 @@ var __exports__ = (() => {
|
|
|
66
66
|
ExternalTexture: () => ExternalTexture,
|
|
67
67
|
Fence: () => Fence,
|
|
68
68
|
Framebuffer: () => Framebuffer,
|
|
69
|
+
PipelineFactory: () => PipelineFactory,
|
|
69
70
|
PipelineLayout: () => PipelineLayout,
|
|
71
|
+
PresentationContext: () => PresentationContext,
|
|
70
72
|
QuerySet: () => QuerySet,
|
|
71
73
|
RenderPass: () => RenderPass,
|
|
72
74
|
RenderPipeline: () => RenderPipeline,
|
|
73
75
|
Resource: () => Resource,
|
|
74
76
|
Sampler: () => Sampler,
|
|
75
77
|
Shader: () => Shader,
|
|
78
|
+
ShaderFactory: () => ShaderFactory,
|
|
79
|
+
SharedRenderPipeline: () => SharedRenderPipeline,
|
|
76
80
|
Texture: () => Texture,
|
|
77
|
-
TextureFormatDecoder: () => TextureFormatDecoder,
|
|
78
81
|
TextureView: () => TextureView,
|
|
79
82
|
TransformFeedback: () => TransformFeedback,
|
|
80
83
|
UniformBlock: () => UniformBlock,
|
|
81
84
|
UniformBufferLayout: () => UniformBufferLayout,
|
|
82
85
|
UniformStore: () => UniformStore,
|
|
83
86
|
VertexArray: () => VertexArray,
|
|
87
|
+
_getDefaultBindGroupFactory: () => _getDefaultBindGroupFactory,
|
|
84
88
|
_getTextureFormatDefinition: () => getTextureFormatDefinition,
|
|
85
89
|
_getTextureFormatTable: () => getTextureFormatTable,
|
|
86
90
|
assert: () => assert2,
|
|
87
91
|
assertDefined: () => assertDefined,
|
|
92
|
+
dataTypeDecoder: () => dataTypeDecoder,
|
|
93
|
+
flattenBindingsByGroup: () => flattenBindingsByGroup,
|
|
88
94
|
getAttributeInfosFromLayouts: () => getAttributeInfosFromLayouts,
|
|
89
95
|
getAttributeShaderTypeInfo: () => getAttributeShaderTypeInfo,
|
|
90
|
-
getDataType: () => getDataType,
|
|
91
|
-
getDataTypeInfo: () => getDataTypeInfo,
|
|
92
96
|
getExternalImageSize: () => getExternalImageSize,
|
|
93
|
-
getNormalizedDataType: () => getNormalizedDataType,
|
|
94
97
|
getScratchArray: () => getScratchArray,
|
|
98
|
+
getShaderLayoutBinding: () => getShaderLayoutBinding,
|
|
95
99
|
getTextureImageView: () => getTextureImageView,
|
|
96
100
|
getTypedArrayConstructor: () => getTypedArrayConstructor,
|
|
97
101
|
getVariableShaderTypeInfo: () => getVariableShaderTypeInfo,
|
|
98
|
-
getVertexFormatFromAttribute: () => getVertexFormatFromAttribute,
|
|
99
|
-
getVertexFormatInfo: () => getVertexFormatInfo,
|
|
100
102
|
isExternalImage: () => isExternalImage,
|
|
101
103
|
log: () => log,
|
|
102
104
|
luma: () => luma,
|
|
103
|
-
|
|
105
|
+
normalizeBindingsByGroup: () => normalizeBindingsByGroup,
|
|
104
106
|
readPixel: () => readPixel,
|
|
105
107
|
setTextureImageData: () => setTextureImageData,
|
|
108
|
+
shaderTypeDecoder: () => shaderTypeDecoder,
|
|
106
109
|
textureFormatDecoder: () => textureFormatDecoder,
|
|
110
|
+
vertexFormatDecoder: () => vertexFormatDecoder,
|
|
107
111
|
writePixel: () => writePixel
|
|
108
112
|
});
|
|
109
113
|
|
|
@@ -301,6 +305,24 @@ var __exports__ = (() => {
|
|
|
301
305
|
};
|
|
302
306
|
|
|
303
307
|
// ../core/src/utils/stats-manager.ts
|
|
308
|
+
var GPU_TIME_AND_MEMORY_STATS = "GPU Time and Memory";
|
|
309
|
+
var GPU_TIME_AND_MEMORY_STAT_ORDER = [
|
|
310
|
+
"Adapter",
|
|
311
|
+
"GPU",
|
|
312
|
+
"GPU Type",
|
|
313
|
+
"GPU Backend",
|
|
314
|
+
"Frame Rate",
|
|
315
|
+
"CPU Time",
|
|
316
|
+
"GPU Time",
|
|
317
|
+
"GPU Memory",
|
|
318
|
+
"Buffer Memory",
|
|
319
|
+
"Texture Memory",
|
|
320
|
+
"Referenced Buffer Memory",
|
|
321
|
+
"Referenced Texture Memory",
|
|
322
|
+
"Swap Chain Texture"
|
|
323
|
+
];
|
|
324
|
+
var ORDERED_STATS_CACHE = /* @__PURE__ */ new WeakMap();
|
|
325
|
+
var ORDERED_STAT_NAME_SET_CACHE = /* @__PURE__ */ new WeakMap();
|
|
304
326
|
var StatsManager = class {
|
|
305
327
|
stats = /* @__PURE__ */ new Map();
|
|
306
328
|
getStats(name2) {
|
|
@@ -310,10 +332,50 @@ var __exports__ = (() => {
|
|
|
310
332
|
if (!this.stats.has(name2)) {
|
|
311
333
|
this.stats.set(name2, new Stats({ id: name2 }));
|
|
312
334
|
}
|
|
313
|
-
|
|
335
|
+
const stats = this.stats.get(name2);
|
|
336
|
+
if (name2 === GPU_TIME_AND_MEMORY_STATS) {
|
|
337
|
+
initializeStats(stats, GPU_TIME_AND_MEMORY_STAT_ORDER);
|
|
338
|
+
}
|
|
339
|
+
return stats;
|
|
314
340
|
}
|
|
315
341
|
};
|
|
316
342
|
var lumaStats = new StatsManager();
|
|
343
|
+
function initializeStats(stats, orderedStatNames) {
|
|
344
|
+
const statsMap = stats.stats;
|
|
345
|
+
let addedOrderedStat = false;
|
|
346
|
+
for (const statName of orderedStatNames) {
|
|
347
|
+
if (!statsMap[statName]) {
|
|
348
|
+
stats.get(statName);
|
|
349
|
+
addedOrderedStat = true;
|
|
350
|
+
}
|
|
351
|
+
}
|
|
352
|
+
const statCount = Object.keys(statsMap).length;
|
|
353
|
+
const cachedStats = ORDERED_STATS_CACHE.get(stats);
|
|
354
|
+
if (!addedOrderedStat && cachedStats?.orderedStatNames === orderedStatNames && cachedStats.statCount === statCount) {
|
|
355
|
+
return;
|
|
356
|
+
}
|
|
357
|
+
const reorderedStats = {};
|
|
358
|
+
let orderedStatNamesSet = ORDERED_STAT_NAME_SET_CACHE.get(orderedStatNames);
|
|
359
|
+
if (!orderedStatNamesSet) {
|
|
360
|
+
orderedStatNamesSet = new Set(orderedStatNames);
|
|
361
|
+
ORDERED_STAT_NAME_SET_CACHE.set(orderedStatNames, orderedStatNamesSet);
|
|
362
|
+
}
|
|
363
|
+
for (const statName of orderedStatNames) {
|
|
364
|
+
if (statsMap[statName]) {
|
|
365
|
+
reorderedStats[statName] = statsMap[statName];
|
|
366
|
+
}
|
|
367
|
+
}
|
|
368
|
+
for (const [statName, stat] of Object.entries(statsMap)) {
|
|
369
|
+
if (!orderedStatNamesSet.has(statName)) {
|
|
370
|
+
reorderedStats[statName] = stat;
|
|
371
|
+
}
|
|
372
|
+
}
|
|
373
|
+
for (const statName of Object.keys(statsMap)) {
|
|
374
|
+
delete statsMap[statName];
|
|
375
|
+
}
|
|
376
|
+
Object.assign(statsMap, reorderedStats);
|
|
377
|
+
ORDERED_STATS_CACHE.set(stats, { orderedStatNames, statCount });
|
|
378
|
+
}
|
|
317
379
|
|
|
318
380
|
// ../../node_modules/@probe.gl/env/dist/lib/globals.js
|
|
319
381
|
var window_ = globalThis;
|
|
@@ -848,6 +910,57 @@ var __exports__ = (() => {
|
|
|
848
910
|
}
|
|
849
911
|
|
|
850
912
|
// ../core/src/adapter/resources/resource.ts
|
|
913
|
+
var CPU_HOTSPOT_PROFILER_MODULE = "cpu-hotspot-profiler";
|
|
914
|
+
var RESOURCE_COUNTS_STATS = "GPU Resource Counts";
|
|
915
|
+
var LEGACY_RESOURCE_COUNTS_STATS = "Resource Counts";
|
|
916
|
+
var GPU_TIME_AND_MEMORY_STATS2 = "GPU Time and Memory";
|
|
917
|
+
var BASE_RESOURCE_COUNT_ORDER = [
|
|
918
|
+
"Resources",
|
|
919
|
+
"Buffers",
|
|
920
|
+
"Textures",
|
|
921
|
+
"Samplers",
|
|
922
|
+
"TextureViews",
|
|
923
|
+
"Framebuffers",
|
|
924
|
+
"QuerySets",
|
|
925
|
+
"Shaders",
|
|
926
|
+
"RenderPipelines",
|
|
927
|
+
"ComputePipelines",
|
|
928
|
+
"PipelineLayouts",
|
|
929
|
+
"VertexArrays",
|
|
930
|
+
"RenderPasss",
|
|
931
|
+
"ComputePasss",
|
|
932
|
+
"CommandEncoders",
|
|
933
|
+
"CommandBuffers"
|
|
934
|
+
];
|
|
935
|
+
var WEBGL_RESOURCE_COUNT_ORDER = [
|
|
936
|
+
"Resources",
|
|
937
|
+
"Buffers",
|
|
938
|
+
"Textures",
|
|
939
|
+
"Samplers",
|
|
940
|
+
"TextureViews",
|
|
941
|
+
"Framebuffers",
|
|
942
|
+
"QuerySets",
|
|
943
|
+
"Shaders",
|
|
944
|
+
"RenderPipelines",
|
|
945
|
+
"SharedRenderPipelines",
|
|
946
|
+
"ComputePipelines",
|
|
947
|
+
"PipelineLayouts",
|
|
948
|
+
"VertexArrays",
|
|
949
|
+
"RenderPasss",
|
|
950
|
+
"ComputePasss",
|
|
951
|
+
"CommandEncoders",
|
|
952
|
+
"CommandBuffers"
|
|
953
|
+
];
|
|
954
|
+
var BASE_RESOURCE_COUNT_STAT_ORDER = BASE_RESOURCE_COUNT_ORDER.flatMap((resourceType) => [
|
|
955
|
+
`${resourceType} Created`,
|
|
956
|
+
`${resourceType} Active`
|
|
957
|
+
]);
|
|
958
|
+
var WEBGL_RESOURCE_COUNT_STAT_ORDER = WEBGL_RESOURCE_COUNT_ORDER.flatMap((resourceType) => [
|
|
959
|
+
`${resourceType} Created`,
|
|
960
|
+
`${resourceType} Active`
|
|
961
|
+
]);
|
|
962
|
+
var ORDERED_STATS_CACHE2 = /* @__PURE__ */ new WeakMap();
|
|
963
|
+
var ORDERED_STAT_NAME_SET_CACHE2 = /* @__PURE__ */ new WeakMap();
|
|
851
964
|
var Resource = class {
|
|
852
965
|
toString() {
|
|
853
966
|
return `${this[Symbol.toStringTag] || this.constructor.name}:"${this.id}"`;
|
|
@@ -864,6 +977,8 @@ var __exports__ = (() => {
|
|
|
864
977
|
destroyed = false;
|
|
865
978
|
/** For resources that allocate GPU memory */
|
|
866
979
|
allocatedBytes = 0;
|
|
980
|
+
/** Stats bucket currently holding the tracked allocation */
|
|
981
|
+
allocatedBytesName = null;
|
|
867
982
|
/** Attached resources will be destroyed when this resource is destroyed. Tracks auto-created "sub" resources. */
|
|
868
983
|
_attachedResources = /* @__PURE__ */ new Set();
|
|
869
984
|
/**
|
|
@@ -885,6 +1000,9 @@ var __exports__ = (() => {
|
|
|
885
1000
|
* destroy can be called on any resource to release it before it is garbage collected.
|
|
886
1001
|
*/
|
|
887
1002
|
destroy() {
|
|
1003
|
+
if (this.destroyed) {
|
|
1004
|
+
return;
|
|
1005
|
+
}
|
|
888
1006
|
this.destroyResource();
|
|
889
1007
|
}
|
|
890
1008
|
/** @deprecated Use destroy() */
|
|
@@ -923,7 +1041,7 @@ var __exports__ = (() => {
|
|
|
923
1041
|
}
|
|
924
1042
|
/** Destroy all owned resources. Make sure the resources are no longer needed before calling. */
|
|
925
1043
|
destroyAttachedResources() {
|
|
926
|
-
for (const resource of
|
|
1044
|
+
for (const resource of this._attachedResources) {
|
|
927
1045
|
resource.destroy();
|
|
928
1046
|
}
|
|
929
1047
|
this._attachedResources = /* @__PURE__ */ new Set();
|
|
@@ -931,37 +1049,107 @@ var __exports__ = (() => {
|
|
|
931
1049
|
// PROTECTED METHODS
|
|
932
1050
|
/** Perform all destroy steps. Can be called by derived resources when overriding destroy() */
|
|
933
1051
|
destroyResource() {
|
|
1052
|
+
if (this.destroyed) {
|
|
1053
|
+
return;
|
|
1054
|
+
}
|
|
934
1055
|
this.destroyAttachedResources();
|
|
935
1056
|
this.removeStats();
|
|
936
1057
|
this.destroyed = true;
|
|
937
1058
|
}
|
|
938
1059
|
/** Called by .destroy() to track object destruction. Subclass must call if overriding destroy() */
|
|
939
1060
|
removeStats() {
|
|
940
|
-
const
|
|
941
|
-
const
|
|
942
|
-
|
|
1061
|
+
const profiler = getCpuHotspotProfiler(this._device);
|
|
1062
|
+
const startTime = profiler ? getTimestamp() : 0;
|
|
1063
|
+
const statsObjects = [
|
|
1064
|
+
this._device.statsManager.getStats(RESOURCE_COUNTS_STATS),
|
|
1065
|
+
this._device.statsManager.getStats(LEGACY_RESOURCE_COUNTS_STATS)
|
|
1066
|
+
];
|
|
1067
|
+
const orderedStatNames = getResourceCountStatOrder(this._device);
|
|
1068
|
+
for (const stats of statsObjects) {
|
|
1069
|
+
initializeStats2(stats, orderedStatNames);
|
|
1070
|
+
}
|
|
1071
|
+
const name2 = this.getStatsName();
|
|
1072
|
+
for (const stats of statsObjects) {
|
|
1073
|
+
stats.get("Resources Active").decrementCount();
|
|
1074
|
+
stats.get(`${name2}s Active`).decrementCount();
|
|
1075
|
+
}
|
|
1076
|
+
if (profiler) {
|
|
1077
|
+
profiler.statsBookkeepingCalls = (profiler.statsBookkeepingCalls || 0) + 1;
|
|
1078
|
+
profiler.statsBookkeepingTimeMs = (profiler.statsBookkeepingTimeMs || 0) + (getTimestamp() - startTime);
|
|
1079
|
+
}
|
|
943
1080
|
}
|
|
944
1081
|
/** Called by subclass to track memory allocations */
|
|
945
|
-
trackAllocatedMemory(bytes, name2 = this
|
|
946
|
-
const
|
|
1082
|
+
trackAllocatedMemory(bytes, name2 = this.getStatsName()) {
|
|
1083
|
+
const profiler = getCpuHotspotProfiler(this._device);
|
|
1084
|
+
const startTime = profiler ? getTimestamp() : 0;
|
|
1085
|
+
const stats = this._device.statsManager.getStats(GPU_TIME_AND_MEMORY_STATS2);
|
|
1086
|
+
if (this.allocatedBytes > 0 && this.allocatedBytesName) {
|
|
1087
|
+
stats.get("GPU Memory").subtractCount(this.allocatedBytes);
|
|
1088
|
+
stats.get(`${this.allocatedBytesName} Memory`).subtractCount(this.allocatedBytes);
|
|
1089
|
+
}
|
|
947
1090
|
stats.get("GPU Memory").addCount(bytes);
|
|
948
1091
|
stats.get(`${name2} Memory`).addCount(bytes);
|
|
1092
|
+
if (profiler) {
|
|
1093
|
+
profiler.statsBookkeepingCalls = (profiler.statsBookkeepingCalls || 0) + 1;
|
|
1094
|
+
profiler.statsBookkeepingTimeMs = (profiler.statsBookkeepingTimeMs || 0) + (getTimestamp() - startTime);
|
|
1095
|
+
}
|
|
949
1096
|
this.allocatedBytes = bytes;
|
|
1097
|
+
this.allocatedBytesName = name2;
|
|
1098
|
+
}
|
|
1099
|
+
/** Called by subclass to track handle-backed memory allocations separately from owned allocations */
|
|
1100
|
+
trackReferencedMemory(bytes, name2 = this.getStatsName()) {
|
|
1101
|
+
this.trackAllocatedMemory(bytes, `Referenced ${name2}`);
|
|
950
1102
|
}
|
|
951
1103
|
/** Called by subclass to track memory deallocations */
|
|
952
|
-
trackDeallocatedMemory(name2 = this
|
|
953
|
-
|
|
1104
|
+
trackDeallocatedMemory(name2 = this.getStatsName()) {
|
|
1105
|
+
if (this.allocatedBytes === 0) {
|
|
1106
|
+
this.allocatedBytesName = null;
|
|
1107
|
+
return;
|
|
1108
|
+
}
|
|
1109
|
+
const profiler = getCpuHotspotProfiler(this._device);
|
|
1110
|
+
const startTime = profiler ? getTimestamp() : 0;
|
|
1111
|
+
const stats = this._device.statsManager.getStats(GPU_TIME_AND_MEMORY_STATS2);
|
|
954
1112
|
stats.get("GPU Memory").subtractCount(this.allocatedBytes);
|
|
955
|
-
stats.get(`${name2} Memory`).subtractCount(this.allocatedBytes);
|
|
1113
|
+
stats.get(`${this.allocatedBytesName || name2} Memory`).subtractCount(this.allocatedBytes);
|
|
1114
|
+
if (profiler) {
|
|
1115
|
+
profiler.statsBookkeepingCalls = (profiler.statsBookkeepingCalls || 0) + 1;
|
|
1116
|
+
profiler.statsBookkeepingTimeMs = (profiler.statsBookkeepingTimeMs || 0) + (getTimestamp() - startTime);
|
|
1117
|
+
}
|
|
956
1118
|
this.allocatedBytes = 0;
|
|
1119
|
+
this.allocatedBytesName = null;
|
|
1120
|
+
}
|
|
1121
|
+
/** Called by subclass to deallocate handle-backed memory tracked via trackReferencedMemory() */
|
|
1122
|
+
trackDeallocatedReferencedMemory(name2 = this.getStatsName()) {
|
|
1123
|
+
this.trackDeallocatedMemory(`Referenced ${name2}`);
|
|
957
1124
|
}
|
|
958
1125
|
/** Called by resource constructor to track object creation */
|
|
959
1126
|
addStats() {
|
|
960
|
-
const
|
|
961
|
-
const
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
1127
|
+
const name2 = this.getStatsName();
|
|
1128
|
+
const profiler = getCpuHotspotProfiler(this._device);
|
|
1129
|
+
const startTime = profiler ? getTimestamp() : 0;
|
|
1130
|
+
const statsObjects = [
|
|
1131
|
+
this._device.statsManager.getStats(RESOURCE_COUNTS_STATS),
|
|
1132
|
+
this._device.statsManager.getStats(LEGACY_RESOURCE_COUNTS_STATS)
|
|
1133
|
+
];
|
|
1134
|
+
const orderedStatNames = getResourceCountStatOrder(this._device);
|
|
1135
|
+
for (const stats of statsObjects) {
|
|
1136
|
+
initializeStats2(stats, orderedStatNames);
|
|
1137
|
+
}
|
|
1138
|
+
for (const stats of statsObjects) {
|
|
1139
|
+
stats.get("Resources Created").incrementCount();
|
|
1140
|
+
stats.get("Resources Active").incrementCount();
|
|
1141
|
+
stats.get(`${name2}s Created`).incrementCount();
|
|
1142
|
+
stats.get(`${name2}s Active`).incrementCount();
|
|
1143
|
+
}
|
|
1144
|
+
if (profiler) {
|
|
1145
|
+
profiler.statsBookkeepingCalls = (profiler.statsBookkeepingCalls || 0) + 1;
|
|
1146
|
+
profiler.statsBookkeepingTimeMs = (profiler.statsBookkeepingTimeMs || 0) + (getTimestamp() - startTime);
|
|
1147
|
+
}
|
|
1148
|
+
recordTransientCanvasResourceCreate(this._device, name2);
|
|
1149
|
+
}
|
|
1150
|
+
/** Canonical resource name used for stats buckets. */
|
|
1151
|
+
getStatsName() {
|
|
1152
|
+
return getCanonicalResourceName(this);
|
|
965
1153
|
}
|
|
966
1154
|
};
|
|
967
1155
|
/** Default properties for resource */
|
|
@@ -979,6 +1167,96 @@ var __exports__ = (() => {
|
|
|
979
1167
|
}
|
|
980
1168
|
return mergedProps;
|
|
981
1169
|
}
|
|
1170
|
+
function initializeStats2(stats, orderedStatNames) {
|
|
1171
|
+
const statsMap = stats.stats;
|
|
1172
|
+
let addedOrderedStat = false;
|
|
1173
|
+
for (const statName of orderedStatNames) {
|
|
1174
|
+
if (!statsMap[statName]) {
|
|
1175
|
+
stats.get(statName);
|
|
1176
|
+
addedOrderedStat = true;
|
|
1177
|
+
}
|
|
1178
|
+
}
|
|
1179
|
+
const statCount = Object.keys(statsMap).length;
|
|
1180
|
+
const cachedStats = ORDERED_STATS_CACHE2.get(stats);
|
|
1181
|
+
if (!addedOrderedStat && cachedStats?.orderedStatNames === orderedStatNames && cachedStats.statCount === statCount) {
|
|
1182
|
+
return;
|
|
1183
|
+
}
|
|
1184
|
+
const reorderedStats = {};
|
|
1185
|
+
let orderedStatNamesSet = ORDERED_STAT_NAME_SET_CACHE2.get(orderedStatNames);
|
|
1186
|
+
if (!orderedStatNamesSet) {
|
|
1187
|
+
orderedStatNamesSet = new Set(orderedStatNames);
|
|
1188
|
+
ORDERED_STAT_NAME_SET_CACHE2.set(orderedStatNames, orderedStatNamesSet);
|
|
1189
|
+
}
|
|
1190
|
+
for (const statName of orderedStatNames) {
|
|
1191
|
+
if (statsMap[statName]) {
|
|
1192
|
+
reorderedStats[statName] = statsMap[statName];
|
|
1193
|
+
}
|
|
1194
|
+
}
|
|
1195
|
+
for (const [statName, stat] of Object.entries(statsMap)) {
|
|
1196
|
+
if (!orderedStatNamesSet.has(statName)) {
|
|
1197
|
+
reorderedStats[statName] = stat;
|
|
1198
|
+
}
|
|
1199
|
+
}
|
|
1200
|
+
for (const statName of Object.keys(statsMap)) {
|
|
1201
|
+
delete statsMap[statName];
|
|
1202
|
+
}
|
|
1203
|
+
Object.assign(statsMap, reorderedStats);
|
|
1204
|
+
ORDERED_STATS_CACHE2.set(stats, { orderedStatNames, statCount });
|
|
1205
|
+
}
|
|
1206
|
+
function getResourceCountStatOrder(device) {
|
|
1207
|
+
return device.type === "webgl" ? WEBGL_RESOURCE_COUNT_STAT_ORDER : BASE_RESOURCE_COUNT_STAT_ORDER;
|
|
1208
|
+
}
|
|
1209
|
+
function getCpuHotspotProfiler(device) {
|
|
1210
|
+
const profiler = device.userData[CPU_HOTSPOT_PROFILER_MODULE];
|
|
1211
|
+
return profiler?.enabled ? profiler : null;
|
|
1212
|
+
}
|
|
1213
|
+
function getTimestamp() {
|
|
1214
|
+
return globalThis.performance?.now?.() ?? Date.now();
|
|
1215
|
+
}
|
|
1216
|
+
function recordTransientCanvasResourceCreate(device, name2) {
|
|
1217
|
+
const profiler = getCpuHotspotProfiler(device);
|
|
1218
|
+
if (!profiler || !profiler.activeDefaultFramebufferAcquireDepth) {
|
|
1219
|
+
return;
|
|
1220
|
+
}
|
|
1221
|
+
profiler.transientCanvasResourceCreates = (profiler.transientCanvasResourceCreates || 0) + 1;
|
|
1222
|
+
switch (name2) {
|
|
1223
|
+
case "Texture":
|
|
1224
|
+
profiler.transientCanvasTextureCreates = (profiler.transientCanvasTextureCreates || 0) + 1;
|
|
1225
|
+
break;
|
|
1226
|
+
case "TextureView":
|
|
1227
|
+
profiler.transientCanvasTextureViewCreates = (profiler.transientCanvasTextureViewCreates || 0) + 1;
|
|
1228
|
+
break;
|
|
1229
|
+
case "Sampler":
|
|
1230
|
+
profiler.transientCanvasSamplerCreates = (profiler.transientCanvasSamplerCreates || 0) + 1;
|
|
1231
|
+
break;
|
|
1232
|
+
case "Framebuffer":
|
|
1233
|
+
profiler.transientCanvasFramebufferCreates = (profiler.transientCanvasFramebufferCreates || 0) + 1;
|
|
1234
|
+
break;
|
|
1235
|
+
default:
|
|
1236
|
+
break;
|
|
1237
|
+
}
|
|
1238
|
+
}
|
|
1239
|
+
function getCanonicalResourceName(resource) {
|
|
1240
|
+
let prototype = Object.getPrototypeOf(resource);
|
|
1241
|
+
while (prototype) {
|
|
1242
|
+
const parentPrototype = Object.getPrototypeOf(prototype);
|
|
1243
|
+
if (!parentPrototype || parentPrototype === Resource.prototype) {
|
|
1244
|
+
return getPrototypeToStringTag(prototype) || resource[Symbol.toStringTag] || resource.constructor.name;
|
|
1245
|
+
}
|
|
1246
|
+
prototype = parentPrototype;
|
|
1247
|
+
}
|
|
1248
|
+
return resource[Symbol.toStringTag] || resource.constructor.name;
|
|
1249
|
+
}
|
|
1250
|
+
function getPrototypeToStringTag(prototype) {
|
|
1251
|
+
const descriptor = Object.getOwnPropertyDescriptor(prototype, Symbol.toStringTag);
|
|
1252
|
+
if (typeof descriptor?.get === "function") {
|
|
1253
|
+
return descriptor.get.call(prototype);
|
|
1254
|
+
}
|
|
1255
|
+
if (typeof descriptor?.value === "string") {
|
|
1256
|
+
return descriptor.value;
|
|
1257
|
+
}
|
|
1258
|
+
return null;
|
|
1259
|
+
}
|
|
982
1260
|
|
|
983
1261
|
// ../core/src/adapter/resources/buffer.ts
|
|
984
1262
|
var _Buffer = class extends Resource {
|
|
@@ -1018,18 +1296,26 @@ var __exports__ = (() => {
|
|
|
1018
1296
|
/** A partial CPU-side copy of the data in this buffer, for debugging purposes */
|
|
1019
1297
|
debugData = new ArrayBuffer(0);
|
|
1020
1298
|
/** This doesn't handle partial non-zero offset updates correctly */
|
|
1021
|
-
_setDebugData(data,
|
|
1022
|
-
|
|
1299
|
+
_setDebugData(data, _byteOffset, byteLength) {
|
|
1300
|
+
let arrayBufferView = null;
|
|
1301
|
+
let arrayBuffer2;
|
|
1302
|
+
if (ArrayBuffer.isView(data)) {
|
|
1303
|
+
arrayBufferView = data;
|
|
1304
|
+
arrayBuffer2 = data.buffer;
|
|
1305
|
+
} else {
|
|
1306
|
+
arrayBuffer2 = data;
|
|
1307
|
+
}
|
|
1023
1308
|
const debugDataLength = Math.min(
|
|
1024
1309
|
data ? data.byteLength : byteLength,
|
|
1025
1310
|
_Buffer.DEBUG_DATA_MAX_LENGTH
|
|
1026
1311
|
);
|
|
1027
1312
|
if (arrayBuffer2 === null) {
|
|
1028
1313
|
this.debugData = new ArrayBuffer(debugDataLength);
|
|
1029
|
-
} else if (byteOffset === 0 && byteLength === arrayBuffer2.byteLength) {
|
|
1030
|
-
this.debugData = arrayBuffer2.slice(0, debugDataLength);
|
|
1031
1314
|
} else {
|
|
1032
|
-
|
|
1315
|
+
const sourceByteOffset = Math.min(arrayBufferView?.byteOffset || 0, arrayBuffer2.byteLength);
|
|
1316
|
+
const availableByteLength = Math.max(0, arrayBuffer2.byteLength - sourceByteOffset);
|
|
1317
|
+
const copyByteLength = Math.min(debugDataLength, availableByteLength);
|
|
1318
|
+
this.debugData = new Uint8Array(arrayBuffer2, sourceByteOffset, copyByteLength).slice().buffer;
|
|
1033
1319
|
}
|
|
1034
1320
|
}
|
|
1035
1321
|
};
|
|
@@ -1063,62 +1349,73 @@ var __exports__ = (() => {
|
|
|
1063
1349
|
onMapped: void 0
|
|
1064
1350
|
});
|
|
1065
1351
|
|
|
1066
|
-
// ../core/src/shadertypes/data-types/
|
|
1067
|
-
|
|
1068
|
-
|
|
1069
|
-
|
|
1070
|
-
|
|
1071
|
-
|
|
1072
|
-
|
|
1073
|
-
|
|
1074
|
-
|
|
1075
|
-
|
|
1076
|
-
|
|
1077
|
-
|
|
1078
|
-
|
|
1079
|
-
|
|
1080
|
-
|
|
1081
|
-
|
|
1082
|
-
|
|
1083
|
-
|
|
1084
|
-
|
|
1085
|
-
|
|
1086
|
-
return "unorm8";
|
|
1087
|
-
case "sint8":
|
|
1088
|
-
return "snorm8";
|
|
1089
|
-
case "uint16":
|
|
1090
|
-
return "unorm16";
|
|
1091
|
-
case "sint16":
|
|
1092
|
-
return "snorm16";
|
|
1093
|
-
default:
|
|
1094
|
-
return dataType;
|
|
1352
|
+
// ../core/src/shadertypes/data-types/data-type-decoder.ts
|
|
1353
|
+
var DataTypeDecoder = class {
|
|
1354
|
+
/**
|
|
1355
|
+
* Gets info about a data type constant (signed or normalized)
|
|
1356
|
+
* @returns underlying primitive / signed types, byte length, normalization, integer, signed flags
|
|
1357
|
+
*/
|
|
1358
|
+
getDataTypeInfo(type) {
|
|
1359
|
+
const [signedType, primitiveType, byteLength] = NORMALIZED_TYPE_MAP[type];
|
|
1360
|
+
const normalized = type.includes("norm");
|
|
1361
|
+
const integer = !normalized && !type.startsWith("float");
|
|
1362
|
+
const signed = type.startsWith("s");
|
|
1363
|
+
return {
|
|
1364
|
+
signedType,
|
|
1365
|
+
primitiveType,
|
|
1366
|
+
byteLength,
|
|
1367
|
+
normalized,
|
|
1368
|
+
integer,
|
|
1369
|
+
signed
|
|
1370
|
+
// TODO - add webglOnly flag
|
|
1371
|
+
};
|
|
1095
1372
|
}
|
|
1096
|
-
|
|
1097
|
-
|
|
1098
|
-
|
|
1099
|
-
|
|
1100
|
-
|
|
1101
|
-
|
|
1102
|
-
|
|
1103
|
-
|
|
1104
|
-
|
|
1373
|
+
/** Build a vertex format from a signed data type and a component */
|
|
1374
|
+
getNormalizedDataType(signedDataType) {
|
|
1375
|
+
const dataType = signedDataType;
|
|
1376
|
+
switch (dataType) {
|
|
1377
|
+
case "uint8":
|
|
1378
|
+
return "unorm8";
|
|
1379
|
+
case "sint8":
|
|
1380
|
+
return "snorm8";
|
|
1381
|
+
case "uint16":
|
|
1382
|
+
return "unorm16";
|
|
1383
|
+
case "sint16":
|
|
1384
|
+
return "snorm16";
|
|
1385
|
+
default:
|
|
1386
|
+
return dataType;
|
|
1387
|
+
}
|
|
1105
1388
|
}
|
|
1106
|
-
|
|
1107
|
-
|
|
1108
|
-
|
|
1109
|
-
|
|
1110
|
-
|
|
1389
|
+
/** Align offset to 1, 2 or 4 elements (4, 8 or 16 bytes) */
|
|
1390
|
+
alignTo(size, count) {
|
|
1391
|
+
switch (count) {
|
|
1392
|
+
case 1:
|
|
1393
|
+
return size;
|
|
1394
|
+
case 2:
|
|
1395
|
+
return size + size % 2;
|
|
1396
|
+
default:
|
|
1397
|
+
return size + (4 - size % 4) % 4;
|
|
1398
|
+
}
|
|
1111
1399
|
}
|
|
1112
|
-
|
|
1113
|
-
|
|
1114
|
-
|
|
1400
|
+
/** Returns the VariableShaderType that corresponds to a typed array */
|
|
1401
|
+
getDataType(arrayOrType) {
|
|
1402
|
+
const Constructor = ArrayBuffer.isView(arrayOrType) ? arrayOrType.constructor : arrayOrType;
|
|
1403
|
+
if (Constructor === Uint8ClampedArray) {
|
|
1404
|
+
return "uint8";
|
|
1405
|
+
}
|
|
1406
|
+
const info = Object.values(NORMALIZED_TYPE_MAP).find((entry) => Constructor === entry[4]);
|
|
1407
|
+
if (!info) {
|
|
1408
|
+
throw new Error(Constructor.name);
|
|
1409
|
+
}
|
|
1410
|
+
return info[0];
|
|
1115
1411
|
}
|
|
1116
|
-
|
|
1117
|
-
|
|
1118
|
-
|
|
1119
|
-
|
|
1120
|
-
|
|
1121
|
-
}
|
|
1412
|
+
/** Returns the TypedArray that corresponds to a shader data type */
|
|
1413
|
+
getTypedArrayConstructor(type) {
|
|
1414
|
+
const [, , , , Constructor] = NORMALIZED_TYPE_MAP[type];
|
|
1415
|
+
return Constructor;
|
|
1416
|
+
}
|
|
1417
|
+
};
|
|
1418
|
+
var dataTypeDecoder = new DataTypeDecoder();
|
|
1122
1419
|
var NORMALIZED_TYPE_MAP = {
|
|
1123
1420
|
uint8: ["uint8", "u32", 1, false, Uint8Array],
|
|
1124
1421
|
sint8: ["sint8", "i32", 1, false, Int8Array],
|
|
@@ -1134,87 +1431,99 @@ var __exports__ = (() => {
|
|
|
1134
1431
|
sint32: ["sint32", "i32", 4, false, Int32Array]
|
|
1135
1432
|
};
|
|
1136
1433
|
|
|
1137
|
-
// ../core/src/shadertypes/vertex-
|
|
1138
|
-
|
|
1139
|
-
|
|
1140
|
-
|
|
1141
|
-
|
|
1142
|
-
|
|
1143
|
-
|
|
1144
|
-
|
|
1145
|
-
|
|
1146
|
-
|
|
1147
|
-
|
|
1148
|
-
|
|
1149
|
-
type
|
|
1150
|
-
components
|
|
1151
|
-
|
|
1152
|
-
|
|
1153
|
-
|
|
1154
|
-
|
|
1155
|
-
|
|
1156
|
-
|
|
1157
|
-
|
|
1158
|
-
|
|
1159
|
-
|
|
1160
|
-
|
|
1161
|
-
|
|
1162
|
-
|
|
1163
|
-
|
|
1164
|
-
case "unorm8":
|
|
1165
|
-
if (components === 1) {
|
|
1166
|
-
return "unorm8";
|
|
1167
|
-
}
|
|
1168
|
-
if (components === 3) {
|
|
1169
|
-
return "unorm8x3-webgl";
|
|
1170
|
-
}
|
|
1171
|
-
return `${dataType}x${components}`;
|
|
1172
|
-
case "snorm8":
|
|
1173
|
-
case "uint8":
|
|
1174
|
-
case "sint8":
|
|
1175
|
-
case "uint16":
|
|
1176
|
-
case "sint16":
|
|
1177
|
-
case "unorm16":
|
|
1178
|
-
case "snorm16":
|
|
1179
|
-
case "float16":
|
|
1180
|
-
if (components === 1 || components === 3) {
|
|
1181
|
-
throw new Error(`size: ${components}`);
|
|
1182
|
-
}
|
|
1183
|
-
return `${dataType}x${components}`;
|
|
1184
|
-
default:
|
|
1185
|
-
return components === 1 ? dataType : `${dataType}x${components}`;
|
|
1434
|
+
// ../core/src/shadertypes/vertex-types/vertex-format-decoder.ts
|
|
1435
|
+
var VertexFormatDecoder = class {
|
|
1436
|
+
/**
|
|
1437
|
+
* Decodes a vertex format, returning type, components, byte length and flags (integer, signed, normalized)
|
|
1438
|
+
*/
|
|
1439
|
+
getVertexFormatInfo(format) {
|
|
1440
|
+
let webglOnly;
|
|
1441
|
+
if (format.endsWith("-webgl")) {
|
|
1442
|
+
format.replace("-webgl", "");
|
|
1443
|
+
webglOnly = true;
|
|
1444
|
+
}
|
|
1445
|
+
const [type_, count] = format.split("x");
|
|
1446
|
+
const type = type_;
|
|
1447
|
+
const components = count ? parseInt(count) : 1;
|
|
1448
|
+
const decodedType = dataTypeDecoder.getDataTypeInfo(type);
|
|
1449
|
+
const result = {
|
|
1450
|
+
type,
|
|
1451
|
+
components,
|
|
1452
|
+
byteLength: decodedType.byteLength * components,
|
|
1453
|
+
integer: decodedType.integer,
|
|
1454
|
+
signed: decodedType.signed,
|
|
1455
|
+
normalized: decodedType.normalized
|
|
1456
|
+
};
|
|
1457
|
+
if (webglOnly) {
|
|
1458
|
+
result.webglOnly = true;
|
|
1459
|
+
}
|
|
1460
|
+
return result;
|
|
1186
1461
|
}
|
|
1187
|
-
|
|
1188
|
-
|
|
1189
|
-
|
|
1190
|
-
|
|
1462
|
+
/** Build a vertex format from a signed data type and a component */
|
|
1463
|
+
makeVertexFormat(signedDataType, components, normalized) {
|
|
1464
|
+
const dataType = normalized ? dataTypeDecoder.getNormalizedDataType(signedDataType) : signedDataType;
|
|
1465
|
+
switch (dataType) {
|
|
1466
|
+
case "unorm8":
|
|
1467
|
+
if (components === 1) {
|
|
1468
|
+
return "unorm8";
|
|
1469
|
+
}
|
|
1470
|
+
if (components === 3) {
|
|
1471
|
+
return "unorm8x3-webgl";
|
|
1472
|
+
}
|
|
1473
|
+
return `${dataType}x${components}`;
|
|
1474
|
+
case "snorm8":
|
|
1475
|
+
case "uint8":
|
|
1476
|
+
case "sint8":
|
|
1477
|
+
case "uint16":
|
|
1478
|
+
case "sint16":
|
|
1479
|
+
case "unorm16":
|
|
1480
|
+
case "snorm16":
|
|
1481
|
+
case "float16":
|
|
1482
|
+
if (components === 1 || components === 3) {
|
|
1483
|
+
throw new Error(`size: ${components}`);
|
|
1484
|
+
}
|
|
1485
|
+
return `${dataType}x${components}`;
|
|
1486
|
+
default:
|
|
1487
|
+
return components === 1 ? dataType : `${dataType}x${components}`;
|
|
1488
|
+
}
|
|
1191
1489
|
}
|
|
1192
|
-
|
|
1193
|
-
|
|
1194
|
-
|
|
1195
|
-
|
|
1196
|
-
|
|
1197
|
-
|
|
1198
|
-
|
|
1199
|
-
|
|
1200
|
-
vertexType = "float32";
|
|
1201
|
-
break;
|
|
1202
|
-
case "i32":
|
|
1203
|
-
vertexType = "sint32";
|
|
1204
|
-
break;
|
|
1205
|
-
case "u32":
|
|
1206
|
-
vertexType = "uint32";
|
|
1207
|
-
break;
|
|
1208
|
-
case "f16":
|
|
1209
|
-
return opts.components <= 2 ? "float16x2" : "float16x4";
|
|
1490
|
+
/** Get the vertex format for an attribute with TypedArray and size */
|
|
1491
|
+
getVertexFormatFromAttribute(typedArray, size, normalized) {
|
|
1492
|
+
if (!size || size > 4) {
|
|
1493
|
+
throw new Error(`size ${size}`);
|
|
1494
|
+
}
|
|
1495
|
+
const components = size;
|
|
1496
|
+
const signedDataType = dataTypeDecoder.getDataType(typedArray);
|
|
1497
|
+
return this.makeVertexFormat(signedDataType, components, normalized);
|
|
1210
1498
|
}
|
|
1211
|
-
|
|
1212
|
-
|
|
1499
|
+
/**
|
|
1500
|
+
* Return a "default" vertex format for a certain shader data type
|
|
1501
|
+
* The simplest vertex format that matches the shader attribute's data type
|
|
1502
|
+
*/
|
|
1503
|
+
getCompatibleVertexFormat(opts) {
|
|
1504
|
+
let vertexType;
|
|
1505
|
+
switch (opts.primitiveType) {
|
|
1506
|
+
case "f32":
|
|
1507
|
+
vertexType = "float32";
|
|
1508
|
+
break;
|
|
1509
|
+
case "i32":
|
|
1510
|
+
vertexType = "sint32";
|
|
1511
|
+
break;
|
|
1512
|
+
case "u32":
|
|
1513
|
+
vertexType = "uint32";
|
|
1514
|
+
break;
|
|
1515
|
+
case "f16":
|
|
1516
|
+
return opts.components <= 2 ? "float16x2" : "float16x4";
|
|
1517
|
+
}
|
|
1518
|
+
if (opts.components === 1) {
|
|
1519
|
+
return vertexType;
|
|
1520
|
+
}
|
|
1521
|
+
return `${vertexType}x${opts.components}`;
|
|
1213
1522
|
}
|
|
1214
|
-
|
|
1215
|
-
|
|
1523
|
+
};
|
|
1524
|
+
var vertexFormatDecoder = new VertexFormatDecoder();
|
|
1216
1525
|
|
|
1217
|
-
// ../core/src/shadertypes/
|
|
1526
|
+
// ../core/src/shadertypes/texture-types/texture-format-table.ts
|
|
1218
1527
|
var texture_compression_bc = "texture-compression-bc";
|
|
1219
1528
|
var texture_compression_astc = "texture-compression-astc";
|
|
1220
1529
|
var texture_compression_etc2 = "texture-compression-etc2";
|
|
@@ -1225,6 +1534,7 @@ var __exports__ = (() => {
|
|
|
1225
1534
|
var float16_renderable = "float16-renderable-webgl";
|
|
1226
1535
|
var rgb9e5ufloat_renderable = "rgb9e5ufloat-renderable-webgl";
|
|
1227
1536
|
var snorm8_renderable = "snorm8-renderable-webgl";
|
|
1537
|
+
var norm16_webgl = "norm16-webgl";
|
|
1228
1538
|
var norm16_renderable = "norm16-renderable-webgl";
|
|
1229
1539
|
var snorm16_renderable = "snorm16-renderable-webgl";
|
|
1230
1540
|
var float32_filterable = "float32-filterable";
|
|
@@ -1258,16 +1568,16 @@ var __exports__ = (() => {
|
|
|
1258
1568
|
"rgba8sint": {},
|
|
1259
1569
|
"bgra8unorm": {},
|
|
1260
1570
|
"bgra8unorm-srgb": {},
|
|
1261
|
-
"r16unorm": { f: norm16_renderable },
|
|
1262
|
-
"rg16unorm": { render: norm16_renderable },
|
|
1263
|
-
"rgb16unorm-webgl": { f:
|
|
1571
|
+
"r16unorm": { f: norm16_webgl, render: norm16_renderable },
|
|
1572
|
+
"rg16unorm": { f: norm16_webgl, render: norm16_renderable },
|
|
1573
|
+
"rgb16unorm-webgl": { f: norm16_webgl, render: false },
|
|
1264
1574
|
// rgb not renderable
|
|
1265
|
-
"rgba16unorm": { render: norm16_renderable },
|
|
1266
|
-
"r16snorm": { f: snorm16_renderable },
|
|
1267
|
-
"rg16snorm": { render: snorm16_renderable },
|
|
1268
|
-
"rgb16snorm-webgl": { f:
|
|
1575
|
+
"rgba16unorm": { f: norm16_webgl, render: norm16_renderable },
|
|
1576
|
+
"r16snorm": { f: norm16_webgl, render: snorm16_renderable },
|
|
1577
|
+
"rg16snorm": { f: norm16_webgl, render: snorm16_renderable },
|
|
1578
|
+
"rgb16snorm-webgl": { f: norm16_webgl, render: false },
|
|
1269
1579
|
// rgb not renderable
|
|
1270
|
-
"rgba16snorm": { render: snorm16_renderable },
|
|
1580
|
+
"rgba16snorm": { f: norm16_webgl, render: snorm16_renderable },
|
|
1271
1581
|
"r16uint": {},
|
|
1272
1582
|
"rg16uint": {},
|
|
1273
1583
|
"rgba16uint": {},
|
|
@@ -1370,7 +1680,7 @@ var __exports__ = (() => {
|
|
|
1370
1680
|
// WEBGL_compressed_texture_pvrtc
|
|
1371
1681
|
"pvrtc-rgb4unorm-webgl": { f: texture_compression_pvrtc_webgl },
|
|
1372
1682
|
"pvrtc-rgba4unorm-webgl": { f: texture_compression_pvrtc_webgl },
|
|
1373
|
-
"pvrtc-
|
|
1683
|
+
"pvrtc-rgb2unorm-webgl": { f: texture_compression_pvrtc_webgl },
|
|
1374
1684
|
"pvrtc-rgba2unorm-webgl": { f: texture_compression_pvrtc_webgl },
|
|
1375
1685
|
// WEBGL_compressed_texture_etc1
|
|
1376
1686
|
"etc1-rbg-unorm-webgl": { f: texture_compression_etc1_webgl },
|
|
@@ -1384,7 +1694,7 @@ var __exports__ = (() => {
|
|
|
1384
1694
|
...TEXTURE_FORMAT_COMPRESSED_TABLE
|
|
1385
1695
|
};
|
|
1386
1696
|
|
|
1387
|
-
// ../core/src/shadertypes/
|
|
1697
|
+
// ../core/src/shadertypes/texture-types/texture-format-decoder.ts
|
|
1388
1698
|
var RGB_FORMAT_REGEX = /^(r|rg|rgb|rgba|bgra)([0-9]*)([a-z]*)(-srgb)?(-webgl)?$/;
|
|
1389
1699
|
var COLOR_FORMAT_PREFIXES = ["rgb", "rgba", "bgra"];
|
|
1390
1700
|
var DEPTH_FORMAT_PREFIXES = ["depth", "stencil"];
|
|
@@ -1437,10 +1747,19 @@ var __exports__ = (() => {
|
|
|
1437
1747
|
depth,
|
|
1438
1748
|
byteAlignment
|
|
1439
1749
|
}) {
|
|
1440
|
-
const
|
|
1441
|
-
const
|
|
1750
|
+
const formatInfo = textureFormatDecoder.getInfo(format);
|
|
1751
|
+
const {
|
|
1752
|
+
bytesPerPixel,
|
|
1753
|
+
bytesPerBlock = bytesPerPixel,
|
|
1754
|
+
blockWidth = 1,
|
|
1755
|
+
blockHeight = 1,
|
|
1756
|
+
compressed = false
|
|
1757
|
+
} = formatInfo;
|
|
1758
|
+
const blockColumns = compressed ? Math.ceil(width / blockWidth) : width;
|
|
1759
|
+
const blockRows = compressed ? Math.ceil(height / blockHeight) : height;
|
|
1760
|
+
const unpaddedBytesPerRow = blockColumns * bytesPerBlock;
|
|
1442
1761
|
const bytesPerRow = Math.ceil(unpaddedBytesPerRow / byteAlignment) * byteAlignment;
|
|
1443
|
-
const rowsPerImage =
|
|
1762
|
+
const rowsPerImage = blockRows;
|
|
1444
1763
|
const byteLength = bytesPerRow * rowsPerImage * depth;
|
|
1445
1764
|
return {
|
|
1446
1765
|
bytesPerPixel,
|
|
@@ -1466,7 +1785,8 @@ var __exports__ = (() => {
|
|
|
1466
1785
|
const isSigned = formatInfo?.signed;
|
|
1467
1786
|
const isInteger = formatInfo?.integer;
|
|
1468
1787
|
const isWebGLSpecific = formatInfo?.webgl;
|
|
1469
|
-
|
|
1788
|
+
const isCompressed = Boolean(formatInfo?.compressed);
|
|
1789
|
+
formatCapabilities.render &&= !isDepthStencil && !isCompressed;
|
|
1470
1790
|
formatCapabilities.filter &&= !isDepthStencil && !isSigned && !isInteger && !isWebGLSpecific;
|
|
1471
1791
|
return formatCapabilities;
|
|
1472
1792
|
}
|
|
@@ -1478,17 +1798,18 @@ var __exports__ = (() => {
|
|
|
1478
1798
|
formatInfo.bytesPerPixel = 1;
|
|
1479
1799
|
formatInfo.srgb = false;
|
|
1480
1800
|
formatInfo.compressed = true;
|
|
1801
|
+
formatInfo.bytesPerBlock = getCompressedTextureBlockByteLength(format);
|
|
1481
1802
|
const blockSize = getCompressedTextureBlockSize(format);
|
|
1482
1803
|
if (blockSize) {
|
|
1483
1804
|
formatInfo.blockWidth = blockSize.blockWidth;
|
|
1484
1805
|
formatInfo.blockHeight = blockSize.blockHeight;
|
|
1485
1806
|
}
|
|
1486
1807
|
}
|
|
1487
|
-
const matches = RGB_FORMAT_REGEX.exec(format);
|
|
1808
|
+
const matches = !formatInfo.packed ? RGB_FORMAT_REGEX.exec(format) : null;
|
|
1488
1809
|
if (matches) {
|
|
1489
1810
|
const [, channels, length, type, srgb, suffix] = matches;
|
|
1490
1811
|
const dataType = `${type}${length}`;
|
|
1491
|
-
const decodedType = getDataTypeInfo(dataType);
|
|
1812
|
+
const decodedType = dataTypeDecoder.getDataTypeInfo(dataType);
|
|
1492
1813
|
const bits = decodedType.byteLength * 8;
|
|
1493
1814
|
const components = channels?.length ?? 1;
|
|
1494
1815
|
const bitsPerChannel = [
|
|
@@ -1563,10 +1884,31 @@ var __exports__ = (() => {
|
|
|
1563
1884
|
const [, blockWidth, blockHeight] = matches;
|
|
1564
1885
|
return { blockWidth: Number(blockWidth), blockHeight: Number(blockHeight) };
|
|
1565
1886
|
}
|
|
1887
|
+
if (format.startsWith("bc") || format.startsWith("etc1") || format.startsWith("etc2") || format.startsWith("eac") || format.startsWith("atc")) {
|
|
1888
|
+
return { blockWidth: 4, blockHeight: 4 };
|
|
1889
|
+
}
|
|
1890
|
+
if (format.startsWith("pvrtc-rgb4") || format.startsWith("pvrtc-rgba4")) {
|
|
1891
|
+
return { blockWidth: 4, blockHeight: 4 };
|
|
1892
|
+
}
|
|
1893
|
+
if (format.startsWith("pvrtc-rgb2") || format.startsWith("pvrtc-rgba2")) {
|
|
1894
|
+
return { blockWidth: 8, blockHeight: 4 };
|
|
1895
|
+
}
|
|
1566
1896
|
return null;
|
|
1567
1897
|
}
|
|
1898
|
+
function getCompressedTextureBlockByteLength(format) {
|
|
1899
|
+
if (format.startsWith("bc1") || format.startsWith("bc4") || format.startsWith("etc1") || format.startsWith("etc2-rgb8") || format.startsWith("etc2-rgb8a1") || format.startsWith("eac-r11") || format === "atc-rgb-unorm-webgl") {
|
|
1900
|
+
return 8;
|
|
1901
|
+
}
|
|
1902
|
+
if (format.startsWith("bc2") || format.startsWith("bc3") || format.startsWith("bc5") || format.startsWith("bc6h") || format.startsWith("bc7") || format.startsWith("etc2-rgba8") || format.startsWith("eac-rg11") || format.startsWith("astc") || format === "atc-rgba-unorm-webgl" || format === "atc-rgbai-unorm-webgl") {
|
|
1903
|
+
return 16;
|
|
1904
|
+
}
|
|
1905
|
+
if (format.startsWith("pvrtc")) {
|
|
1906
|
+
return 8;
|
|
1907
|
+
}
|
|
1908
|
+
return 16;
|
|
1909
|
+
}
|
|
1568
1910
|
|
|
1569
|
-
// ../core/src/image-
|
|
1911
|
+
// ../core/src/shadertypes/image-types/image-types.ts
|
|
1570
1912
|
function isExternalImage(data) {
|
|
1571
1913
|
return typeof ImageData !== "undefined" && data instanceof ImageData || typeof ImageBitmap !== "undefined" && data instanceof ImageBitmap || typeof HTMLImageElement !== "undefined" && data instanceof HTMLImageElement || typeof HTMLVideoElement !== "undefined" && data instanceof HTMLVideoElement || typeof VideoFrame !== "undefined" && data instanceof VideoFrame || typeof HTMLCanvasElement !== "undefined" && data instanceof HTMLCanvasElement || typeof OffscreenCanvas !== "undefined" && data instanceof OffscreenCanvas;
|
|
1572
1914
|
}
|
|
@@ -1589,6 +1931,52 @@ var __exports__ = (() => {
|
|
|
1589
1931
|
// ../core/src/adapter/device.ts
|
|
1590
1932
|
var DeviceLimits = class {
|
|
1591
1933
|
};
|
|
1934
|
+
function formatErrorLogArguments(context, args) {
|
|
1935
|
+
const formattedContext = formatErrorLogValue(context);
|
|
1936
|
+
const formattedArgs = args.map(formatErrorLogValue).filter((arg) => arg !== void 0);
|
|
1937
|
+
return [formattedContext, ...formattedArgs].filter((arg) => arg !== void 0);
|
|
1938
|
+
}
|
|
1939
|
+
function formatErrorLogValue(value) {
|
|
1940
|
+
if (value === void 0) {
|
|
1941
|
+
return void 0;
|
|
1942
|
+
}
|
|
1943
|
+
if (value === null || typeof value === "string" || typeof value === "number" || typeof value === "boolean") {
|
|
1944
|
+
return value;
|
|
1945
|
+
}
|
|
1946
|
+
if (value instanceof Error) {
|
|
1947
|
+
return value.message;
|
|
1948
|
+
}
|
|
1949
|
+
if (Array.isArray(value)) {
|
|
1950
|
+
return value.map(formatErrorLogValue);
|
|
1951
|
+
}
|
|
1952
|
+
if (typeof value === "object") {
|
|
1953
|
+
if (hasCustomToString(value)) {
|
|
1954
|
+
const stringValue = String(value);
|
|
1955
|
+
if (stringValue !== "[object Object]") {
|
|
1956
|
+
return stringValue;
|
|
1957
|
+
}
|
|
1958
|
+
}
|
|
1959
|
+
if (looksLikeGPUCompilationMessage(value)) {
|
|
1960
|
+
return formatGPUCompilationMessage(value);
|
|
1961
|
+
}
|
|
1962
|
+
return value.constructor?.name || "Object";
|
|
1963
|
+
}
|
|
1964
|
+
return String(value);
|
|
1965
|
+
}
|
|
1966
|
+
function hasCustomToString(value) {
|
|
1967
|
+
return "toString" in value && typeof value.toString === "function" && value.toString !== Object.prototype.toString;
|
|
1968
|
+
}
|
|
1969
|
+
function looksLikeGPUCompilationMessage(value) {
|
|
1970
|
+
return "message" in value && "type" in value;
|
|
1971
|
+
}
|
|
1972
|
+
function formatGPUCompilationMessage(value) {
|
|
1973
|
+
const type = typeof value.type === "string" ? value.type : "message";
|
|
1974
|
+
const message = typeof value.message === "string" ? value.message : "";
|
|
1975
|
+
const lineNum = typeof value.lineNum === "number" ? value.lineNum : null;
|
|
1976
|
+
const linePos = typeof value.linePos === "number" ? value.linePos : null;
|
|
1977
|
+
const location = lineNum !== null && linePos !== null ? ` @ ${lineNum}:${linePos}` : lineNum !== null ? ` @ ${lineNum}` : "";
|
|
1978
|
+
return `${type}${location}: ${message}`.trim();
|
|
1979
|
+
}
|
|
1592
1980
|
var DeviceFeatures = class {
|
|
1593
1981
|
features;
|
|
1594
1982
|
disabledFeatures;
|
|
@@ -1618,6 +2006,8 @@ var __exports__ = (() => {
|
|
|
1618
2006
|
userData = {};
|
|
1619
2007
|
/** stats */
|
|
1620
2008
|
statsManager = lumaStats;
|
|
2009
|
+
/** Internal per-device factory storage */
|
|
2010
|
+
_factories = {};
|
|
1621
2011
|
/** An abstract timestamp used for change tracking */
|
|
1622
2012
|
timestamp = 0;
|
|
1623
2013
|
/** True if this device has been reused during device creation (app has multiple references) */
|
|
@@ -1625,12 +2015,15 @@ var __exports__ = (() => {
|
|
|
1625
2015
|
/** Used by other luma.gl modules to store data on the device */
|
|
1626
2016
|
_moduleData = {};
|
|
1627
2017
|
_textureCaps = {};
|
|
2018
|
+
/** Internal timestamp query set used when GPU timing collection is enabled for this device. */
|
|
2019
|
+
_debugGPUTimeQuery = null;
|
|
1628
2020
|
constructor(props) {
|
|
1629
2021
|
this.props = { ..._Device.defaultProps, ...props };
|
|
1630
2022
|
this.id = this.props.id || uid(this[Symbol.toStringTag].toLowerCase());
|
|
1631
2023
|
}
|
|
2024
|
+
// TODO - just expose the shadertypes decoders?
|
|
1632
2025
|
getVertexFormatInfo(format) {
|
|
1633
|
-
return getVertexFormatInfo(format);
|
|
2026
|
+
return vertexFormatDecoder.getVertexFormatInfo(format);
|
|
1634
2027
|
}
|
|
1635
2028
|
isVertexFormatSupported(format) {
|
|
1636
2029
|
return true;
|
|
@@ -1678,6 +2071,16 @@ var __exports__ = (() => {
|
|
|
1678
2071
|
isTextureFormatCompressed(format) {
|
|
1679
2072
|
return textureFormatDecoder.isCompressed(format);
|
|
1680
2073
|
}
|
|
2074
|
+
/** Returns the compressed texture formats that can be created and sampled on this device */
|
|
2075
|
+
getSupportedCompressedTextureFormats() {
|
|
2076
|
+
const supportedFormats = [];
|
|
2077
|
+
for (const format of Object.keys(getTextureFormatTable())) {
|
|
2078
|
+
if (this.isTextureFormatCompressed(format) && this.isTextureFormatSupported(format)) {
|
|
2079
|
+
supportedFormats.push(format);
|
|
2080
|
+
}
|
|
2081
|
+
}
|
|
2082
|
+
return supportedFormats;
|
|
2083
|
+
}
|
|
1681
2084
|
// DEBUG METHODS
|
|
1682
2085
|
pushDebugGroup(groupLabel) {
|
|
1683
2086
|
this.commandEncoder.pushDebugGroup(groupLabel);
|
|
@@ -1720,12 +2123,12 @@ var __exports__ = (() => {
|
|
|
1720
2123
|
reportError(error, context, ...args) {
|
|
1721
2124
|
const isHandled = this.props.onError(error, context);
|
|
1722
2125
|
if (!isHandled) {
|
|
2126
|
+
const logArguments = formatErrorLogArguments(context, args);
|
|
1723
2127
|
return log.error(
|
|
1724
2128
|
this.type === "webgl" ? "%cWebGL" : "%cWebGPU",
|
|
1725
2129
|
"color: white; background: red; padding: 2px 6px; border-radius: 3px;",
|
|
1726
2130
|
error.message,
|
|
1727
|
-
|
|
1728
|
-
...args
|
|
2131
|
+
...logArguments
|
|
1729
2132
|
);
|
|
1730
2133
|
}
|
|
1731
2134
|
return () => {
|
|
@@ -1760,6 +2163,78 @@ or create a device with the 'debug: true' prop.`;
|
|
|
1760
2163
|
beginComputePass(props) {
|
|
1761
2164
|
return this.commandEncoder.beginComputePass(props);
|
|
1762
2165
|
}
|
|
2166
|
+
/**
|
|
2167
|
+
* Generate mipmaps for a WebGPU texture.
|
|
2168
|
+
* WebGPU textures must be created up front with the required mip count, usage flags, and a format that supports the chosen generation path.
|
|
2169
|
+
* WebGL uses `Texture.generateMipmapsWebGL()` directly because the backend manages mip generation on the texture object itself.
|
|
2170
|
+
*/
|
|
2171
|
+
generateMipmapsWebGPU(_texture) {
|
|
2172
|
+
throw new Error("not implemented");
|
|
2173
|
+
}
|
|
2174
|
+
/** Internal helper for creating a shareable WebGL render-pipeline implementation. */
|
|
2175
|
+
_createSharedRenderPipelineWebGL(_props) {
|
|
2176
|
+
throw new Error("_createSharedRenderPipelineWebGL() not implemented");
|
|
2177
|
+
}
|
|
2178
|
+
/** Internal WebGPU-only helper for retrieving the native bind-group layout for a pipeline group. */
|
|
2179
|
+
_createBindGroupLayoutWebGPU(_pipeline, _group) {
|
|
2180
|
+
throw new Error("_createBindGroupLayoutWebGPU() not implemented");
|
|
2181
|
+
}
|
|
2182
|
+
/** Internal WebGPU-only helper for creating a native bind group. */
|
|
2183
|
+
_createBindGroupWebGPU(_bindGroupLayout, _shaderLayout, _bindings, _group) {
|
|
2184
|
+
throw new Error("_createBindGroupWebGPU() not implemented");
|
|
2185
|
+
}
|
|
2186
|
+
/**
|
|
2187
|
+
* Internal helper that returns `true` when timestamp-query GPU timing should be
|
|
2188
|
+
* collected for this device.
|
|
2189
|
+
*/
|
|
2190
|
+
_supportsDebugGPUTime() {
|
|
2191
|
+
return this.features.has("timestamp-query") && Boolean(this.props.debug || this.props.debugGPUTime);
|
|
2192
|
+
}
|
|
2193
|
+
/**
|
|
2194
|
+
* Internal helper that enables device-managed GPU timing collection on the
|
|
2195
|
+
* default command encoder. Reuses the existing query set if timing is already enabled.
|
|
2196
|
+
*
|
|
2197
|
+
* @param queryCount - Number of timestamp slots reserved for profiled passes.
|
|
2198
|
+
* @returns The device-managed timestamp QuerySet, or `null` when timing is not supported or could not be enabled.
|
|
2199
|
+
*/
|
|
2200
|
+
_enableDebugGPUTime(queryCount = 256) {
|
|
2201
|
+
if (!this._supportsDebugGPUTime()) {
|
|
2202
|
+
return null;
|
|
2203
|
+
}
|
|
2204
|
+
if (this._debugGPUTimeQuery) {
|
|
2205
|
+
return this._debugGPUTimeQuery;
|
|
2206
|
+
}
|
|
2207
|
+
try {
|
|
2208
|
+
this._debugGPUTimeQuery = this.createQuerySet({ type: "timestamp", count: queryCount });
|
|
2209
|
+
this.commandEncoder = this.createCommandEncoder({
|
|
2210
|
+
id: this.commandEncoder.props.id,
|
|
2211
|
+
timeProfilingQuerySet: this._debugGPUTimeQuery
|
|
2212
|
+
});
|
|
2213
|
+
} catch {
|
|
2214
|
+
this._debugGPUTimeQuery = null;
|
|
2215
|
+
}
|
|
2216
|
+
return this._debugGPUTimeQuery;
|
|
2217
|
+
}
|
|
2218
|
+
/**
|
|
2219
|
+
* Internal helper that disables device-managed GPU timing collection and restores
|
|
2220
|
+
* the default command encoder to an unprofiled state.
|
|
2221
|
+
*/
|
|
2222
|
+
_disableDebugGPUTime() {
|
|
2223
|
+
if (!this._debugGPUTimeQuery) {
|
|
2224
|
+
return;
|
|
2225
|
+
}
|
|
2226
|
+
if (this.commandEncoder.getTimeProfilingQuerySet() === this._debugGPUTimeQuery) {
|
|
2227
|
+
this.commandEncoder = this.createCommandEncoder({
|
|
2228
|
+
id: this.commandEncoder.props.id
|
|
2229
|
+
});
|
|
2230
|
+
}
|
|
2231
|
+
this._debugGPUTimeQuery.destroy();
|
|
2232
|
+
this._debugGPUTimeQuery = null;
|
|
2233
|
+
}
|
|
2234
|
+
/** Internal helper that returns `true` when device-managed GPU timing is currently active. */
|
|
2235
|
+
_isDebugGPUTimeEnabled() {
|
|
2236
|
+
return this._debugGPUTimeQuery !== null;
|
|
2237
|
+
}
|
|
1763
2238
|
// DEPRECATED METHODS
|
|
1764
2239
|
/** @deprecated Use getDefaultCanvasContext() */
|
|
1765
2240
|
getCanvasContext() {
|
|
@@ -1867,7 +2342,8 @@ or create a device with the 'debug: true' prop.`;
|
|
|
1867
2342
|
onVisibilityChange: (context) => log.log(1, `${context} Visibility changed ${context.isVisible}`)(),
|
|
1868
2343
|
onDevicePixelRatioChange: (context, info) => log.log(1, `${context} DPR changed ${info.oldRatio} => ${context.devicePixelRatio}`)(),
|
|
1869
2344
|
// Debug flags
|
|
1870
|
-
debug:
|
|
2345
|
+
debug: getDefaultDebugValue(),
|
|
2346
|
+
debugGPUTime: false,
|
|
1871
2347
|
debugShaders: log.get("debug-shaders") || void 0,
|
|
1872
2348
|
debugFramebuffers: Boolean(log.get("debug-framebuffers")),
|
|
1873
2349
|
debugFactories: Boolean(log.get("debug-factories")),
|
|
@@ -1878,9 +2354,11 @@ or create a device with the 'debug: true' prop.`;
|
|
|
1878
2354
|
// Experimental
|
|
1879
2355
|
_reuseDevices: false,
|
|
1880
2356
|
_requestMaxLimits: true,
|
|
1881
|
-
_cacheShaders:
|
|
1882
|
-
|
|
1883
|
-
|
|
2357
|
+
_cacheShaders: true,
|
|
2358
|
+
_destroyShaders: false,
|
|
2359
|
+
_cachePipelines: true,
|
|
2360
|
+
_sharePipelines: true,
|
|
2361
|
+
_destroyPipelines: false,
|
|
1884
2362
|
// TODO - Change these after confirming things work as expected
|
|
1885
2363
|
_initializeFeatures: true,
|
|
1886
2364
|
_disabledFeatures: {
|
|
@@ -1889,6 +2367,25 @@ or create a device with the 'debug: true' prop.`;
|
|
|
1889
2367
|
// INTERNAL
|
|
1890
2368
|
_handle: void 0
|
|
1891
2369
|
});
|
|
2370
|
+
function _getDefaultDebugValue(logDebugValue, nodeEnv) {
|
|
2371
|
+
if (logDebugValue !== void 0 && logDebugValue !== null) {
|
|
2372
|
+
return Boolean(logDebugValue);
|
|
2373
|
+
}
|
|
2374
|
+
if (nodeEnv !== void 0) {
|
|
2375
|
+
return nodeEnv !== "production";
|
|
2376
|
+
}
|
|
2377
|
+
return false;
|
|
2378
|
+
}
|
|
2379
|
+
function getDefaultDebugValue() {
|
|
2380
|
+
return _getDefaultDebugValue(log.get("debug"), getNodeEnv());
|
|
2381
|
+
}
|
|
2382
|
+
function getNodeEnv() {
|
|
2383
|
+
const processObject = globalThis.process;
|
|
2384
|
+
if (!processObject?.env) {
|
|
2385
|
+
return void 0;
|
|
2386
|
+
}
|
|
2387
|
+
return processObject.env["NODE_ENV"];
|
|
2388
|
+
}
|
|
1892
2389
|
|
|
1893
2390
|
// ../core/src/adapter/luma.ts
|
|
1894
2391
|
var STARTUP_MESSAGE = "set luma.log.level=1 (or higher) to trace rendering";
|
|
@@ -2066,6 +2563,100 @@ or create a device with the 'debug: true' prop.`;
|
|
|
2066
2563
|
return pageLoadPromise;
|
|
2067
2564
|
}
|
|
2068
2565
|
|
|
2566
|
+
// ../core/src/adapter/canvas-observer.ts
|
|
2567
|
+
var CanvasObserver = class {
|
|
2568
|
+
props;
|
|
2569
|
+
_resizeObserver;
|
|
2570
|
+
_intersectionObserver;
|
|
2571
|
+
_observeDevicePixelRatioTimeout = null;
|
|
2572
|
+
_observeDevicePixelRatioMediaQuery = null;
|
|
2573
|
+
_handleDevicePixelRatioChange = () => this._refreshDevicePixelRatio();
|
|
2574
|
+
_trackPositionInterval = null;
|
|
2575
|
+
_started = false;
|
|
2576
|
+
get started() {
|
|
2577
|
+
return this._started;
|
|
2578
|
+
}
|
|
2579
|
+
constructor(props) {
|
|
2580
|
+
this.props = props;
|
|
2581
|
+
}
|
|
2582
|
+
start() {
|
|
2583
|
+
if (this._started || !this.props.canvas) {
|
|
2584
|
+
return;
|
|
2585
|
+
}
|
|
2586
|
+
this._started = true;
|
|
2587
|
+
this._intersectionObserver ||= new IntersectionObserver(
|
|
2588
|
+
(entries) => this.props.onIntersection(entries)
|
|
2589
|
+
);
|
|
2590
|
+
this._resizeObserver ||= new ResizeObserver((entries) => this.props.onResize(entries));
|
|
2591
|
+
this._intersectionObserver.observe(this.props.canvas);
|
|
2592
|
+
try {
|
|
2593
|
+
this._resizeObserver.observe(this.props.canvas, { box: "device-pixel-content-box" });
|
|
2594
|
+
} catch {
|
|
2595
|
+
this._resizeObserver.observe(this.props.canvas, { box: "content-box" });
|
|
2596
|
+
}
|
|
2597
|
+
this._observeDevicePixelRatioTimeout = setTimeout(() => this._refreshDevicePixelRatio(), 0);
|
|
2598
|
+
if (this.props.trackPosition) {
|
|
2599
|
+
this._trackPosition();
|
|
2600
|
+
}
|
|
2601
|
+
}
|
|
2602
|
+
stop() {
|
|
2603
|
+
if (!this._started) {
|
|
2604
|
+
return;
|
|
2605
|
+
}
|
|
2606
|
+
this._started = false;
|
|
2607
|
+
if (this._observeDevicePixelRatioTimeout) {
|
|
2608
|
+
clearTimeout(this._observeDevicePixelRatioTimeout);
|
|
2609
|
+
this._observeDevicePixelRatioTimeout = null;
|
|
2610
|
+
}
|
|
2611
|
+
if (this._observeDevicePixelRatioMediaQuery) {
|
|
2612
|
+
this._observeDevicePixelRatioMediaQuery.removeEventListener(
|
|
2613
|
+
"change",
|
|
2614
|
+
this._handleDevicePixelRatioChange
|
|
2615
|
+
);
|
|
2616
|
+
this._observeDevicePixelRatioMediaQuery = null;
|
|
2617
|
+
}
|
|
2618
|
+
if (this._trackPositionInterval) {
|
|
2619
|
+
clearInterval(this._trackPositionInterval);
|
|
2620
|
+
this._trackPositionInterval = null;
|
|
2621
|
+
}
|
|
2622
|
+
this._resizeObserver?.disconnect();
|
|
2623
|
+
this._intersectionObserver?.disconnect();
|
|
2624
|
+
}
|
|
2625
|
+
_refreshDevicePixelRatio() {
|
|
2626
|
+
if (!this._started) {
|
|
2627
|
+
return;
|
|
2628
|
+
}
|
|
2629
|
+
this.props.onDevicePixelRatioChange();
|
|
2630
|
+
this._observeDevicePixelRatioMediaQuery?.removeEventListener(
|
|
2631
|
+
"change",
|
|
2632
|
+
this._handleDevicePixelRatioChange
|
|
2633
|
+
);
|
|
2634
|
+
this._observeDevicePixelRatioMediaQuery = matchMedia(
|
|
2635
|
+
`(resolution: ${window.devicePixelRatio}dppx)`
|
|
2636
|
+
);
|
|
2637
|
+
this._observeDevicePixelRatioMediaQuery.addEventListener(
|
|
2638
|
+
"change",
|
|
2639
|
+
this._handleDevicePixelRatioChange,
|
|
2640
|
+
{ once: true }
|
|
2641
|
+
);
|
|
2642
|
+
}
|
|
2643
|
+
_trackPosition(intervalMs = 100) {
|
|
2644
|
+
if (this._trackPositionInterval) {
|
|
2645
|
+
return;
|
|
2646
|
+
}
|
|
2647
|
+
this._trackPositionInterval = setInterval(() => {
|
|
2648
|
+
if (!this._started) {
|
|
2649
|
+
if (this._trackPositionInterval) {
|
|
2650
|
+
clearInterval(this._trackPositionInterval);
|
|
2651
|
+
this._trackPositionInterval = null;
|
|
2652
|
+
}
|
|
2653
|
+
} else {
|
|
2654
|
+
this.props.onPositionChange();
|
|
2655
|
+
}
|
|
2656
|
+
}, intervalMs);
|
|
2657
|
+
}
|
|
2658
|
+
};
|
|
2659
|
+
|
|
2069
2660
|
// ../core/src/utils/promise-utils.ts
|
|
2070
2661
|
function withResolvers() {
|
|
2071
2662
|
let resolve;
|
|
@@ -2090,8 +2681,8 @@ or create a device with the 'debug: true' prop.`;
|
|
|
2090
2681
|
return value;
|
|
2091
2682
|
}
|
|
2092
2683
|
|
|
2093
|
-
// ../core/src/adapter/canvas-
|
|
2094
|
-
var
|
|
2684
|
+
// ../core/src/adapter/canvas-surface.ts
|
|
2685
|
+
var _CanvasSurface = class {
|
|
2095
2686
|
static isHTMLCanvas(canvas) {
|
|
2096
2687
|
return typeof HTMLCanvasElement !== "undefined" && canvas instanceof HTMLCanvasElement;
|
|
2097
2688
|
}
|
|
@@ -2127,11 +2718,7 @@ or create a device with the 'debug: true' prop.`;
|
|
|
2127
2718
|
drawingBufferHeight;
|
|
2128
2719
|
/** Resolves when the canvas is initialized, i.e. when the ResizeObserver has updated the pixel size */
|
|
2129
2720
|
_initializedResolvers = withResolvers();
|
|
2130
|
-
|
|
2131
|
-
_resizeObserver;
|
|
2132
|
-
/** IntersectionObserver to track canvas visibility changes */
|
|
2133
|
-
_intersectionObserver;
|
|
2134
|
-
_observeDevicePixelRatioTimeout = null;
|
|
2721
|
+
_canvasObserver;
|
|
2135
2722
|
/** Position of the canvas in the document, updated by a timer */
|
|
2136
2723
|
_position = [0, 0];
|
|
2137
2724
|
/** Whether this canvas context has been destroyed */
|
|
@@ -2142,7 +2729,7 @@ or create a device with the 'debug: true' prop.`;
|
|
|
2142
2729
|
return `${this[Symbol.toStringTag]}(${this.id})`;
|
|
2143
2730
|
}
|
|
2144
2731
|
constructor(props) {
|
|
2145
|
-
this.props = { ...
|
|
2732
|
+
this.props = { ..._CanvasSurface.defaultProps, ...props };
|
|
2146
2733
|
props = this.props;
|
|
2147
2734
|
this.initialized = this._initializedResolvers.promise;
|
|
2148
2735
|
if (!isBrowser()) {
|
|
@@ -2154,11 +2741,11 @@ or create a device with the 'debug: true' prop.`;
|
|
|
2154
2741
|
} else {
|
|
2155
2742
|
this.canvas = props.canvas;
|
|
2156
2743
|
}
|
|
2157
|
-
if (
|
|
2744
|
+
if (_CanvasSurface.isHTMLCanvas(this.canvas)) {
|
|
2158
2745
|
this.id = props.id || this.canvas.id;
|
|
2159
2746
|
this.type = "html-canvas";
|
|
2160
2747
|
this.htmlCanvas = this.canvas;
|
|
2161
|
-
} else if (
|
|
2748
|
+
} else if (_CanvasSurface.isOffscreenCanvas(this.canvas)) {
|
|
2162
2749
|
this.id = props.id || "offscreen-canvas";
|
|
2163
2750
|
this.type = "offscreen-canvas";
|
|
2164
2751
|
this.offscreenCanvas = this.canvas;
|
|
@@ -2174,33 +2761,20 @@ or create a device with the 'debug: true' prop.`;
|
|
|
2174
2761
|
this.drawingBufferHeight = this.canvas.height;
|
|
2175
2762
|
this.devicePixelRatio = globalThis.devicePixelRatio || 1;
|
|
2176
2763
|
this._position = [0, 0];
|
|
2177
|
-
|
|
2178
|
-
this.
|
|
2179
|
-
|
|
2180
|
-
)
|
|
2181
|
-
this.
|
|
2182
|
-
|
|
2183
|
-
|
|
2184
|
-
|
|
2185
|
-
} catch {
|
|
2186
|
-
this._resizeObserver.observe(this.canvas, { box: "content-box" });
|
|
2187
|
-
}
|
|
2188
|
-
this._observeDevicePixelRatioTimeout = setTimeout(() => this._observeDevicePixelRatio(), 0);
|
|
2189
|
-
if (this.props.trackPosition) {
|
|
2190
|
-
this._trackPosition();
|
|
2191
|
-
}
|
|
2192
|
-
}
|
|
2764
|
+
this._canvasObserver = new CanvasObserver({
|
|
2765
|
+
canvas: this.htmlCanvas,
|
|
2766
|
+
trackPosition: this.props.trackPosition,
|
|
2767
|
+
onResize: (entries) => this._handleResize(entries),
|
|
2768
|
+
onIntersection: (entries) => this._handleIntersection(entries),
|
|
2769
|
+
onDevicePixelRatioChange: () => this._observeDevicePixelRatio(),
|
|
2770
|
+
onPositionChange: () => this.updatePosition()
|
|
2771
|
+
});
|
|
2193
2772
|
}
|
|
2194
2773
|
destroy() {
|
|
2195
2774
|
if (!this.destroyed) {
|
|
2196
2775
|
this.destroyed = true;
|
|
2197
|
-
|
|
2198
|
-
clearTimeout(this._observeDevicePixelRatioTimeout);
|
|
2199
|
-
this._observeDevicePixelRatioTimeout = null;
|
|
2200
|
-
}
|
|
2776
|
+
this._stopObservers();
|
|
2201
2777
|
this.device = null;
|
|
2202
|
-
this._resizeObserver?.disconnect();
|
|
2203
|
-
this._intersectionObserver?.disconnect();
|
|
2204
2778
|
}
|
|
2205
2779
|
}
|
|
2206
2780
|
setProps(props) {
|
|
@@ -2215,41 +2789,22 @@ or create a device with the 'debug: true' prop.`;
|
|
|
2215
2789
|
this._resizeDrawingBufferIfNeeded();
|
|
2216
2790
|
return this._getCurrentFramebuffer(options);
|
|
2217
2791
|
}
|
|
2218
|
-
// SIZE METHODS
|
|
2219
|
-
/**
|
|
2220
|
-
* Returns the size covered by the canvas in CSS pixels
|
|
2221
|
-
* @note This can be different from the actual device pixel size of a canvas due to DPR scaling, and rounding to integer pixels
|
|
2222
|
-
* @note This is independent of the canvas' internal drawing buffer size (.width, .height).
|
|
2223
|
-
*/
|
|
2224
2792
|
getCSSSize() {
|
|
2225
2793
|
return [this.cssWidth, this.cssHeight];
|
|
2226
2794
|
}
|
|
2227
2795
|
getPosition() {
|
|
2228
2796
|
return this._position;
|
|
2229
2797
|
}
|
|
2230
|
-
/**
|
|
2231
|
-
* Returns the size covered by the canvas in actual device pixels.
|
|
2232
|
-
* @note This can be different from the 'CSS' size of a canvas due to DPR scaling, and rounding to integer pixels
|
|
2233
|
-
* @note This is independent of the canvas' internal drawing buffer size (.width, .height).
|
|
2234
|
-
*/
|
|
2235
2798
|
getDevicePixelSize() {
|
|
2236
2799
|
return [this.devicePixelWidth, this.devicePixelHeight];
|
|
2237
2800
|
}
|
|
2238
|
-
/** Get the drawing buffer size (number of pixels GPU is rendering into, can be different from CSS size) */
|
|
2239
2801
|
getDrawingBufferSize() {
|
|
2240
2802
|
return [this.drawingBufferWidth, this.drawingBufferHeight];
|
|
2241
2803
|
}
|
|
2242
|
-
/** Returns the biggest allowed framebuffer size. @todo Allow the application to limit this? */
|
|
2243
2804
|
getMaxDrawingBufferSize() {
|
|
2244
2805
|
const maxTextureDimension = this.device.limits.maxTextureDimension2D;
|
|
2245
2806
|
return [maxTextureDimension, maxTextureDimension];
|
|
2246
2807
|
}
|
|
2247
|
-
/**
|
|
2248
|
-
* Update the canvas drawing buffer size.
|
|
2249
|
-
* @note - Called automatically if props.autoResize is true.
|
|
2250
|
-
* @note - Defers update of drawing buffer size until framebuffer is requested to avoid flicker
|
|
2251
|
-
* (resizing clears the drawing buffer)!
|
|
2252
|
-
*/
|
|
2253
2808
|
setDrawingBufferSize(width, height) {
|
|
2254
2809
|
width = Math.floor(width);
|
|
2255
2810
|
height = Math.floor(height);
|
|
@@ -2260,19 +2815,10 @@ or create a device with the 'debug: true' prop.`;
|
|
|
2260
2815
|
this.drawingBufferHeight = height;
|
|
2261
2816
|
this._needsDrawingBufferResize = true;
|
|
2262
2817
|
}
|
|
2263
|
-
/**
|
|
2264
|
-
* Returns the current DPR (number of physical pixels per CSS pixel), if props.useDevicePixels is true
|
|
2265
|
-
* @note This can be a fractional (non-integer) number, e.g. when the user zooms in the browser.
|
|
2266
|
-
* @note This function handles the non-HTML canvas cases
|
|
2267
|
-
*/
|
|
2268
2818
|
getDevicePixelRatio() {
|
|
2269
|
-
const
|
|
2270
|
-
return
|
|
2819
|
+
const devicePixelRatio2 = typeof window !== "undefined" && window.devicePixelRatio;
|
|
2820
|
+
return devicePixelRatio2 || 1;
|
|
2271
2821
|
}
|
|
2272
|
-
// DEPRECATED METHODS
|
|
2273
|
-
/**
|
|
2274
|
-
* Maps CSS pixel position to device pixel position
|
|
2275
|
-
*/
|
|
2276
2822
|
cssToDevicePixels(cssPixel, yInvert = true) {
|
|
2277
2823
|
const ratio = this.cssToDeviceRatio();
|
|
2278
2824
|
const [width, height] = this.getDrawingBufferSize();
|
|
@@ -2282,10 +2828,10 @@ or create a device with the 'debug: true' prop.`;
|
|
|
2282
2828
|
getPixelSize() {
|
|
2283
2829
|
return this.getDevicePixelSize();
|
|
2284
2830
|
}
|
|
2285
|
-
/** @deprecated
|
|
2831
|
+
/** @deprecated Use the current drawing buffer size for projection setup. */
|
|
2286
2832
|
getAspect() {
|
|
2287
|
-
const [width, height] = this.
|
|
2288
|
-
return width / height;
|
|
2833
|
+
const [width, height] = this.getDrawingBufferSize();
|
|
2834
|
+
return width > 0 && height > 0 ? width / height : 1;
|
|
2289
2835
|
}
|
|
2290
2836
|
/** @deprecated Returns multiplier need to convert CSS size to Device size */
|
|
2291
2837
|
cssToDeviceRatio() {
|
|
@@ -2301,17 +2847,36 @@ or create a device with the 'debug: true' prop.`;
|
|
|
2301
2847
|
resize(size) {
|
|
2302
2848
|
this.setDrawingBufferSize(size.width, size.height);
|
|
2303
2849
|
}
|
|
2304
|
-
// IMPLEMENTATION
|
|
2305
|
-
/**
|
|
2306
|
-
* Allows subclass constructor to override the canvas id for auto created canvases.
|
|
2307
|
-
* This can really help when debugging DOM in apps that create multiple devices
|
|
2308
|
-
*/
|
|
2309
2850
|
_setAutoCreatedCanvasId(id) {
|
|
2310
2851
|
if (this.htmlCanvas?.id === "lumagl-auto-created-canvas") {
|
|
2311
2852
|
this.htmlCanvas.id = id;
|
|
2312
2853
|
}
|
|
2313
2854
|
}
|
|
2314
|
-
/**
|
|
2855
|
+
/**
|
|
2856
|
+
* Starts DOM observation after the derived context and its device are fully initialized.
|
|
2857
|
+
*
|
|
2858
|
+
* `CanvasSurface` construction runs before subclasses can assign `this.device`, and the
|
|
2859
|
+
* default WebGL canvas context is created before `WebGLDevice` has initialized `limits`,
|
|
2860
|
+
* `features`, and the rest of its runtime state. Deferring observer startup avoids early
|
|
2861
|
+
* `ResizeObserver` and DPR callbacks running against a partially initialized device.
|
|
2862
|
+
*/
|
|
2863
|
+
_startObservers() {
|
|
2864
|
+
if (this.destroyed) {
|
|
2865
|
+
return;
|
|
2866
|
+
}
|
|
2867
|
+
this._canvasObserver.start();
|
|
2868
|
+
}
|
|
2869
|
+
/**
|
|
2870
|
+
* Stops all DOM observation and timers associated with a canvas surface.
|
|
2871
|
+
*
|
|
2872
|
+
* This pairs with `_startObservers()` so teardown uses the same lifecycle whether a context is
|
|
2873
|
+
* explicitly destroyed, abandoned during device reuse, or temporarily has not started observing
|
|
2874
|
+
* yet. Centralizing shutdown here keeps resize/DPR/position watchers from surviving past the
|
|
2875
|
+
* lifetime of the owning device.
|
|
2876
|
+
*/
|
|
2877
|
+
_stopObservers() {
|
|
2878
|
+
this._canvasObserver.stop();
|
|
2879
|
+
}
|
|
2315
2880
|
_handleIntersection(entries) {
|
|
2316
2881
|
if (this.destroyed) {
|
|
2317
2882
|
return;
|
|
@@ -2326,11 +2891,6 @@ or create a device with the 'debug: true' prop.`;
|
|
|
2326
2891
|
this.device.props.onVisibilityChange(this);
|
|
2327
2892
|
}
|
|
2328
2893
|
}
|
|
2329
|
-
/**
|
|
2330
|
-
* Reacts to an observed resize by using the most accurate pixel size information the browser can provide
|
|
2331
|
-
* @see https://web.dev/articles/device-pixel-content-box
|
|
2332
|
-
* @see https://webgpufundamentals.org/webgpu/lessons/webgpu-resizing-the-canvas.html
|
|
2333
|
-
*/
|
|
2334
2894
|
_handleResize(entries) {
|
|
2335
2895
|
if (this.destroyed) {
|
|
2336
2896
|
return;
|
|
@@ -2351,12 +2911,14 @@ or create a device with the 'debug: true' prop.`;
|
|
|
2351
2911
|
this._updateDrawingBufferSize();
|
|
2352
2912
|
this.device.props.onResize(this, { oldPixelSize });
|
|
2353
2913
|
}
|
|
2354
|
-
/** Initiate a deferred update for the canvas drawing buffer size */
|
|
2355
2914
|
_updateDrawingBufferSize() {
|
|
2356
2915
|
if (this.props.autoResize) {
|
|
2357
2916
|
if (typeof this.props.useDevicePixels === "number") {
|
|
2358
|
-
const
|
|
2359
|
-
this.setDrawingBufferSize(
|
|
2917
|
+
const devicePixelRatio2 = this.props.useDevicePixels;
|
|
2918
|
+
this.setDrawingBufferSize(
|
|
2919
|
+
this.cssWidth * devicePixelRatio2,
|
|
2920
|
+
this.cssHeight * devicePixelRatio2
|
|
2921
|
+
);
|
|
2360
2922
|
} else if (this.props.useDevicePixels) {
|
|
2361
2923
|
this.setDrawingBufferSize(this.devicePixelWidth, this.devicePixelHeight);
|
|
2362
2924
|
} else {
|
|
@@ -2367,7 +2929,6 @@ or create a device with the 'debug: true' prop.`;
|
|
|
2367
2929
|
this.isInitialized = true;
|
|
2368
2930
|
this.updatePosition();
|
|
2369
2931
|
}
|
|
2370
|
-
/** Perform a deferred resize of the drawing buffer if needed */
|
|
2371
2932
|
_resizeDrawingBufferIfNeeded() {
|
|
2372
2933
|
if (this._needsDrawingBufferResize) {
|
|
2373
2934
|
this._needsDrawingBufferResize = false;
|
|
@@ -2379,36 +2940,17 @@ or create a device with the 'debug: true' prop.`;
|
|
|
2379
2940
|
}
|
|
2380
2941
|
}
|
|
2381
2942
|
}
|
|
2382
|
-
/** Monitor DPR changes */
|
|
2383
2943
|
_observeDevicePixelRatio() {
|
|
2384
|
-
if (this.destroyed) {
|
|
2944
|
+
if (this.destroyed || !this._canvasObserver.started) {
|
|
2385
2945
|
return;
|
|
2386
2946
|
}
|
|
2387
2947
|
const oldRatio = this.devicePixelRatio;
|
|
2388
2948
|
this.devicePixelRatio = window.devicePixelRatio;
|
|
2389
2949
|
this.updatePosition();
|
|
2390
|
-
this.device.props.onDevicePixelRatioChange?.(this, {
|
|
2391
|
-
|
|
2392
|
-
|
|
2393
|
-
() => this._observeDevicePixelRatio(),
|
|
2394
|
-
{ once: true }
|
|
2395
|
-
);
|
|
2396
|
-
}
|
|
2397
|
-
/** Start tracking positions with a timer */
|
|
2398
|
-
_trackPosition(intervalMs = 100) {
|
|
2399
|
-
const intervalId = setInterval(() => {
|
|
2400
|
-
if (this.destroyed) {
|
|
2401
|
-
clearInterval(intervalId);
|
|
2402
|
-
} else {
|
|
2403
|
-
this.updatePosition();
|
|
2404
|
-
}
|
|
2405
|
-
}, intervalMs);
|
|
2950
|
+
this.device.props.onDevicePixelRatioChange?.(this, {
|
|
2951
|
+
oldRatio
|
|
2952
|
+
});
|
|
2406
2953
|
}
|
|
2407
|
-
/**
|
|
2408
|
-
* Calculated the absolute position of the canvas
|
|
2409
|
-
* @note - getBoundingClientRect() is normally cheap but can be expensive
|
|
2410
|
-
* if called before browser has finished a reflow. Should not be the case here.
|
|
2411
|
-
*/
|
|
2412
2954
|
updatePosition() {
|
|
2413
2955
|
if (this.destroyed) {
|
|
2414
2956
|
return;
|
|
@@ -2421,13 +2963,15 @@ or create a device with the 'debug: true' prop.`;
|
|
|
2421
2963
|
if (positionChanged) {
|
|
2422
2964
|
const oldPosition = this._position;
|
|
2423
2965
|
this._position = position;
|
|
2424
|
-
this.device.props.onPositionChange?.(this, {
|
|
2966
|
+
this.device.props.onPositionChange?.(this, {
|
|
2967
|
+
oldPosition
|
|
2968
|
+
});
|
|
2425
2969
|
}
|
|
2426
2970
|
}
|
|
2427
2971
|
}
|
|
2428
2972
|
};
|
|
2429
|
-
var
|
|
2430
|
-
__publicField(
|
|
2973
|
+
var CanvasSurface = _CanvasSurface;
|
|
2974
|
+
__publicField(CanvasSurface, "defaultProps", {
|
|
2431
2975
|
id: void 0,
|
|
2432
2976
|
canvas: null,
|
|
2433
2977
|
width: 800,
|
|
@@ -2455,7 +2999,7 @@ or create a device with the 'debug: true' prop.`;
|
|
|
2455
2999
|
}
|
|
2456
3000
|
function getCanvasFromDOM(canvasId) {
|
|
2457
3001
|
const canvas = document.getElementById(canvasId);
|
|
2458
|
-
if (!
|
|
3002
|
+
if (!CanvasSurface.isHTMLCanvas(canvas)) {
|
|
2459
3003
|
throw new Error("Object is not a canvas element");
|
|
2460
3004
|
}
|
|
2461
3005
|
return canvas;
|
|
@@ -2479,33 +3023,40 @@ or create a device with the 'debug: true' prop.`;
|
|
|
2479
3023
|
const point = pixel;
|
|
2480
3024
|
const x = scaleX(point[0], ratio, width);
|
|
2481
3025
|
let y = scaleY(point[1], ratio, height, yInvert);
|
|
2482
|
-
let
|
|
2483
|
-
const xHigh =
|
|
2484
|
-
|
|
3026
|
+
let temporary = scaleX(point[0] + 1, ratio, width);
|
|
3027
|
+
const xHigh = temporary === width - 1 ? temporary : temporary - 1;
|
|
3028
|
+
temporary = scaleY(point[1] + 1, ratio, height, yInvert);
|
|
2485
3029
|
let yHigh;
|
|
2486
3030
|
if (yInvert) {
|
|
2487
|
-
|
|
3031
|
+
temporary = temporary === 0 ? temporary : temporary + 1;
|
|
2488
3032
|
yHigh = y;
|
|
2489
|
-
y =
|
|
3033
|
+
y = temporary;
|
|
2490
3034
|
} else {
|
|
2491
|
-
yHigh =
|
|
3035
|
+
yHigh = temporary === height - 1 ? temporary : temporary - 1;
|
|
2492
3036
|
}
|
|
2493
3037
|
return {
|
|
2494
3038
|
x,
|
|
2495
3039
|
y,
|
|
2496
|
-
// when ratio < 1, current css pixel and next css pixel may point to same device pixel, set width/height to 1 in those cases.
|
|
2497
3040
|
width: Math.max(xHigh - x + 1, 1),
|
|
2498
3041
|
height: Math.max(yHigh - y + 1, 1)
|
|
2499
3042
|
};
|
|
2500
3043
|
}
|
|
2501
3044
|
function scaleX(x, ratio, width) {
|
|
2502
|
-
|
|
2503
|
-
return r;
|
|
3045
|
+
return Math.min(Math.round(x * ratio), width - 1);
|
|
2504
3046
|
}
|
|
2505
3047
|
function scaleY(y, ratio, height, yInvert) {
|
|
2506
3048
|
return yInvert ? Math.max(0, height - 1 - Math.round(y * ratio)) : Math.min(Math.round(y * ratio), height - 1);
|
|
2507
3049
|
}
|
|
2508
3050
|
|
|
3051
|
+
// ../core/src/adapter/canvas-context.ts
|
|
3052
|
+
var CanvasContext = class extends CanvasSurface {
|
|
3053
|
+
};
|
|
3054
|
+
__publicField(CanvasContext, "defaultProps", CanvasSurface.defaultProps);
|
|
3055
|
+
|
|
3056
|
+
// ../core/src/adapter/presentation-context.ts
|
|
3057
|
+
var PresentationContext = class extends CanvasSurface {
|
|
3058
|
+
};
|
|
3059
|
+
|
|
2509
3060
|
// ../core/src/adapter/resources/sampler.ts
|
|
2510
3061
|
var _Sampler = class extends Resource {
|
|
2511
3062
|
get [Symbol.toStringTag]() {
|
|
@@ -2560,6 +3111,8 @@ or create a device with the 'debug: true' prop.`;
|
|
|
2560
3111
|
depth;
|
|
2561
3112
|
/** mip levels in this texture */
|
|
2562
3113
|
mipLevels;
|
|
3114
|
+
/** sample count */
|
|
3115
|
+
samples;
|
|
2563
3116
|
/** Rows are multiples of this length, padded with extra bytes if needed */
|
|
2564
3117
|
byteAlignment;
|
|
2565
3118
|
/** The ready promise is always resolved. It is provided for type compatibility with DynamicTexture. */
|
|
@@ -2585,6 +3138,7 @@ or create a device with the 'debug: true' prop.`;
|
|
|
2585
3138
|
this.height = this.props.height;
|
|
2586
3139
|
this.depth = this.props.depth;
|
|
2587
3140
|
this.mipLevels = this.props.mipLevels;
|
|
3141
|
+
this.samples = this.props.samples || 1;
|
|
2588
3142
|
if (this.dimension === "cube") {
|
|
2589
3143
|
this.depth = 6;
|
|
2590
3144
|
}
|
|
@@ -2618,9 +3172,25 @@ or create a device with the 'debug: true' prop.`;
|
|
|
2618
3172
|
setSampler(sampler) {
|
|
2619
3173
|
this.sampler = sampler instanceof Sampler ? sampler : this.device.createSampler(sampler);
|
|
2620
3174
|
}
|
|
3175
|
+
/**
|
|
3176
|
+
* Copy raw image data (bytes) into the texture.
|
|
3177
|
+
*
|
|
3178
|
+
* @note Deprecated compatibility wrapper over {@link writeData}.
|
|
3179
|
+
* @note Uses the same layout defaults and alignment rules as {@link writeData}.
|
|
3180
|
+
* @note Tightly packed CPU uploads can omit `bytesPerRow` and `rowsPerImage`.
|
|
3181
|
+
* @note If the CPU source rows are padded, pass explicit `bytesPerRow` and `rowsPerImage`.
|
|
3182
|
+
* @deprecated Use writeData()
|
|
3183
|
+
*/
|
|
3184
|
+
copyImageData(options) {
|
|
3185
|
+
const { data, depth, ...writeOptions } = options;
|
|
3186
|
+
this.writeData(data, {
|
|
3187
|
+
...writeOptions,
|
|
3188
|
+
depthOrArrayLayers: writeOptions.depthOrArrayLayers ?? depth
|
|
3189
|
+
});
|
|
3190
|
+
}
|
|
2621
3191
|
/**
|
|
2622
3192
|
* Calculates the memory layout of the texture, required when reading and writing data.
|
|
2623
|
-
* @return the
|
|
3193
|
+
* @return the backend-aligned linear layout, in particular bytesPerRow which includes any required padding for buffer copy/read paths
|
|
2624
3194
|
*/
|
|
2625
3195
|
computeMemoryLayout(options_ = {}) {
|
|
2626
3196
|
const options = this._normalizeTextureReadOptions(options_);
|
|
@@ -2639,9 +3209,11 @@ or create a device with the 'debug: true' prop.`;
|
|
|
2639
3209
|
* @returns A Buffer containing the texture data.
|
|
2640
3210
|
*
|
|
2641
3211
|
* @note The memory layout of the texture data is determined by the texture format and dimensions.
|
|
2642
|
-
* @note The application can call Texture.computeMemoryLayout() to compute the layout.
|
|
2643
|
-
* @note The application can call Buffer.readAsync()
|
|
2644
|
-
* @note
|
|
3212
|
+
* @note The application can call Texture.computeMemoryLayout() to compute the backend-aligned layout.
|
|
3213
|
+
* @note The application can call Buffer.readAsync() to read the returned buffer on the CPU.
|
|
3214
|
+
* @note The destination buffer must be supplied by the caller and must be large enough for the requested region.
|
|
3215
|
+
* @note On WebGPU this corresponds to a texture-to-buffer copy and uses buffer-copy alignment rules.
|
|
3216
|
+
* @note On WebGL, luma.gl emulates the same logical readback behavior.
|
|
2645
3217
|
*/
|
|
2646
3218
|
readBuffer(options, buffer) {
|
|
2647
3219
|
throw new Error("readBuffer not implemented");
|
|
@@ -2652,15 +3224,20 @@ or create a device with the 'debug: true' prop.`;
|
|
|
2652
3224
|
*
|
|
2653
3225
|
* @note The memory layout of the texture data is determined by the texture format and dimensions.
|
|
2654
3226
|
* @note The application can call Texture.computeMemoryLayout() to compute the layout.
|
|
3227
|
+
* @deprecated Use Texture.readBuffer() with an explicit destination buffer, or DynamicTexture.readAsync() for convenience readback.
|
|
2655
3228
|
*/
|
|
2656
3229
|
readDataAsync(options) {
|
|
2657
3230
|
throw new Error("readBuffer not implemented");
|
|
2658
3231
|
}
|
|
2659
3232
|
/**
|
|
2660
|
-
* Writes
|
|
3233
|
+
* Writes a GPU Buffer into a texture.
|
|
2661
3234
|
*
|
|
3235
|
+
* @param buffer - Source GPU buffer.
|
|
3236
|
+
* @param options - Destination subresource, extent, and source layout options.
|
|
2662
3237
|
* @note The memory layout of the texture data is determined by the texture format and dimensions.
|
|
2663
|
-
* @note The application can call Texture.computeMemoryLayout() to compute the layout.
|
|
3238
|
+
* @note The application can call Texture.computeMemoryLayout() to compute the backend-aligned layout.
|
|
3239
|
+
* @note On WebGPU this corresponds to a buffer-to-texture copy and uses buffer-copy alignment rules.
|
|
3240
|
+
* @note On WebGL, luma.gl emulates the same destination and layout semantics.
|
|
2664
3241
|
*/
|
|
2665
3242
|
writeBuffer(buffer, options) {
|
|
2666
3243
|
throw new Error("readBuffer not implemented");
|
|
@@ -2668,8 +3245,11 @@ or create a device with the 'debug: true' prop.`;
|
|
|
2668
3245
|
/**
|
|
2669
3246
|
* Writes an array buffer into a texture.
|
|
2670
3247
|
*
|
|
2671
|
-
* @
|
|
2672
|
-
* @
|
|
3248
|
+
* @param data - Source texel data.
|
|
3249
|
+
* @param options - Destination subresource, extent, and source layout options.
|
|
3250
|
+
* @note If `bytesPerRow` and `rowsPerImage` are omitted, luma.gl computes a tightly packed CPU-memory layout for the requested region.
|
|
3251
|
+
* @note On WebGPU this corresponds to `GPUQueue.writeTexture()` and does not implicitly pad rows to 256 bytes.
|
|
3252
|
+
* @note On WebGL, padded CPU data is supported via the same `bytesPerRow` and `rowsPerImage` options.
|
|
2673
3253
|
*/
|
|
2674
3254
|
writeData(data, options) {
|
|
2675
3255
|
throw new Error("readBuffer not implemented");
|
|
@@ -2732,37 +3312,166 @@ or create a device with the 'debug: true' prop.`;
|
|
|
2732
3312
|
}
|
|
2733
3313
|
}
|
|
2734
3314
|
_normalizeCopyImageDataOptions(options_) {
|
|
2735
|
-
const {
|
|
2736
|
-
const options = {
|
|
2737
|
-
|
|
2738
|
-
|
|
2739
|
-
|
|
2740
|
-
}
|
|
2741
|
-
options.bytesPerRow = options_.bytesPerRow || width * (info.bytesPerPixel || 4);
|
|
2742
|
-
options.rowsPerImage = options_.rowsPerImage || height;
|
|
2743
|
-
return options;
|
|
3315
|
+
const { data, depth, ...writeOptions } = options_;
|
|
3316
|
+
const options = this._normalizeTextureWriteOptions({
|
|
3317
|
+
...writeOptions,
|
|
3318
|
+
depthOrArrayLayers: writeOptions.depthOrArrayLayers ?? depth
|
|
3319
|
+
});
|
|
3320
|
+
return { data, depth: options.depthOrArrayLayers, ...options };
|
|
2744
3321
|
}
|
|
2745
3322
|
_normalizeCopyExternalImageOptions(options_) {
|
|
3323
|
+
const optionsWithoutUndefined = _Texture._omitUndefined(options_);
|
|
3324
|
+
const mipLevel = optionsWithoutUndefined.mipLevel ?? 0;
|
|
3325
|
+
const mipLevelSize = this._getMipLevelSize(mipLevel);
|
|
2746
3326
|
const size = this.device.getExternalImageSize(options_.image);
|
|
2747
|
-
const options = {
|
|
2748
|
-
|
|
2749
|
-
|
|
3327
|
+
const options = {
|
|
3328
|
+
..._Texture.defaultCopyExternalImageOptions,
|
|
3329
|
+
...mipLevelSize,
|
|
3330
|
+
...size,
|
|
3331
|
+
...optionsWithoutUndefined
|
|
3332
|
+
};
|
|
3333
|
+
options.width = Math.min(options.width, mipLevelSize.width - options.x);
|
|
3334
|
+
options.height = Math.min(options.height, mipLevelSize.height - options.y);
|
|
3335
|
+
options.depth = Math.min(options.depth, mipLevelSize.depthOrArrayLayers - options.z);
|
|
2750
3336
|
return options;
|
|
2751
3337
|
}
|
|
2752
3338
|
_normalizeTextureReadOptions(options_) {
|
|
2753
|
-
const
|
|
2754
|
-
const
|
|
2755
|
-
|
|
2756
|
-
options
|
|
3339
|
+
const optionsWithoutUndefined = _Texture._omitUndefined(options_);
|
|
3340
|
+
const mipLevel = optionsWithoutUndefined.mipLevel ?? 0;
|
|
3341
|
+
const mipLevelSize = this._getMipLevelSize(mipLevel);
|
|
3342
|
+
const options = {
|
|
3343
|
+
..._Texture.defaultTextureReadOptions,
|
|
3344
|
+
...mipLevelSize,
|
|
3345
|
+
...optionsWithoutUndefined
|
|
3346
|
+
};
|
|
3347
|
+
options.width = Math.min(options.width, mipLevelSize.width - options.x);
|
|
3348
|
+
options.height = Math.min(options.height, mipLevelSize.height - options.y);
|
|
3349
|
+
options.depthOrArrayLayers = Math.min(
|
|
3350
|
+
options.depthOrArrayLayers,
|
|
3351
|
+
mipLevelSize.depthOrArrayLayers - options.z
|
|
3352
|
+
);
|
|
2757
3353
|
return options;
|
|
2758
3354
|
}
|
|
3355
|
+
/**
|
|
3356
|
+
* Normalizes a texture read request and validates the color-only readback contract used by the
|
|
3357
|
+
* current texture read APIs. Supported dimensions are `2d`, `cube`, `cube-array`,
|
|
3358
|
+
* `2d-array`, and `3d`.
|
|
3359
|
+
*
|
|
3360
|
+
* @throws if the texture format, aspect, or dimension is not supported by the first-pass
|
|
3361
|
+
* color-read implementation.
|
|
3362
|
+
*/
|
|
3363
|
+
_getSupportedColorReadOptions(options_) {
|
|
3364
|
+
const options = this._normalizeTextureReadOptions(options_);
|
|
3365
|
+
const formatInfo = textureFormatDecoder.getInfo(this.format);
|
|
3366
|
+
this._validateColorReadAspect(options);
|
|
3367
|
+
this._validateColorReadFormat(formatInfo);
|
|
3368
|
+
switch (this.dimension) {
|
|
3369
|
+
case "2d":
|
|
3370
|
+
case "cube":
|
|
3371
|
+
case "cube-array":
|
|
3372
|
+
case "2d-array":
|
|
3373
|
+
case "3d":
|
|
3374
|
+
return options;
|
|
3375
|
+
default:
|
|
3376
|
+
throw new Error(`${this} color readback does not support ${this.dimension} textures`);
|
|
3377
|
+
}
|
|
3378
|
+
}
|
|
3379
|
+
/** Validates that a read request targets the full color aspect of the texture. */
|
|
3380
|
+
_validateColorReadAspect(options) {
|
|
3381
|
+
if (options.aspect !== "all") {
|
|
3382
|
+
throw new Error(`${this} color readback only supports aspect 'all'`);
|
|
3383
|
+
}
|
|
3384
|
+
}
|
|
3385
|
+
/** Validates that a read request targets an uncompressed color-renderable texture format. */
|
|
3386
|
+
_validateColorReadFormat(formatInfo) {
|
|
3387
|
+
if (formatInfo.compressed) {
|
|
3388
|
+
throw new Error(
|
|
3389
|
+
`${this} color readback does not support compressed formats (${this.format})`
|
|
3390
|
+
);
|
|
3391
|
+
}
|
|
3392
|
+
switch (formatInfo.attachment) {
|
|
3393
|
+
case "color":
|
|
3394
|
+
return;
|
|
3395
|
+
case "depth":
|
|
3396
|
+
throw new Error(`${this} color readback does not support depth formats (${this.format})`);
|
|
3397
|
+
case "stencil":
|
|
3398
|
+
throw new Error(`${this} color readback does not support stencil formats (${this.format})`);
|
|
3399
|
+
case "depth-stencil":
|
|
3400
|
+
throw new Error(
|
|
3401
|
+
`${this} color readback does not support depth-stencil formats (${this.format})`
|
|
3402
|
+
);
|
|
3403
|
+
default:
|
|
3404
|
+
throw new Error(`${this} color readback does not support format ${this.format}`);
|
|
3405
|
+
}
|
|
3406
|
+
}
|
|
2759
3407
|
_normalizeTextureWriteOptions(options_) {
|
|
2760
|
-
const
|
|
2761
|
-
const
|
|
2762
|
-
|
|
2763
|
-
options
|
|
3408
|
+
const optionsWithoutUndefined = _Texture._omitUndefined(options_);
|
|
3409
|
+
const mipLevel = optionsWithoutUndefined.mipLevel ?? 0;
|
|
3410
|
+
const mipLevelSize = this._getMipLevelSize(mipLevel);
|
|
3411
|
+
const options = {
|
|
3412
|
+
..._Texture.defaultTextureWriteOptions,
|
|
3413
|
+
...mipLevelSize,
|
|
3414
|
+
...optionsWithoutUndefined
|
|
3415
|
+
};
|
|
3416
|
+
options.width = Math.min(options.width, mipLevelSize.width - options.x);
|
|
3417
|
+
options.height = Math.min(options.height, mipLevelSize.height - options.y);
|
|
3418
|
+
options.depthOrArrayLayers = Math.min(
|
|
3419
|
+
options.depthOrArrayLayers,
|
|
3420
|
+
mipLevelSize.depthOrArrayLayers - options.z
|
|
3421
|
+
);
|
|
3422
|
+
const layout = textureFormatDecoder.computeMemoryLayout({
|
|
3423
|
+
format: this.format,
|
|
3424
|
+
width: options.width,
|
|
3425
|
+
height: options.height,
|
|
3426
|
+
depth: options.depthOrArrayLayers,
|
|
3427
|
+
byteAlignment: this.byteAlignment
|
|
3428
|
+
});
|
|
3429
|
+
const minimumBytesPerRow = layout.bytesPerPixel * options.width;
|
|
3430
|
+
options.bytesPerRow = optionsWithoutUndefined.bytesPerRow ?? layout.bytesPerRow;
|
|
3431
|
+
options.rowsPerImage = optionsWithoutUndefined.rowsPerImage ?? options.height;
|
|
3432
|
+
if (options.bytesPerRow < minimumBytesPerRow) {
|
|
3433
|
+
throw new Error(
|
|
3434
|
+
`bytesPerRow (${options.bytesPerRow}) must be at least ${minimumBytesPerRow} for ${this.format}`
|
|
3435
|
+
);
|
|
3436
|
+
}
|
|
3437
|
+
if (options.rowsPerImage < options.height) {
|
|
3438
|
+
throw new Error(
|
|
3439
|
+
`rowsPerImage (${options.rowsPerImage}) must be at least ${options.height} for ${this.format}`
|
|
3440
|
+
);
|
|
3441
|
+
}
|
|
3442
|
+
const bytesPerPixel = this.device.getTextureFormatInfo(this.format).bytesPerPixel;
|
|
3443
|
+
if (bytesPerPixel && options.bytesPerRow % bytesPerPixel !== 0) {
|
|
3444
|
+
throw new Error(
|
|
3445
|
+
`bytesPerRow (${options.bytesPerRow}) must be a multiple of bytesPerPixel (${bytesPerPixel}) for ${this.format}`
|
|
3446
|
+
);
|
|
3447
|
+
}
|
|
2764
3448
|
return options;
|
|
2765
3449
|
}
|
|
3450
|
+
_getMipLevelSize(mipLevel) {
|
|
3451
|
+
const width = Math.max(1, this.width >> mipLevel);
|
|
3452
|
+
const height = this.baseDimension === "1d" ? 1 : Math.max(1, this.height >> mipLevel);
|
|
3453
|
+
const depthOrArrayLayers = this.dimension === "3d" ? Math.max(1, this.depth >> mipLevel) : this.depth;
|
|
3454
|
+
return { width, height, depthOrArrayLayers };
|
|
3455
|
+
}
|
|
3456
|
+
getAllocatedByteLength() {
|
|
3457
|
+
let allocatedByteLength = 0;
|
|
3458
|
+
for (let mipLevel = 0; mipLevel < this.mipLevels; mipLevel++) {
|
|
3459
|
+
const { width, height, depthOrArrayLayers } = this._getMipLevelSize(mipLevel);
|
|
3460
|
+
allocatedByteLength += textureFormatDecoder.computeMemoryLayout({
|
|
3461
|
+
format: this.format,
|
|
3462
|
+
width,
|
|
3463
|
+
height,
|
|
3464
|
+
depth: depthOrArrayLayers,
|
|
3465
|
+
byteAlignment: 1
|
|
3466
|
+
}).byteLength;
|
|
3467
|
+
}
|
|
3468
|
+
return allocatedByteLength * this.samples;
|
|
3469
|
+
}
|
|
3470
|
+
static _omitUndefined(options) {
|
|
3471
|
+
return Object.fromEntries(
|
|
3472
|
+
Object.entries(options).filter(([, value]) => value !== void 0)
|
|
3473
|
+
);
|
|
3474
|
+
}
|
|
2766
3475
|
};
|
|
2767
3476
|
var Texture = _Texture;
|
|
2768
3477
|
/** The texture can be bound for use as a sampled texture in a shader */
|
|
@@ -2798,6 +3507,10 @@ or create a device with the 'debug: true' prop.`;
|
|
|
2798
3507
|
byteOffset: 0,
|
|
2799
3508
|
bytesPerRow: void 0,
|
|
2800
3509
|
rowsPerImage: void 0,
|
|
3510
|
+
width: void 0,
|
|
3511
|
+
height: void 0,
|
|
3512
|
+
depthOrArrayLayers: void 0,
|
|
3513
|
+
depth: 1,
|
|
2801
3514
|
mipLevel: 0,
|
|
2802
3515
|
x: 0,
|
|
2803
3516
|
y: 0,
|
|
@@ -2831,6 +3544,19 @@ or create a device with the 'debug: true' prop.`;
|
|
|
2831
3544
|
mipLevel: 0,
|
|
2832
3545
|
aspect: "all"
|
|
2833
3546
|
});
|
|
3547
|
+
__publicField(Texture, "defaultTextureWriteOptions", {
|
|
3548
|
+
byteOffset: 0,
|
|
3549
|
+
bytesPerRow: void 0,
|
|
3550
|
+
rowsPerImage: void 0,
|
|
3551
|
+
x: 0,
|
|
3552
|
+
y: 0,
|
|
3553
|
+
z: 0,
|
|
3554
|
+
width: void 0,
|
|
3555
|
+
height: void 0,
|
|
3556
|
+
depthOrArrayLayers: 1,
|
|
3557
|
+
mipLevel: 0,
|
|
3558
|
+
aspect: "all"
|
|
3559
|
+
});
|
|
2834
3560
|
|
|
2835
3561
|
// ../core/src/adapter/resources/texture-view.ts
|
|
2836
3562
|
var _TextureView = class extends Resource {
|
|
@@ -3209,10 +3935,21 @@ ${numberedLines}${positionIndicator}${message.type.toUpperCase()}: ${message.mes
|
|
|
3209
3935
|
linkStatus = "pending";
|
|
3210
3936
|
/** The hash of the pipeline */
|
|
3211
3937
|
hash = "";
|
|
3938
|
+
/** Optional shared backend implementation */
|
|
3939
|
+
sharedRenderPipeline = null;
|
|
3940
|
+
/** Whether shader or pipeline compilation/linking is still in progress */
|
|
3941
|
+
get isPending() {
|
|
3942
|
+
return this.linkStatus === "pending" || this.vs.compilationStatus === "pending" || this.fs?.compilationStatus === "pending";
|
|
3943
|
+
}
|
|
3944
|
+
/** Whether shader or pipeline compilation/linking has failed */
|
|
3945
|
+
get isErrored() {
|
|
3946
|
+
return this.linkStatus === "error" || this.vs.compilationStatus === "error" || this.fs?.compilationStatus === "error";
|
|
3947
|
+
}
|
|
3212
3948
|
constructor(device, props) {
|
|
3213
3949
|
super(device, props, _RenderPipeline.defaultProps);
|
|
3214
3950
|
this.shaderLayout = this.props.shaderLayout;
|
|
3215
3951
|
this.bufferLayout = this.props.bufferLayout || [];
|
|
3952
|
+
this.sharedRenderPipeline = this.props._sharedRenderPipeline || null;
|
|
3216
3953
|
}
|
|
3217
3954
|
};
|
|
3218
3955
|
var RenderPipeline = _RenderPipeline;
|
|
@@ -3230,10 +3967,507 @@ ${numberedLines}${positionIndicator}${message.type.toUpperCase()}: ${message.mes
|
|
|
3230
3967
|
colorAttachmentFormats: void 0,
|
|
3231
3968
|
depthStencilAttachmentFormat: void 0,
|
|
3232
3969
|
parameters: {},
|
|
3233
|
-
|
|
3234
|
-
|
|
3970
|
+
varyings: void 0,
|
|
3971
|
+
bufferMode: void 0,
|
|
3972
|
+
disableWarnings: false,
|
|
3973
|
+
_sharedRenderPipeline: void 0,
|
|
3974
|
+
bindings: void 0,
|
|
3975
|
+
bindGroups: void 0
|
|
3235
3976
|
});
|
|
3236
3977
|
|
|
3978
|
+
// ../core/src/adapter/resources/shared-render-pipeline.ts
|
|
3979
|
+
var SharedRenderPipeline = class extends Resource {
|
|
3980
|
+
get [Symbol.toStringTag]() {
|
|
3981
|
+
return "SharedRenderPipeline";
|
|
3982
|
+
}
|
|
3983
|
+
constructor(device, props) {
|
|
3984
|
+
super(device, props, {
|
|
3985
|
+
...Resource.defaultProps,
|
|
3986
|
+
handle: void 0,
|
|
3987
|
+
vs: void 0,
|
|
3988
|
+
fs: void 0,
|
|
3989
|
+
varyings: void 0,
|
|
3990
|
+
bufferMode: void 0
|
|
3991
|
+
});
|
|
3992
|
+
}
|
|
3993
|
+
};
|
|
3994
|
+
|
|
3995
|
+
// ../core/src/adapter/resources/compute-pipeline.ts
|
|
3996
|
+
var _ComputePipeline = class extends Resource {
|
|
3997
|
+
get [Symbol.toStringTag]() {
|
|
3998
|
+
return "ComputePipeline";
|
|
3999
|
+
}
|
|
4000
|
+
hash = "";
|
|
4001
|
+
/** The merged shader layout */
|
|
4002
|
+
shaderLayout;
|
|
4003
|
+
constructor(device, props) {
|
|
4004
|
+
super(device, props, _ComputePipeline.defaultProps);
|
|
4005
|
+
this.shaderLayout = props.shaderLayout;
|
|
4006
|
+
}
|
|
4007
|
+
};
|
|
4008
|
+
var ComputePipeline = _ComputePipeline;
|
|
4009
|
+
__publicField(ComputePipeline, "defaultProps", {
|
|
4010
|
+
...Resource.defaultProps,
|
|
4011
|
+
shader: void 0,
|
|
4012
|
+
entryPoint: void 0,
|
|
4013
|
+
constants: {},
|
|
4014
|
+
shaderLayout: void 0
|
|
4015
|
+
});
|
|
4016
|
+
|
|
4017
|
+
// ../core/src/factories/pipeline-factory.ts
|
|
4018
|
+
var _PipelineFactory = class {
|
|
4019
|
+
/** Get the singleton default pipeline factory for the specified device */
|
|
4020
|
+
static getDefaultPipelineFactory(device) {
|
|
4021
|
+
const moduleData = device.getModuleData("@luma.gl/core");
|
|
4022
|
+
moduleData.defaultPipelineFactory ||= new _PipelineFactory(device);
|
|
4023
|
+
return moduleData.defaultPipelineFactory;
|
|
4024
|
+
}
|
|
4025
|
+
device;
|
|
4026
|
+
_hashCounter = 0;
|
|
4027
|
+
_hashes = {};
|
|
4028
|
+
_renderPipelineCache = {};
|
|
4029
|
+
_computePipelineCache = {};
|
|
4030
|
+
_sharedRenderPipelineCache = {};
|
|
4031
|
+
get [Symbol.toStringTag]() {
|
|
4032
|
+
return "PipelineFactory";
|
|
4033
|
+
}
|
|
4034
|
+
toString() {
|
|
4035
|
+
return `PipelineFactory(${this.device.id})`;
|
|
4036
|
+
}
|
|
4037
|
+
constructor(device) {
|
|
4038
|
+
this.device = device;
|
|
4039
|
+
}
|
|
4040
|
+
/**
|
|
4041
|
+
* WebGL has two cache layers with different priorities:
|
|
4042
|
+
* - `_sharedRenderPipelineCache` owns `WEBGLSharedRenderPipeline` / `WebGLProgram` reuse.
|
|
4043
|
+
* - `_renderPipelineCache` owns `RenderPipeline` wrapper reuse.
|
|
4044
|
+
*
|
|
4045
|
+
* Shared WebGL program reuse is the hard requirement. Wrapper reuse is beneficial,
|
|
4046
|
+
* but wrapper cache misses are acceptable if that keeps the cache logic simple and
|
|
4047
|
+
* prevents incorrect cache hits.
|
|
4048
|
+
*
|
|
4049
|
+
* In particular, wrapper hash logic must never force program creation or linked-program
|
|
4050
|
+
* introspection just to decide whether a shared WebGL program can be reused.
|
|
4051
|
+
*/
|
|
4052
|
+
/** Return a RenderPipeline matching supplied props. Reuses an equivalent pipeline if already created. */
|
|
4053
|
+
createRenderPipeline(props) {
|
|
4054
|
+
if (!this.device.props._cachePipelines) {
|
|
4055
|
+
return this.device.createRenderPipeline(props);
|
|
4056
|
+
}
|
|
4057
|
+
const allProps = { ...RenderPipeline.defaultProps, ...props };
|
|
4058
|
+
const cache = this._renderPipelineCache;
|
|
4059
|
+
const hash = this._hashRenderPipeline(allProps);
|
|
4060
|
+
let pipeline = cache[hash]?.resource;
|
|
4061
|
+
if (!pipeline) {
|
|
4062
|
+
const sharedRenderPipeline = this.device.type === "webgl" && this.device.props._sharePipelines ? this.createSharedRenderPipeline(allProps) : void 0;
|
|
4063
|
+
pipeline = this.device.createRenderPipeline({
|
|
4064
|
+
...allProps,
|
|
4065
|
+
id: allProps.id ? `${allProps.id}-cached` : uid("unnamed-cached"),
|
|
4066
|
+
_sharedRenderPipeline: sharedRenderPipeline
|
|
4067
|
+
});
|
|
4068
|
+
pipeline.hash = hash;
|
|
4069
|
+
cache[hash] = { resource: pipeline, useCount: 1 };
|
|
4070
|
+
if (this.device.props.debugFactories) {
|
|
4071
|
+
log.log(3, `${this}: ${pipeline} created, count=${cache[hash].useCount}`)();
|
|
4072
|
+
}
|
|
4073
|
+
} else {
|
|
4074
|
+
cache[hash].useCount++;
|
|
4075
|
+
if (this.device.props.debugFactories) {
|
|
4076
|
+
log.log(
|
|
4077
|
+
3,
|
|
4078
|
+
`${this}: ${cache[hash].resource} reused, count=${cache[hash].useCount}, (id=${props.id})`
|
|
4079
|
+
)();
|
|
4080
|
+
}
|
|
4081
|
+
}
|
|
4082
|
+
return pipeline;
|
|
4083
|
+
}
|
|
4084
|
+
/** Return a ComputePipeline matching supplied props. Reuses an equivalent pipeline if already created. */
|
|
4085
|
+
createComputePipeline(props) {
|
|
4086
|
+
if (!this.device.props._cachePipelines) {
|
|
4087
|
+
return this.device.createComputePipeline(props);
|
|
4088
|
+
}
|
|
4089
|
+
const allProps = { ...ComputePipeline.defaultProps, ...props };
|
|
4090
|
+
const cache = this._computePipelineCache;
|
|
4091
|
+
const hash = this._hashComputePipeline(allProps);
|
|
4092
|
+
let pipeline = cache[hash]?.resource;
|
|
4093
|
+
if (!pipeline) {
|
|
4094
|
+
pipeline = this.device.createComputePipeline({
|
|
4095
|
+
...allProps,
|
|
4096
|
+
id: allProps.id ? `${allProps.id}-cached` : void 0
|
|
4097
|
+
});
|
|
4098
|
+
pipeline.hash = hash;
|
|
4099
|
+
cache[hash] = { resource: pipeline, useCount: 1 };
|
|
4100
|
+
if (this.device.props.debugFactories) {
|
|
4101
|
+
log.log(3, `${this}: ${pipeline} created, count=${cache[hash].useCount}`)();
|
|
4102
|
+
}
|
|
4103
|
+
} else {
|
|
4104
|
+
cache[hash].useCount++;
|
|
4105
|
+
if (this.device.props.debugFactories) {
|
|
4106
|
+
log.log(
|
|
4107
|
+
3,
|
|
4108
|
+
`${this}: ${cache[hash].resource} reused, count=${cache[hash].useCount}, (id=${props.id})`
|
|
4109
|
+
)();
|
|
4110
|
+
}
|
|
4111
|
+
}
|
|
4112
|
+
return pipeline;
|
|
4113
|
+
}
|
|
4114
|
+
release(pipeline) {
|
|
4115
|
+
if (!this.device.props._cachePipelines) {
|
|
4116
|
+
pipeline.destroy();
|
|
4117
|
+
return;
|
|
4118
|
+
}
|
|
4119
|
+
const cache = this._getCache(pipeline);
|
|
4120
|
+
const hash = pipeline.hash;
|
|
4121
|
+
cache[hash].useCount--;
|
|
4122
|
+
if (cache[hash].useCount === 0) {
|
|
4123
|
+
this._destroyPipeline(pipeline);
|
|
4124
|
+
if (this.device.props.debugFactories) {
|
|
4125
|
+
log.log(3, `${this}: ${pipeline} released and destroyed`)();
|
|
4126
|
+
}
|
|
4127
|
+
} else if (cache[hash].useCount < 0) {
|
|
4128
|
+
log.error(`${this}: ${pipeline} released, useCount < 0, resetting`)();
|
|
4129
|
+
cache[hash].useCount = 0;
|
|
4130
|
+
} else if (this.device.props.debugFactories) {
|
|
4131
|
+
log.log(3, `${this}: ${pipeline} released, count=${cache[hash].useCount}`)();
|
|
4132
|
+
}
|
|
4133
|
+
}
|
|
4134
|
+
createSharedRenderPipeline(props) {
|
|
4135
|
+
const sharedPipelineHash = this._hashSharedRenderPipeline(props);
|
|
4136
|
+
let sharedCacheItem = this._sharedRenderPipelineCache[sharedPipelineHash];
|
|
4137
|
+
if (!sharedCacheItem) {
|
|
4138
|
+
const sharedRenderPipeline = this.device._createSharedRenderPipelineWebGL(props);
|
|
4139
|
+
sharedCacheItem = { resource: sharedRenderPipeline, useCount: 0 };
|
|
4140
|
+
this._sharedRenderPipelineCache[sharedPipelineHash] = sharedCacheItem;
|
|
4141
|
+
}
|
|
4142
|
+
sharedCacheItem.useCount++;
|
|
4143
|
+
return sharedCacheItem.resource;
|
|
4144
|
+
}
|
|
4145
|
+
releaseSharedRenderPipeline(pipeline) {
|
|
4146
|
+
if (!pipeline.sharedRenderPipeline) {
|
|
4147
|
+
return;
|
|
4148
|
+
}
|
|
4149
|
+
const sharedPipelineHash = this._hashSharedRenderPipeline(pipeline.sharedRenderPipeline.props);
|
|
4150
|
+
const sharedCacheItem = this._sharedRenderPipelineCache[sharedPipelineHash];
|
|
4151
|
+
if (!sharedCacheItem) {
|
|
4152
|
+
return;
|
|
4153
|
+
}
|
|
4154
|
+
sharedCacheItem.useCount--;
|
|
4155
|
+
if (sharedCacheItem.useCount === 0) {
|
|
4156
|
+
sharedCacheItem.resource.destroy();
|
|
4157
|
+
delete this._sharedRenderPipelineCache[sharedPipelineHash];
|
|
4158
|
+
}
|
|
4159
|
+
}
|
|
4160
|
+
// PRIVATE
|
|
4161
|
+
/** Destroy a cached pipeline, removing it from the cache if configured to do so. */
|
|
4162
|
+
_destroyPipeline(pipeline) {
|
|
4163
|
+
const cache = this._getCache(pipeline);
|
|
4164
|
+
if (!this.device.props._destroyPipelines) {
|
|
4165
|
+
return false;
|
|
4166
|
+
}
|
|
4167
|
+
delete cache[pipeline.hash];
|
|
4168
|
+
pipeline.destroy();
|
|
4169
|
+
if (pipeline instanceof RenderPipeline) {
|
|
4170
|
+
this.releaseSharedRenderPipeline(pipeline);
|
|
4171
|
+
}
|
|
4172
|
+
return true;
|
|
4173
|
+
}
|
|
4174
|
+
/** Get the appropriate cache for the type of pipeline */
|
|
4175
|
+
_getCache(pipeline) {
|
|
4176
|
+
let cache;
|
|
4177
|
+
if (pipeline instanceof ComputePipeline) {
|
|
4178
|
+
cache = this._computePipelineCache;
|
|
4179
|
+
}
|
|
4180
|
+
if (pipeline instanceof RenderPipeline) {
|
|
4181
|
+
cache = this._renderPipelineCache;
|
|
4182
|
+
}
|
|
4183
|
+
if (!cache) {
|
|
4184
|
+
throw new Error(`${this}`);
|
|
4185
|
+
}
|
|
4186
|
+
if (!cache[pipeline.hash]) {
|
|
4187
|
+
throw new Error(`${this}: ${pipeline} matched incorrect entry`);
|
|
4188
|
+
}
|
|
4189
|
+
return cache;
|
|
4190
|
+
}
|
|
4191
|
+
/** Calculate a hash based on all the inputs for a compute pipeline */
|
|
4192
|
+
_hashComputePipeline(props) {
|
|
4193
|
+
const { type } = this.device;
|
|
4194
|
+
const shaderHash = this._getHash(props.shader.source);
|
|
4195
|
+
const shaderLayoutHash = this._getHash(JSON.stringify(props.shaderLayout));
|
|
4196
|
+
return `${type}/C/${shaderHash}SL${shaderLayoutHash}`;
|
|
4197
|
+
}
|
|
4198
|
+
/** Calculate a hash based on all the inputs for a render pipeline */
|
|
4199
|
+
_hashRenderPipeline(props) {
|
|
4200
|
+
const vsHash = props.vs ? this._getHash(props.vs.source) : 0;
|
|
4201
|
+
const fsHash = props.fs ? this._getHash(props.fs.source) : 0;
|
|
4202
|
+
const varyingHash = this._getWebGLVaryingHash(props);
|
|
4203
|
+
const shaderLayoutHash = this._getHash(JSON.stringify(props.shaderLayout));
|
|
4204
|
+
const bufferLayoutHash = this._getHash(JSON.stringify(props.bufferLayout));
|
|
4205
|
+
const { type } = this.device;
|
|
4206
|
+
switch (type) {
|
|
4207
|
+
case "webgl":
|
|
4208
|
+
const webglParameterHash = this._getHash(JSON.stringify(props.parameters));
|
|
4209
|
+
return `${type}/R/${vsHash}/${fsHash}V${varyingHash}T${props.topology}P${webglParameterHash}SL${shaderLayoutHash}BL${bufferLayoutHash}`;
|
|
4210
|
+
case "webgpu":
|
|
4211
|
+
default:
|
|
4212
|
+
const entryPointHash = this._getHash(
|
|
4213
|
+
JSON.stringify({
|
|
4214
|
+
vertexEntryPoint: props.vertexEntryPoint,
|
|
4215
|
+
fragmentEntryPoint: props.fragmentEntryPoint
|
|
4216
|
+
})
|
|
4217
|
+
);
|
|
4218
|
+
const parameterHash = this._getHash(JSON.stringify(props.parameters));
|
|
4219
|
+
const attachmentHash = this._getWebGPUAttachmentHash(props);
|
|
4220
|
+
return `${type}/R/${vsHash}/${fsHash}V${varyingHash}T${props.topology}EP${entryPointHash}P${parameterHash}SL${shaderLayoutHash}BL${bufferLayoutHash}A${attachmentHash}`;
|
|
4221
|
+
}
|
|
4222
|
+
}
|
|
4223
|
+
// This is the only gate for shared `WebGLProgram` reuse.
|
|
4224
|
+
// Only include inputs that affect program linking or transform-feedback linkage.
|
|
4225
|
+
// Wrapper-only concerns such as topology, parameters, attachment formats and layout
|
|
4226
|
+
// overrides must not be added here.
|
|
4227
|
+
_hashSharedRenderPipeline(props) {
|
|
4228
|
+
const vsHash = props.vs ? this._getHash(props.vs.source) : 0;
|
|
4229
|
+
const fsHash = props.fs ? this._getHash(props.fs.source) : 0;
|
|
4230
|
+
const varyingHash = this._getWebGLVaryingHash(props);
|
|
4231
|
+
return `webgl/S/${vsHash}/${fsHash}V${varyingHash}`;
|
|
4232
|
+
}
|
|
4233
|
+
_getHash(key) {
|
|
4234
|
+
if (this._hashes[key] === void 0) {
|
|
4235
|
+
this._hashes[key] = this._hashCounter++;
|
|
4236
|
+
}
|
|
4237
|
+
return this._hashes[key];
|
|
4238
|
+
}
|
|
4239
|
+
_getWebGLVaryingHash(props) {
|
|
4240
|
+
const { varyings = [], bufferMode = null } = props;
|
|
4241
|
+
return this._getHash(JSON.stringify({ varyings, bufferMode }));
|
|
4242
|
+
}
|
|
4243
|
+
_getWebGPUAttachmentHash(props) {
|
|
4244
|
+
const colorAttachmentFormats = props.colorAttachmentFormats ?? [
|
|
4245
|
+
this.device.preferredColorFormat
|
|
4246
|
+
];
|
|
4247
|
+
const depthStencilAttachmentFormat = props.parameters?.depthWriteEnabled ? props.depthStencilAttachmentFormat || this.device.preferredDepthFormat : null;
|
|
4248
|
+
return this._getHash(
|
|
4249
|
+
JSON.stringify({
|
|
4250
|
+
colorAttachmentFormats,
|
|
4251
|
+
depthStencilAttachmentFormat
|
|
4252
|
+
})
|
|
4253
|
+
);
|
|
4254
|
+
}
|
|
4255
|
+
};
|
|
4256
|
+
var PipelineFactory = _PipelineFactory;
|
|
4257
|
+
__publicField(PipelineFactory, "defaultProps", { ...RenderPipeline.defaultProps });
|
|
4258
|
+
|
|
4259
|
+
// ../core/src/factories/shader-factory.ts
|
|
4260
|
+
var _ShaderFactory = class {
|
|
4261
|
+
/** Returns the default ShaderFactory for the given {@link Device}, creating one if necessary. */
|
|
4262
|
+
static getDefaultShaderFactory(device) {
|
|
4263
|
+
const moduleData = device.getModuleData("@luma.gl/core");
|
|
4264
|
+
moduleData.defaultShaderFactory ||= new _ShaderFactory(device);
|
|
4265
|
+
return moduleData.defaultShaderFactory;
|
|
4266
|
+
}
|
|
4267
|
+
device;
|
|
4268
|
+
_cache = {};
|
|
4269
|
+
get [Symbol.toStringTag]() {
|
|
4270
|
+
return "ShaderFactory";
|
|
4271
|
+
}
|
|
4272
|
+
toString() {
|
|
4273
|
+
return `${this[Symbol.toStringTag]}(${this.device.id})`;
|
|
4274
|
+
}
|
|
4275
|
+
/** @internal */
|
|
4276
|
+
constructor(device) {
|
|
4277
|
+
this.device = device;
|
|
4278
|
+
}
|
|
4279
|
+
/** Requests a {@link Shader} from the cache, creating a new Shader only if necessary. */
|
|
4280
|
+
createShader(props) {
|
|
4281
|
+
if (!this.device.props._cacheShaders) {
|
|
4282
|
+
return this.device.createShader(props);
|
|
4283
|
+
}
|
|
4284
|
+
const key = this._hashShader(props);
|
|
4285
|
+
let cacheEntry = this._cache[key];
|
|
4286
|
+
if (!cacheEntry) {
|
|
4287
|
+
const resource = this.device.createShader({
|
|
4288
|
+
...props,
|
|
4289
|
+
id: props.id ? `${props.id}-cached` : void 0
|
|
4290
|
+
});
|
|
4291
|
+
this._cache[key] = cacheEntry = { resource, useCount: 1 };
|
|
4292
|
+
if (this.device.props.debugFactories) {
|
|
4293
|
+
log.log(3, `${this}: Created new shader ${resource.id}`)();
|
|
4294
|
+
}
|
|
4295
|
+
} else {
|
|
4296
|
+
cacheEntry.useCount++;
|
|
4297
|
+
if (this.device.props.debugFactories) {
|
|
4298
|
+
log.log(
|
|
4299
|
+
3,
|
|
4300
|
+
`${this}: Reusing shader ${cacheEntry.resource.id} count=${cacheEntry.useCount}`
|
|
4301
|
+
)();
|
|
4302
|
+
}
|
|
4303
|
+
}
|
|
4304
|
+
return cacheEntry.resource;
|
|
4305
|
+
}
|
|
4306
|
+
/** Releases a previously-requested {@link Shader}, destroying it if no users remain. */
|
|
4307
|
+
release(shader) {
|
|
4308
|
+
if (!this.device.props._cacheShaders) {
|
|
4309
|
+
shader.destroy();
|
|
4310
|
+
return;
|
|
4311
|
+
}
|
|
4312
|
+
const key = this._hashShader(shader);
|
|
4313
|
+
const cacheEntry = this._cache[key];
|
|
4314
|
+
if (cacheEntry) {
|
|
4315
|
+
cacheEntry.useCount--;
|
|
4316
|
+
if (cacheEntry.useCount === 0) {
|
|
4317
|
+
if (this.device.props._destroyShaders) {
|
|
4318
|
+
delete this._cache[key];
|
|
4319
|
+
cacheEntry.resource.destroy();
|
|
4320
|
+
if (this.device.props.debugFactories) {
|
|
4321
|
+
log.log(3, `${this}: Releasing shader ${shader.id}, destroyed`)();
|
|
4322
|
+
}
|
|
4323
|
+
}
|
|
4324
|
+
} else if (cacheEntry.useCount < 0) {
|
|
4325
|
+
throw new Error(`ShaderFactory: Shader ${shader.id} released too many times`);
|
|
4326
|
+
} else if (this.device.props.debugFactories) {
|
|
4327
|
+
log.log(3, `${this}: Releasing shader ${shader.id} count=${cacheEntry.useCount}`)();
|
|
4328
|
+
}
|
|
4329
|
+
}
|
|
4330
|
+
}
|
|
4331
|
+
// PRIVATE
|
|
4332
|
+
_hashShader(value) {
|
|
4333
|
+
return `${value.stage}:${value.source}`;
|
|
4334
|
+
}
|
|
4335
|
+
};
|
|
4336
|
+
var ShaderFactory = _ShaderFactory;
|
|
4337
|
+
__publicField(ShaderFactory, "defaultProps", { ...Shader.defaultProps });
|
|
4338
|
+
|
|
4339
|
+
// ../core/src/adapter-utils/bind-groups.ts
|
|
4340
|
+
function getShaderLayoutBinding(shaderLayout, bindingName, options) {
|
|
4341
|
+
const bindingLayout = shaderLayout.bindings.find(
|
|
4342
|
+
(binding) => binding.name === bindingName || `${binding.name.toLocaleLowerCase()}uniforms` === bindingName.toLocaleLowerCase()
|
|
4343
|
+
);
|
|
4344
|
+
if (!bindingLayout && !options?.ignoreWarnings) {
|
|
4345
|
+
log.warn(`Binding ${bindingName} not set: Not found in shader layout.`)();
|
|
4346
|
+
}
|
|
4347
|
+
return bindingLayout || null;
|
|
4348
|
+
}
|
|
4349
|
+
function normalizeBindingsByGroup(shaderLayout, bindingsOrBindGroups) {
|
|
4350
|
+
if (!bindingsOrBindGroups) {
|
|
4351
|
+
return {};
|
|
4352
|
+
}
|
|
4353
|
+
if (areBindingsGrouped(bindingsOrBindGroups)) {
|
|
4354
|
+
const bindGroups2 = bindingsOrBindGroups;
|
|
4355
|
+
return Object.fromEntries(
|
|
4356
|
+
Object.entries(bindGroups2).map(([group, bindings]) => [Number(group), { ...bindings }])
|
|
4357
|
+
);
|
|
4358
|
+
}
|
|
4359
|
+
const bindGroups = {};
|
|
4360
|
+
for (const [bindingName, binding] of Object.entries(bindingsOrBindGroups)) {
|
|
4361
|
+
const bindingLayout = getShaderLayoutBinding(shaderLayout, bindingName);
|
|
4362
|
+
const group = bindingLayout?.group ?? 0;
|
|
4363
|
+
bindGroups[group] ||= {};
|
|
4364
|
+
bindGroups[group][bindingName] = binding;
|
|
4365
|
+
}
|
|
4366
|
+
return bindGroups;
|
|
4367
|
+
}
|
|
4368
|
+
function flattenBindingsByGroup(bindGroups) {
|
|
4369
|
+
const bindings = {};
|
|
4370
|
+
for (const groupBindings of Object.values(bindGroups)) {
|
|
4371
|
+
Object.assign(bindings, groupBindings);
|
|
4372
|
+
}
|
|
4373
|
+
return bindings;
|
|
4374
|
+
}
|
|
4375
|
+
function areBindingsGrouped(bindingsOrBindGroups) {
|
|
4376
|
+
const keys = Object.keys(bindingsOrBindGroups);
|
|
4377
|
+
return keys.length > 0 && keys.every((key) => /^\d+$/.test(key));
|
|
4378
|
+
}
|
|
4379
|
+
|
|
4380
|
+
// ../core/src/factories/bind-group-factory.ts
|
|
4381
|
+
var BindGroupFactory = class {
|
|
4382
|
+
device;
|
|
4383
|
+
_layoutCacheByPipeline = /* @__PURE__ */ new WeakMap();
|
|
4384
|
+
_bindGroupCacheByLayout = /* @__PURE__ */ new WeakMap();
|
|
4385
|
+
constructor(device) {
|
|
4386
|
+
this.device = device;
|
|
4387
|
+
}
|
|
4388
|
+
getBindGroups(pipeline, bindings, bindGroupCacheKeys) {
|
|
4389
|
+
if (this.device.type !== "webgpu" || pipeline.shaderLayout.bindings.length === 0) {
|
|
4390
|
+
return {};
|
|
4391
|
+
}
|
|
4392
|
+
const bindingsByGroup = normalizeBindingsByGroup(pipeline.shaderLayout, bindings);
|
|
4393
|
+
const resolvedBindGroups = {};
|
|
4394
|
+
for (const group of getBindGroupIndicesUpToMax(pipeline.shaderLayout.bindings)) {
|
|
4395
|
+
const groupBindings = bindingsByGroup[group];
|
|
4396
|
+
const bindGroupLayout = this._getBindGroupLayout(pipeline, group);
|
|
4397
|
+
if (!groupBindings || Object.keys(groupBindings).length === 0) {
|
|
4398
|
+
if (!hasBindingsInGroup(pipeline.shaderLayout.bindings, group)) {
|
|
4399
|
+
resolvedBindGroups[group] = this._getEmptyBindGroup(
|
|
4400
|
+
bindGroupLayout,
|
|
4401
|
+
pipeline.shaderLayout,
|
|
4402
|
+
group
|
|
4403
|
+
);
|
|
4404
|
+
}
|
|
4405
|
+
continue;
|
|
4406
|
+
}
|
|
4407
|
+
const bindGroupCacheKey = bindGroupCacheKeys?.[group];
|
|
4408
|
+
if (bindGroupCacheKey) {
|
|
4409
|
+
const layoutCache = this._getLayoutBindGroupCache(bindGroupLayout);
|
|
4410
|
+
if (layoutCache.bindGroupsBySource.has(bindGroupCacheKey)) {
|
|
4411
|
+
resolvedBindGroups[group] = layoutCache.bindGroupsBySource.get(bindGroupCacheKey) || null;
|
|
4412
|
+
continue;
|
|
4413
|
+
}
|
|
4414
|
+
const bindGroup = this.device._createBindGroupWebGPU(
|
|
4415
|
+
bindGroupLayout,
|
|
4416
|
+
pipeline.shaderLayout,
|
|
4417
|
+
groupBindings,
|
|
4418
|
+
group
|
|
4419
|
+
);
|
|
4420
|
+
layoutCache.bindGroupsBySource.set(bindGroupCacheKey, bindGroup);
|
|
4421
|
+
resolvedBindGroups[group] = bindGroup;
|
|
4422
|
+
} else {
|
|
4423
|
+
resolvedBindGroups[group] = this.device._createBindGroupWebGPU(
|
|
4424
|
+
bindGroupLayout,
|
|
4425
|
+
pipeline.shaderLayout,
|
|
4426
|
+
groupBindings,
|
|
4427
|
+
group
|
|
4428
|
+
);
|
|
4429
|
+
}
|
|
4430
|
+
}
|
|
4431
|
+
return resolvedBindGroups;
|
|
4432
|
+
}
|
|
4433
|
+
_getBindGroupLayout(pipeline, group) {
|
|
4434
|
+
let layoutCache = this._layoutCacheByPipeline.get(pipeline);
|
|
4435
|
+
if (!layoutCache) {
|
|
4436
|
+
layoutCache = {};
|
|
4437
|
+
this._layoutCacheByPipeline.set(pipeline, layoutCache);
|
|
4438
|
+
}
|
|
4439
|
+
layoutCache[group] ||= this.device._createBindGroupLayoutWebGPU(pipeline, group);
|
|
4440
|
+
return layoutCache[group];
|
|
4441
|
+
}
|
|
4442
|
+
_getEmptyBindGroup(bindGroupLayout, shaderLayout, group) {
|
|
4443
|
+
const layoutCache = this._getLayoutBindGroupCache(bindGroupLayout);
|
|
4444
|
+
layoutCache.emptyBindGroup ||= this.device._createBindGroupWebGPU(bindGroupLayout, shaderLayout, {}, group) || null;
|
|
4445
|
+
return layoutCache.emptyBindGroup;
|
|
4446
|
+
}
|
|
4447
|
+
_getLayoutBindGroupCache(bindGroupLayout) {
|
|
4448
|
+
let layoutCache = this._bindGroupCacheByLayout.get(bindGroupLayout);
|
|
4449
|
+
if (!layoutCache) {
|
|
4450
|
+
layoutCache = { bindGroupsBySource: /* @__PURE__ */ new WeakMap() };
|
|
4451
|
+
this._bindGroupCacheByLayout.set(bindGroupLayout, layoutCache);
|
|
4452
|
+
}
|
|
4453
|
+
return layoutCache;
|
|
4454
|
+
}
|
|
4455
|
+
};
|
|
4456
|
+
function _getDefaultBindGroupFactory(device) {
|
|
4457
|
+
device._factories.bindGroupFactory ||= new BindGroupFactory(device);
|
|
4458
|
+
return device._factories.bindGroupFactory;
|
|
4459
|
+
}
|
|
4460
|
+
function getBindGroupIndicesUpToMax(bindings) {
|
|
4461
|
+
const maxGroup = bindings.reduce(
|
|
4462
|
+
(highestGroup, binding) => Math.max(highestGroup, binding.group),
|
|
4463
|
+
-1
|
|
4464
|
+
);
|
|
4465
|
+
return Array.from({ length: maxGroup + 1 }, (_, group) => group);
|
|
4466
|
+
}
|
|
4467
|
+
function hasBindingsInGroup(bindings, group) {
|
|
4468
|
+
return bindings.some((binding) => binding.group === group);
|
|
4469
|
+
}
|
|
4470
|
+
|
|
3237
4471
|
// ../core/src/adapter/resources/render-pass.ts
|
|
3238
4472
|
var _RenderPass = class extends Resource {
|
|
3239
4473
|
get [Symbol.toStringTag]() {
|
|
@@ -3272,28 +4506,6 @@ ${numberedLines}${positionIndicator}${message.type.toUpperCase()}: ${message.mes
|
|
|
3272
4506
|
endTimestampIndex: void 0
|
|
3273
4507
|
});
|
|
3274
4508
|
|
|
3275
|
-
// ../core/src/adapter/resources/compute-pipeline.ts
|
|
3276
|
-
var _ComputePipeline = class extends Resource {
|
|
3277
|
-
get [Symbol.toStringTag]() {
|
|
3278
|
-
return "ComputePipeline";
|
|
3279
|
-
}
|
|
3280
|
-
hash = "";
|
|
3281
|
-
/** The merged shader layout */
|
|
3282
|
-
shaderLayout;
|
|
3283
|
-
constructor(device, props) {
|
|
3284
|
-
super(device, props, _ComputePipeline.defaultProps);
|
|
3285
|
-
this.shaderLayout = props.shaderLayout;
|
|
3286
|
-
}
|
|
3287
|
-
};
|
|
3288
|
-
var ComputePipeline = _ComputePipeline;
|
|
3289
|
-
__publicField(ComputePipeline, "defaultProps", {
|
|
3290
|
-
...Resource.defaultProps,
|
|
3291
|
-
shader: void 0,
|
|
3292
|
-
entryPoint: void 0,
|
|
3293
|
-
constants: {},
|
|
3294
|
-
shaderLayout: void 0
|
|
3295
|
-
});
|
|
3296
|
-
|
|
3297
4509
|
// ../core/src/adapter/resources/compute-pass.ts
|
|
3298
4510
|
var _ComputePass = class extends Resource {
|
|
3299
4511
|
constructor(device, props) {
|
|
@@ -3316,8 +4528,69 @@ ${numberedLines}${positionIndicator}${message.type.toUpperCase()}: ${message.mes
|
|
|
3316
4528
|
get [Symbol.toStringTag]() {
|
|
3317
4529
|
return "CommandEncoder";
|
|
3318
4530
|
}
|
|
4531
|
+
_timeProfilingQuerySet = null;
|
|
4532
|
+
_timeProfilingSlotCount = 0;
|
|
4533
|
+
_gpuTimeMs;
|
|
3319
4534
|
constructor(device, props) {
|
|
3320
4535
|
super(device, props, _CommandEncoder.defaultProps);
|
|
4536
|
+
this._timeProfilingQuerySet = props.timeProfilingQuerySet ?? null;
|
|
4537
|
+
this._timeProfilingSlotCount = 0;
|
|
4538
|
+
this._gpuTimeMs = void 0;
|
|
4539
|
+
}
|
|
4540
|
+
/**
|
|
4541
|
+
* Reads all resolved timestamp pairs on the current profiler query set and caches the sum
|
|
4542
|
+
* as milliseconds on this encoder.
|
|
4543
|
+
*/
|
|
4544
|
+
async resolveTimeProfilingQuerySet() {
|
|
4545
|
+
this._gpuTimeMs = void 0;
|
|
4546
|
+
if (!this._timeProfilingQuerySet) {
|
|
4547
|
+
return;
|
|
4548
|
+
}
|
|
4549
|
+
const pairCount = Math.floor(this._timeProfilingSlotCount / 2);
|
|
4550
|
+
if (pairCount <= 0) {
|
|
4551
|
+
return;
|
|
4552
|
+
}
|
|
4553
|
+
const queryCount = pairCount * 2;
|
|
4554
|
+
const results = await this._timeProfilingQuerySet.readResults({
|
|
4555
|
+
firstQuery: 0,
|
|
4556
|
+
queryCount
|
|
4557
|
+
});
|
|
4558
|
+
let totalDurationNanoseconds = 0n;
|
|
4559
|
+
for (let queryIndex = 0; queryIndex < queryCount; queryIndex += 2) {
|
|
4560
|
+
totalDurationNanoseconds += results[queryIndex + 1] - results[queryIndex];
|
|
4561
|
+
}
|
|
4562
|
+
this._gpuTimeMs = Number(totalDurationNanoseconds) / 1e6;
|
|
4563
|
+
}
|
|
4564
|
+
/** Returns the number of query slots consumed by automatic pass profiling on this encoder. */
|
|
4565
|
+
getTimeProfilingSlotCount() {
|
|
4566
|
+
return this._timeProfilingSlotCount;
|
|
4567
|
+
}
|
|
4568
|
+
getTimeProfilingQuerySet() {
|
|
4569
|
+
return this._timeProfilingQuerySet;
|
|
4570
|
+
}
|
|
4571
|
+
/** Internal helper for auto-assigning timestamp slots to render/compute passes on this encoder. */
|
|
4572
|
+
_applyTimeProfilingToPassProps(props) {
|
|
4573
|
+
const passProps = props || {};
|
|
4574
|
+
if (!this._supportsTimestampQueries() || !this._timeProfilingQuerySet) {
|
|
4575
|
+
return passProps;
|
|
4576
|
+
}
|
|
4577
|
+
if (passProps.timestampQuerySet !== void 0 || passProps.beginTimestampIndex !== void 0 || passProps.endTimestampIndex !== void 0) {
|
|
4578
|
+
return passProps;
|
|
4579
|
+
}
|
|
4580
|
+
const beginTimestampIndex = this._timeProfilingSlotCount;
|
|
4581
|
+
if (beginTimestampIndex + 1 >= this._timeProfilingQuerySet.props.count) {
|
|
4582
|
+
return passProps;
|
|
4583
|
+
}
|
|
4584
|
+
this._timeProfilingSlotCount += 2;
|
|
4585
|
+
return {
|
|
4586
|
+
...passProps,
|
|
4587
|
+
timestampQuerySet: this._timeProfilingQuerySet,
|
|
4588
|
+
beginTimestampIndex,
|
|
4589
|
+
endTimestampIndex: beginTimestampIndex + 1
|
|
4590
|
+
};
|
|
4591
|
+
}
|
|
4592
|
+
_supportsTimestampQueries() {
|
|
4593
|
+
return this.device.features.has("timestamp-query");
|
|
3321
4594
|
}
|
|
3322
4595
|
};
|
|
3323
4596
|
var CommandEncoder = _CommandEncoder;
|
|
@@ -3326,7 +4599,8 @@ ${numberedLines}${positionIndicator}${message.type.toUpperCase()}: ${message.mes
|
|
|
3326
4599
|
// beginComputePass(optional GPUComputePassDescriptor descriptor = {}): GPUComputePassEncoder;
|
|
3327
4600
|
__publicField(CommandEncoder, "defaultProps", {
|
|
3328
4601
|
...Resource.defaultProps,
|
|
3329
|
-
measureExecutionTime: void 0
|
|
4602
|
+
measureExecutionTime: void 0,
|
|
4603
|
+
timeProfilingQuerySet: void 0
|
|
3330
4604
|
});
|
|
3331
4605
|
|
|
3332
4606
|
// ../core/src/adapter/resources/command-buffer.ts
|
|
@@ -3343,13 +4617,22 @@ ${numberedLines}${positionIndicator}${message.type.toUpperCase()}: ${message.mes
|
|
|
3343
4617
|
...Resource.defaultProps
|
|
3344
4618
|
});
|
|
3345
4619
|
|
|
3346
|
-
// ../core/src/shadertypes/
|
|
4620
|
+
// ../core/src/shadertypes/shader-types/shader-type-decoder.ts
|
|
3347
4621
|
function getVariableShaderTypeInfo(format) {
|
|
3348
|
-
const
|
|
4622
|
+
const resolvedFormat = resolveVariableShaderTypeAlias(format);
|
|
4623
|
+
const decoded = UNIFORM_FORMATS[resolvedFormat];
|
|
4624
|
+
if (!decoded) {
|
|
4625
|
+
throw new Error(`Unsupported variable shader type: ${format}`);
|
|
4626
|
+
}
|
|
3349
4627
|
return decoded;
|
|
3350
4628
|
}
|
|
3351
4629
|
function getAttributeShaderTypeInfo(attributeType) {
|
|
3352
|
-
const
|
|
4630
|
+
const resolvedAttributeType = resolveAttributeShaderTypeAlias(attributeType);
|
|
4631
|
+
const decoded = TYPE_INFO[resolvedAttributeType];
|
|
4632
|
+
if (!decoded) {
|
|
4633
|
+
throw new Error(`Unsupported attribute shader type: ${attributeType}`);
|
|
4634
|
+
}
|
|
4635
|
+
const [primitiveType, components] = decoded;
|
|
3353
4636
|
const integer = primitiveType === "i32" || primitiveType === "u32";
|
|
3354
4637
|
const signed = primitiveType !== "u32";
|
|
3355
4638
|
const byteLength = PRIMITIVE_TYPE_SIZES[primitiveType] * components;
|
|
@@ -3361,6 +4644,33 @@ ${numberedLines}${positionIndicator}${message.type.toUpperCase()}: ${message.mes
|
|
|
3361
4644
|
signed
|
|
3362
4645
|
};
|
|
3363
4646
|
}
|
|
4647
|
+
var ShaderTypeDecoder = class {
|
|
4648
|
+
getVariableShaderTypeInfo(format) {
|
|
4649
|
+
return getVariableShaderTypeInfo(format);
|
|
4650
|
+
}
|
|
4651
|
+
getAttributeShaderTypeInfo(attributeType) {
|
|
4652
|
+
return getAttributeShaderTypeInfo(attributeType);
|
|
4653
|
+
}
|
|
4654
|
+
makeShaderAttributeType(primitiveType, components) {
|
|
4655
|
+
return makeShaderAttributeType(primitiveType, components);
|
|
4656
|
+
}
|
|
4657
|
+
resolveAttributeShaderTypeAlias(alias) {
|
|
4658
|
+
return resolveAttributeShaderTypeAlias(alias);
|
|
4659
|
+
}
|
|
4660
|
+
resolveVariableShaderTypeAlias(alias) {
|
|
4661
|
+
return resolveVariableShaderTypeAlias(alias);
|
|
4662
|
+
}
|
|
4663
|
+
};
|
|
4664
|
+
function makeShaderAttributeType(primitiveType, components) {
|
|
4665
|
+
return components === 1 ? primitiveType : `vec${components}<${primitiveType}>`;
|
|
4666
|
+
}
|
|
4667
|
+
function resolveAttributeShaderTypeAlias(alias) {
|
|
4668
|
+
return WGSL_ATTRIBUTE_TYPE_ALIAS_MAP[alias] || alias;
|
|
4669
|
+
}
|
|
4670
|
+
function resolveVariableShaderTypeAlias(alias) {
|
|
4671
|
+
return WGSL_VARIABLE_TYPE_ALIAS_MAP[alias] || alias;
|
|
4672
|
+
}
|
|
4673
|
+
var shaderTypeDecoder = new ShaderTypeDecoder();
|
|
3364
4674
|
var PRIMITIVE_TYPE_SIZES = {
|
|
3365
4675
|
f32: 4,
|
|
3366
4676
|
f16: 2,
|
|
@@ -3457,7 +4767,18 @@ ${numberedLines}${positionIndicator}${message.type.toUpperCase()}: ${message.mes
|
|
|
3457
4767
|
vec4h: "vec4<f16>"
|
|
3458
4768
|
};
|
|
3459
4769
|
var WGSL_VARIABLE_TYPE_ALIAS_MAP = {
|
|
3460
|
-
|
|
4770
|
+
vec2i: "vec2<i32>",
|
|
4771
|
+
vec3i: "vec3<i32>",
|
|
4772
|
+
vec4i: "vec4<i32>",
|
|
4773
|
+
vec2u: "vec2<u32>",
|
|
4774
|
+
vec3u: "vec3<u32>",
|
|
4775
|
+
vec4u: "vec4<u32>",
|
|
4776
|
+
vec2f: "vec2<f32>",
|
|
4777
|
+
vec3f: "vec3<f32>",
|
|
4778
|
+
vec4f: "vec4<f32>",
|
|
4779
|
+
vec2h: "vec2<f16>",
|
|
4780
|
+
vec3h: "vec3<f16>",
|
|
4781
|
+
vec4h: "vec4<f16>",
|
|
3461
4782
|
mat2x2f: "mat2x2<f32>",
|
|
3462
4783
|
mat2x3f: "mat2x3<f32>",
|
|
3463
4784
|
mat2x4f: "mat2x4<f32>",
|
|
@@ -3524,10 +4845,10 @@ ${numberedLines}${positionIndicator}${message.type.toUpperCase()}: ${message.mes
|
|
|
3524
4845
|
if (!shaderDeclaration) {
|
|
3525
4846
|
return null;
|
|
3526
4847
|
}
|
|
3527
|
-
const attributeTypeInfo = getAttributeShaderTypeInfo(shaderDeclaration.type);
|
|
3528
|
-
const defaultVertexFormat = getCompatibleVertexFormat(attributeTypeInfo);
|
|
4848
|
+
const attributeTypeInfo = shaderTypeDecoder.getAttributeShaderTypeInfo(shaderDeclaration.type);
|
|
4849
|
+
const defaultVertexFormat = vertexFormatDecoder.getCompatibleVertexFormat(attributeTypeInfo);
|
|
3529
4850
|
const vertexFormat = bufferMapping?.vertexFormat || defaultVertexFormat;
|
|
3530
|
-
const vertexFormatInfo = getVertexFormatInfo(vertexFormat);
|
|
4851
|
+
const vertexFormatInfo = vertexFormatDecoder.getVertexFormatInfo(vertexFormat);
|
|
3531
4852
|
return {
|
|
3532
4853
|
attributeName: bufferMapping?.attributeName || shaderDeclaration.name,
|
|
3533
4854
|
bufferName: bufferMapping?.bufferName || shaderDeclaration.name,
|
|
@@ -3595,7 +4916,7 @@ ${numberedLines}${positionIndicator}${message.type.toUpperCase()}: ${message.mes
|
|
|
3595
4916
|
let byteStride = bufferLayout.byteStride;
|
|
3596
4917
|
if (typeof bufferLayout.byteStride !== "number") {
|
|
3597
4918
|
for (const attributeMapping2 of bufferLayout.attributes || []) {
|
|
3598
|
-
const info = getVertexFormatInfo(attributeMapping2.format);
|
|
4919
|
+
const info = vertexFormatDecoder.getVertexFormatInfo(attributeMapping2.format);
|
|
3599
4920
|
byteStride += info.byteLength;
|
|
3600
4921
|
}
|
|
3601
4922
|
}
|
|
@@ -3685,7 +5006,9 @@ ${numberedLines}${positionIndicator}${message.type.toUpperCase()}: ${message.mes
|
|
|
3685
5006
|
|
|
3686
5007
|
// ../core/src/adapter/resources/fence.ts
|
|
3687
5008
|
var _Fence = class extends Resource {
|
|
3688
|
-
[Symbol.toStringTag]
|
|
5009
|
+
get [Symbol.toStringTag]() {
|
|
5010
|
+
return "Fence";
|
|
5011
|
+
}
|
|
3689
5012
|
constructor(device, props = {}) {
|
|
3690
5013
|
super(device, props, _Fence.defaultProps);
|
|
3691
5014
|
}
|
|
@@ -3713,6 +5036,36 @@ ${numberedLines}${positionIndicator}${message.type.toUpperCase()}: ${message.mes
|
|
|
3713
5036
|
}
|
|
3714
5037
|
});
|
|
3715
5038
|
|
|
5039
|
+
// ../core/src/shadertypes/data-types/decode-data-types.ts
|
|
5040
|
+
function alignTo(size, count) {
|
|
5041
|
+
switch (count) {
|
|
5042
|
+
case 1:
|
|
5043
|
+
return size;
|
|
5044
|
+
case 2:
|
|
5045
|
+
return size + size % 2;
|
|
5046
|
+
default:
|
|
5047
|
+
return size + (4 - size % 4) % 4;
|
|
5048
|
+
}
|
|
5049
|
+
}
|
|
5050
|
+
function getTypedArrayConstructor(type) {
|
|
5051
|
+
const [, , , , Constructor] = NORMALIZED_TYPE_MAP2[type];
|
|
5052
|
+
return Constructor;
|
|
5053
|
+
}
|
|
5054
|
+
var NORMALIZED_TYPE_MAP2 = {
|
|
5055
|
+
uint8: ["uint8", "u32", 1, false, Uint8Array],
|
|
5056
|
+
sint8: ["sint8", "i32", 1, false, Int8Array],
|
|
5057
|
+
unorm8: ["uint8", "f32", 1, true, Uint8Array],
|
|
5058
|
+
snorm8: ["sint8", "f32", 1, true, Int8Array],
|
|
5059
|
+
uint16: ["uint16", "u32", 2, false, Uint16Array],
|
|
5060
|
+
sint16: ["sint16", "i32", 2, false, Int16Array],
|
|
5061
|
+
unorm16: ["uint16", "u32", 2, true, Uint16Array],
|
|
5062
|
+
snorm16: ["sint16", "i32", 2, true, Int16Array],
|
|
5063
|
+
float16: ["float16", "f16", 2, false, Uint16Array],
|
|
5064
|
+
float32: ["float32", "f32", 4, false, Float32Array],
|
|
5065
|
+
uint32: ["uint32", "u32", 4, false, Uint32Array],
|
|
5066
|
+
sint32: ["sint32", "i32", 4, false, Int32Array]
|
|
5067
|
+
};
|
|
5068
|
+
|
|
3716
5069
|
// ../core/src/utils/array-utils-flat.ts
|
|
3717
5070
|
var arrayBuffer;
|
|
3718
5071
|
function getScratchArrayBuffer(byteLength) {
|
|
@@ -3726,19 +5079,32 @@ ${numberedLines}${positionIndicator}${message.type.toUpperCase()}: ${message.mes
|
|
|
3726
5079
|
return new Type(scratchArrayBuffer, 0, length);
|
|
3727
5080
|
}
|
|
3728
5081
|
|
|
5082
|
+
// ../core/src/utils/is-array.ts
|
|
5083
|
+
function isTypedArray(value) {
|
|
5084
|
+
return ArrayBuffer.isView(value) && !(value instanceof DataView);
|
|
5085
|
+
}
|
|
5086
|
+
function isNumberArray(value) {
|
|
5087
|
+
if (Array.isArray(value)) {
|
|
5088
|
+
return value.length === 0 || typeof value[0] === "number";
|
|
5089
|
+
}
|
|
5090
|
+
return isTypedArray(value);
|
|
5091
|
+
}
|
|
5092
|
+
|
|
3729
5093
|
// ../core/src/portable/uniform-buffer-layout.ts
|
|
3730
5094
|
var minBufferSize = 1024;
|
|
3731
5095
|
var UniformBufferLayout = class {
|
|
3732
5096
|
layout = {};
|
|
5097
|
+
uniformTypes;
|
|
3733
5098
|
/** number of bytes needed for buffer allocation */
|
|
3734
5099
|
byteLength;
|
|
3735
5100
|
/** Create a new UniformBufferLayout given a map of attributes. */
|
|
3736
|
-
constructor(uniformTypes
|
|
5101
|
+
constructor(uniformTypes) {
|
|
5102
|
+
this.uniformTypes = { ...uniformTypes };
|
|
3737
5103
|
let size = 0;
|
|
3738
|
-
for (const [key, uniformType] of Object.entries(uniformTypes)) {
|
|
3739
|
-
size = this._addToLayout(key, uniformType, size
|
|
5104
|
+
for (const [key, uniformType] of Object.entries(this.uniformTypes)) {
|
|
5105
|
+
size = this._addToLayout(key, uniformType, size);
|
|
3740
5106
|
}
|
|
3741
|
-
size
|
|
5107
|
+
size = alignTo(size, 4);
|
|
3742
5108
|
this.byteLength = Math.max(size * 4, minBufferSize);
|
|
3743
5109
|
}
|
|
3744
5110
|
/** Does this layout have a field with specified name */
|
|
@@ -3750,115 +5116,264 @@ ${numberedLines}${positionIndicator}${message.type.toUpperCase()}: ${message.mes
|
|
|
3750
5116
|
const layout = this.layout[name2];
|
|
3751
5117
|
return layout;
|
|
3752
5118
|
}
|
|
5119
|
+
/** Flatten nested uniform values into leaf-path values understood by UniformBlock. */
|
|
5120
|
+
getFlatUniformValues(uniformValues) {
|
|
5121
|
+
const flattenedUniformValues = {};
|
|
5122
|
+
for (const [name2, value] of Object.entries(uniformValues)) {
|
|
5123
|
+
const uniformType = this.uniformTypes[name2];
|
|
5124
|
+
if (uniformType) {
|
|
5125
|
+
this._flattenCompositeValue(flattenedUniformValues, name2, uniformType, value);
|
|
5126
|
+
} else if (this.layout[name2]) {
|
|
5127
|
+
flattenedUniformValues[name2] = value;
|
|
5128
|
+
}
|
|
5129
|
+
}
|
|
5130
|
+
return flattenedUniformValues;
|
|
5131
|
+
}
|
|
3753
5132
|
/** Get the data for the complete buffer */
|
|
3754
5133
|
getData(uniformValues) {
|
|
3755
5134
|
const buffer = getScratchArrayBuffer(this.byteLength);
|
|
5135
|
+
new Uint8Array(buffer, 0, this.byteLength).fill(0);
|
|
3756
5136
|
const typedArrays = {
|
|
3757
5137
|
i32: new Int32Array(buffer),
|
|
3758
5138
|
u32: new Uint32Array(buffer),
|
|
3759
5139
|
f32: new Float32Array(buffer),
|
|
3760
5140
|
f16: new Uint16Array(buffer)
|
|
3761
5141
|
};
|
|
3762
|
-
|
|
3763
|
-
|
|
5142
|
+
const flattenedUniformValues = this.getFlatUniformValues(uniformValues);
|
|
5143
|
+
for (const [name2, value] of Object.entries(flattenedUniformValues)) {
|
|
5144
|
+
this._writeLeafValue(typedArrays, name2, value);
|
|
3764
5145
|
}
|
|
3765
5146
|
return new Uint8Array(buffer, 0, this.byteLength);
|
|
3766
5147
|
}
|
|
3767
5148
|
// Recursively add a uniform to the layout
|
|
3768
|
-
_addToLayout(name2, type, offset
|
|
5149
|
+
_addToLayout(name2, type, offset) {
|
|
3769
5150
|
if (typeof type === "string") {
|
|
3770
|
-
const info =
|
|
3771
|
-
const
|
|
3772
|
-
const alignedOffset = alignTo(offset, info.components);
|
|
5151
|
+
const info = getLeafLayoutInfo(type);
|
|
5152
|
+
const alignedOffset = alignTo(offset, info.alignment);
|
|
3773
5153
|
this.layout[name2] = {
|
|
3774
5154
|
offset: alignedOffset,
|
|
3775
|
-
|
|
3776
|
-
type: info.type
|
|
5155
|
+
...info
|
|
3777
5156
|
};
|
|
3778
|
-
return alignedOffset +
|
|
5157
|
+
return alignedOffset + info.size;
|
|
3779
5158
|
}
|
|
3780
5159
|
if (Array.isArray(type)) {
|
|
5160
|
+
if (Array.isArray(type[0])) {
|
|
5161
|
+
throw new Error(`Nested arrays are not supported for ${name2}`);
|
|
5162
|
+
}
|
|
3781
5163
|
const elementType = type[0];
|
|
3782
|
-
const length =
|
|
3783
|
-
|
|
5164
|
+
const length = type[1];
|
|
5165
|
+
const stride = alignTo(getTypeSize(elementType), 4);
|
|
5166
|
+
const arrayOffset = alignTo(offset, 4);
|
|
3784
5167
|
for (let i = 0; i < length; i++) {
|
|
3785
|
-
|
|
5168
|
+
this._addToLayout(`${name2}[${i}]`, elementType, arrayOffset + i * stride);
|
|
3786
5169
|
}
|
|
3787
|
-
return arrayOffset;
|
|
5170
|
+
return arrayOffset + stride * length;
|
|
3788
5171
|
}
|
|
3789
|
-
if (
|
|
5172
|
+
if (isCompositeShaderTypeStruct(type)) {
|
|
3790
5173
|
let structOffset = alignTo(offset, 4);
|
|
3791
5174
|
for (const [memberName, memberType] of Object.entries(type)) {
|
|
3792
5175
|
structOffset = this._addToLayout(`${name2}.${memberName}`, memberType, structOffset);
|
|
3793
5176
|
}
|
|
3794
|
-
return structOffset;
|
|
5177
|
+
return alignTo(structOffset, 4);
|
|
3795
5178
|
}
|
|
3796
5179
|
throw new Error(`Unsupported CompositeShaderType for ${name2}`);
|
|
3797
5180
|
}
|
|
3798
|
-
|
|
3799
|
-
if (
|
|
3800
|
-
|
|
5181
|
+
_flattenCompositeValue(flattenedUniformValues, baseName, uniformType, value) {
|
|
5182
|
+
if (value === void 0) {
|
|
5183
|
+
return;
|
|
5184
|
+
}
|
|
5185
|
+
if (typeof uniformType === "string" || this.layout[baseName]) {
|
|
5186
|
+
flattenedUniformValues[baseName] = value;
|
|
3801
5187
|
return;
|
|
3802
5188
|
}
|
|
3803
|
-
if (Array.isArray(
|
|
3804
|
-
|
|
3805
|
-
|
|
3806
|
-
|
|
3807
|
-
|
|
5189
|
+
if (Array.isArray(uniformType)) {
|
|
5190
|
+
const elementType = uniformType[0];
|
|
5191
|
+
const length = uniformType[1];
|
|
5192
|
+
if (Array.isArray(elementType)) {
|
|
5193
|
+
throw new Error(`Nested arrays are not supported for ${baseName}`);
|
|
5194
|
+
}
|
|
5195
|
+
if (typeof elementType === "string" && isNumberArray(value)) {
|
|
5196
|
+
this._flattenPackedArray(flattenedUniformValues, baseName, elementType, length, value);
|
|
5197
|
+
return;
|
|
5198
|
+
}
|
|
5199
|
+
if (!Array.isArray(value)) {
|
|
5200
|
+
log.warn(`Unsupported uniform array value for ${baseName}:`, value)();
|
|
5201
|
+
return;
|
|
5202
|
+
}
|
|
5203
|
+
for (let index = 0; index < Math.min(value.length, length); index++) {
|
|
5204
|
+
const elementValue = value[index];
|
|
5205
|
+
if (elementValue === void 0) {
|
|
5206
|
+
continue;
|
|
5207
|
+
}
|
|
5208
|
+
this._flattenCompositeValue(
|
|
5209
|
+
flattenedUniformValues,
|
|
5210
|
+
`${baseName}[${index}]`,
|
|
5211
|
+
elementType,
|
|
5212
|
+
elementValue
|
|
5213
|
+
);
|
|
3808
5214
|
}
|
|
3809
5215
|
return;
|
|
3810
5216
|
}
|
|
3811
|
-
if (
|
|
5217
|
+
if (isCompositeShaderTypeStruct(uniformType) && isCompositeUniformObject(value)) {
|
|
3812
5218
|
for (const [key, subValue] of Object.entries(value)) {
|
|
5219
|
+
if (subValue === void 0) {
|
|
5220
|
+
continue;
|
|
5221
|
+
}
|
|
3813
5222
|
const nestedName = `${baseName}.${key}`;
|
|
3814
|
-
this.
|
|
5223
|
+
this._flattenCompositeValue(flattenedUniformValues, nestedName, uniformType[key], subValue);
|
|
3815
5224
|
}
|
|
3816
5225
|
return;
|
|
3817
5226
|
}
|
|
3818
5227
|
log.warn(`Unsupported uniform value for ${baseName}:`, value)();
|
|
3819
5228
|
}
|
|
3820
|
-
|
|
5229
|
+
_flattenPackedArray(flattenedUniformValues, baseName, elementType, length, value) {
|
|
5230
|
+
const numericValue = value;
|
|
5231
|
+
const elementLayout = getLeafLayoutInfo(elementType);
|
|
5232
|
+
const packedElementLength = elementLayout.components;
|
|
5233
|
+
for (let index = 0; index < length; index++) {
|
|
5234
|
+
const start = index * packedElementLength;
|
|
5235
|
+
if (start >= numericValue.length) {
|
|
5236
|
+
break;
|
|
5237
|
+
}
|
|
5238
|
+
if (packedElementLength === 1) {
|
|
5239
|
+
flattenedUniformValues[`${baseName}[${index}]`] = Number(numericValue[start]);
|
|
5240
|
+
} else {
|
|
5241
|
+
flattenedUniformValues[`${baseName}[${index}]`] = sliceNumericArray(
|
|
5242
|
+
value,
|
|
5243
|
+
start,
|
|
5244
|
+
start + packedElementLength
|
|
5245
|
+
);
|
|
5246
|
+
}
|
|
5247
|
+
}
|
|
5248
|
+
}
|
|
5249
|
+
_writeLeafValue(typedArrays, name2, value) {
|
|
3821
5250
|
const layout = this.layout[name2];
|
|
3822
5251
|
if (!layout) {
|
|
3823
5252
|
log.warn(`Uniform ${name2} not found in layout`)();
|
|
3824
5253
|
return;
|
|
3825
5254
|
}
|
|
3826
|
-
const { type,
|
|
5255
|
+
const { type, components, columns, rows, offset } = layout;
|
|
3827
5256
|
const array = typedArrays[type];
|
|
3828
|
-
if (
|
|
5257
|
+
if (components === 1) {
|
|
3829
5258
|
array[offset] = Number(value);
|
|
3830
|
-
|
|
3831
|
-
|
|
5259
|
+
return;
|
|
5260
|
+
}
|
|
5261
|
+
const sourceValue = value;
|
|
5262
|
+
if (columns === 1) {
|
|
5263
|
+
for (let componentIndex = 0; componentIndex < components; componentIndex++) {
|
|
5264
|
+
array[offset + componentIndex] = Number(sourceValue[componentIndex] ?? 0);
|
|
5265
|
+
}
|
|
5266
|
+
return;
|
|
5267
|
+
}
|
|
5268
|
+
let sourceIndex = 0;
|
|
5269
|
+
for (let columnIndex = 0; columnIndex < columns; columnIndex++) {
|
|
5270
|
+
const columnOffset = offset + columnIndex * 4;
|
|
5271
|
+
for (let rowIndex = 0; rowIndex < rows; rowIndex++) {
|
|
5272
|
+
array[columnOffset + rowIndex] = Number(sourceValue[sourceIndex++] ?? 0);
|
|
5273
|
+
}
|
|
3832
5274
|
}
|
|
3833
5275
|
}
|
|
3834
5276
|
};
|
|
3835
|
-
|
|
3836
|
-
|
|
3837
|
-
|
|
3838
|
-
|
|
5277
|
+
function getTypeSize(type) {
|
|
5278
|
+
if (typeof type === "string") {
|
|
5279
|
+
return getLeafLayoutInfo(type).size;
|
|
5280
|
+
}
|
|
5281
|
+
if (Array.isArray(type)) {
|
|
5282
|
+
const elementType = type[0];
|
|
5283
|
+
const length = type[1];
|
|
5284
|
+
if (Array.isArray(elementType)) {
|
|
5285
|
+
throw new Error("Nested arrays are not supported");
|
|
5286
|
+
}
|
|
5287
|
+
return alignTo(getTypeSize(elementType), 4) * length;
|
|
5288
|
+
}
|
|
5289
|
+
let size = 0;
|
|
5290
|
+
for (const memberType of Object.values(type)) {
|
|
5291
|
+
const compositeMemberType = memberType;
|
|
5292
|
+
size = alignTo(size, getTypeAlignment(compositeMemberType));
|
|
5293
|
+
size += getTypeSize(compositeMemberType);
|
|
5294
|
+
}
|
|
5295
|
+
return alignTo(size, 4);
|
|
3839
5296
|
}
|
|
3840
|
-
function
|
|
3841
|
-
if (
|
|
3842
|
-
return
|
|
5297
|
+
function getTypeAlignment(type) {
|
|
5298
|
+
if (typeof type === "string") {
|
|
5299
|
+
return getLeafLayoutInfo(type).alignment;
|
|
3843
5300
|
}
|
|
3844
|
-
|
|
5301
|
+
if (Array.isArray(type)) {
|
|
5302
|
+
return 4;
|
|
5303
|
+
}
|
|
5304
|
+
return 4;
|
|
5305
|
+
}
|
|
5306
|
+
function getLeafLayoutInfo(type) {
|
|
5307
|
+
const resolvedType = resolveVariableShaderTypeAlias(type);
|
|
5308
|
+
const decodedType = getVariableShaderTypeInfo(resolvedType);
|
|
5309
|
+
const matrixMatch = /^mat(\d)x(\d)<.+>$/.exec(resolvedType);
|
|
5310
|
+
if (matrixMatch) {
|
|
5311
|
+
const columns = Number(matrixMatch[1]);
|
|
5312
|
+
const rows = Number(matrixMatch[2]);
|
|
5313
|
+
return {
|
|
5314
|
+
alignment: 4,
|
|
5315
|
+
size: columns * 4,
|
|
5316
|
+
components: columns * rows,
|
|
5317
|
+
columns,
|
|
5318
|
+
rows,
|
|
5319
|
+
shaderType: resolvedType,
|
|
5320
|
+
type: decodedType.type
|
|
5321
|
+
};
|
|
5322
|
+
}
|
|
5323
|
+
const vectorMatch = /^vec(\d)<.+>$/.exec(resolvedType);
|
|
5324
|
+
if (vectorMatch) {
|
|
5325
|
+
const components = Number(vectorMatch[1]);
|
|
5326
|
+
return {
|
|
5327
|
+
alignment: components === 2 ? 2 : 4,
|
|
5328
|
+
size: components === 3 ? 4 : components,
|
|
5329
|
+
components,
|
|
5330
|
+
columns: 1,
|
|
5331
|
+
rows: components,
|
|
5332
|
+
shaderType: resolvedType,
|
|
5333
|
+
type: decodedType.type
|
|
5334
|
+
};
|
|
5335
|
+
}
|
|
5336
|
+
return {
|
|
5337
|
+
alignment: 1,
|
|
5338
|
+
size: 1,
|
|
5339
|
+
components: 1,
|
|
5340
|
+
columns: 1,
|
|
5341
|
+
rows: 1,
|
|
5342
|
+
shaderType: resolvedType,
|
|
5343
|
+
type: decodedType.type
|
|
5344
|
+
};
|
|
5345
|
+
}
|
|
5346
|
+
function isCompositeShaderTypeStruct(value) {
|
|
5347
|
+
return Boolean(value) && typeof value === "object" && !Array.isArray(value);
|
|
5348
|
+
}
|
|
5349
|
+
function isCompositeUniformObject(value) {
|
|
5350
|
+
return Boolean(value) && typeof value === "object" && !Array.isArray(value) && !ArrayBuffer.isView(value);
|
|
5351
|
+
}
|
|
5352
|
+
function sliceNumericArray(value, start, end) {
|
|
5353
|
+
return Array.prototype.slice.call(value, start, end);
|
|
3845
5354
|
}
|
|
3846
5355
|
|
|
3847
5356
|
// ../core/src/utils/array-equal.ts
|
|
5357
|
+
var MAX_ELEMENTWISE_ARRAY_COMPARE_LENGTH = 128;
|
|
3848
5358
|
function arrayEqual(a, b, limit = 16) {
|
|
3849
|
-
if (a
|
|
3850
|
-
return
|
|
5359
|
+
if (a === b) {
|
|
5360
|
+
return true;
|
|
3851
5361
|
}
|
|
3852
5362
|
const arrayA = a;
|
|
3853
5363
|
const arrayB = b;
|
|
3854
|
-
if (!isNumberArray(arrayA)) {
|
|
5364
|
+
if (!isNumberArray(arrayA) || !isNumberArray(arrayB)) {
|
|
3855
5365
|
return false;
|
|
3856
5366
|
}
|
|
3857
|
-
if (
|
|
3858
|
-
|
|
3859
|
-
|
|
3860
|
-
|
|
3861
|
-
|
|
5367
|
+
if (arrayA.length !== arrayB.length) {
|
|
5368
|
+
return false;
|
|
5369
|
+
}
|
|
5370
|
+
const maxCompareLength = Math.min(limit, MAX_ELEMENTWISE_ARRAY_COMPARE_LENGTH);
|
|
5371
|
+
if (arrayA.length > maxCompareLength) {
|
|
5372
|
+
return false;
|
|
5373
|
+
}
|
|
5374
|
+
for (let i = 0; i < arrayA.length; ++i) {
|
|
5375
|
+
if (arrayB[i] !== arrayA[i]) {
|
|
5376
|
+
return false;
|
|
3862
5377
|
}
|
|
3863
5378
|
}
|
|
3864
5379
|
return true;
|
|
@@ -3937,13 +5452,12 @@ ${numberedLines}${positionIndicator}${message.type.toUpperCase()}: ${message.mes
|
|
|
3937
5452
|
constructor(blocks) {
|
|
3938
5453
|
for (const [bufferName, block] of Object.entries(blocks)) {
|
|
3939
5454
|
const uniformBufferName = bufferName;
|
|
3940
|
-
const uniformBufferLayout = new UniformBufferLayout(
|
|
3941
|
-
block.uniformTypes ?? {},
|
|
3942
|
-
block.uniformSizes ?? {}
|
|
3943
|
-
);
|
|
5455
|
+
const uniformBufferLayout = new UniformBufferLayout(block.uniformTypes ?? {});
|
|
3944
5456
|
this.uniformBufferLayouts.set(uniformBufferName, uniformBufferLayout);
|
|
3945
5457
|
const uniformBlock = new UniformBlock({ name: bufferName });
|
|
3946
|
-
uniformBlock.setUniforms(
|
|
5458
|
+
uniformBlock.setUniforms(
|
|
5459
|
+
uniformBufferLayout.getFlatUniformValues(block.defaultUniforms || {})
|
|
5460
|
+
);
|
|
3947
5461
|
this.uniformBlocks.set(uniformBufferName, uniformBlock);
|
|
3948
5462
|
}
|
|
3949
5463
|
}
|
|
@@ -3959,7 +5473,12 @@ ${numberedLines}${positionIndicator}${message.type.toUpperCase()}: ${message.mes
|
|
|
3959
5473
|
*/
|
|
3960
5474
|
setUniforms(uniforms) {
|
|
3961
5475
|
for (const [blockName, uniformValues] of Object.entries(uniforms)) {
|
|
3962
|
-
|
|
5476
|
+
const uniformBufferName = blockName;
|
|
5477
|
+
const uniformBufferLayout = this.uniformBufferLayouts.get(uniformBufferName);
|
|
5478
|
+
const flattenedUniforms = uniformBufferLayout?.getFlatUniformValues(
|
|
5479
|
+
uniformValues || {}
|
|
5480
|
+
);
|
|
5481
|
+
this.uniformBlocks.get(uniformBufferName)?.setUniforms(flattenedUniforms || {});
|
|
3963
5482
|
}
|
|
3964
5483
|
this.updateUniformBuffers();
|
|
3965
5484
|
}
|
|
@@ -4035,7 +5554,7 @@ ${numberedLines}${positionIndicator}${message.type.toUpperCase()}: ${message.mes
|
|
|
4035
5554
|
}
|
|
4036
5555
|
};
|
|
4037
5556
|
|
|
4038
|
-
// ../core/src/shadertypes/
|
|
5557
|
+
// ../core/src/shadertypes/texture-types/texture-layout.ts
|
|
4039
5558
|
function getTextureImageView(arrayBuffer2, memoryLayout, format, image = 0) {
|
|
4040
5559
|
const formatInfo = textureFormatDecoder.getInfo(format);
|
|
4041
5560
|
const bytesPerComponent = formatInfo.bytesPerPixel / formatInfo.components;
|
|
@@ -4073,7 +5592,7 @@ ${numberedLines}${positionIndicator}${message.type.toUpperCase()}: ${message.mes
|
|
|
4073
5592
|
typedArray.set(subArray, offset);
|
|
4074
5593
|
}
|
|
4075
5594
|
|
|
4076
|
-
// ../core/src/shadertypes/
|
|
5595
|
+
// ../core/src/shadertypes/texture-types/pixel-utils.ts
|
|
4077
5596
|
function readPixel(pixelData, x, y, bitsPerChannel) {
|
|
4078
5597
|
if (x < 0 || x >= pixelData.width || y < 0 || y >= pixelData.height) {
|
|
4079
5598
|
throw new Error("Coordinates out of bounds.");
|