@luma.gl/effects 9.3.0-alpha.4 → 9.3.0-alpha.6
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 +952 -193
- package/dist/dist.min.js +6 -6
- package/dist/index.cjs +419 -258
- package/dist/index.cjs.map +2 -2
- 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 -4
- package/dist/passes/postprocessing/image-adjust-filters/brightnesscontrast.js.map +1 -1
- package/dist/passes/postprocessing/image-adjust-filters/denoise.d.ts +1 -1
- package/dist/passes/postprocessing/image-adjust-filters/denoise.d.ts.map +1 -1
- package/dist/passes/postprocessing/image-adjust-filters/denoise.js +29 -21
- 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 +26 -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 +8 -7
- 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 +10 -9
- 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.d.ts.map +1 -1
- package/dist/passes/postprocessing/image-adjust-filters/vibrance.js +9 -8
- package/dist/passes/postprocessing/image-adjust-filters/vibrance.js.map +1 -1
- 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 +9 -13
- 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 +34 -16
- 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 +21 -12
- 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 +20 -11
- 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 +18 -16
- 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 +83 -12
- 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 +33 -21
- 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 +24 -15
- 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 +16 -11
- package/dist/passes/postprocessing/image-fun-filters/magnify.js.map +1 -1
- package/dist/passes/postprocessing/image-warp-filters/bulgepinch.d.ts +2 -2
- package/dist/passes/postprocessing/image-warp-filters/bulgepinch.d.ts.map +1 -1
- package/dist/passes/postprocessing/image-warp-filters/bulgepinch.js +24 -10
- package/dist/passes/postprocessing/image-warp-filters/bulgepinch.js.map +1 -1
- package/dist/passes/postprocessing/image-warp-filters/swirl.d.ts +2 -2
- package/dist/passes/postprocessing/image-warp-filters/swirl.d.ts.map +1 -1
- package/dist/passes/postprocessing/image-warp-filters/swirl.js +18 -13
- 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 +2 -2
- package/src/passes/postprocessing/image-adjust-filters/brightnesscontrast.ts +5 -4
- package/src/passes/postprocessing/image-adjust-filters/denoise.ts +31 -23
- package/src/passes/postprocessing/image-adjust-filters/huesaturation.ts +28 -34
- package/src/passes/postprocessing/image-adjust-filters/noise.ts +8 -7
- package/src/passes/postprocessing/image-adjust-filters/sepia.ts +10 -9
- package/src/passes/postprocessing/image-adjust-filters/vibrance.ts +9 -8
- package/src/passes/postprocessing/image-adjust-filters/vignette.ts +9 -13
- package/src/passes/postprocessing/image-blur-filters/tiltshift.ts +36 -18
- package/src/passes/postprocessing/image-blur-filters/triangleblur.ts +21 -12
- package/src/passes/postprocessing/image-blur-filters/zoomblur.ts +21 -12
- package/src/passes/postprocessing/image-fun-filters/colorhalftone.ts +18 -16
- package/src/passes/postprocessing/image-fun-filters/dotscreen.ts +11 -11
- package/src/passes/postprocessing/image-fun-filters/edgework.ts +84 -13
- package/src/passes/postprocessing/image-fun-filters/hexagonalpixelate.ts +36 -24
- package/src/passes/postprocessing/image-fun-filters/ink.ts +24 -15
- package/src/passes/postprocessing/image-fun-filters/magnify.ts +16 -11
- package/src/passes/postprocessing/image-warp-filters/bulgepinch.ts +24 -10
- package/src/passes/postprocessing/image-warp-filters/swirl.ts +18 -13
- package/src/passes/postprocessing/image-warp-filters/warp.ts +9 -4
package/dist/dist.dev.js
CHANGED
|
@@ -67,12 +67,14 @@ var __exports__ = (() => {
|
|
|
67
67
|
Fence: () => Fence,
|
|
68
68
|
Framebuffer: () => Framebuffer,
|
|
69
69
|
PipelineLayout: () => PipelineLayout,
|
|
70
|
+
PresentationContext: () => PresentationContext,
|
|
70
71
|
QuerySet: () => QuerySet,
|
|
71
72
|
RenderPass: () => RenderPass,
|
|
72
73
|
RenderPipeline: () => RenderPipeline,
|
|
73
74
|
Resource: () => Resource,
|
|
74
75
|
Sampler: () => Sampler,
|
|
75
76
|
Shader: () => Shader,
|
|
77
|
+
SharedRenderPipeline: () => SharedRenderPipeline,
|
|
76
78
|
Texture: () => Texture,
|
|
77
79
|
TextureFormatDecoder: () => TextureFormatDecoder,
|
|
78
80
|
TextureView: () => TextureView,
|
|
@@ -301,6 +303,24 @@ var __exports__ = (() => {
|
|
|
301
303
|
};
|
|
302
304
|
|
|
303
305
|
// ../core/src/utils/stats-manager.ts
|
|
306
|
+
var GPU_TIME_AND_MEMORY_STATS = "GPU Time and Memory";
|
|
307
|
+
var GPU_TIME_AND_MEMORY_STAT_ORDER = [
|
|
308
|
+
"Adapter",
|
|
309
|
+
"GPU",
|
|
310
|
+
"GPU Type",
|
|
311
|
+
"GPU Backend",
|
|
312
|
+
"Frame Rate",
|
|
313
|
+
"CPU Time",
|
|
314
|
+
"GPU Time",
|
|
315
|
+
"GPU Memory",
|
|
316
|
+
"Buffer Memory",
|
|
317
|
+
"Texture Memory",
|
|
318
|
+
"Referenced Buffer Memory",
|
|
319
|
+
"Referenced Texture Memory",
|
|
320
|
+
"Swap Chain Texture"
|
|
321
|
+
];
|
|
322
|
+
var ORDERED_STATS_CACHE = /* @__PURE__ */ new WeakMap();
|
|
323
|
+
var ORDERED_STAT_NAME_SET_CACHE = /* @__PURE__ */ new WeakMap();
|
|
304
324
|
var StatsManager = class {
|
|
305
325
|
stats = /* @__PURE__ */ new Map();
|
|
306
326
|
getStats(name2) {
|
|
@@ -310,10 +330,50 @@ var __exports__ = (() => {
|
|
|
310
330
|
if (!this.stats.has(name2)) {
|
|
311
331
|
this.stats.set(name2, new Stats({ id: name2 }));
|
|
312
332
|
}
|
|
313
|
-
|
|
333
|
+
const stats = this.stats.get(name2);
|
|
334
|
+
if (name2 === GPU_TIME_AND_MEMORY_STATS) {
|
|
335
|
+
initializeStats(stats, GPU_TIME_AND_MEMORY_STAT_ORDER);
|
|
336
|
+
}
|
|
337
|
+
return stats;
|
|
314
338
|
}
|
|
315
339
|
};
|
|
316
340
|
var lumaStats = new StatsManager();
|
|
341
|
+
function initializeStats(stats, orderedStatNames) {
|
|
342
|
+
const statsMap = stats.stats;
|
|
343
|
+
let addedOrderedStat = false;
|
|
344
|
+
for (const statName of orderedStatNames) {
|
|
345
|
+
if (!statsMap[statName]) {
|
|
346
|
+
stats.get(statName);
|
|
347
|
+
addedOrderedStat = true;
|
|
348
|
+
}
|
|
349
|
+
}
|
|
350
|
+
const statCount = Object.keys(statsMap).length;
|
|
351
|
+
const cachedStats = ORDERED_STATS_CACHE.get(stats);
|
|
352
|
+
if (!addedOrderedStat && cachedStats?.orderedStatNames === orderedStatNames && cachedStats.statCount === statCount) {
|
|
353
|
+
return;
|
|
354
|
+
}
|
|
355
|
+
const reorderedStats = {};
|
|
356
|
+
let orderedStatNamesSet = ORDERED_STAT_NAME_SET_CACHE.get(orderedStatNames);
|
|
357
|
+
if (!orderedStatNamesSet) {
|
|
358
|
+
orderedStatNamesSet = new Set(orderedStatNames);
|
|
359
|
+
ORDERED_STAT_NAME_SET_CACHE.set(orderedStatNames, orderedStatNamesSet);
|
|
360
|
+
}
|
|
361
|
+
for (const statName of orderedStatNames) {
|
|
362
|
+
if (statsMap[statName]) {
|
|
363
|
+
reorderedStats[statName] = statsMap[statName];
|
|
364
|
+
}
|
|
365
|
+
}
|
|
366
|
+
for (const [statName, stat] of Object.entries(statsMap)) {
|
|
367
|
+
if (!orderedStatNamesSet.has(statName)) {
|
|
368
|
+
reorderedStats[statName] = stat;
|
|
369
|
+
}
|
|
370
|
+
}
|
|
371
|
+
for (const statName of Object.keys(statsMap)) {
|
|
372
|
+
delete statsMap[statName];
|
|
373
|
+
}
|
|
374
|
+
Object.assign(statsMap, reorderedStats);
|
|
375
|
+
ORDERED_STATS_CACHE.set(stats, { orderedStatNames, statCount });
|
|
376
|
+
}
|
|
317
377
|
|
|
318
378
|
// ../../node_modules/@probe.gl/env/dist/lib/globals.js
|
|
319
379
|
var window_ = globalThis;
|
|
@@ -848,6 +908,57 @@ var __exports__ = (() => {
|
|
|
848
908
|
}
|
|
849
909
|
|
|
850
910
|
// ../core/src/adapter/resources/resource.ts
|
|
911
|
+
var CPU_HOTSPOT_PROFILER_MODULE = "cpu-hotspot-profiler";
|
|
912
|
+
var RESOURCE_COUNTS_STATS = "GPU Resource Counts";
|
|
913
|
+
var LEGACY_RESOURCE_COUNTS_STATS = "Resource Counts";
|
|
914
|
+
var GPU_TIME_AND_MEMORY_STATS2 = "GPU Time and Memory";
|
|
915
|
+
var BASE_RESOURCE_COUNT_ORDER = [
|
|
916
|
+
"Resources",
|
|
917
|
+
"Buffers",
|
|
918
|
+
"Textures",
|
|
919
|
+
"Samplers",
|
|
920
|
+
"TextureViews",
|
|
921
|
+
"Framebuffers",
|
|
922
|
+
"QuerySets",
|
|
923
|
+
"Shaders",
|
|
924
|
+
"RenderPipelines",
|
|
925
|
+
"ComputePipelines",
|
|
926
|
+
"PipelineLayouts",
|
|
927
|
+
"VertexArrays",
|
|
928
|
+
"RenderPasss",
|
|
929
|
+
"ComputePasss",
|
|
930
|
+
"CommandEncoders",
|
|
931
|
+
"CommandBuffers"
|
|
932
|
+
];
|
|
933
|
+
var WEBGL_RESOURCE_COUNT_ORDER = [
|
|
934
|
+
"Resources",
|
|
935
|
+
"Buffers",
|
|
936
|
+
"Textures",
|
|
937
|
+
"Samplers",
|
|
938
|
+
"TextureViews",
|
|
939
|
+
"Framebuffers",
|
|
940
|
+
"QuerySets",
|
|
941
|
+
"Shaders",
|
|
942
|
+
"RenderPipelines",
|
|
943
|
+
"SharedRenderPipelines",
|
|
944
|
+
"ComputePipelines",
|
|
945
|
+
"PipelineLayouts",
|
|
946
|
+
"VertexArrays",
|
|
947
|
+
"RenderPasss",
|
|
948
|
+
"ComputePasss",
|
|
949
|
+
"CommandEncoders",
|
|
950
|
+
"CommandBuffers"
|
|
951
|
+
];
|
|
952
|
+
var BASE_RESOURCE_COUNT_STAT_ORDER = BASE_RESOURCE_COUNT_ORDER.flatMap((resourceType) => [
|
|
953
|
+
`${resourceType} Created`,
|
|
954
|
+
`${resourceType} Active`
|
|
955
|
+
]);
|
|
956
|
+
var WEBGL_RESOURCE_COUNT_STAT_ORDER = WEBGL_RESOURCE_COUNT_ORDER.flatMap((resourceType) => [
|
|
957
|
+
`${resourceType} Created`,
|
|
958
|
+
`${resourceType} Active`
|
|
959
|
+
]);
|
|
960
|
+
var ORDERED_STATS_CACHE2 = /* @__PURE__ */ new WeakMap();
|
|
961
|
+
var ORDERED_STAT_NAME_SET_CACHE2 = /* @__PURE__ */ new WeakMap();
|
|
851
962
|
var Resource = class {
|
|
852
963
|
toString() {
|
|
853
964
|
return `${this[Symbol.toStringTag] || this.constructor.name}:"${this.id}"`;
|
|
@@ -864,6 +975,8 @@ var __exports__ = (() => {
|
|
|
864
975
|
destroyed = false;
|
|
865
976
|
/** For resources that allocate GPU memory */
|
|
866
977
|
allocatedBytes = 0;
|
|
978
|
+
/** Stats bucket currently holding the tracked allocation */
|
|
979
|
+
allocatedBytesName = null;
|
|
867
980
|
/** Attached resources will be destroyed when this resource is destroyed. Tracks auto-created "sub" resources. */
|
|
868
981
|
_attachedResources = /* @__PURE__ */ new Set();
|
|
869
982
|
/**
|
|
@@ -885,6 +998,9 @@ var __exports__ = (() => {
|
|
|
885
998
|
* destroy can be called on any resource to release it before it is garbage collected.
|
|
886
999
|
*/
|
|
887
1000
|
destroy() {
|
|
1001
|
+
if (this.destroyed) {
|
|
1002
|
+
return;
|
|
1003
|
+
}
|
|
888
1004
|
this.destroyResource();
|
|
889
1005
|
}
|
|
890
1006
|
/** @deprecated Use destroy() */
|
|
@@ -923,7 +1039,7 @@ var __exports__ = (() => {
|
|
|
923
1039
|
}
|
|
924
1040
|
/** Destroy all owned resources. Make sure the resources are no longer needed before calling. */
|
|
925
1041
|
destroyAttachedResources() {
|
|
926
|
-
for (const resource of
|
|
1042
|
+
for (const resource of this._attachedResources) {
|
|
927
1043
|
resource.destroy();
|
|
928
1044
|
}
|
|
929
1045
|
this._attachedResources = /* @__PURE__ */ new Set();
|
|
@@ -931,37 +1047,107 @@ var __exports__ = (() => {
|
|
|
931
1047
|
// PROTECTED METHODS
|
|
932
1048
|
/** Perform all destroy steps. Can be called by derived resources when overriding destroy() */
|
|
933
1049
|
destroyResource() {
|
|
1050
|
+
if (this.destroyed) {
|
|
1051
|
+
return;
|
|
1052
|
+
}
|
|
934
1053
|
this.destroyAttachedResources();
|
|
935
1054
|
this.removeStats();
|
|
936
1055
|
this.destroyed = true;
|
|
937
1056
|
}
|
|
938
1057
|
/** Called by .destroy() to track object destruction. Subclass must call if overriding destroy() */
|
|
939
1058
|
removeStats() {
|
|
940
|
-
const
|
|
941
|
-
const
|
|
942
|
-
|
|
1059
|
+
const profiler = getCpuHotspotProfiler(this._device);
|
|
1060
|
+
const startTime = profiler ? getTimestamp() : 0;
|
|
1061
|
+
const statsObjects = [
|
|
1062
|
+
this._device.statsManager.getStats(RESOURCE_COUNTS_STATS),
|
|
1063
|
+
this._device.statsManager.getStats(LEGACY_RESOURCE_COUNTS_STATS)
|
|
1064
|
+
];
|
|
1065
|
+
const orderedStatNames = getResourceCountStatOrder(this._device);
|
|
1066
|
+
for (const stats of statsObjects) {
|
|
1067
|
+
initializeStats2(stats, orderedStatNames);
|
|
1068
|
+
}
|
|
1069
|
+
const name2 = this.getStatsName();
|
|
1070
|
+
for (const stats of statsObjects) {
|
|
1071
|
+
stats.get("Resources Active").decrementCount();
|
|
1072
|
+
stats.get(`${name2}s Active`).decrementCount();
|
|
1073
|
+
}
|
|
1074
|
+
if (profiler) {
|
|
1075
|
+
profiler.statsBookkeepingCalls = (profiler.statsBookkeepingCalls || 0) + 1;
|
|
1076
|
+
profiler.statsBookkeepingTimeMs = (profiler.statsBookkeepingTimeMs || 0) + (getTimestamp() - startTime);
|
|
1077
|
+
}
|
|
943
1078
|
}
|
|
944
1079
|
/** Called by subclass to track memory allocations */
|
|
945
|
-
trackAllocatedMemory(bytes, name2 = this
|
|
946
|
-
const
|
|
1080
|
+
trackAllocatedMemory(bytes, name2 = this.getStatsName()) {
|
|
1081
|
+
const profiler = getCpuHotspotProfiler(this._device);
|
|
1082
|
+
const startTime = profiler ? getTimestamp() : 0;
|
|
1083
|
+
const stats = this._device.statsManager.getStats(GPU_TIME_AND_MEMORY_STATS2);
|
|
1084
|
+
if (this.allocatedBytes > 0 && this.allocatedBytesName) {
|
|
1085
|
+
stats.get("GPU Memory").subtractCount(this.allocatedBytes);
|
|
1086
|
+
stats.get(`${this.allocatedBytesName} Memory`).subtractCount(this.allocatedBytes);
|
|
1087
|
+
}
|
|
947
1088
|
stats.get("GPU Memory").addCount(bytes);
|
|
948
1089
|
stats.get(`${name2} Memory`).addCount(bytes);
|
|
1090
|
+
if (profiler) {
|
|
1091
|
+
profiler.statsBookkeepingCalls = (profiler.statsBookkeepingCalls || 0) + 1;
|
|
1092
|
+
profiler.statsBookkeepingTimeMs = (profiler.statsBookkeepingTimeMs || 0) + (getTimestamp() - startTime);
|
|
1093
|
+
}
|
|
949
1094
|
this.allocatedBytes = bytes;
|
|
1095
|
+
this.allocatedBytesName = name2;
|
|
1096
|
+
}
|
|
1097
|
+
/** Called by subclass to track handle-backed memory allocations separately from owned allocations */
|
|
1098
|
+
trackReferencedMemory(bytes, name2 = this.getStatsName()) {
|
|
1099
|
+
this.trackAllocatedMemory(bytes, `Referenced ${name2}`);
|
|
950
1100
|
}
|
|
951
1101
|
/** Called by subclass to track memory deallocations */
|
|
952
|
-
trackDeallocatedMemory(name2 = this
|
|
953
|
-
|
|
1102
|
+
trackDeallocatedMemory(name2 = this.getStatsName()) {
|
|
1103
|
+
if (this.allocatedBytes === 0) {
|
|
1104
|
+
this.allocatedBytesName = null;
|
|
1105
|
+
return;
|
|
1106
|
+
}
|
|
1107
|
+
const profiler = getCpuHotspotProfiler(this._device);
|
|
1108
|
+
const startTime = profiler ? getTimestamp() : 0;
|
|
1109
|
+
const stats = this._device.statsManager.getStats(GPU_TIME_AND_MEMORY_STATS2);
|
|
954
1110
|
stats.get("GPU Memory").subtractCount(this.allocatedBytes);
|
|
955
|
-
stats.get(`${name2} Memory`).subtractCount(this.allocatedBytes);
|
|
1111
|
+
stats.get(`${this.allocatedBytesName || name2} Memory`).subtractCount(this.allocatedBytes);
|
|
1112
|
+
if (profiler) {
|
|
1113
|
+
profiler.statsBookkeepingCalls = (profiler.statsBookkeepingCalls || 0) + 1;
|
|
1114
|
+
profiler.statsBookkeepingTimeMs = (profiler.statsBookkeepingTimeMs || 0) + (getTimestamp() - startTime);
|
|
1115
|
+
}
|
|
956
1116
|
this.allocatedBytes = 0;
|
|
1117
|
+
this.allocatedBytesName = null;
|
|
1118
|
+
}
|
|
1119
|
+
/** Called by subclass to deallocate handle-backed memory tracked via trackReferencedMemory() */
|
|
1120
|
+
trackDeallocatedReferencedMemory(name2 = this.getStatsName()) {
|
|
1121
|
+
this.trackDeallocatedMemory(`Referenced ${name2}`);
|
|
957
1122
|
}
|
|
958
1123
|
/** Called by resource constructor to track object creation */
|
|
959
1124
|
addStats() {
|
|
960
|
-
const
|
|
961
|
-
const
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
1125
|
+
const name2 = this.getStatsName();
|
|
1126
|
+
const profiler = getCpuHotspotProfiler(this._device);
|
|
1127
|
+
const startTime = profiler ? getTimestamp() : 0;
|
|
1128
|
+
const statsObjects = [
|
|
1129
|
+
this._device.statsManager.getStats(RESOURCE_COUNTS_STATS),
|
|
1130
|
+
this._device.statsManager.getStats(LEGACY_RESOURCE_COUNTS_STATS)
|
|
1131
|
+
];
|
|
1132
|
+
const orderedStatNames = getResourceCountStatOrder(this._device);
|
|
1133
|
+
for (const stats of statsObjects) {
|
|
1134
|
+
initializeStats2(stats, orderedStatNames);
|
|
1135
|
+
}
|
|
1136
|
+
for (const stats of statsObjects) {
|
|
1137
|
+
stats.get("Resources Created").incrementCount();
|
|
1138
|
+
stats.get("Resources Active").incrementCount();
|
|
1139
|
+
stats.get(`${name2}s Created`).incrementCount();
|
|
1140
|
+
stats.get(`${name2}s Active`).incrementCount();
|
|
1141
|
+
}
|
|
1142
|
+
if (profiler) {
|
|
1143
|
+
profiler.statsBookkeepingCalls = (profiler.statsBookkeepingCalls || 0) + 1;
|
|
1144
|
+
profiler.statsBookkeepingTimeMs = (profiler.statsBookkeepingTimeMs || 0) + (getTimestamp() - startTime);
|
|
1145
|
+
}
|
|
1146
|
+
recordTransientCanvasResourceCreate(this._device, name2);
|
|
1147
|
+
}
|
|
1148
|
+
/** Canonical resource name used for stats buckets. */
|
|
1149
|
+
getStatsName() {
|
|
1150
|
+
return getCanonicalResourceName(this);
|
|
965
1151
|
}
|
|
966
1152
|
};
|
|
967
1153
|
/** Default properties for resource */
|
|
@@ -979,6 +1165,96 @@ var __exports__ = (() => {
|
|
|
979
1165
|
}
|
|
980
1166
|
return mergedProps;
|
|
981
1167
|
}
|
|
1168
|
+
function initializeStats2(stats, orderedStatNames) {
|
|
1169
|
+
const statsMap = stats.stats;
|
|
1170
|
+
let addedOrderedStat = false;
|
|
1171
|
+
for (const statName of orderedStatNames) {
|
|
1172
|
+
if (!statsMap[statName]) {
|
|
1173
|
+
stats.get(statName);
|
|
1174
|
+
addedOrderedStat = true;
|
|
1175
|
+
}
|
|
1176
|
+
}
|
|
1177
|
+
const statCount = Object.keys(statsMap).length;
|
|
1178
|
+
const cachedStats = ORDERED_STATS_CACHE2.get(stats);
|
|
1179
|
+
if (!addedOrderedStat && cachedStats?.orderedStatNames === orderedStatNames && cachedStats.statCount === statCount) {
|
|
1180
|
+
return;
|
|
1181
|
+
}
|
|
1182
|
+
const reorderedStats = {};
|
|
1183
|
+
let orderedStatNamesSet = ORDERED_STAT_NAME_SET_CACHE2.get(orderedStatNames);
|
|
1184
|
+
if (!orderedStatNamesSet) {
|
|
1185
|
+
orderedStatNamesSet = new Set(orderedStatNames);
|
|
1186
|
+
ORDERED_STAT_NAME_SET_CACHE2.set(orderedStatNames, orderedStatNamesSet);
|
|
1187
|
+
}
|
|
1188
|
+
for (const statName of orderedStatNames) {
|
|
1189
|
+
if (statsMap[statName]) {
|
|
1190
|
+
reorderedStats[statName] = statsMap[statName];
|
|
1191
|
+
}
|
|
1192
|
+
}
|
|
1193
|
+
for (const [statName, stat] of Object.entries(statsMap)) {
|
|
1194
|
+
if (!orderedStatNamesSet.has(statName)) {
|
|
1195
|
+
reorderedStats[statName] = stat;
|
|
1196
|
+
}
|
|
1197
|
+
}
|
|
1198
|
+
for (const statName of Object.keys(statsMap)) {
|
|
1199
|
+
delete statsMap[statName];
|
|
1200
|
+
}
|
|
1201
|
+
Object.assign(statsMap, reorderedStats);
|
|
1202
|
+
ORDERED_STATS_CACHE2.set(stats, { orderedStatNames, statCount });
|
|
1203
|
+
}
|
|
1204
|
+
function getResourceCountStatOrder(device) {
|
|
1205
|
+
return device.type === "webgl" ? WEBGL_RESOURCE_COUNT_STAT_ORDER : BASE_RESOURCE_COUNT_STAT_ORDER;
|
|
1206
|
+
}
|
|
1207
|
+
function getCpuHotspotProfiler(device) {
|
|
1208
|
+
const profiler = device.userData[CPU_HOTSPOT_PROFILER_MODULE];
|
|
1209
|
+
return profiler?.enabled ? profiler : null;
|
|
1210
|
+
}
|
|
1211
|
+
function getTimestamp() {
|
|
1212
|
+
return globalThis.performance?.now?.() ?? Date.now();
|
|
1213
|
+
}
|
|
1214
|
+
function recordTransientCanvasResourceCreate(device, name2) {
|
|
1215
|
+
const profiler = getCpuHotspotProfiler(device);
|
|
1216
|
+
if (!profiler || !profiler.activeDefaultFramebufferAcquireDepth) {
|
|
1217
|
+
return;
|
|
1218
|
+
}
|
|
1219
|
+
profiler.transientCanvasResourceCreates = (profiler.transientCanvasResourceCreates || 0) + 1;
|
|
1220
|
+
switch (name2) {
|
|
1221
|
+
case "Texture":
|
|
1222
|
+
profiler.transientCanvasTextureCreates = (profiler.transientCanvasTextureCreates || 0) + 1;
|
|
1223
|
+
break;
|
|
1224
|
+
case "TextureView":
|
|
1225
|
+
profiler.transientCanvasTextureViewCreates = (profiler.transientCanvasTextureViewCreates || 0) + 1;
|
|
1226
|
+
break;
|
|
1227
|
+
case "Sampler":
|
|
1228
|
+
profiler.transientCanvasSamplerCreates = (profiler.transientCanvasSamplerCreates || 0) + 1;
|
|
1229
|
+
break;
|
|
1230
|
+
case "Framebuffer":
|
|
1231
|
+
profiler.transientCanvasFramebufferCreates = (profiler.transientCanvasFramebufferCreates || 0) + 1;
|
|
1232
|
+
break;
|
|
1233
|
+
default:
|
|
1234
|
+
break;
|
|
1235
|
+
}
|
|
1236
|
+
}
|
|
1237
|
+
function getCanonicalResourceName(resource) {
|
|
1238
|
+
let prototype = Object.getPrototypeOf(resource);
|
|
1239
|
+
while (prototype) {
|
|
1240
|
+
const parentPrototype = Object.getPrototypeOf(prototype);
|
|
1241
|
+
if (!parentPrototype || parentPrototype === Resource.prototype) {
|
|
1242
|
+
return getPrototypeToStringTag(prototype) || resource[Symbol.toStringTag] || resource.constructor.name;
|
|
1243
|
+
}
|
|
1244
|
+
prototype = parentPrototype;
|
|
1245
|
+
}
|
|
1246
|
+
return resource[Symbol.toStringTag] || resource.constructor.name;
|
|
1247
|
+
}
|
|
1248
|
+
function getPrototypeToStringTag(prototype) {
|
|
1249
|
+
const descriptor = Object.getOwnPropertyDescriptor(prototype, Symbol.toStringTag);
|
|
1250
|
+
if (typeof descriptor?.get === "function") {
|
|
1251
|
+
return descriptor.get.call(prototype);
|
|
1252
|
+
}
|
|
1253
|
+
if (typeof descriptor?.value === "string") {
|
|
1254
|
+
return descriptor.value;
|
|
1255
|
+
}
|
|
1256
|
+
return null;
|
|
1257
|
+
}
|
|
982
1258
|
|
|
983
1259
|
// ../core/src/adapter/resources/buffer.ts
|
|
984
1260
|
var _Buffer = class extends Resource {
|
|
@@ -1018,18 +1294,26 @@ var __exports__ = (() => {
|
|
|
1018
1294
|
/** A partial CPU-side copy of the data in this buffer, for debugging purposes */
|
|
1019
1295
|
debugData = new ArrayBuffer(0);
|
|
1020
1296
|
/** This doesn't handle partial non-zero offset updates correctly */
|
|
1021
|
-
_setDebugData(data,
|
|
1022
|
-
|
|
1297
|
+
_setDebugData(data, _byteOffset, byteLength) {
|
|
1298
|
+
let arrayBufferView = null;
|
|
1299
|
+
let arrayBuffer2;
|
|
1300
|
+
if (ArrayBuffer.isView(data)) {
|
|
1301
|
+
arrayBufferView = data;
|
|
1302
|
+
arrayBuffer2 = data.buffer;
|
|
1303
|
+
} else {
|
|
1304
|
+
arrayBuffer2 = data;
|
|
1305
|
+
}
|
|
1023
1306
|
const debugDataLength = Math.min(
|
|
1024
1307
|
data ? data.byteLength : byteLength,
|
|
1025
1308
|
_Buffer.DEBUG_DATA_MAX_LENGTH
|
|
1026
1309
|
);
|
|
1027
1310
|
if (arrayBuffer2 === null) {
|
|
1028
1311
|
this.debugData = new ArrayBuffer(debugDataLength);
|
|
1029
|
-
} else if (byteOffset === 0 && byteLength === arrayBuffer2.byteLength) {
|
|
1030
|
-
this.debugData = arrayBuffer2.slice(0, debugDataLength);
|
|
1031
1312
|
} else {
|
|
1032
|
-
|
|
1313
|
+
const sourceByteOffset = Math.min(arrayBufferView?.byteOffset || 0, arrayBuffer2.byteLength);
|
|
1314
|
+
const availableByteLength = Math.max(0, arrayBuffer2.byteLength - sourceByteOffset);
|
|
1315
|
+
const copyByteLength = Math.min(debugDataLength, availableByteLength);
|
|
1316
|
+
this.debugData = new Uint8Array(arrayBuffer2, sourceByteOffset, copyByteLength).slice().buffer;
|
|
1033
1317
|
}
|
|
1034
1318
|
}
|
|
1035
1319
|
};
|
|
@@ -1225,6 +1509,7 @@ var __exports__ = (() => {
|
|
|
1225
1509
|
var float16_renderable = "float16-renderable-webgl";
|
|
1226
1510
|
var rgb9e5ufloat_renderable = "rgb9e5ufloat-renderable-webgl";
|
|
1227
1511
|
var snorm8_renderable = "snorm8-renderable-webgl";
|
|
1512
|
+
var norm16_webgl = "norm16-webgl";
|
|
1228
1513
|
var norm16_renderable = "norm16-renderable-webgl";
|
|
1229
1514
|
var snorm16_renderable = "snorm16-renderable-webgl";
|
|
1230
1515
|
var float32_filterable = "float32-filterable";
|
|
@@ -1258,16 +1543,16 @@ var __exports__ = (() => {
|
|
|
1258
1543
|
"rgba8sint": {},
|
|
1259
1544
|
"bgra8unorm": {},
|
|
1260
1545
|
"bgra8unorm-srgb": {},
|
|
1261
|
-
"r16unorm": { f: norm16_renderable },
|
|
1262
|
-
"rg16unorm": { render: norm16_renderable },
|
|
1263
|
-
"rgb16unorm-webgl": { f:
|
|
1546
|
+
"r16unorm": { f: norm16_webgl, render: norm16_renderable },
|
|
1547
|
+
"rg16unorm": { f: norm16_webgl, render: norm16_renderable },
|
|
1548
|
+
"rgb16unorm-webgl": { f: norm16_webgl, render: false },
|
|
1264
1549
|
// rgb not renderable
|
|
1265
|
-
"rgba16unorm": { render: norm16_renderable },
|
|
1266
|
-
"r16snorm": { f: snorm16_renderable },
|
|
1267
|
-
"rg16snorm": { render: snorm16_renderable },
|
|
1268
|
-
"rgb16snorm-webgl": { f:
|
|
1550
|
+
"rgba16unorm": { f: norm16_webgl, render: norm16_renderable },
|
|
1551
|
+
"r16snorm": { f: norm16_webgl, render: snorm16_renderable },
|
|
1552
|
+
"rg16snorm": { f: norm16_webgl, render: snorm16_renderable },
|
|
1553
|
+
"rgb16snorm-webgl": { f: norm16_webgl, render: false },
|
|
1269
1554
|
// rgb not renderable
|
|
1270
|
-
"rgba16snorm": { render: snorm16_renderable },
|
|
1555
|
+
"rgba16snorm": { f: norm16_webgl, render: snorm16_renderable },
|
|
1271
1556
|
"r16uint": {},
|
|
1272
1557
|
"rg16uint": {},
|
|
1273
1558
|
"rgba16uint": {},
|
|
@@ -1370,7 +1655,7 @@ var __exports__ = (() => {
|
|
|
1370
1655
|
// WEBGL_compressed_texture_pvrtc
|
|
1371
1656
|
"pvrtc-rgb4unorm-webgl": { f: texture_compression_pvrtc_webgl },
|
|
1372
1657
|
"pvrtc-rgba4unorm-webgl": { f: texture_compression_pvrtc_webgl },
|
|
1373
|
-
"pvrtc-
|
|
1658
|
+
"pvrtc-rgb2unorm-webgl": { f: texture_compression_pvrtc_webgl },
|
|
1374
1659
|
"pvrtc-rgba2unorm-webgl": { f: texture_compression_pvrtc_webgl },
|
|
1375
1660
|
// WEBGL_compressed_texture_etc1
|
|
1376
1661
|
"etc1-rbg-unorm-webgl": { f: texture_compression_etc1_webgl },
|
|
@@ -1437,10 +1722,19 @@ var __exports__ = (() => {
|
|
|
1437
1722
|
depth,
|
|
1438
1723
|
byteAlignment
|
|
1439
1724
|
}) {
|
|
1440
|
-
const
|
|
1441
|
-
const
|
|
1725
|
+
const formatInfo = textureFormatDecoder.getInfo(format);
|
|
1726
|
+
const {
|
|
1727
|
+
bytesPerPixel,
|
|
1728
|
+
bytesPerBlock = bytesPerPixel,
|
|
1729
|
+
blockWidth = 1,
|
|
1730
|
+
blockHeight = 1,
|
|
1731
|
+
compressed = false
|
|
1732
|
+
} = formatInfo;
|
|
1733
|
+
const blockColumns = compressed ? Math.ceil(width / blockWidth) : width;
|
|
1734
|
+
const blockRows = compressed ? Math.ceil(height / blockHeight) : height;
|
|
1735
|
+
const unpaddedBytesPerRow = blockColumns * bytesPerBlock;
|
|
1442
1736
|
const bytesPerRow = Math.ceil(unpaddedBytesPerRow / byteAlignment) * byteAlignment;
|
|
1443
|
-
const rowsPerImage =
|
|
1737
|
+
const rowsPerImage = blockRows;
|
|
1444
1738
|
const byteLength = bytesPerRow * rowsPerImage * depth;
|
|
1445
1739
|
return {
|
|
1446
1740
|
bytesPerPixel,
|
|
@@ -1466,7 +1760,8 @@ var __exports__ = (() => {
|
|
|
1466
1760
|
const isSigned = formatInfo?.signed;
|
|
1467
1761
|
const isInteger = formatInfo?.integer;
|
|
1468
1762
|
const isWebGLSpecific = formatInfo?.webgl;
|
|
1469
|
-
|
|
1763
|
+
const isCompressed = Boolean(formatInfo?.compressed);
|
|
1764
|
+
formatCapabilities.render &&= !isDepthStencil && !isCompressed;
|
|
1470
1765
|
formatCapabilities.filter &&= !isDepthStencil && !isSigned && !isInteger && !isWebGLSpecific;
|
|
1471
1766
|
return formatCapabilities;
|
|
1472
1767
|
}
|
|
@@ -1478,6 +1773,7 @@ var __exports__ = (() => {
|
|
|
1478
1773
|
formatInfo.bytesPerPixel = 1;
|
|
1479
1774
|
formatInfo.srgb = false;
|
|
1480
1775
|
formatInfo.compressed = true;
|
|
1776
|
+
formatInfo.bytesPerBlock = getCompressedTextureBlockByteLength(format);
|
|
1481
1777
|
const blockSize = getCompressedTextureBlockSize(format);
|
|
1482
1778
|
if (blockSize) {
|
|
1483
1779
|
formatInfo.blockWidth = blockSize.blockWidth;
|
|
@@ -1563,8 +1859,29 @@ var __exports__ = (() => {
|
|
|
1563
1859
|
const [, blockWidth, blockHeight] = matches;
|
|
1564
1860
|
return { blockWidth: Number(blockWidth), blockHeight: Number(blockHeight) };
|
|
1565
1861
|
}
|
|
1862
|
+
if (format.startsWith("bc") || format.startsWith("etc1") || format.startsWith("etc2") || format.startsWith("eac") || format.startsWith("atc")) {
|
|
1863
|
+
return { blockWidth: 4, blockHeight: 4 };
|
|
1864
|
+
}
|
|
1865
|
+
if (format.startsWith("pvrtc-rgb4") || format.startsWith("pvrtc-rgba4")) {
|
|
1866
|
+
return { blockWidth: 4, blockHeight: 4 };
|
|
1867
|
+
}
|
|
1868
|
+
if (format.startsWith("pvrtc-rgb2") || format.startsWith("pvrtc-rgba2")) {
|
|
1869
|
+
return { blockWidth: 8, blockHeight: 4 };
|
|
1870
|
+
}
|
|
1566
1871
|
return null;
|
|
1567
1872
|
}
|
|
1873
|
+
function getCompressedTextureBlockByteLength(format) {
|
|
1874
|
+
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") {
|
|
1875
|
+
return 8;
|
|
1876
|
+
}
|
|
1877
|
+
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") {
|
|
1878
|
+
return 16;
|
|
1879
|
+
}
|
|
1880
|
+
if (format.startsWith("pvrtc")) {
|
|
1881
|
+
return 8;
|
|
1882
|
+
}
|
|
1883
|
+
return 16;
|
|
1884
|
+
}
|
|
1568
1885
|
|
|
1569
1886
|
// ../core/src/image-utils/image-types.ts
|
|
1570
1887
|
function isExternalImage(data) {
|
|
@@ -1625,6 +1942,8 @@ var __exports__ = (() => {
|
|
|
1625
1942
|
/** Used by other luma.gl modules to store data on the device */
|
|
1626
1943
|
_moduleData = {};
|
|
1627
1944
|
_textureCaps = {};
|
|
1945
|
+
/** Internal timestamp query set used when GPU timing collection is enabled for this device. */
|
|
1946
|
+
_debugGPUTimeQuery = null;
|
|
1628
1947
|
constructor(props) {
|
|
1629
1948
|
this.props = { ..._Device.defaultProps, ...props };
|
|
1630
1949
|
this.id = this.props.id || uid(this[Symbol.toStringTag].toLowerCase());
|
|
@@ -1678,6 +1997,16 @@ var __exports__ = (() => {
|
|
|
1678
1997
|
isTextureFormatCompressed(format) {
|
|
1679
1998
|
return textureFormatDecoder.isCompressed(format);
|
|
1680
1999
|
}
|
|
2000
|
+
/** Returns the compressed texture formats that can be created and sampled on this device */
|
|
2001
|
+
getSupportedCompressedTextureFormats() {
|
|
2002
|
+
const supportedFormats = [];
|
|
2003
|
+
for (const format of Object.keys(getTextureFormatTable())) {
|
|
2004
|
+
if (this.isTextureFormatCompressed(format) && this.isTextureFormatSupported(format)) {
|
|
2005
|
+
supportedFormats.push(format);
|
|
2006
|
+
}
|
|
2007
|
+
}
|
|
2008
|
+
return supportedFormats;
|
|
2009
|
+
}
|
|
1681
2010
|
// DEBUG METHODS
|
|
1682
2011
|
pushDebugGroup(groupLabel) {
|
|
1683
2012
|
this.commandEncoder.pushDebugGroup(groupLabel);
|
|
@@ -1760,6 +2089,70 @@ or create a device with the 'debug: true' prop.`;
|
|
|
1760
2089
|
beginComputePass(props) {
|
|
1761
2090
|
return this.commandEncoder.beginComputePass(props);
|
|
1762
2091
|
}
|
|
2092
|
+
/**
|
|
2093
|
+
* Generate mipmaps for a WebGPU texture.
|
|
2094
|
+
* WebGPU textures must be created up front with the required mip count, usage flags, and a format that supports the chosen generation path.
|
|
2095
|
+
* WebGL uses `Texture.generateMipmapsWebGL()` directly because the backend manages mip generation on the texture object itself.
|
|
2096
|
+
*/
|
|
2097
|
+
generateMipmapsWebGPU(_texture) {
|
|
2098
|
+
throw new Error("not implemented");
|
|
2099
|
+
}
|
|
2100
|
+
/** Internal helper for creating a shareable WebGL render-pipeline implementation. */
|
|
2101
|
+
_createSharedRenderPipelineWebGL(_props) {
|
|
2102
|
+
throw new Error("_createSharedRenderPipelineWebGL() not implemented");
|
|
2103
|
+
}
|
|
2104
|
+
/**
|
|
2105
|
+
* Internal helper that returns `true` when timestamp-query GPU timing should be
|
|
2106
|
+
* collected for this device.
|
|
2107
|
+
*/
|
|
2108
|
+
_supportsDebugGPUTime() {
|
|
2109
|
+
return this.features.has("timestamp-query") && Boolean(this.props.debug || this.props.debugGPUTime);
|
|
2110
|
+
}
|
|
2111
|
+
/**
|
|
2112
|
+
* Internal helper that enables device-managed GPU timing collection on the
|
|
2113
|
+
* default command encoder. Reuses the existing query set if timing is already enabled.
|
|
2114
|
+
*
|
|
2115
|
+
* @param queryCount - Number of timestamp slots reserved for profiled passes.
|
|
2116
|
+
* @returns The device-managed timestamp QuerySet, or `null` when timing is not supported or could not be enabled.
|
|
2117
|
+
*/
|
|
2118
|
+
_enableDebugGPUTime(queryCount = 256) {
|
|
2119
|
+
if (!this._supportsDebugGPUTime()) {
|
|
2120
|
+
return null;
|
|
2121
|
+
}
|
|
2122
|
+
if (this._debugGPUTimeQuery) {
|
|
2123
|
+
return this._debugGPUTimeQuery;
|
|
2124
|
+
}
|
|
2125
|
+
try {
|
|
2126
|
+
this._debugGPUTimeQuery = this.createQuerySet({ type: "timestamp", count: queryCount });
|
|
2127
|
+
this.commandEncoder = this.createCommandEncoder({
|
|
2128
|
+
id: this.commandEncoder.props.id,
|
|
2129
|
+
timeProfilingQuerySet: this._debugGPUTimeQuery
|
|
2130
|
+
});
|
|
2131
|
+
} catch {
|
|
2132
|
+
this._debugGPUTimeQuery = null;
|
|
2133
|
+
}
|
|
2134
|
+
return this._debugGPUTimeQuery;
|
|
2135
|
+
}
|
|
2136
|
+
/**
|
|
2137
|
+
* Internal helper that disables device-managed GPU timing collection and restores
|
|
2138
|
+
* the default command encoder to an unprofiled state.
|
|
2139
|
+
*/
|
|
2140
|
+
_disableDebugGPUTime() {
|
|
2141
|
+
if (!this._debugGPUTimeQuery) {
|
|
2142
|
+
return;
|
|
2143
|
+
}
|
|
2144
|
+
if (this.commandEncoder.getTimeProfilingQuerySet() === this._debugGPUTimeQuery) {
|
|
2145
|
+
this.commandEncoder = this.createCommandEncoder({
|
|
2146
|
+
id: this.commandEncoder.props.id
|
|
2147
|
+
});
|
|
2148
|
+
}
|
|
2149
|
+
this._debugGPUTimeQuery.destroy();
|
|
2150
|
+
this._debugGPUTimeQuery = null;
|
|
2151
|
+
}
|
|
2152
|
+
/** Internal helper that returns `true` when device-managed GPU timing is currently active. */
|
|
2153
|
+
_isDebugGPUTimeEnabled() {
|
|
2154
|
+
return this._debugGPUTimeQuery !== null;
|
|
2155
|
+
}
|
|
1763
2156
|
// DEPRECATED METHODS
|
|
1764
2157
|
/** @deprecated Use getDefaultCanvasContext() */
|
|
1765
2158
|
getCanvasContext() {
|
|
@@ -1867,7 +2260,8 @@ or create a device with the 'debug: true' prop.`;
|
|
|
1867
2260
|
onVisibilityChange: (context) => log.log(1, `${context} Visibility changed ${context.isVisible}`)(),
|
|
1868
2261
|
onDevicePixelRatioChange: (context, info) => log.log(1, `${context} DPR changed ${info.oldRatio} => ${context.devicePixelRatio}`)(),
|
|
1869
2262
|
// Debug flags
|
|
1870
|
-
debug:
|
|
2263
|
+
debug: getDefaultDebugValue(),
|
|
2264
|
+
debugGPUTime: false,
|
|
1871
2265
|
debugShaders: log.get("debug-shaders") || void 0,
|
|
1872
2266
|
debugFramebuffers: Boolean(log.get("debug-framebuffers")),
|
|
1873
2267
|
debugFactories: Boolean(log.get("debug-factories")),
|
|
@@ -1878,9 +2272,11 @@ or create a device with the 'debug: true' prop.`;
|
|
|
1878
2272
|
// Experimental
|
|
1879
2273
|
_reuseDevices: false,
|
|
1880
2274
|
_requestMaxLimits: true,
|
|
1881
|
-
_cacheShaders:
|
|
1882
|
-
|
|
1883
|
-
|
|
2275
|
+
_cacheShaders: true,
|
|
2276
|
+
_destroyShaders: false,
|
|
2277
|
+
_cachePipelines: true,
|
|
2278
|
+
_sharePipelines: true,
|
|
2279
|
+
_destroyPipelines: false,
|
|
1884
2280
|
// TODO - Change these after confirming things work as expected
|
|
1885
2281
|
_initializeFeatures: true,
|
|
1886
2282
|
_disabledFeatures: {
|
|
@@ -1889,6 +2285,25 @@ or create a device with the 'debug: true' prop.`;
|
|
|
1889
2285
|
// INTERNAL
|
|
1890
2286
|
_handle: void 0
|
|
1891
2287
|
});
|
|
2288
|
+
function _getDefaultDebugValue(logDebugValue, nodeEnv) {
|
|
2289
|
+
if (logDebugValue !== void 0 && logDebugValue !== null) {
|
|
2290
|
+
return Boolean(logDebugValue);
|
|
2291
|
+
}
|
|
2292
|
+
if (nodeEnv !== void 0) {
|
|
2293
|
+
return nodeEnv !== "production";
|
|
2294
|
+
}
|
|
2295
|
+
return false;
|
|
2296
|
+
}
|
|
2297
|
+
function getDefaultDebugValue() {
|
|
2298
|
+
return _getDefaultDebugValue(log.get("debug"), getNodeEnv());
|
|
2299
|
+
}
|
|
2300
|
+
function getNodeEnv() {
|
|
2301
|
+
const processObject = globalThis.process;
|
|
2302
|
+
if (!processObject?.env) {
|
|
2303
|
+
return void 0;
|
|
2304
|
+
}
|
|
2305
|
+
return processObject.env["NODE_ENV"];
|
|
2306
|
+
}
|
|
1892
2307
|
|
|
1893
2308
|
// ../core/src/adapter/luma.ts
|
|
1894
2309
|
var STARTUP_MESSAGE = "set luma.log.level=1 (or higher) to trace rendering";
|
|
@@ -2066,6 +2481,100 @@ or create a device with the 'debug: true' prop.`;
|
|
|
2066
2481
|
return pageLoadPromise;
|
|
2067
2482
|
}
|
|
2068
2483
|
|
|
2484
|
+
// ../core/src/adapter/canvas-observer.ts
|
|
2485
|
+
var CanvasObserver = class {
|
|
2486
|
+
props;
|
|
2487
|
+
_resizeObserver;
|
|
2488
|
+
_intersectionObserver;
|
|
2489
|
+
_observeDevicePixelRatioTimeout = null;
|
|
2490
|
+
_observeDevicePixelRatioMediaQuery = null;
|
|
2491
|
+
_handleDevicePixelRatioChange = () => this._refreshDevicePixelRatio();
|
|
2492
|
+
_trackPositionInterval = null;
|
|
2493
|
+
_started = false;
|
|
2494
|
+
get started() {
|
|
2495
|
+
return this._started;
|
|
2496
|
+
}
|
|
2497
|
+
constructor(props) {
|
|
2498
|
+
this.props = props;
|
|
2499
|
+
}
|
|
2500
|
+
start() {
|
|
2501
|
+
if (this._started || !this.props.canvas) {
|
|
2502
|
+
return;
|
|
2503
|
+
}
|
|
2504
|
+
this._started = true;
|
|
2505
|
+
this._intersectionObserver ||= new IntersectionObserver(
|
|
2506
|
+
(entries) => this.props.onIntersection(entries)
|
|
2507
|
+
);
|
|
2508
|
+
this._resizeObserver ||= new ResizeObserver((entries) => this.props.onResize(entries));
|
|
2509
|
+
this._intersectionObserver.observe(this.props.canvas);
|
|
2510
|
+
try {
|
|
2511
|
+
this._resizeObserver.observe(this.props.canvas, { box: "device-pixel-content-box" });
|
|
2512
|
+
} catch {
|
|
2513
|
+
this._resizeObserver.observe(this.props.canvas, { box: "content-box" });
|
|
2514
|
+
}
|
|
2515
|
+
this._observeDevicePixelRatioTimeout = setTimeout(() => this._refreshDevicePixelRatio(), 0);
|
|
2516
|
+
if (this.props.trackPosition) {
|
|
2517
|
+
this._trackPosition();
|
|
2518
|
+
}
|
|
2519
|
+
}
|
|
2520
|
+
stop() {
|
|
2521
|
+
if (!this._started) {
|
|
2522
|
+
return;
|
|
2523
|
+
}
|
|
2524
|
+
this._started = false;
|
|
2525
|
+
if (this._observeDevicePixelRatioTimeout) {
|
|
2526
|
+
clearTimeout(this._observeDevicePixelRatioTimeout);
|
|
2527
|
+
this._observeDevicePixelRatioTimeout = null;
|
|
2528
|
+
}
|
|
2529
|
+
if (this._observeDevicePixelRatioMediaQuery) {
|
|
2530
|
+
this._observeDevicePixelRatioMediaQuery.removeEventListener(
|
|
2531
|
+
"change",
|
|
2532
|
+
this._handleDevicePixelRatioChange
|
|
2533
|
+
);
|
|
2534
|
+
this._observeDevicePixelRatioMediaQuery = null;
|
|
2535
|
+
}
|
|
2536
|
+
if (this._trackPositionInterval) {
|
|
2537
|
+
clearInterval(this._trackPositionInterval);
|
|
2538
|
+
this._trackPositionInterval = null;
|
|
2539
|
+
}
|
|
2540
|
+
this._resizeObserver?.disconnect();
|
|
2541
|
+
this._intersectionObserver?.disconnect();
|
|
2542
|
+
}
|
|
2543
|
+
_refreshDevicePixelRatio() {
|
|
2544
|
+
if (!this._started) {
|
|
2545
|
+
return;
|
|
2546
|
+
}
|
|
2547
|
+
this.props.onDevicePixelRatioChange();
|
|
2548
|
+
this._observeDevicePixelRatioMediaQuery?.removeEventListener(
|
|
2549
|
+
"change",
|
|
2550
|
+
this._handleDevicePixelRatioChange
|
|
2551
|
+
);
|
|
2552
|
+
this._observeDevicePixelRatioMediaQuery = matchMedia(
|
|
2553
|
+
`(resolution: ${window.devicePixelRatio}dppx)`
|
|
2554
|
+
);
|
|
2555
|
+
this._observeDevicePixelRatioMediaQuery.addEventListener(
|
|
2556
|
+
"change",
|
|
2557
|
+
this._handleDevicePixelRatioChange,
|
|
2558
|
+
{ once: true }
|
|
2559
|
+
);
|
|
2560
|
+
}
|
|
2561
|
+
_trackPosition(intervalMs = 100) {
|
|
2562
|
+
if (this._trackPositionInterval) {
|
|
2563
|
+
return;
|
|
2564
|
+
}
|
|
2565
|
+
this._trackPositionInterval = setInterval(() => {
|
|
2566
|
+
if (!this._started) {
|
|
2567
|
+
if (this._trackPositionInterval) {
|
|
2568
|
+
clearInterval(this._trackPositionInterval);
|
|
2569
|
+
this._trackPositionInterval = null;
|
|
2570
|
+
}
|
|
2571
|
+
} else {
|
|
2572
|
+
this.props.onPositionChange();
|
|
2573
|
+
}
|
|
2574
|
+
}, intervalMs);
|
|
2575
|
+
}
|
|
2576
|
+
};
|
|
2577
|
+
|
|
2069
2578
|
// ../core/src/utils/promise-utils.ts
|
|
2070
2579
|
function withResolvers() {
|
|
2071
2580
|
let resolve;
|
|
@@ -2090,8 +2599,8 @@ or create a device with the 'debug: true' prop.`;
|
|
|
2090
2599
|
return value;
|
|
2091
2600
|
}
|
|
2092
2601
|
|
|
2093
|
-
// ../core/src/adapter/canvas-
|
|
2094
|
-
var
|
|
2602
|
+
// ../core/src/adapter/canvas-surface.ts
|
|
2603
|
+
var _CanvasSurface = class {
|
|
2095
2604
|
static isHTMLCanvas(canvas) {
|
|
2096
2605
|
return typeof HTMLCanvasElement !== "undefined" && canvas instanceof HTMLCanvasElement;
|
|
2097
2606
|
}
|
|
@@ -2127,11 +2636,7 @@ or create a device with the 'debug: true' prop.`;
|
|
|
2127
2636
|
drawingBufferHeight;
|
|
2128
2637
|
/** Resolves when the canvas is initialized, i.e. when the ResizeObserver has updated the pixel size */
|
|
2129
2638
|
_initializedResolvers = withResolvers();
|
|
2130
|
-
|
|
2131
|
-
_resizeObserver;
|
|
2132
|
-
/** IntersectionObserver to track canvas visibility changes */
|
|
2133
|
-
_intersectionObserver;
|
|
2134
|
-
_observeDevicePixelRatioTimeout = null;
|
|
2639
|
+
_canvasObserver;
|
|
2135
2640
|
/** Position of the canvas in the document, updated by a timer */
|
|
2136
2641
|
_position = [0, 0];
|
|
2137
2642
|
/** Whether this canvas context has been destroyed */
|
|
@@ -2142,7 +2647,7 @@ or create a device with the 'debug: true' prop.`;
|
|
|
2142
2647
|
return `${this[Symbol.toStringTag]}(${this.id})`;
|
|
2143
2648
|
}
|
|
2144
2649
|
constructor(props) {
|
|
2145
|
-
this.props = { ...
|
|
2650
|
+
this.props = { ..._CanvasSurface.defaultProps, ...props };
|
|
2146
2651
|
props = this.props;
|
|
2147
2652
|
this.initialized = this._initializedResolvers.promise;
|
|
2148
2653
|
if (!isBrowser()) {
|
|
@@ -2154,11 +2659,11 @@ or create a device with the 'debug: true' prop.`;
|
|
|
2154
2659
|
} else {
|
|
2155
2660
|
this.canvas = props.canvas;
|
|
2156
2661
|
}
|
|
2157
|
-
if (
|
|
2662
|
+
if (_CanvasSurface.isHTMLCanvas(this.canvas)) {
|
|
2158
2663
|
this.id = props.id || this.canvas.id;
|
|
2159
2664
|
this.type = "html-canvas";
|
|
2160
2665
|
this.htmlCanvas = this.canvas;
|
|
2161
|
-
} else if (
|
|
2666
|
+
} else if (_CanvasSurface.isOffscreenCanvas(this.canvas)) {
|
|
2162
2667
|
this.id = props.id || "offscreen-canvas";
|
|
2163
2668
|
this.type = "offscreen-canvas";
|
|
2164
2669
|
this.offscreenCanvas = this.canvas;
|
|
@@ -2174,33 +2679,20 @@ or create a device with the 'debug: true' prop.`;
|
|
|
2174
2679
|
this.drawingBufferHeight = this.canvas.height;
|
|
2175
2680
|
this.devicePixelRatio = globalThis.devicePixelRatio || 1;
|
|
2176
2681
|
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
|
-
}
|
|
2682
|
+
this._canvasObserver = new CanvasObserver({
|
|
2683
|
+
canvas: this.htmlCanvas,
|
|
2684
|
+
trackPosition: this.props.trackPosition,
|
|
2685
|
+
onResize: (entries) => this._handleResize(entries),
|
|
2686
|
+
onIntersection: (entries) => this._handleIntersection(entries),
|
|
2687
|
+
onDevicePixelRatioChange: () => this._observeDevicePixelRatio(),
|
|
2688
|
+
onPositionChange: () => this.updatePosition()
|
|
2689
|
+
});
|
|
2193
2690
|
}
|
|
2194
2691
|
destroy() {
|
|
2195
2692
|
if (!this.destroyed) {
|
|
2196
2693
|
this.destroyed = true;
|
|
2197
|
-
|
|
2198
|
-
clearTimeout(this._observeDevicePixelRatioTimeout);
|
|
2199
|
-
this._observeDevicePixelRatioTimeout = null;
|
|
2200
|
-
}
|
|
2694
|
+
this._stopObservers();
|
|
2201
2695
|
this.device = null;
|
|
2202
|
-
this._resizeObserver?.disconnect();
|
|
2203
|
-
this._intersectionObserver?.disconnect();
|
|
2204
2696
|
}
|
|
2205
2697
|
}
|
|
2206
2698
|
setProps(props) {
|
|
@@ -2215,41 +2707,22 @@ or create a device with the 'debug: true' prop.`;
|
|
|
2215
2707
|
this._resizeDrawingBufferIfNeeded();
|
|
2216
2708
|
return this._getCurrentFramebuffer(options);
|
|
2217
2709
|
}
|
|
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
2710
|
getCSSSize() {
|
|
2225
2711
|
return [this.cssWidth, this.cssHeight];
|
|
2226
2712
|
}
|
|
2227
2713
|
getPosition() {
|
|
2228
2714
|
return this._position;
|
|
2229
2715
|
}
|
|
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
2716
|
getDevicePixelSize() {
|
|
2236
2717
|
return [this.devicePixelWidth, this.devicePixelHeight];
|
|
2237
2718
|
}
|
|
2238
|
-
/** Get the drawing buffer size (number of pixels GPU is rendering into, can be different from CSS size) */
|
|
2239
2719
|
getDrawingBufferSize() {
|
|
2240
2720
|
return [this.drawingBufferWidth, this.drawingBufferHeight];
|
|
2241
2721
|
}
|
|
2242
|
-
/** Returns the biggest allowed framebuffer size. @todo Allow the application to limit this? */
|
|
2243
2722
|
getMaxDrawingBufferSize() {
|
|
2244
2723
|
const maxTextureDimension = this.device.limits.maxTextureDimension2D;
|
|
2245
2724
|
return [maxTextureDimension, maxTextureDimension];
|
|
2246
2725
|
}
|
|
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
2726
|
setDrawingBufferSize(width, height) {
|
|
2254
2727
|
width = Math.floor(width);
|
|
2255
2728
|
height = Math.floor(height);
|
|
@@ -2260,19 +2733,10 @@ or create a device with the 'debug: true' prop.`;
|
|
|
2260
2733
|
this.drawingBufferHeight = height;
|
|
2261
2734
|
this._needsDrawingBufferResize = true;
|
|
2262
2735
|
}
|
|
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
2736
|
getDevicePixelRatio() {
|
|
2269
|
-
const
|
|
2270
|
-
return
|
|
2737
|
+
const devicePixelRatio2 = typeof window !== "undefined" && window.devicePixelRatio;
|
|
2738
|
+
return devicePixelRatio2 || 1;
|
|
2271
2739
|
}
|
|
2272
|
-
// DEPRECATED METHODS
|
|
2273
|
-
/**
|
|
2274
|
-
* Maps CSS pixel position to device pixel position
|
|
2275
|
-
*/
|
|
2276
2740
|
cssToDevicePixels(cssPixel, yInvert = true) {
|
|
2277
2741
|
const ratio = this.cssToDeviceRatio();
|
|
2278
2742
|
const [width, height] = this.getDrawingBufferSize();
|
|
@@ -2282,10 +2746,10 @@ or create a device with the 'debug: true' prop.`;
|
|
|
2282
2746
|
getPixelSize() {
|
|
2283
2747
|
return this.getDevicePixelSize();
|
|
2284
2748
|
}
|
|
2285
|
-
/** @deprecated
|
|
2749
|
+
/** @deprecated Use the current drawing buffer size for projection setup. */
|
|
2286
2750
|
getAspect() {
|
|
2287
|
-
const [width, height] = this.
|
|
2288
|
-
return width / height;
|
|
2751
|
+
const [width, height] = this.getDrawingBufferSize();
|
|
2752
|
+
return width > 0 && height > 0 ? width / height : 1;
|
|
2289
2753
|
}
|
|
2290
2754
|
/** @deprecated Returns multiplier need to convert CSS size to Device size */
|
|
2291
2755
|
cssToDeviceRatio() {
|
|
@@ -2301,17 +2765,36 @@ or create a device with the 'debug: true' prop.`;
|
|
|
2301
2765
|
resize(size) {
|
|
2302
2766
|
this.setDrawingBufferSize(size.width, size.height);
|
|
2303
2767
|
}
|
|
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
2768
|
_setAutoCreatedCanvasId(id) {
|
|
2310
2769
|
if (this.htmlCanvas?.id === "lumagl-auto-created-canvas") {
|
|
2311
2770
|
this.htmlCanvas.id = id;
|
|
2312
2771
|
}
|
|
2313
2772
|
}
|
|
2314
|
-
/**
|
|
2773
|
+
/**
|
|
2774
|
+
* Starts DOM observation after the derived context and its device are fully initialized.
|
|
2775
|
+
*
|
|
2776
|
+
* `CanvasSurface` construction runs before subclasses can assign `this.device`, and the
|
|
2777
|
+
* default WebGL canvas context is created before `WebGLDevice` has initialized `limits`,
|
|
2778
|
+
* `features`, and the rest of its runtime state. Deferring observer startup avoids early
|
|
2779
|
+
* `ResizeObserver` and DPR callbacks running against a partially initialized device.
|
|
2780
|
+
*/
|
|
2781
|
+
_startObservers() {
|
|
2782
|
+
if (this.destroyed) {
|
|
2783
|
+
return;
|
|
2784
|
+
}
|
|
2785
|
+
this._canvasObserver.start();
|
|
2786
|
+
}
|
|
2787
|
+
/**
|
|
2788
|
+
* Stops all DOM observation and timers associated with a canvas surface.
|
|
2789
|
+
*
|
|
2790
|
+
* This pairs with `_startObservers()` so teardown uses the same lifecycle whether a context is
|
|
2791
|
+
* explicitly destroyed, abandoned during device reuse, or temporarily has not started observing
|
|
2792
|
+
* yet. Centralizing shutdown here keeps resize/DPR/position watchers from surviving past the
|
|
2793
|
+
* lifetime of the owning device.
|
|
2794
|
+
*/
|
|
2795
|
+
_stopObservers() {
|
|
2796
|
+
this._canvasObserver.stop();
|
|
2797
|
+
}
|
|
2315
2798
|
_handleIntersection(entries) {
|
|
2316
2799
|
if (this.destroyed) {
|
|
2317
2800
|
return;
|
|
@@ -2326,11 +2809,6 @@ or create a device with the 'debug: true' prop.`;
|
|
|
2326
2809
|
this.device.props.onVisibilityChange(this);
|
|
2327
2810
|
}
|
|
2328
2811
|
}
|
|
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
2812
|
_handleResize(entries) {
|
|
2335
2813
|
if (this.destroyed) {
|
|
2336
2814
|
return;
|
|
@@ -2351,12 +2829,14 @@ or create a device with the 'debug: true' prop.`;
|
|
|
2351
2829
|
this._updateDrawingBufferSize();
|
|
2352
2830
|
this.device.props.onResize(this, { oldPixelSize });
|
|
2353
2831
|
}
|
|
2354
|
-
/** Initiate a deferred update for the canvas drawing buffer size */
|
|
2355
2832
|
_updateDrawingBufferSize() {
|
|
2356
2833
|
if (this.props.autoResize) {
|
|
2357
2834
|
if (typeof this.props.useDevicePixels === "number") {
|
|
2358
|
-
const
|
|
2359
|
-
this.setDrawingBufferSize(
|
|
2835
|
+
const devicePixelRatio2 = this.props.useDevicePixels;
|
|
2836
|
+
this.setDrawingBufferSize(
|
|
2837
|
+
this.cssWidth * devicePixelRatio2,
|
|
2838
|
+
this.cssHeight * devicePixelRatio2
|
|
2839
|
+
);
|
|
2360
2840
|
} else if (this.props.useDevicePixels) {
|
|
2361
2841
|
this.setDrawingBufferSize(this.devicePixelWidth, this.devicePixelHeight);
|
|
2362
2842
|
} else {
|
|
@@ -2367,7 +2847,6 @@ or create a device with the 'debug: true' prop.`;
|
|
|
2367
2847
|
this.isInitialized = true;
|
|
2368
2848
|
this.updatePosition();
|
|
2369
2849
|
}
|
|
2370
|
-
/** Perform a deferred resize of the drawing buffer if needed */
|
|
2371
2850
|
_resizeDrawingBufferIfNeeded() {
|
|
2372
2851
|
if (this._needsDrawingBufferResize) {
|
|
2373
2852
|
this._needsDrawingBufferResize = false;
|
|
@@ -2379,36 +2858,17 @@ or create a device with the 'debug: true' prop.`;
|
|
|
2379
2858
|
}
|
|
2380
2859
|
}
|
|
2381
2860
|
}
|
|
2382
|
-
/** Monitor DPR changes */
|
|
2383
2861
|
_observeDevicePixelRatio() {
|
|
2384
|
-
if (this.destroyed) {
|
|
2862
|
+
if (this.destroyed || !this._canvasObserver.started) {
|
|
2385
2863
|
return;
|
|
2386
2864
|
}
|
|
2387
2865
|
const oldRatio = this.devicePixelRatio;
|
|
2388
2866
|
this.devicePixelRatio = window.devicePixelRatio;
|
|
2389
2867
|
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);
|
|
2868
|
+
this.device.props.onDevicePixelRatioChange?.(this, {
|
|
2869
|
+
oldRatio
|
|
2870
|
+
});
|
|
2406
2871
|
}
|
|
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
2872
|
updatePosition() {
|
|
2413
2873
|
if (this.destroyed) {
|
|
2414
2874
|
return;
|
|
@@ -2421,13 +2881,15 @@ or create a device with the 'debug: true' prop.`;
|
|
|
2421
2881
|
if (positionChanged) {
|
|
2422
2882
|
const oldPosition = this._position;
|
|
2423
2883
|
this._position = position;
|
|
2424
|
-
this.device.props.onPositionChange?.(this, {
|
|
2884
|
+
this.device.props.onPositionChange?.(this, {
|
|
2885
|
+
oldPosition
|
|
2886
|
+
});
|
|
2425
2887
|
}
|
|
2426
2888
|
}
|
|
2427
2889
|
}
|
|
2428
2890
|
};
|
|
2429
|
-
var
|
|
2430
|
-
__publicField(
|
|
2891
|
+
var CanvasSurface = _CanvasSurface;
|
|
2892
|
+
__publicField(CanvasSurface, "defaultProps", {
|
|
2431
2893
|
id: void 0,
|
|
2432
2894
|
canvas: null,
|
|
2433
2895
|
width: 800,
|
|
@@ -2455,7 +2917,7 @@ or create a device with the 'debug: true' prop.`;
|
|
|
2455
2917
|
}
|
|
2456
2918
|
function getCanvasFromDOM(canvasId) {
|
|
2457
2919
|
const canvas = document.getElementById(canvasId);
|
|
2458
|
-
if (!
|
|
2920
|
+
if (!CanvasSurface.isHTMLCanvas(canvas)) {
|
|
2459
2921
|
throw new Error("Object is not a canvas element");
|
|
2460
2922
|
}
|
|
2461
2923
|
return canvas;
|
|
@@ -2479,33 +2941,40 @@ or create a device with the 'debug: true' prop.`;
|
|
|
2479
2941
|
const point = pixel;
|
|
2480
2942
|
const x = scaleX(point[0], ratio, width);
|
|
2481
2943
|
let y = scaleY(point[1], ratio, height, yInvert);
|
|
2482
|
-
let
|
|
2483
|
-
const xHigh =
|
|
2484
|
-
|
|
2944
|
+
let temporary = scaleX(point[0] + 1, ratio, width);
|
|
2945
|
+
const xHigh = temporary === width - 1 ? temporary : temporary - 1;
|
|
2946
|
+
temporary = scaleY(point[1] + 1, ratio, height, yInvert);
|
|
2485
2947
|
let yHigh;
|
|
2486
2948
|
if (yInvert) {
|
|
2487
|
-
|
|
2949
|
+
temporary = temporary === 0 ? temporary : temporary + 1;
|
|
2488
2950
|
yHigh = y;
|
|
2489
|
-
y =
|
|
2951
|
+
y = temporary;
|
|
2490
2952
|
} else {
|
|
2491
|
-
yHigh =
|
|
2953
|
+
yHigh = temporary === height - 1 ? temporary : temporary - 1;
|
|
2492
2954
|
}
|
|
2493
2955
|
return {
|
|
2494
2956
|
x,
|
|
2495
2957
|
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
2958
|
width: Math.max(xHigh - x + 1, 1),
|
|
2498
2959
|
height: Math.max(yHigh - y + 1, 1)
|
|
2499
2960
|
};
|
|
2500
2961
|
}
|
|
2501
2962
|
function scaleX(x, ratio, width) {
|
|
2502
|
-
|
|
2503
|
-
return r;
|
|
2963
|
+
return Math.min(Math.round(x * ratio), width - 1);
|
|
2504
2964
|
}
|
|
2505
2965
|
function scaleY(y, ratio, height, yInvert) {
|
|
2506
2966
|
return yInvert ? Math.max(0, height - 1 - Math.round(y * ratio)) : Math.min(Math.round(y * ratio), height - 1);
|
|
2507
2967
|
}
|
|
2508
2968
|
|
|
2969
|
+
// ../core/src/adapter/canvas-context.ts
|
|
2970
|
+
var CanvasContext = class extends CanvasSurface {
|
|
2971
|
+
};
|
|
2972
|
+
__publicField(CanvasContext, "defaultProps", CanvasSurface.defaultProps);
|
|
2973
|
+
|
|
2974
|
+
// ../core/src/adapter/presentation-context.ts
|
|
2975
|
+
var PresentationContext = class extends CanvasSurface {
|
|
2976
|
+
};
|
|
2977
|
+
|
|
2509
2978
|
// ../core/src/adapter/resources/sampler.ts
|
|
2510
2979
|
var _Sampler = class extends Resource {
|
|
2511
2980
|
get [Symbol.toStringTag]() {
|
|
@@ -2560,6 +3029,8 @@ or create a device with the 'debug: true' prop.`;
|
|
|
2560
3029
|
depth;
|
|
2561
3030
|
/** mip levels in this texture */
|
|
2562
3031
|
mipLevels;
|
|
3032
|
+
/** sample count */
|
|
3033
|
+
samples;
|
|
2563
3034
|
/** Rows are multiples of this length, padded with extra bytes if needed */
|
|
2564
3035
|
byteAlignment;
|
|
2565
3036
|
/** The ready promise is always resolved. It is provided for type compatibility with DynamicTexture. */
|
|
@@ -2585,6 +3056,7 @@ or create a device with the 'debug: true' prop.`;
|
|
|
2585
3056
|
this.height = this.props.height;
|
|
2586
3057
|
this.depth = this.props.depth;
|
|
2587
3058
|
this.mipLevels = this.props.mipLevels;
|
|
3059
|
+
this.samples = this.props.samples || 1;
|
|
2588
3060
|
if (this.dimension === "cube") {
|
|
2589
3061
|
this.depth = 6;
|
|
2590
3062
|
}
|
|
@@ -2618,9 +3090,25 @@ or create a device with the 'debug: true' prop.`;
|
|
|
2618
3090
|
setSampler(sampler) {
|
|
2619
3091
|
this.sampler = sampler instanceof Sampler ? sampler : this.device.createSampler(sampler);
|
|
2620
3092
|
}
|
|
3093
|
+
/**
|
|
3094
|
+
* Copy raw image data (bytes) into the texture.
|
|
3095
|
+
*
|
|
3096
|
+
* @note Deprecated compatibility wrapper over {@link writeData}.
|
|
3097
|
+
* @note Uses the same layout defaults and alignment rules as {@link writeData}.
|
|
3098
|
+
* @note Tightly packed CPU uploads can omit `bytesPerRow` and `rowsPerImage`.
|
|
3099
|
+
* @note If the CPU source rows are padded, pass explicit `bytesPerRow` and `rowsPerImage`.
|
|
3100
|
+
* @deprecated Use writeData()
|
|
3101
|
+
*/
|
|
3102
|
+
copyImageData(options) {
|
|
3103
|
+
const { data, depth, ...writeOptions } = options;
|
|
3104
|
+
this.writeData(data, {
|
|
3105
|
+
...writeOptions,
|
|
3106
|
+
depthOrArrayLayers: writeOptions.depthOrArrayLayers ?? depth
|
|
3107
|
+
});
|
|
3108
|
+
}
|
|
2621
3109
|
/**
|
|
2622
3110
|
* Calculates the memory layout of the texture, required when reading and writing data.
|
|
2623
|
-
* @return the
|
|
3111
|
+
* @return the backend-aligned linear layout, in particular bytesPerRow which includes any required padding for buffer copy/read paths
|
|
2624
3112
|
*/
|
|
2625
3113
|
computeMemoryLayout(options_ = {}) {
|
|
2626
3114
|
const options = this._normalizeTextureReadOptions(options_);
|
|
@@ -2639,9 +3127,11 @@ or create a device with the 'debug: true' prop.`;
|
|
|
2639
3127
|
* @returns A Buffer containing the texture data.
|
|
2640
3128
|
*
|
|
2641
3129
|
* @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.
|
|
3130
|
+
* @note The application can call Texture.computeMemoryLayout() to compute the backend-aligned layout.
|
|
2643
3131
|
* @note The application can call Buffer.readAsync()
|
|
2644
3132
|
* @note If not supplied a buffer will be created and the application needs to call Buffer.destroy
|
|
3133
|
+
* @note On WebGPU this corresponds to a texture-to-buffer copy and uses buffer-copy alignment rules.
|
|
3134
|
+
* @note On WebGL, luma.gl emulates the same logical readback behavior.
|
|
2645
3135
|
*/
|
|
2646
3136
|
readBuffer(options, buffer) {
|
|
2647
3137
|
throw new Error("readBuffer not implemented");
|
|
@@ -2657,10 +3147,14 @@ or create a device with the 'debug: true' prop.`;
|
|
|
2657
3147
|
throw new Error("readBuffer not implemented");
|
|
2658
3148
|
}
|
|
2659
3149
|
/**
|
|
2660
|
-
* Writes
|
|
3150
|
+
* Writes a GPU Buffer into a texture.
|
|
2661
3151
|
*
|
|
3152
|
+
* @param buffer - Source GPU buffer.
|
|
3153
|
+
* @param options - Destination subresource, extent, and source layout options.
|
|
2662
3154
|
* @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.
|
|
3155
|
+
* @note The application can call Texture.computeMemoryLayout() to compute the backend-aligned layout.
|
|
3156
|
+
* @note On WebGPU this corresponds to a buffer-to-texture copy and uses buffer-copy alignment rules.
|
|
3157
|
+
* @note On WebGL, luma.gl emulates the same destination and layout semantics.
|
|
2664
3158
|
*/
|
|
2665
3159
|
writeBuffer(buffer, options) {
|
|
2666
3160
|
throw new Error("readBuffer not implemented");
|
|
@@ -2668,8 +3162,11 @@ or create a device with the 'debug: true' prop.`;
|
|
|
2668
3162
|
/**
|
|
2669
3163
|
* Writes an array buffer into a texture.
|
|
2670
3164
|
*
|
|
2671
|
-
* @
|
|
2672
|
-
* @
|
|
3165
|
+
* @param data - Source texel data.
|
|
3166
|
+
* @param options - Destination subresource, extent, and source layout options.
|
|
3167
|
+
* @note If `bytesPerRow` and `rowsPerImage` are omitted, luma.gl computes a tightly packed CPU-memory layout for the requested region.
|
|
3168
|
+
* @note On WebGPU this corresponds to `GPUQueue.writeTexture()` and does not implicitly pad rows to 256 bytes.
|
|
3169
|
+
* @note On WebGL, padded CPU data is supported via the same `bytesPerRow` and `rowsPerImage` options.
|
|
2673
3170
|
*/
|
|
2674
3171
|
writeData(data, options) {
|
|
2675
3172
|
throw new Error("readBuffer not implemented");
|
|
@@ -2732,37 +3229,166 @@ or create a device with the 'debug: true' prop.`;
|
|
|
2732
3229
|
}
|
|
2733
3230
|
}
|
|
2734
3231
|
_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;
|
|
3232
|
+
const { data, depth, ...writeOptions } = options_;
|
|
3233
|
+
const options = this._normalizeTextureWriteOptions({
|
|
3234
|
+
...writeOptions,
|
|
3235
|
+
depthOrArrayLayers: writeOptions.depthOrArrayLayers ?? depth
|
|
3236
|
+
});
|
|
3237
|
+
return { data, depth: options.depthOrArrayLayers, ...options };
|
|
2744
3238
|
}
|
|
2745
3239
|
_normalizeCopyExternalImageOptions(options_) {
|
|
3240
|
+
const optionsWithoutUndefined = _Texture._omitUndefined(options_);
|
|
3241
|
+
const mipLevel = optionsWithoutUndefined.mipLevel ?? 0;
|
|
3242
|
+
const mipLevelSize = this._getMipLevelSize(mipLevel);
|
|
2746
3243
|
const size = this.device.getExternalImageSize(options_.image);
|
|
2747
|
-
const options = {
|
|
2748
|
-
|
|
2749
|
-
|
|
3244
|
+
const options = {
|
|
3245
|
+
..._Texture.defaultCopyExternalImageOptions,
|
|
3246
|
+
...mipLevelSize,
|
|
3247
|
+
...size,
|
|
3248
|
+
...optionsWithoutUndefined
|
|
3249
|
+
};
|
|
3250
|
+
options.width = Math.min(options.width, mipLevelSize.width - options.x);
|
|
3251
|
+
options.height = Math.min(options.height, mipLevelSize.height - options.y);
|
|
3252
|
+
options.depth = Math.min(options.depth, mipLevelSize.depthOrArrayLayers - options.z);
|
|
2750
3253
|
return options;
|
|
2751
3254
|
}
|
|
2752
3255
|
_normalizeTextureReadOptions(options_) {
|
|
2753
|
-
const
|
|
2754
|
-
const
|
|
2755
|
-
|
|
2756
|
-
options
|
|
3256
|
+
const optionsWithoutUndefined = _Texture._omitUndefined(options_);
|
|
3257
|
+
const mipLevel = optionsWithoutUndefined.mipLevel ?? 0;
|
|
3258
|
+
const mipLevelSize = this._getMipLevelSize(mipLevel);
|
|
3259
|
+
const options = {
|
|
3260
|
+
..._Texture.defaultTextureReadOptions,
|
|
3261
|
+
...mipLevelSize,
|
|
3262
|
+
...optionsWithoutUndefined
|
|
3263
|
+
};
|
|
3264
|
+
options.width = Math.min(options.width, mipLevelSize.width - options.x);
|
|
3265
|
+
options.height = Math.min(options.height, mipLevelSize.height - options.y);
|
|
3266
|
+
options.depthOrArrayLayers = Math.min(
|
|
3267
|
+
options.depthOrArrayLayers,
|
|
3268
|
+
mipLevelSize.depthOrArrayLayers - options.z
|
|
3269
|
+
);
|
|
2757
3270
|
return options;
|
|
2758
3271
|
}
|
|
3272
|
+
/**
|
|
3273
|
+
* Normalizes a texture read request and validates the color-only readback contract used by the
|
|
3274
|
+
* current texture read APIs. Supported dimensions are `2d`, `cube`, `cube-array`,
|
|
3275
|
+
* `2d-array`, and `3d`.
|
|
3276
|
+
*
|
|
3277
|
+
* @throws if the texture format, aspect, or dimension is not supported by the first-pass
|
|
3278
|
+
* color-read implementation.
|
|
3279
|
+
*/
|
|
3280
|
+
_getSupportedColorReadOptions(options_) {
|
|
3281
|
+
const options = this._normalizeTextureReadOptions(options_);
|
|
3282
|
+
const formatInfo = textureFormatDecoder.getInfo(this.format);
|
|
3283
|
+
this._validateColorReadAspect(options);
|
|
3284
|
+
this._validateColorReadFormat(formatInfo);
|
|
3285
|
+
switch (this.dimension) {
|
|
3286
|
+
case "2d":
|
|
3287
|
+
case "cube":
|
|
3288
|
+
case "cube-array":
|
|
3289
|
+
case "2d-array":
|
|
3290
|
+
case "3d":
|
|
3291
|
+
return options;
|
|
3292
|
+
default:
|
|
3293
|
+
throw new Error(`${this} color readback does not support ${this.dimension} textures`);
|
|
3294
|
+
}
|
|
3295
|
+
}
|
|
3296
|
+
/** Validates that a read request targets the full color aspect of the texture. */
|
|
3297
|
+
_validateColorReadAspect(options) {
|
|
3298
|
+
if (options.aspect !== "all") {
|
|
3299
|
+
throw new Error(`${this} color readback only supports aspect 'all'`);
|
|
3300
|
+
}
|
|
3301
|
+
}
|
|
3302
|
+
/** Validates that a read request targets an uncompressed color-renderable texture format. */
|
|
3303
|
+
_validateColorReadFormat(formatInfo) {
|
|
3304
|
+
if (formatInfo.compressed) {
|
|
3305
|
+
throw new Error(
|
|
3306
|
+
`${this} color readback does not support compressed formats (${this.format})`
|
|
3307
|
+
);
|
|
3308
|
+
}
|
|
3309
|
+
switch (formatInfo.attachment) {
|
|
3310
|
+
case "color":
|
|
3311
|
+
return;
|
|
3312
|
+
case "depth":
|
|
3313
|
+
throw new Error(`${this} color readback does not support depth formats (${this.format})`);
|
|
3314
|
+
case "stencil":
|
|
3315
|
+
throw new Error(`${this} color readback does not support stencil formats (${this.format})`);
|
|
3316
|
+
case "depth-stencil":
|
|
3317
|
+
throw new Error(
|
|
3318
|
+
`${this} color readback does not support depth-stencil formats (${this.format})`
|
|
3319
|
+
);
|
|
3320
|
+
default:
|
|
3321
|
+
throw new Error(`${this} color readback does not support format ${this.format}`);
|
|
3322
|
+
}
|
|
3323
|
+
}
|
|
2759
3324
|
_normalizeTextureWriteOptions(options_) {
|
|
2760
|
-
const
|
|
2761
|
-
const
|
|
2762
|
-
|
|
2763
|
-
options
|
|
3325
|
+
const optionsWithoutUndefined = _Texture._omitUndefined(options_);
|
|
3326
|
+
const mipLevel = optionsWithoutUndefined.mipLevel ?? 0;
|
|
3327
|
+
const mipLevelSize = this._getMipLevelSize(mipLevel);
|
|
3328
|
+
const options = {
|
|
3329
|
+
..._Texture.defaultTextureWriteOptions,
|
|
3330
|
+
...mipLevelSize,
|
|
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.depthOrArrayLayers = Math.min(
|
|
3336
|
+
options.depthOrArrayLayers,
|
|
3337
|
+
mipLevelSize.depthOrArrayLayers - options.z
|
|
3338
|
+
);
|
|
3339
|
+
const layout = textureFormatDecoder.computeMemoryLayout({
|
|
3340
|
+
format: this.format,
|
|
3341
|
+
width: options.width,
|
|
3342
|
+
height: options.height,
|
|
3343
|
+
depth: options.depthOrArrayLayers,
|
|
3344
|
+
byteAlignment: this.byteAlignment
|
|
3345
|
+
});
|
|
3346
|
+
const minimumBytesPerRow = layout.bytesPerPixel * options.width;
|
|
3347
|
+
options.bytesPerRow = optionsWithoutUndefined.bytesPerRow ?? layout.bytesPerRow;
|
|
3348
|
+
options.rowsPerImage = optionsWithoutUndefined.rowsPerImage ?? options.height;
|
|
3349
|
+
if (options.bytesPerRow < minimumBytesPerRow) {
|
|
3350
|
+
throw new Error(
|
|
3351
|
+
`bytesPerRow (${options.bytesPerRow}) must be at least ${minimumBytesPerRow} for ${this.format}`
|
|
3352
|
+
);
|
|
3353
|
+
}
|
|
3354
|
+
if (options.rowsPerImage < options.height) {
|
|
3355
|
+
throw new Error(
|
|
3356
|
+
`rowsPerImage (${options.rowsPerImage}) must be at least ${options.height} for ${this.format}`
|
|
3357
|
+
);
|
|
3358
|
+
}
|
|
3359
|
+
const bytesPerPixel = this.device.getTextureFormatInfo(this.format).bytesPerPixel;
|
|
3360
|
+
if (bytesPerPixel && options.bytesPerRow % bytesPerPixel !== 0) {
|
|
3361
|
+
throw new Error(
|
|
3362
|
+
`bytesPerRow (${options.bytesPerRow}) must be a multiple of bytesPerPixel (${bytesPerPixel}) for ${this.format}`
|
|
3363
|
+
);
|
|
3364
|
+
}
|
|
2764
3365
|
return options;
|
|
2765
3366
|
}
|
|
3367
|
+
_getMipLevelSize(mipLevel) {
|
|
3368
|
+
const width = Math.max(1, this.width >> mipLevel);
|
|
3369
|
+
const height = this.baseDimension === "1d" ? 1 : Math.max(1, this.height >> mipLevel);
|
|
3370
|
+
const depthOrArrayLayers = this.dimension === "3d" ? Math.max(1, this.depth >> mipLevel) : this.depth;
|
|
3371
|
+
return { width, height, depthOrArrayLayers };
|
|
3372
|
+
}
|
|
3373
|
+
getAllocatedByteLength() {
|
|
3374
|
+
let allocatedByteLength = 0;
|
|
3375
|
+
for (let mipLevel = 0; mipLevel < this.mipLevels; mipLevel++) {
|
|
3376
|
+
const { width, height, depthOrArrayLayers } = this._getMipLevelSize(mipLevel);
|
|
3377
|
+
allocatedByteLength += textureFormatDecoder.computeMemoryLayout({
|
|
3378
|
+
format: this.format,
|
|
3379
|
+
width,
|
|
3380
|
+
height,
|
|
3381
|
+
depth: depthOrArrayLayers,
|
|
3382
|
+
byteAlignment: 1
|
|
3383
|
+
}).byteLength;
|
|
3384
|
+
}
|
|
3385
|
+
return allocatedByteLength * this.samples;
|
|
3386
|
+
}
|
|
3387
|
+
static _omitUndefined(options) {
|
|
3388
|
+
return Object.fromEntries(
|
|
3389
|
+
Object.entries(options).filter(([, value]) => value !== void 0)
|
|
3390
|
+
);
|
|
3391
|
+
}
|
|
2766
3392
|
};
|
|
2767
3393
|
var Texture = _Texture;
|
|
2768
3394
|
/** The texture can be bound for use as a sampled texture in a shader */
|
|
@@ -2798,6 +3424,10 @@ or create a device with the 'debug: true' prop.`;
|
|
|
2798
3424
|
byteOffset: 0,
|
|
2799
3425
|
bytesPerRow: void 0,
|
|
2800
3426
|
rowsPerImage: void 0,
|
|
3427
|
+
width: void 0,
|
|
3428
|
+
height: void 0,
|
|
3429
|
+
depthOrArrayLayers: void 0,
|
|
3430
|
+
depth: 1,
|
|
2801
3431
|
mipLevel: 0,
|
|
2802
3432
|
x: 0,
|
|
2803
3433
|
y: 0,
|
|
@@ -2831,6 +3461,19 @@ or create a device with the 'debug: true' prop.`;
|
|
|
2831
3461
|
mipLevel: 0,
|
|
2832
3462
|
aspect: "all"
|
|
2833
3463
|
});
|
|
3464
|
+
__publicField(Texture, "defaultTextureWriteOptions", {
|
|
3465
|
+
byteOffset: 0,
|
|
3466
|
+
bytesPerRow: void 0,
|
|
3467
|
+
rowsPerImage: void 0,
|
|
3468
|
+
x: 0,
|
|
3469
|
+
y: 0,
|
|
3470
|
+
z: 0,
|
|
3471
|
+
width: void 0,
|
|
3472
|
+
height: void 0,
|
|
3473
|
+
depthOrArrayLayers: 1,
|
|
3474
|
+
mipLevel: 0,
|
|
3475
|
+
aspect: "all"
|
|
3476
|
+
});
|
|
2834
3477
|
|
|
2835
3478
|
// ../core/src/adapter/resources/texture-view.ts
|
|
2836
3479
|
var _TextureView = class extends Resource {
|
|
@@ -3209,10 +3852,21 @@ ${numberedLines}${positionIndicator}${message.type.toUpperCase()}: ${message.mes
|
|
|
3209
3852
|
linkStatus = "pending";
|
|
3210
3853
|
/** The hash of the pipeline */
|
|
3211
3854
|
hash = "";
|
|
3855
|
+
/** Optional shared backend implementation */
|
|
3856
|
+
sharedRenderPipeline = null;
|
|
3857
|
+
/** Whether shader or pipeline compilation/linking is still in progress */
|
|
3858
|
+
get isPending() {
|
|
3859
|
+
return this.linkStatus === "pending" || this.vs.compilationStatus === "pending" || this.fs?.compilationStatus === "pending";
|
|
3860
|
+
}
|
|
3861
|
+
/** Whether shader or pipeline compilation/linking has failed */
|
|
3862
|
+
get isErrored() {
|
|
3863
|
+
return this.linkStatus === "error" || this.vs.compilationStatus === "error" || this.fs?.compilationStatus === "error";
|
|
3864
|
+
}
|
|
3212
3865
|
constructor(device, props) {
|
|
3213
3866
|
super(device, props, _RenderPipeline.defaultProps);
|
|
3214
3867
|
this.shaderLayout = this.props.shaderLayout;
|
|
3215
3868
|
this.bufferLayout = this.props.bufferLayout || [];
|
|
3869
|
+
this.sharedRenderPipeline = this.props._sharedRenderPipeline || null;
|
|
3216
3870
|
}
|
|
3217
3871
|
};
|
|
3218
3872
|
var RenderPipeline = _RenderPipeline;
|
|
@@ -3230,10 +3884,30 @@ ${numberedLines}${positionIndicator}${message.type.toUpperCase()}: ${message.mes
|
|
|
3230
3884
|
colorAttachmentFormats: void 0,
|
|
3231
3885
|
depthStencilAttachmentFormat: void 0,
|
|
3232
3886
|
parameters: {},
|
|
3233
|
-
|
|
3234
|
-
|
|
3887
|
+
varyings: void 0,
|
|
3888
|
+
bufferMode: void 0,
|
|
3889
|
+
disableWarnings: false,
|
|
3890
|
+
_sharedRenderPipeline: void 0,
|
|
3891
|
+
bindings: void 0
|
|
3235
3892
|
});
|
|
3236
3893
|
|
|
3894
|
+
// ../core/src/adapter/resources/shared-render-pipeline.ts
|
|
3895
|
+
var SharedRenderPipeline = class extends Resource {
|
|
3896
|
+
get [Symbol.toStringTag]() {
|
|
3897
|
+
return "SharedRenderPipeline";
|
|
3898
|
+
}
|
|
3899
|
+
constructor(device, props) {
|
|
3900
|
+
super(device, props, {
|
|
3901
|
+
...Resource.defaultProps,
|
|
3902
|
+
handle: void 0,
|
|
3903
|
+
vs: void 0,
|
|
3904
|
+
fs: void 0,
|
|
3905
|
+
varyings: void 0,
|
|
3906
|
+
bufferMode: void 0
|
|
3907
|
+
});
|
|
3908
|
+
}
|
|
3909
|
+
};
|
|
3910
|
+
|
|
3237
3911
|
// ../core/src/adapter/resources/render-pass.ts
|
|
3238
3912
|
var _RenderPass = class extends Resource {
|
|
3239
3913
|
get [Symbol.toStringTag]() {
|
|
@@ -3316,8 +3990,69 @@ ${numberedLines}${positionIndicator}${message.type.toUpperCase()}: ${message.mes
|
|
|
3316
3990
|
get [Symbol.toStringTag]() {
|
|
3317
3991
|
return "CommandEncoder";
|
|
3318
3992
|
}
|
|
3993
|
+
_timeProfilingQuerySet = null;
|
|
3994
|
+
_timeProfilingSlotCount = 0;
|
|
3995
|
+
_gpuTimeMs;
|
|
3319
3996
|
constructor(device, props) {
|
|
3320
3997
|
super(device, props, _CommandEncoder.defaultProps);
|
|
3998
|
+
this._timeProfilingQuerySet = props.timeProfilingQuerySet ?? null;
|
|
3999
|
+
this._timeProfilingSlotCount = 0;
|
|
4000
|
+
this._gpuTimeMs = void 0;
|
|
4001
|
+
}
|
|
4002
|
+
/**
|
|
4003
|
+
* Reads all resolved timestamp pairs on the current profiler query set and caches the sum
|
|
4004
|
+
* as milliseconds on this encoder.
|
|
4005
|
+
*/
|
|
4006
|
+
async resolveTimeProfilingQuerySet() {
|
|
4007
|
+
this._gpuTimeMs = void 0;
|
|
4008
|
+
if (!this._timeProfilingQuerySet) {
|
|
4009
|
+
return;
|
|
4010
|
+
}
|
|
4011
|
+
const pairCount = Math.floor(this._timeProfilingSlotCount / 2);
|
|
4012
|
+
if (pairCount <= 0) {
|
|
4013
|
+
return;
|
|
4014
|
+
}
|
|
4015
|
+
const queryCount = pairCount * 2;
|
|
4016
|
+
const results = await this._timeProfilingQuerySet.readResults({
|
|
4017
|
+
firstQuery: 0,
|
|
4018
|
+
queryCount
|
|
4019
|
+
});
|
|
4020
|
+
let totalDurationNanoseconds = 0n;
|
|
4021
|
+
for (let queryIndex = 0; queryIndex < queryCount; queryIndex += 2) {
|
|
4022
|
+
totalDurationNanoseconds += results[queryIndex + 1] - results[queryIndex];
|
|
4023
|
+
}
|
|
4024
|
+
this._gpuTimeMs = Number(totalDurationNanoseconds) / 1e6;
|
|
4025
|
+
}
|
|
4026
|
+
/** Returns the number of query slots consumed by automatic pass profiling on this encoder. */
|
|
4027
|
+
getTimeProfilingSlotCount() {
|
|
4028
|
+
return this._timeProfilingSlotCount;
|
|
4029
|
+
}
|
|
4030
|
+
getTimeProfilingQuerySet() {
|
|
4031
|
+
return this._timeProfilingQuerySet;
|
|
4032
|
+
}
|
|
4033
|
+
/** Internal helper for auto-assigning timestamp slots to render/compute passes on this encoder. */
|
|
4034
|
+
_applyTimeProfilingToPassProps(props) {
|
|
4035
|
+
const passProps = props || {};
|
|
4036
|
+
if (!this._supportsTimestampQueries() || !this._timeProfilingQuerySet) {
|
|
4037
|
+
return passProps;
|
|
4038
|
+
}
|
|
4039
|
+
if (passProps.timestampQuerySet !== void 0 || passProps.beginTimestampIndex !== void 0 || passProps.endTimestampIndex !== void 0) {
|
|
4040
|
+
return passProps;
|
|
4041
|
+
}
|
|
4042
|
+
const beginTimestampIndex = this._timeProfilingSlotCount;
|
|
4043
|
+
if (beginTimestampIndex + 1 >= this._timeProfilingQuerySet.props.count) {
|
|
4044
|
+
return passProps;
|
|
4045
|
+
}
|
|
4046
|
+
this._timeProfilingSlotCount += 2;
|
|
4047
|
+
return {
|
|
4048
|
+
...passProps,
|
|
4049
|
+
timestampQuerySet: this._timeProfilingQuerySet,
|
|
4050
|
+
beginTimestampIndex,
|
|
4051
|
+
endTimestampIndex: beginTimestampIndex + 1
|
|
4052
|
+
};
|
|
4053
|
+
}
|
|
4054
|
+
_supportsTimestampQueries() {
|
|
4055
|
+
return this.device.features.has("timestamp-query");
|
|
3321
4056
|
}
|
|
3322
4057
|
};
|
|
3323
4058
|
var CommandEncoder = _CommandEncoder;
|
|
@@ -3326,7 +4061,8 @@ ${numberedLines}${positionIndicator}${message.type.toUpperCase()}: ${message.mes
|
|
|
3326
4061
|
// beginComputePass(optional GPUComputePassDescriptor descriptor = {}): GPUComputePassEncoder;
|
|
3327
4062
|
__publicField(CommandEncoder, "defaultProps", {
|
|
3328
4063
|
...Resource.defaultProps,
|
|
3329
|
-
measureExecutionTime: void 0
|
|
4064
|
+
measureExecutionTime: void 0,
|
|
4065
|
+
timeProfilingQuerySet: void 0
|
|
3330
4066
|
});
|
|
3331
4067
|
|
|
3332
4068
|
// ../core/src/adapter/resources/command-buffer.ts
|
|
@@ -3345,11 +4081,20 @@ ${numberedLines}${positionIndicator}${message.type.toUpperCase()}: ${message.mes
|
|
|
3345
4081
|
|
|
3346
4082
|
// ../core/src/shadertypes/data-types/decode-shader-types.ts
|
|
3347
4083
|
function getVariableShaderTypeInfo(format) {
|
|
3348
|
-
const
|
|
4084
|
+
const resolvedFormat = resolveVariableShaderTypeAlias(format);
|
|
4085
|
+
const decoded = UNIFORM_FORMATS[resolvedFormat];
|
|
4086
|
+
if (!decoded) {
|
|
4087
|
+
throw new Error(`Unsupported variable shader type: ${format}`);
|
|
4088
|
+
}
|
|
3349
4089
|
return decoded;
|
|
3350
4090
|
}
|
|
3351
4091
|
function getAttributeShaderTypeInfo(attributeType) {
|
|
3352
|
-
const
|
|
4092
|
+
const resolvedAttributeType = resolveAttributeShaderTypeAlias(attributeType);
|
|
4093
|
+
const decoded = TYPE_INFO[resolvedAttributeType];
|
|
4094
|
+
if (!decoded) {
|
|
4095
|
+
throw new Error(`Unsupported attribute shader type: ${attributeType}`);
|
|
4096
|
+
}
|
|
4097
|
+
const [primitiveType, components] = decoded;
|
|
3353
4098
|
const integer = primitiveType === "i32" || primitiveType === "u32";
|
|
3354
4099
|
const signed = primitiveType !== "u32";
|
|
3355
4100
|
const byteLength = PRIMITIVE_TYPE_SIZES[primitiveType] * components;
|
|
@@ -3361,6 +4106,12 @@ ${numberedLines}${positionIndicator}${message.type.toUpperCase()}: ${message.mes
|
|
|
3361
4106
|
signed
|
|
3362
4107
|
};
|
|
3363
4108
|
}
|
|
4109
|
+
function resolveAttributeShaderTypeAlias(alias) {
|
|
4110
|
+
return WGSL_ATTRIBUTE_TYPE_ALIAS_MAP[alias] || alias;
|
|
4111
|
+
}
|
|
4112
|
+
function resolveVariableShaderTypeAlias(alias) {
|
|
4113
|
+
return WGSL_VARIABLE_TYPE_ALIAS_MAP[alias] || alias;
|
|
4114
|
+
}
|
|
3364
4115
|
var PRIMITIVE_TYPE_SIZES = {
|
|
3365
4116
|
f32: 4,
|
|
3366
4117
|
f16: 2,
|
|
@@ -3685,7 +4436,9 @@ ${numberedLines}${positionIndicator}${message.type.toUpperCase()}: ${message.mes
|
|
|
3685
4436
|
|
|
3686
4437
|
// ../core/src/adapter/resources/fence.ts
|
|
3687
4438
|
var _Fence = class extends Resource {
|
|
3688
|
-
[Symbol.toStringTag]
|
|
4439
|
+
get [Symbol.toStringTag]() {
|
|
4440
|
+
return "Fence";
|
|
4441
|
+
}
|
|
3689
4442
|
constructor(device, props = {}) {
|
|
3690
4443
|
super(device, props, _Fence.defaultProps);
|
|
3691
4444
|
}
|
|
@@ -3845,20 +4598,26 @@ ${numberedLines}${positionIndicator}${message.type.toUpperCase()}: ${message.mes
|
|
|
3845
4598
|
}
|
|
3846
4599
|
|
|
3847
4600
|
// ../core/src/utils/array-equal.ts
|
|
4601
|
+
var MAX_ELEMENTWISE_ARRAY_COMPARE_LENGTH = 128;
|
|
3848
4602
|
function arrayEqual(a, b, limit = 16) {
|
|
3849
|
-
if (a
|
|
3850
|
-
return
|
|
4603
|
+
if (a === b) {
|
|
4604
|
+
return true;
|
|
3851
4605
|
}
|
|
3852
4606
|
const arrayA = a;
|
|
3853
4607
|
const arrayB = b;
|
|
3854
|
-
if (!isNumberArray(arrayA)) {
|
|
4608
|
+
if (!isNumberArray(arrayA) || !isNumberArray(arrayB)) {
|
|
3855
4609
|
return false;
|
|
3856
4610
|
}
|
|
3857
|
-
if (
|
|
3858
|
-
|
|
3859
|
-
|
|
3860
|
-
|
|
3861
|
-
|
|
4611
|
+
if (arrayA.length !== arrayB.length) {
|
|
4612
|
+
return false;
|
|
4613
|
+
}
|
|
4614
|
+
const maxCompareLength = Math.min(limit, MAX_ELEMENTWISE_ARRAY_COMPARE_LENGTH);
|
|
4615
|
+
if (arrayA.length > maxCompareLength) {
|
|
4616
|
+
return false;
|
|
4617
|
+
}
|
|
4618
|
+
for (let i = 0; i < arrayA.length; ++i) {
|
|
4619
|
+
if (arrayB[i] !== arrayA[i]) {
|
|
4620
|
+
return false;
|
|
3862
4621
|
}
|
|
3863
4622
|
}
|
|
3864
4623
|
return true;
|