@luma.gl/core 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/adapter/canvas-context.d.ts +6 -182
- package/dist/adapter/canvas-context.d.ts.map +1 -1
- package/dist/adapter/canvas-context.js +5 -481
- package/dist/adapter/canvas-context.js.map +1 -1
- package/dist/adapter/canvas-observer.d.ts +32 -0
- package/dist/adapter/canvas-observer.d.ts.map +1 -0
- package/dist/adapter/canvas-observer.js +90 -0
- package/dist/adapter/canvas-observer.js.map +1 -0
- package/dist/adapter/canvas-surface.d.ts +150 -0
- package/dist/adapter/canvas-surface.d.ts.map +1 -0
- package/dist/adapter/canvas-surface.js +392 -0
- package/dist/adapter/canvas-surface.js.map +1 -0
- package/dist/adapter/device.d.ts +64 -9
- package/dist/adapter/device.d.ts.map +1 -1
- package/dist/adapter/device.js +108 -4
- package/dist/adapter/device.js.map +1 -1
- package/dist/adapter/luma.js +1 -1
- package/dist/adapter/presentation-context.d.ts +11 -0
- package/dist/adapter/presentation-context.d.ts.map +1 -0
- package/dist/adapter/presentation-context.js +12 -0
- package/dist/adapter/presentation-context.js.map +1 -0
- package/dist/adapter/resources/buffer.d.ts +1 -1
- package/dist/adapter/resources/buffer.d.ts.map +1 -1
- package/dist/adapter/resources/buffer.js +14 -6
- package/dist/adapter/resources/buffer.js.map +1 -1
- package/dist/adapter/resources/command-encoder.d.ts +22 -1
- package/dist/adapter/resources/command-encoder.d.ts.map +1 -1
- package/dist/adapter/resources/command-encoder.js +65 -1
- package/dist/adapter/resources/command-encoder.js.map +1 -1
- package/dist/adapter/resources/fence.d.ts +1 -1
- package/dist/adapter/resources/fence.d.ts.map +1 -1
- package/dist/adapter/resources/fence.js +3 -1
- package/dist/adapter/resources/fence.js.map +1 -1
- package/dist/adapter/resources/query-set.d.ts +17 -1
- package/dist/adapter/resources/query-set.d.ts.map +1 -1
- package/dist/adapter/resources/query-set.js.map +1 -1
- package/dist/adapter/resources/render-pipeline.d.ts +19 -7
- package/dist/adapter/resources/render-pipeline.d.ts.map +1 -1
- package/dist/adapter/resources/render-pipeline.js +20 -2
- package/dist/adapter/resources/render-pipeline.js.map +1 -1
- package/dist/adapter/resources/resource.d.ts +8 -0
- package/dist/adapter/resources/resource.d.ts.map +1 -1
- package/dist/adapter/resources/resource.js +240 -14
- package/dist/adapter/resources/resource.js.map +1 -1
- package/dist/adapter/resources/shared-render-pipeline.d.ts +22 -0
- package/dist/adapter/resources/shared-render-pipeline.d.ts.map +1 -0
- package/dist/adapter/resources/shared-render-pipeline.js +25 -0
- package/dist/adapter/resources/shared-render-pipeline.js.map +1 -0
- package/dist/adapter/resources/texture.d.ts +78 -12
- package/dist/adapter/resources/texture.d.ts.map +1 -1
- package/dist/adapter/resources/texture.js +182 -30
- package/dist/adapter/resources/texture.js.map +1 -1
- package/dist/dist.dev.js +952 -193
- package/dist/dist.min.js +6 -6
- package/dist/index.cjs +918 -190
- package/dist/index.cjs.map +4 -4
- package/dist/index.d.ts +4 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -1
- package/dist/shadertypes/data-types/decode-shader-types.d.ts +2 -2
- package/dist/shadertypes/data-types/decode-shader-types.d.ts.map +1 -1
- package/dist/shadertypes/data-types/decode-shader-types.js +11 -2
- package/dist/shadertypes/data-types/decode-shader-types.js.map +1 -1
- package/dist/shadertypes/textures/texture-format-decoder.d.ts.map +1 -1
- package/dist/shadertypes/textures/texture-format-decoder.js +51 -6
- package/dist/shadertypes/textures/texture-format-decoder.js.map +1 -1
- package/dist/shadertypes/textures/texture-format-table.d.ts.map +1 -1
- package/dist/shadertypes/textures/texture-format-table.js +10 -9
- package/dist/shadertypes/textures/texture-format-table.js.map +1 -1
- package/dist/shadertypes/textures/texture-formats.d.ts +5 -2
- package/dist/shadertypes/textures/texture-formats.d.ts.map +1 -1
- package/dist/shadertypes/textures/texture-formats.js.map +1 -1
- package/dist/shadertypes/textures/texture-layout.d.ts +1 -1
- package/dist/utils/array-equal.d.ts +1 -1
- package/dist/utils/array-equal.d.ts.map +1 -1
- package/dist/utils/array-equal.js +15 -9
- package/dist/utils/array-equal.js.map +1 -1
- package/dist/utils/stats-manager.d.ts.map +1 -1
- package/dist/utils/stats-manager.js +61 -1
- package/dist/utils/stats-manager.js.map +1 -1
- package/package.json +3 -3
- package/src/adapter/canvas-context.ts +7 -623
- package/src/adapter/canvas-observer.ts +130 -0
- package/src/adapter/canvas-surface.ts +521 -0
- package/src/adapter/device.ts +174 -13
- package/src/adapter/presentation-context.ts +16 -0
- package/src/adapter/resources/buffer.ts +13 -5
- package/src/adapter/resources/command-encoder.ts +91 -2
- package/src/adapter/resources/fence.ts +3 -1
- package/src/adapter/resources/query-set.ts +17 -1
- package/src/adapter/resources/render-pipeline.ts +42 -13
- package/src/adapter/resources/resource.ts +284 -14
- package/src/adapter/resources/shared-render-pipeline.ts +40 -0
- package/src/adapter/resources/texture.ts +267 -38
- package/src/index.ts +7 -0
- package/src/shadertypes/data-types/decode-shader-types.ts +13 -4
- package/src/shadertypes/textures/texture-format-decoder.ts +71 -6
- package/src/shadertypes/textures/texture-format-table.ts +10 -9
- package/src/shadertypes/textures/texture-formats.ts +6 -1
- package/src/utils/array-equal.ts +21 -9
- package/src/utils/stats-manager.ts +76 -2
package/dist/dist.dev.js
CHANGED
|
@@ -46,12 +46,14 @@ var __exports__ = (() => {
|
|
|
46
46
|
Fence: () => Fence,
|
|
47
47
|
Framebuffer: () => Framebuffer,
|
|
48
48
|
PipelineLayout: () => PipelineLayout,
|
|
49
|
+
PresentationContext: () => PresentationContext,
|
|
49
50
|
QuerySet: () => QuerySet,
|
|
50
51
|
RenderPass: () => RenderPass,
|
|
51
52
|
RenderPipeline: () => RenderPipeline,
|
|
52
53
|
Resource: () => Resource,
|
|
53
54
|
Sampler: () => Sampler,
|
|
54
55
|
Shader: () => Shader,
|
|
56
|
+
SharedRenderPipeline: () => SharedRenderPipeline,
|
|
55
57
|
Texture: () => Texture,
|
|
56
58
|
TextureFormatDecoder: () => TextureFormatDecoder,
|
|
57
59
|
TextureView: () => TextureView,
|
|
@@ -280,6 +282,24 @@ var __exports__ = (() => {
|
|
|
280
282
|
};
|
|
281
283
|
|
|
282
284
|
// src/utils/stats-manager.ts
|
|
285
|
+
var GPU_TIME_AND_MEMORY_STATS = "GPU Time and Memory";
|
|
286
|
+
var GPU_TIME_AND_MEMORY_STAT_ORDER = [
|
|
287
|
+
"Adapter",
|
|
288
|
+
"GPU",
|
|
289
|
+
"GPU Type",
|
|
290
|
+
"GPU Backend",
|
|
291
|
+
"Frame Rate",
|
|
292
|
+
"CPU Time",
|
|
293
|
+
"GPU Time",
|
|
294
|
+
"GPU Memory",
|
|
295
|
+
"Buffer Memory",
|
|
296
|
+
"Texture Memory",
|
|
297
|
+
"Referenced Buffer Memory",
|
|
298
|
+
"Referenced Texture Memory",
|
|
299
|
+
"Swap Chain Texture"
|
|
300
|
+
];
|
|
301
|
+
var ORDERED_STATS_CACHE = /* @__PURE__ */ new WeakMap();
|
|
302
|
+
var ORDERED_STAT_NAME_SET_CACHE = /* @__PURE__ */ new WeakMap();
|
|
283
303
|
var StatsManager = class {
|
|
284
304
|
stats = /* @__PURE__ */ new Map();
|
|
285
305
|
getStats(name2) {
|
|
@@ -289,10 +309,50 @@ var __exports__ = (() => {
|
|
|
289
309
|
if (!this.stats.has(name2)) {
|
|
290
310
|
this.stats.set(name2, new Stats({ id: name2 }));
|
|
291
311
|
}
|
|
292
|
-
|
|
312
|
+
const stats = this.stats.get(name2);
|
|
313
|
+
if (name2 === GPU_TIME_AND_MEMORY_STATS) {
|
|
314
|
+
initializeStats(stats, GPU_TIME_AND_MEMORY_STAT_ORDER);
|
|
315
|
+
}
|
|
316
|
+
return stats;
|
|
293
317
|
}
|
|
294
318
|
};
|
|
295
319
|
var lumaStats = new StatsManager();
|
|
320
|
+
function initializeStats(stats, orderedStatNames) {
|
|
321
|
+
const statsMap = stats.stats;
|
|
322
|
+
let addedOrderedStat = false;
|
|
323
|
+
for (const statName of orderedStatNames) {
|
|
324
|
+
if (!statsMap[statName]) {
|
|
325
|
+
stats.get(statName);
|
|
326
|
+
addedOrderedStat = true;
|
|
327
|
+
}
|
|
328
|
+
}
|
|
329
|
+
const statCount = Object.keys(statsMap).length;
|
|
330
|
+
const cachedStats = ORDERED_STATS_CACHE.get(stats);
|
|
331
|
+
if (!addedOrderedStat && cachedStats?.orderedStatNames === orderedStatNames && cachedStats.statCount === statCount) {
|
|
332
|
+
return;
|
|
333
|
+
}
|
|
334
|
+
const reorderedStats = {};
|
|
335
|
+
let orderedStatNamesSet = ORDERED_STAT_NAME_SET_CACHE.get(orderedStatNames);
|
|
336
|
+
if (!orderedStatNamesSet) {
|
|
337
|
+
orderedStatNamesSet = new Set(orderedStatNames);
|
|
338
|
+
ORDERED_STAT_NAME_SET_CACHE.set(orderedStatNames, orderedStatNamesSet);
|
|
339
|
+
}
|
|
340
|
+
for (const statName of orderedStatNames) {
|
|
341
|
+
if (statsMap[statName]) {
|
|
342
|
+
reorderedStats[statName] = statsMap[statName];
|
|
343
|
+
}
|
|
344
|
+
}
|
|
345
|
+
for (const [statName, stat] of Object.entries(statsMap)) {
|
|
346
|
+
if (!orderedStatNamesSet.has(statName)) {
|
|
347
|
+
reorderedStats[statName] = stat;
|
|
348
|
+
}
|
|
349
|
+
}
|
|
350
|
+
for (const statName of Object.keys(statsMap)) {
|
|
351
|
+
delete statsMap[statName];
|
|
352
|
+
}
|
|
353
|
+
Object.assign(statsMap, reorderedStats);
|
|
354
|
+
ORDERED_STATS_CACHE.set(stats, { orderedStatNames, statCount });
|
|
355
|
+
}
|
|
296
356
|
|
|
297
357
|
// ../../node_modules/@probe.gl/env/dist/lib/globals.js
|
|
298
358
|
var window_ = globalThis;
|
|
@@ -827,6 +887,57 @@ var __exports__ = (() => {
|
|
|
827
887
|
}
|
|
828
888
|
|
|
829
889
|
// src/adapter/resources/resource.ts
|
|
890
|
+
var CPU_HOTSPOT_PROFILER_MODULE = "cpu-hotspot-profiler";
|
|
891
|
+
var RESOURCE_COUNTS_STATS = "GPU Resource Counts";
|
|
892
|
+
var LEGACY_RESOURCE_COUNTS_STATS = "Resource Counts";
|
|
893
|
+
var GPU_TIME_AND_MEMORY_STATS2 = "GPU Time and Memory";
|
|
894
|
+
var BASE_RESOURCE_COUNT_ORDER = [
|
|
895
|
+
"Resources",
|
|
896
|
+
"Buffers",
|
|
897
|
+
"Textures",
|
|
898
|
+
"Samplers",
|
|
899
|
+
"TextureViews",
|
|
900
|
+
"Framebuffers",
|
|
901
|
+
"QuerySets",
|
|
902
|
+
"Shaders",
|
|
903
|
+
"RenderPipelines",
|
|
904
|
+
"ComputePipelines",
|
|
905
|
+
"PipelineLayouts",
|
|
906
|
+
"VertexArrays",
|
|
907
|
+
"RenderPasss",
|
|
908
|
+
"ComputePasss",
|
|
909
|
+
"CommandEncoders",
|
|
910
|
+
"CommandBuffers"
|
|
911
|
+
];
|
|
912
|
+
var WEBGL_RESOURCE_COUNT_ORDER = [
|
|
913
|
+
"Resources",
|
|
914
|
+
"Buffers",
|
|
915
|
+
"Textures",
|
|
916
|
+
"Samplers",
|
|
917
|
+
"TextureViews",
|
|
918
|
+
"Framebuffers",
|
|
919
|
+
"QuerySets",
|
|
920
|
+
"Shaders",
|
|
921
|
+
"RenderPipelines",
|
|
922
|
+
"SharedRenderPipelines",
|
|
923
|
+
"ComputePipelines",
|
|
924
|
+
"PipelineLayouts",
|
|
925
|
+
"VertexArrays",
|
|
926
|
+
"RenderPasss",
|
|
927
|
+
"ComputePasss",
|
|
928
|
+
"CommandEncoders",
|
|
929
|
+
"CommandBuffers"
|
|
930
|
+
];
|
|
931
|
+
var BASE_RESOURCE_COUNT_STAT_ORDER = BASE_RESOURCE_COUNT_ORDER.flatMap((resourceType) => [
|
|
932
|
+
`${resourceType} Created`,
|
|
933
|
+
`${resourceType} Active`
|
|
934
|
+
]);
|
|
935
|
+
var WEBGL_RESOURCE_COUNT_STAT_ORDER = WEBGL_RESOURCE_COUNT_ORDER.flatMap((resourceType) => [
|
|
936
|
+
`${resourceType} Created`,
|
|
937
|
+
`${resourceType} Active`
|
|
938
|
+
]);
|
|
939
|
+
var ORDERED_STATS_CACHE2 = /* @__PURE__ */ new WeakMap();
|
|
940
|
+
var ORDERED_STAT_NAME_SET_CACHE2 = /* @__PURE__ */ new WeakMap();
|
|
830
941
|
var Resource = class {
|
|
831
942
|
toString() {
|
|
832
943
|
return `${this[Symbol.toStringTag] || this.constructor.name}:"${this.id}"`;
|
|
@@ -843,6 +954,8 @@ var __exports__ = (() => {
|
|
|
843
954
|
destroyed = false;
|
|
844
955
|
/** For resources that allocate GPU memory */
|
|
845
956
|
allocatedBytes = 0;
|
|
957
|
+
/** Stats bucket currently holding the tracked allocation */
|
|
958
|
+
allocatedBytesName = null;
|
|
846
959
|
/** Attached resources will be destroyed when this resource is destroyed. Tracks auto-created "sub" resources. */
|
|
847
960
|
_attachedResources = /* @__PURE__ */ new Set();
|
|
848
961
|
/**
|
|
@@ -864,6 +977,9 @@ var __exports__ = (() => {
|
|
|
864
977
|
* destroy can be called on any resource to release it before it is garbage collected.
|
|
865
978
|
*/
|
|
866
979
|
destroy() {
|
|
980
|
+
if (this.destroyed) {
|
|
981
|
+
return;
|
|
982
|
+
}
|
|
867
983
|
this.destroyResource();
|
|
868
984
|
}
|
|
869
985
|
/** @deprecated Use destroy() */
|
|
@@ -902,7 +1018,7 @@ var __exports__ = (() => {
|
|
|
902
1018
|
}
|
|
903
1019
|
/** Destroy all owned resources. Make sure the resources are no longer needed before calling. */
|
|
904
1020
|
destroyAttachedResources() {
|
|
905
|
-
for (const resource of
|
|
1021
|
+
for (const resource of this._attachedResources) {
|
|
906
1022
|
resource.destroy();
|
|
907
1023
|
}
|
|
908
1024
|
this._attachedResources = /* @__PURE__ */ new Set();
|
|
@@ -910,37 +1026,107 @@ var __exports__ = (() => {
|
|
|
910
1026
|
// PROTECTED METHODS
|
|
911
1027
|
/** Perform all destroy steps. Can be called by derived resources when overriding destroy() */
|
|
912
1028
|
destroyResource() {
|
|
1029
|
+
if (this.destroyed) {
|
|
1030
|
+
return;
|
|
1031
|
+
}
|
|
913
1032
|
this.destroyAttachedResources();
|
|
914
1033
|
this.removeStats();
|
|
915
1034
|
this.destroyed = true;
|
|
916
1035
|
}
|
|
917
1036
|
/** Called by .destroy() to track object destruction. Subclass must call if overriding destroy() */
|
|
918
1037
|
removeStats() {
|
|
919
|
-
const
|
|
920
|
-
const
|
|
921
|
-
|
|
1038
|
+
const profiler = getCpuHotspotProfiler(this._device);
|
|
1039
|
+
const startTime = profiler ? getTimestamp() : 0;
|
|
1040
|
+
const statsObjects = [
|
|
1041
|
+
this._device.statsManager.getStats(RESOURCE_COUNTS_STATS),
|
|
1042
|
+
this._device.statsManager.getStats(LEGACY_RESOURCE_COUNTS_STATS)
|
|
1043
|
+
];
|
|
1044
|
+
const orderedStatNames = getResourceCountStatOrder(this._device);
|
|
1045
|
+
for (const stats of statsObjects) {
|
|
1046
|
+
initializeStats2(stats, orderedStatNames);
|
|
1047
|
+
}
|
|
1048
|
+
const name2 = this.getStatsName();
|
|
1049
|
+
for (const stats of statsObjects) {
|
|
1050
|
+
stats.get("Resources Active").decrementCount();
|
|
1051
|
+
stats.get(`${name2}s Active`).decrementCount();
|
|
1052
|
+
}
|
|
1053
|
+
if (profiler) {
|
|
1054
|
+
profiler.statsBookkeepingCalls = (profiler.statsBookkeepingCalls || 0) + 1;
|
|
1055
|
+
profiler.statsBookkeepingTimeMs = (profiler.statsBookkeepingTimeMs || 0) + (getTimestamp() - startTime);
|
|
1056
|
+
}
|
|
922
1057
|
}
|
|
923
1058
|
/** Called by subclass to track memory allocations */
|
|
924
|
-
trackAllocatedMemory(bytes, name2 = this
|
|
925
|
-
const
|
|
1059
|
+
trackAllocatedMemory(bytes, name2 = this.getStatsName()) {
|
|
1060
|
+
const profiler = getCpuHotspotProfiler(this._device);
|
|
1061
|
+
const startTime = profiler ? getTimestamp() : 0;
|
|
1062
|
+
const stats = this._device.statsManager.getStats(GPU_TIME_AND_MEMORY_STATS2);
|
|
1063
|
+
if (this.allocatedBytes > 0 && this.allocatedBytesName) {
|
|
1064
|
+
stats.get("GPU Memory").subtractCount(this.allocatedBytes);
|
|
1065
|
+
stats.get(`${this.allocatedBytesName} Memory`).subtractCount(this.allocatedBytes);
|
|
1066
|
+
}
|
|
926
1067
|
stats.get("GPU Memory").addCount(bytes);
|
|
927
1068
|
stats.get(`${name2} Memory`).addCount(bytes);
|
|
1069
|
+
if (profiler) {
|
|
1070
|
+
profiler.statsBookkeepingCalls = (profiler.statsBookkeepingCalls || 0) + 1;
|
|
1071
|
+
profiler.statsBookkeepingTimeMs = (profiler.statsBookkeepingTimeMs || 0) + (getTimestamp() - startTime);
|
|
1072
|
+
}
|
|
928
1073
|
this.allocatedBytes = bytes;
|
|
1074
|
+
this.allocatedBytesName = name2;
|
|
1075
|
+
}
|
|
1076
|
+
/** Called by subclass to track handle-backed memory allocations separately from owned allocations */
|
|
1077
|
+
trackReferencedMemory(bytes, name2 = this.getStatsName()) {
|
|
1078
|
+
this.trackAllocatedMemory(bytes, `Referenced ${name2}`);
|
|
929
1079
|
}
|
|
930
1080
|
/** Called by subclass to track memory deallocations */
|
|
931
|
-
trackDeallocatedMemory(name2 = this
|
|
932
|
-
|
|
1081
|
+
trackDeallocatedMemory(name2 = this.getStatsName()) {
|
|
1082
|
+
if (this.allocatedBytes === 0) {
|
|
1083
|
+
this.allocatedBytesName = null;
|
|
1084
|
+
return;
|
|
1085
|
+
}
|
|
1086
|
+
const profiler = getCpuHotspotProfiler(this._device);
|
|
1087
|
+
const startTime = profiler ? getTimestamp() : 0;
|
|
1088
|
+
const stats = this._device.statsManager.getStats(GPU_TIME_AND_MEMORY_STATS2);
|
|
933
1089
|
stats.get("GPU Memory").subtractCount(this.allocatedBytes);
|
|
934
|
-
stats.get(`${name2} Memory`).subtractCount(this.allocatedBytes);
|
|
1090
|
+
stats.get(`${this.allocatedBytesName || name2} Memory`).subtractCount(this.allocatedBytes);
|
|
1091
|
+
if (profiler) {
|
|
1092
|
+
profiler.statsBookkeepingCalls = (profiler.statsBookkeepingCalls || 0) + 1;
|
|
1093
|
+
profiler.statsBookkeepingTimeMs = (profiler.statsBookkeepingTimeMs || 0) + (getTimestamp() - startTime);
|
|
1094
|
+
}
|
|
935
1095
|
this.allocatedBytes = 0;
|
|
1096
|
+
this.allocatedBytesName = null;
|
|
1097
|
+
}
|
|
1098
|
+
/** Called by subclass to deallocate handle-backed memory tracked via trackReferencedMemory() */
|
|
1099
|
+
trackDeallocatedReferencedMemory(name2 = this.getStatsName()) {
|
|
1100
|
+
this.trackDeallocatedMemory(`Referenced ${name2}`);
|
|
936
1101
|
}
|
|
937
1102
|
/** Called by resource constructor to track object creation */
|
|
938
1103
|
addStats() {
|
|
939
|
-
const
|
|
940
|
-
const
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
1104
|
+
const name2 = this.getStatsName();
|
|
1105
|
+
const profiler = getCpuHotspotProfiler(this._device);
|
|
1106
|
+
const startTime = profiler ? getTimestamp() : 0;
|
|
1107
|
+
const statsObjects = [
|
|
1108
|
+
this._device.statsManager.getStats(RESOURCE_COUNTS_STATS),
|
|
1109
|
+
this._device.statsManager.getStats(LEGACY_RESOURCE_COUNTS_STATS)
|
|
1110
|
+
];
|
|
1111
|
+
const orderedStatNames = getResourceCountStatOrder(this._device);
|
|
1112
|
+
for (const stats of statsObjects) {
|
|
1113
|
+
initializeStats2(stats, orderedStatNames);
|
|
1114
|
+
}
|
|
1115
|
+
for (const stats of statsObjects) {
|
|
1116
|
+
stats.get("Resources Created").incrementCount();
|
|
1117
|
+
stats.get("Resources Active").incrementCount();
|
|
1118
|
+
stats.get(`${name2}s Created`).incrementCount();
|
|
1119
|
+
stats.get(`${name2}s Active`).incrementCount();
|
|
1120
|
+
}
|
|
1121
|
+
if (profiler) {
|
|
1122
|
+
profiler.statsBookkeepingCalls = (profiler.statsBookkeepingCalls || 0) + 1;
|
|
1123
|
+
profiler.statsBookkeepingTimeMs = (profiler.statsBookkeepingTimeMs || 0) + (getTimestamp() - startTime);
|
|
1124
|
+
}
|
|
1125
|
+
recordTransientCanvasResourceCreate(this._device, name2);
|
|
1126
|
+
}
|
|
1127
|
+
/** Canonical resource name used for stats buckets. */
|
|
1128
|
+
getStatsName() {
|
|
1129
|
+
return getCanonicalResourceName(this);
|
|
944
1130
|
}
|
|
945
1131
|
};
|
|
946
1132
|
/** Default properties for resource */
|
|
@@ -958,6 +1144,96 @@ var __exports__ = (() => {
|
|
|
958
1144
|
}
|
|
959
1145
|
return mergedProps;
|
|
960
1146
|
}
|
|
1147
|
+
function initializeStats2(stats, orderedStatNames) {
|
|
1148
|
+
const statsMap = stats.stats;
|
|
1149
|
+
let addedOrderedStat = false;
|
|
1150
|
+
for (const statName of orderedStatNames) {
|
|
1151
|
+
if (!statsMap[statName]) {
|
|
1152
|
+
stats.get(statName);
|
|
1153
|
+
addedOrderedStat = true;
|
|
1154
|
+
}
|
|
1155
|
+
}
|
|
1156
|
+
const statCount = Object.keys(statsMap).length;
|
|
1157
|
+
const cachedStats = ORDERED_STATS_CACHE2.get(stats);
|
|
1158
|
+
if (!addedOrderedStat && cachedStats?.orderedStatNames === orderedStatNames && cachedStats.statCount === statCount) {
|
|
1159
|
+
return;
|
|
1160
|
+
}
|
|
1161
|
+
const reorderedStats = {};
|
|
1162
|
+
let orderedStatNamesSet = ORDERED_STAT_NAME_SET_CACHE2.get(orderedStatNames);
|
|
1163
|
+
if (!orderedStatNamesSet) {
|
|
1164
|
+
orderedStatNamesSet = new Set(orderedStatNames);
|
|
1165
|
+
ORDERED_STAT_NAME_SET_CACHE2.set(orderedStatNames, orderedStatNamesSet);
|
|
1166
|
+
}
|
|
1167
|
+
for (const statName of orderedStatNames) {
|
|
1168
|
+
if (statsMap[statName]) {
|
|
1169
|
+
reorderedStats[statName] = statsMap[statName];
|
|
1170
|
+
}
|
|
1171
|
+
}
|
|
1172
|
+
for (const [statName, stat] of Object.entries(statsMap)) {
|
|
1173
|
+
if (!orderedStatNamesSet.has(statName)) {
|
|
1174
|
+
reorderedStats[statName] = stat;
|
|
1175
|
+
}
|
|
1176
|
+
}
|
|
1177
|
+
for (const statName of Object.keys(statsMap)) {
|
|
1178
|
+
delete statsMap[statName];
|
|
1179
|
+
}
|
|
1180
|
+
Object.assign(statsMap, reorderedStats);
|
|
1181
|
+
ORDERED_STATS_CACHE2.set(stats, { orderedStatNames, statCount });
|
|
1182
|
+
}
|
|
1183
|
+
function getResourceCountStatOrder(device) {
|
|
1184
|
+
return device.type === "webgl" ? WEBGL_RESOURCE_COUNT_STAT_ORDER : BASE_RESOURCE_COUNT_STAT_ORDER;
|
|
1185
|
+
}
|
|
1186
|
+
function getCpuHotspotProfiler(device) {
|
|
1187
|
+
const profiler = device.userData[CPU_HOTSPOT_PROFILER_MODULE];
|
|
1188
|
+
return profiler?.enabled ? profiler : null;
|
|
1189
|
+
}
|
|
1190
|
+
function getTimestamp() {
|
|
1191
|
+
return globalThis.performance?.now?.() ?? Date.now();
|
|
1192
|
+
}
|
|
1193
|
+
function recordTransientCanvasResourceCreate(device, name2) {
|
|
1194
|
+
const profiler = getCpuHotspotProfiler(device);
|
|
1195
|
+
if (!profiler || !profiler.activeDefaultFramebufferAcquireDepth) {
|
|
1196
|
+
return;
|
|
1197
|
+
}
|
|
1198
|
+
profiler.transientCanvasResourceCreates = (profiler.transientCanvasResourceCreates || 0) + 1;
|
|
1199
|
+
switch (name2) {
|
|
1200
|
+
case "Texture":
|
|
1201
|
+
profiler.transientCanvasTextureCreates = (profiler.transientCanvasTextureCreates || 0) + 1;
|
|
1202
|
+
break;
|
|
1203
|
+
case "TextureView":
|
|
1204
|
+
profiler.transientCanvasTextureViewCreates = (profiler.transientCanvasTextureViewCreates || 0) + 1;
|
|
1205
|
+
break;
|
|
1206
|
+
case "Sampler":
|
|
1207
|
+
profiler.transientCanvasSamplerCreates = (profiler.transientCanvasSamplerCreates || 0) + 1;
|
|
1208
|
+
break;
|
|
1209
|
+
case "Framebuffer":
|
|
1210
|
+
profiler.transientCanvasFramebufferCreates = (profiler.transientCanvasFramebufferCreates || 0) + 1;
|
|
1211
|
+
break;
|
|
1212
|
+
default:
|
|
1213
|
+
break;
|
|
1214
|
+
}
|
|
1215
|
+
}
|
|
1216
|
+
function getCanonicalResourceName(resource) {
|
|
1217
|
+
let prototype = Object.getPrototypeOf(resource);
|
|
1218
|
+
while (prototype) {
|
|
1219
|
+
const parentPrototype = Object.getPrototypeOf(prototype);
|
|
1220
|
+
if (!parentPrototype || parentPrototype === Resource.prototype) {
|
|
1221
|
+
return getPrototypeToStringTag(prototype) || resource[Symbol.toStringTag] || resource.constructor.name;
|
|
1222
|
+
}
|
|
1223
|
+
prototype = parentPrototype;
|
|
1224
|
+
}
|
|
1225
|
+
return resource[Symbol.toStringTag] || resource.constructor.name;
|
|
1226
|
+
}
|
|
1227
|
+
function getPrototypeToStringTag(prototype) {
|
|
1228
|
+
const descriptor = Object.getOwnPropertyDescriptor(prototype, Symbol.toStringTag);
|
|
1229
|
+
if (typeof descriptor?.get === "function") {
|
|
1230
|
+
return descriptor.get.call(prototype);
|
|
1231
|
+
}
|
|
1232
|
+
if (typeof descriptor?.value === "string") {
|
|
1233
|
+
return descriptor.value;
|
|
1234
|
+
}
|
|
1235
|
+
return null;
|
|
1236
|
+
}
|
|
961
1237
|
|
|
962
1238
|
// src/adapter/resources/buffer.ts
|
|
963
1239
|
var _Buffer = class extends Resource {
|
|
@@ -997,18 +1273,26 @@ var __exports__ = (() => {
|
|
|
997
1273
|
/** A partial CPU-side copy of the data in this buffer, for debugging purposes */
|
|
998
1274
|
debugData = new ArrayBuffer(0);
|
|
999
1275
|
/** This doesn't handle partial non-zero offset updates correctly */
|
|
1000
|
-
_setDebugData(data,
|
|
1001
|
-
|
|
1276
|
+
_setDebugData(data, _byteOffset, byteLength) {
|
|
1277
|
+
let arrayBufferView = null;
|
|
1278
|
+
let arrayBuffer2;
|
|
1279
|
+
if (ArrayBuffer.isView(data)) {
|
|
1280
|
+
arrayBufferView = data;
|
|
1281
|
+
arrayBuffer2 = data.buffer;
|
|
1282
|
+
} else {
|
|
1283
|
+
arrayBuffer2 = data;
|
|
1284
|
+
}
|
|
1002
1285
|
const debugDataLength = Math.min(
|
|
1003
1286
|
data ? data.byteLength : byteLength,
|
|
1004
1287
|
_Buffer.DEBUG_DATA_MAX_LENGTH
|
|
1005
1288
|
);
|
|
1006
1289
|
if (arrayBuffer2 === null) {
|
|
1007
1290
|
this.debugData = new ArrayBuffer(debugDataLength);
|
|
1008
|
-
} else if (byteOffset === 0 && byteLength === arrayBuffer2.byteLength) {
|
|
1009
|
-
this.debugData = arrayBuffer2.slice(0, debugDataLength);
|
|
1010
1291
|
} else {
|
|
1011
|
-
|
|
1292
|
+
const sourceByteOffset = Math.min(arrayBufferView?.byteOffset || 0, arrayBuffer2.byteLength);
|
|
1293
|
+
const availableByteLength = Math.max(0, arrayBuffer2.byteLength - sourceByteOffset);
|
|
1294
|
+
const copyByteLength = Math.min(debugDataLength, availableByteLength);
|
|
1295
|
+
this.debugData = new Uint8Array(arrayBuffer2, sourceByteOffset, copyByteLength).slice().buffer;
|
|
1012
1296
|
}
|
|
1013
1297
|
}
|
|
1014
1298
|
};
|
|
@@ -1204,6 +1488,7 @@ var __exports__ = (() => {
|
|
|
1204
1488
|
var float16_renderable = "float16-renderable-webgl";
|
|
1205
1489
|
var rgb9e5ufloat_renderable = "rgb9e5ufloat-renderable-webgl";
|
|
1206
1490
|
var snorm8_renderable = "snorm8-renderable-webgl";
|
|
1491
|
+
var norm16_webgl = "norm16-webgl";
|
|
1207
1492
|
var norm16_renderable = "norm16-renderable-webgl";
|
|
1208
1493
|
var snorm16_renderable = "snorm16-renderable-webgl";
|
|
1209
1494
|
var float32_filterable = "float32-filterable";
|
|
@@ -1237,16 +1522,16 @@ var __exports__ = (() => {
|
|
|
1237
1522
|
"rgba8sint": {},
|
|
1238
1523
|
"bgra8unorm": {},
|
|
1239
1524
|
"bgra8unorm-srgb": {},
|
|
1240
|
-
"r16unorm": { f: norm16_renderable },
|
|
1241
|
-
"rg16unorm": { render: norm16_renderable },
|
|
1242
|
-
"rgb16unorm-webgl": { f:
|
|
1525
|
+
"r16unorm": { f: norm16_webgl, render: norm16_renderable },
|
|
1526
|
+
"rg16unorm": { f: norm16_webgl, render: norm16_renderable },
|
|
1527
|
+
"rgb16unorm-webgl": { f: norm16_webgl, render: false },
|
|
1243
1528
|
// rgb not renderable
|
|
1244
|
-
"rgba16unorm": { render: norm16_renderable },
|
|
1245
|
-
"r16snorm": { f: snorm16_renderable },
|
|
1246
|
-
"rg16snorm": { render: snorm16_renderable },
|
|
1247
|
-
"rgb16snorm-webgl": { f:
|
|
1529
|
+
"rgba16unorm": { f: norm16_webgl, render: norm16_renderable },
|
|
1530
|
+
"r16snorm": { f: norm16_webgl, render: snorm16_renderable },
|
|
1531
|
+
"rg16snorm": { f: norm16_webgl, render: snorm16_renderable },
|
|
1532
|
+
"rgb16snorm-webgl": { f: norm16_webgl, render: false },
|
|
1248
1533
|
// rgb not renderable
|
|
1249
|
-
"rgba16snorm": { render: snorm16_renderable },
|
|
1534
|
+
"rgba16snorm": { f: norm16_webgl, render: snorm16_renderable },
|
|
1250
1535
|
"r16uint": {},
|
|
1251
1536
|
"rg16uint": {},
|
|
1252
1537
|
"rgba16uint": {},
|
|
@@ -1349,7 +1634,7 @@ var __exports__ = (() => {
|
|
|
1349
1634
|
// WEBGL_compressed_texture_pvrtc
|
|
1350
1635
|
"pvrtc-rgb4unorm-webgl": { f: texture_compression_pvrtc_webgl },
|
|
1351
1636
|
"pvrtc-rgba4unorm-webgl": { f: texture_compression_pvrtc_webgl },
|
|
1352
|
-
"pvrtc-
|
|
1637
|
+
"pvrtc-rgb2unorm-webgl": { f: texture_compression_pvrtc_webgl },
|
|
1353
1638
|
"pvrtc-rgba2unorm-webgl": { f: texture_compression_pvrtc_webgl },
|
|
1354
1639
|
// WEBGL_compressed_texture_etc1
|
|
1355
1640
|
"etc1-rbg-unorm-webgl": { f: texture_compression_etc1_webgl },
|
|
@@ -1416,10 +1701,19 @@ var __exports__ = (() => {
|
|
|
1416
1701
|
depth,
|
|
1417
1702
|
byteAlignment
|
|
1418
1703
|
}) {
|
|
1419
|
-
const
|
|
1420
|
-
const
|
|
1704
|
+
const formatInfo = textureFormatDecoder.getInfo(format);
|
|
1705
|
+
const {
|
|
1706
|
+
bytesPerPixel,
|
|
1707
|
+
bytesPerBlock = bytesPerPixel,
|
|
1708
|
+
blockWidth = 1,
|
|
1709
|
+
blockHeight = 1,
|
|
1710
|
+
compressed = false
|
|
1711
|
+
} = formatInfo;
|
|
1712
|
+
const blockColumns = compressed ? Math.ceil(width / blockWidth) : width;
|
|
1713
|
+
const blockRows = compressed ? Math.ceil(height / blockHeight) : height;
|
|
1714
|
+
const unpaddedBytesPerRow = blockColumns * bytesPerBlock;
|
|
1421
1715
|
const bytesPerRow = Math.ceil(unpaddedBytesPerRow / byteAlignment) * byteAlignment;
|
|
1422
|
-
const rowsPerImage =
|
|
1716
|
+
const rowsPerImage = blockRows;
|
|
1423
1717
|
const byteLength = bytesPerRow * rowsPerImage * depth;
|
|
1424
1718
|
return {
|
|
1425
1719
|
bytesPerPixel,
|
|
@@ -1445,7 +1739,8 @@ var __exports__ = (() => {
|
|
|
1445
1739
|
const isSigned = formatInfo?.signed;
|
|
1446
1740
|
const isInteger = formatInfo?.integer;
|
|
1447
1741
|
const isWebGLSpecific = formatInfo?.webgl;
|
|
1448
|
-
|
|
1742
|
+
const isCompressed = Boolean(formatInfo?.compressed);
|
|
1743
|
+
formatCapabilities.render &&= !isDepthStencil && !isCompressed;
|
|
1449
1744
|
formatCapabilities.filter &&= !isDepthStencil && !isSigned && !isInteger && !isWebGLSpecific;
|
|
1450
1745
|
return formatCapabilities;
|
|
1451
1746
|
}
|
|
@@ -1457,6 +1752,7 @@ var __exports__ = (() => {
|
|
|
1457
1752
|
formatInfo.bytesPerPixel = 1;
|
|
1458
1753
|
formatInfo.srgb = false;
|
|
1459
1754
|
formatInfo.compressed = true;
|
|
1755
|
+
formatInfo.bytesPerBlock = getCompressedTextureBlockByteLength(format);
|
|
1460
1756
|
const blockSize = getCompressedTextureBlockSize(format);
|
|
1461
1757
|
if (blockSize) {
|
|
1462
1758
|
formatInfo.blockWidth = blockSize.blockWidth;
|
|
@@ -1542,8 +1838,29 @@ var __exports__ = (() => {
|
|
|
1542
1838
|
const [, blockWidth, blockHeight] = matches;
|
|
1543
1839
|
return { blockWidth: Number(blockWidth), blockHeight: Number(blockHeight) };
|
|
1544
1840
|
}
|
|
1841
|
+
if (format.startsWith("bc") || format.startsWith("etc1") || format.startsWith("etc2") || format.startsWith("eac") || format.startsWith("atc")) {
|
|
1842
|
+
return { blockWidth: 4, blockHeight: 4 };
|
|
1843
|
+
}
|
|
1844
|
+
if (format.startsWith("pvrtc-rgb4") || format.startsWith("pvrtc-rgba4")) {
|
|
1845
|
+
return { blockWidth: 4, blockHeight: 4 };
|
|
1846
|
+
}
|
|
1847
|
+
if (format.startsWith("pvrtc-rgb2") || format.startsWith("pvrtc-rgba2")) {
|
|
1848
|
+
return { blockWidth: 8, blockHeight: 4 };
|
|
1849
|
+
}
|
|
1545
1850
|
return null;
|
|
1546
1851
|
}
|
|
1852
|
+
function getCompressedTextureBlockByteLength(format) {
|
|
1853
|
+
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") {
|
|
1854
|
+
return 8;
|
|
1855
|
+
}
|
|
1856
|
+
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") {
|
|
1857
|
+
return 16;
|
|
1858
|
+
}
|
|
1859
|
+
if (format.startsWith("pvrtc")) {
|
|
1860
|
+
return 8;
|
|
1861
|
+
}
|
|
1862
|
+
return 16;
|
|
1863
|
+
}
|
|
1547
1864
|
|
|
1548
1865
|
// src/image-utils/image-types.ts
|
|
1549
1866
|
function isExternalImage(data) {
|
|
@@ -1604,6 +1921,8 @@ var __exports__ = (() => {
|
|
|
1604
1921
|
/** Used by other luma.gl modules to store data on the device */
|
|
1605
1922
|
_moduleData = {};
|
|
1606
1923
|
_textureCaps = {};
|
|
1924
|
+
/** Internal timestamp query set used when GPU timing collection is enabled for this device. */
|
|
1925
|
+
_debugGPUTimeQuery = null;
|
|
1607
1926
|
constructor(props) {
|
|
1608
1927
|
this.props = { ..._Device.defaultProps, ...props };
|
|
1609
1928
|
this.id = this.props.id || uid(this[Symbol.toStringTag].toLowerCase());
|
|
@@ -1657,6 +1976,16 @@ var __exports__ = (() => {
|
|
|
1657
1976
|
isTextureFormatCompressed(format) {
|
|
1658
1977
|
return textureFormatDecoder.isCompressed(format);
|
|
1659
1978
|
}
|
|
1979
|
+
/** Returns the compressed texture formats that can be created and sampled on this device */
|
|
1980
|
+
getSupportedCompressedTextureFormats() {
|
|
1981
|
+
const supportedFormats = [];
|
|
1982
|
+
for (const format of Object.keys(getTextureFormatTable())) {
|
|
1983
|
+
if (this.isTextureFormatCompressed(format) && this.isTextureFormatSupported(format)) {
|
|
1984
|
+
supportedFormats.push(format);
|
|
1985
|
+
}
|
|
1986
|
+
}
|
|
1987
|
+
return supportedFormats;
|
|
1988
|
+
}
|
|
1660
1989
|
// DEBUG METHODS
|
|
1661
1990
|
pushDebugGroup(groupLabel) {
|
|
1662
1991
|
this.commandEncoder.pushDebugGroup(groupLabel);
|
|
@@ -1739,6 +2068,70 @@ or create a device with the 'debug: true' prop.`;
|
|
|
1739
2068
|
beginComputePass(props) {
|
|
1740
2069
|
return this.commandEncoder.beginComputePass(props);
|
|
1741
2070
|
}
|
|
2071
|
+
/**
|
|
2072
|
+
* Generate mipmaps for a WebGPU texture.
|
|
2073
|
+
* WebGPU textures must be created up front with the required mip count, usage flags, and a format that supports the chosen generation path.
|
|
2074
|
+
* WebGL uses `Texture.generateMipmapsWebGL()` directly because the backend manages mip generation on the texture object itself.
|
|
2075
|
+
*/
|
|
2076
|
+
generateMipmapsWebGPU(_texture) {
|
|
2077
|
+
throw new Error("not implemented");
|
|
2078
|
+
}
|
|
2079
|
+
/** Internal helper for creating a shareable WebGL render-pipeline implementation. */
|
|
2080
|
+
_createSharedRenderPipelineWebGL(_props) {
|
|
2081
|
+
throw new Error("_createSharedRenderPipelineWebGL() not implemented");
|
|
2082
|
+
}
|
|
2083
|
+
/**
|
|
2084
|
+
* Internal helper that returns `true` when timestamp-query GPU timing should be
|
|
2085
|
+
* collected for this device.
|
|
2086
|
+
*/
|
|
2087
|
+
_supportsDebugGPUTime() {
|
|
2088
|
+
return this.features.has("timestamp-query") && Boolean(this.props.debug || this.props.debugGPUTime);
|
|
2089
|
+
}
|
|
2090
|
+
/**
|
|
2091
|
+
* Internal helper that enables device-managed GPU timing collection on the
|
|
2092
|
+
* default command encoder. Reuses the existing query set if timing is already enabled.
|
|
2093
|
+
*
|
|
2094
|
+
* @param queryCount - Number of timestamp slots reserved for profiled passes.
|
|
2095
|
+
* @returns The device-managed timestamp QuerySet, or `null` when timing is not supported or could not be enabled.
|
|
2096
|
+
*/
|
|
2097
|
+
_enableDebugGPUTime(queryCount = 256) {
|
|
2098
|
+
if (!this._supportsDebugGPUTime()) {
|
|
2099
|
+
return null;
|
|
2100
|
+
}
|
|
2101
|
+
if (this._debugGPUTimeQuery) {
|
|
2102
|
+
return this._debugGPUTimeQuery;
|
|
2103
|
+
}
|
|
2104
|
+
try {
|
|
2105
|
+
this._debugGPUTimeQuery = this.createQuerySet({ type: "timestamp", count: queryCount });
|
|
2106
|
+
this.commandEncoder = this.createCommandEncoder({
|
|
2107
|
+
id: this.commandEncoder.props.id,
|
|
2108
|
+
timeProfilingQuerySet: this._debugGPUTimeQuery
|
|
2109
|
+
});
|
|
2110
|
+
} catch {
|
|
2111
|
+
this._debugGPUTimeQuery = null;
|
|
2112
|
+
}
|
|
2113
|
+
return this._debugGPUTimeQuery;
|
|
2114
|
+
}
|
|
2115
|
+
/**
|
|
2116
|
+
* Internal helper that disables device-managed GPU timing collection and restores
|
|
2117
|
+
* the default command encoder to an unprofiled state.
|
|
2118
|
+
*/
|
|
2119
|
+
_disableDebugGPUTime() {
|
|
2120
|
+
if (!this._debugGPUTimeQuery) {
|
|
2121
|
+
return;
|
|
2122
|
+
}
|
|
2123
|
+
if (this.commandEncoder.getTimeProfilingQuerySet() === this._debugGPUTimeQuery) {
|
|
2124
|
+
this.commandEncoder = this.createCommandEncoder({
|
|
2125
|
+
id: this.commandEncoder.props.id
|
|
2126
|
+
});
|
|
2127
|
+
}
|
|
2128
|
+
this._debugGPUTimeQuery.destroy();
|
|
2129
|
+
this._debugGPUTimeQuery = null;
|
|
2130
|
+
}
|
|
2131
|
+
/** Internal helper that returns `true` when device-managed GPU timing is currently active. */
|
|
2132
|
+
_isDebugGPUTimeEnabled() {
|
|
2133
|
+
return this._debugGPUTimeQuery !== null;
|
|
2134
|
+
}
|
|
1742
2135
|
// DEPRECATED METHODS
|
|
1743
2136
|
/** @deprecated Use getDefaultCanvasContext() */
|
|
1744
2137
|
getCanvasContext() {
|
|
@@ -1846,7 +2239,8 @@ or create a device with the 'debug: true' prop.`;
|
|
|
1846
2239
|
onVisibilityChange: (context) => log.log(1, `${context} Visibility changed ${context.isVisible}`)(),
|
|
1847
2240
|
onDevicePixelRatioChange: (context, info) => log.log(1, `${context} DPR changed ${info.oldRatio} => ${context.devicePixelRatio}`)(),
|
|
1848
2241
|
// Debug flags
|
|
1849
|
-
debug:
|
|
2242
|
+
debug: getDefaultDebugValue(),
|
|
2243
|
+
debugGPUTime: false,
|
|
1850
2244
|
debugShaders: log.get("debug-shaders") || void 0,
|
|
1851
2245
|
debugFramebuffers: Boolean(log.get("debug-framebuffers")),
|
|
1852
2246
|
debugFactories: Boolean(log.get("debug-factories")),
|
|
@@ -1857,9 +2251,11 @@ or create a device with the 'debug: true' prop.`;
|
|
|
1857
2251
|
// Experimental
|
|
1858
2252
|
_reuseDevices: false,
|
|
1859
2253
|
_requestMaxLimits: true,
|
|
1860
|
-
_cacheShaders:
|
|
1861
|
-
|
|
1862
|
-
|
|
2254
|
+
_cacheShaders: true,
|
|
2255
|
+
_destroyShaders: false,
|
|
2256
|
+
_cachePipelines: true,
|
|
2257
|
+
_sharePipelines: true,
|
|
2258
|
+
_destroyPipelines: false,
|
|
1863
2259
|
// TODO - Change these after confirming things work as expected
|
|
1864
2260
|
_initializeFeatures: true,
|
|
1865
2261
|
_disabledFeatures: {
|
|
@@ -1868,6 +2264,25 @@ or create a device with the 'debug: true' prop.`;
|
|
|
1868
2264
|
// INTERNAL
|
|
1869
2265
|
_handle: void 0
|
|
1870
2266
|
});
|
|
2267
|
+
function _getDefaultDebugValue(logDebugValue, nodeEnv) {
|
|
2268
|
+
if (logDebugValue !== void 0 && logDebugValue !== null) {
|
|
2269
|
+
return Boolean(logDebugValue);
|
|
2270
|
+
}
|
|
2271
|
+
if (nodeEnv !== void 0) {
|
|
2272
|
+
return nodeEnv !== "production";
|
|
2273
|
+
}
|
|
2274
|
+
return false;
|
|
2275
|
+
}
|
|
2276
|
+
function getDefaultDebugValue() {
|
|
2277
|
+
return _getDefaultDebugValue(log.get("debug"), getNodeEnv());
|
|
2278
|
+
}
|
|
2279
|
+
function getNodeEnv() {
|
|
2280
|
+
const processObject = globalThis.process;
|
|
2281
|
+
if (!processObject?.env) {
|
|
2282
|
+
return void 0;
|
|
2283
|
+
}
|
|
2284
|
+
return processObject.env["NODE_ENV"];
|
|
2285
|
+
}
|
|
1871
2286
|
|
|
1872
2287
|
// src/adapter/luma.ts
|
|
1873
2288
|
var STARTUP_MESSAGE = "set luma.log.level=1 (or higher) to trace rendering";
|
|
@@ -2045,6 +2460,100 @@ or create a device with the 'debug: true' prop.`;
|
|
|
2045
2460
|
return pageLoadPromise;
|
|
2046
2461
|
}
|
|
2047
2462
|
|
|
2463
|
+
// src/adapter/canvas-observer.ts
|
|
2464
|
+
var CanvasObserver = class {
|
|
2465
|
+
props;
|
|
2466
|
+
_resizeObserver;
|
|
2467
|
+
_intersectionObserver;
|
|
2468
|
+
_observeDevicePixelRatioTimeout = null;
|
|
2469
|
+
_observeDevicePixelRatioMediaQuery = null;
|
|
2470
|
+
_handleDevicePixelRatioChange = () => this._refreshDevicePixelRatio();
|
|
2471
|
+
_trackPositionInterval = null;
|
|
2472
|
+
_started = false;
|
|
2473
|
+
get started() {
|
|
2474
|
+
return this._started;
|
|
2475
|
+
}
|
|
2476
|
+
constructor(props) {
|
|
2477
|
+
this.props = props;
|
|
2478
|
+
}
|
|
2479
|
+
start() {
|
|
2480
|
+
if (this._started || !this.props.canvas) {
|
|
2481
|
+
return;
|
|
2482
|
+
}
|
|
2483
|
+
this._started = true;
|
|
2484
|
+
this._intersectionObserver ||= new IntersectionObserver(
|
|
2485
|
+
(entries) => this.props.onIntersection(entries)
|
|
2486
|
+
);
|
|
2487
|
+
this._resizeObserver ||= new ResizeObserver((entries) => this.props.onResize(entries));
|
|
2488
|
+
this._intersectionObserver.observe(this.props.canvas);
|
|
2489
|
+
try {
|
|
2490
|
+
this._resizeObserver.observe(this.props.canvas, { box: "device-pixel-content-box" });
|
|
2491
|
+
} catch {
|
|
2492
|
+
this._resizeObserver.observe(this.props.canvas, { box: "content-box" });
|
|
2493
|
+
}
|
|
2494
|
+
this._observeDevicePixelRatioTimeout = setTimeout(() => this._refreshDevicePixelRatio(), 0);
|
|
2495
|
+
if (this.props.trackPosition) {
|
|
2496
|
+
this._trackPosition();
|
|
2497
|
+
}
|
|
2498
|
+
}
|
|
2499
|
+
stop() {
|
|
2500
|
+
if (!this._started) {
|
|
2501
|
+
return;
|
|
2502
|
+
}
|
|
2503
|
+
this._started = false;
|
|
2504
|
+
if (this._observeDevicePixelRatioTimeout) {
|
|
2505
|
+
clearTimeout(this._observeDevicePixelRatioTimeout);
|
|
2506
|
+
this._observeDevicePixelRatioTimeout = null;
|
|
2507
|
+
}
|
|
2508
|
+
if (this._observeDevicePixelRatioMediaQuery) {
|
|
2509
|
+
this._observeDevicePixelRatioMediaQuery.removeEventListener(
|
|
2510
|
+
"change",
|
|
2511
|
+
this._handleDevicePixelRatioChange
|
|
2512
|
+
);
|
|
2513
|
+
this._observeDevicePixelRatioMediaQuery = null;
|
|
2514
|
+
}
|
|
2515
|
+
if (this._trackPositionInterval) {
|
|
2516
|
+
clearInterval(this._trackPositionInterval);
|
|
2517
|
+
this._trackPositionInterval = null;
|
|
2518
|
+
}
|
|
2519
|
+
this._resizeObserver?.disconnect();
|
|
2520
|
+
this._intersectionObserver?.disconnect();
|
|
2521
|
+
}
|
|
2522
|
+
_refreshDevicePixelRatio() {
|
|
2523
|
+
if (!this._started) {
|
|
2524
|
+
return;
|
|
2525
|
+
}
|
|
2526
|
+
this.props.onDevicePixelRatioChange();
|
|
2527
|
+
this._observeDevicePixelRatioMediaQuery?.removeEventListener(
|
|
2528
|
+
"change",
|
|
2529
|
+
this._handleDevicePixelRatioChange
|
|
2530
|
+
);
|
|
2531
|
+
this._observeDevicePixelRatioMediaQuery = matchMedia(
|
|
2532
|
+
`(resolution: ${window.devicePixelRatio}dppx)`
|
|
2533
|
+
);
|
|
2534
|
+
this._observeDevicePixelRatioMediaQuery.addEventListener(
|
|
2535
|
+
"change",
|
|
2536
|
+
this._handleDevicePixelRatioChange,
|
|
2537
|
+
{ once: true }
|
|
2538
|
+
);
|
|
2539
|
+
}
|
|
2540
|
+
_trackPosition(intervalMs = 100) {
|
|
2541
|
+
if (this._trackPositionInterval) {
|
|
2542
|
+
return;
|
|
2543
|
+
}
|
|
2544
|
+
this._trackPositionInterval = setInterval(() => {
|
|
2545
|
+
if (!this._started) {
|
|
2546
|
+
if (this._trackPositionInterval) {
|
|
2547
|
+
clearInterval(this._trackPositionInterval);
|
|
2548
|
+
this._trackPositionInterval = null;
|
|
2549
|
+
}
|
|
2550
|
+
} else {
|
|
2551
|
+
this.props.onPositionChange();
|
|
2552
|
+
}
|
|
2553
|
+
}, intervalMs);
|
|
2554
|
+
}
|
|
2555
|
+
};
|
|
2556
|
+
|
|
2048
2557
|
// src/utils/promise-utils.ts
|
|
2049
2558
|
function withResolvers() {
|
|
2050
2559
|
let resolve;
|
|
@@ -2069,8 +2578,8 @@ or create a device with the 'debug: true' prop.`;
|
|
|
2069
2578
|
return value;
|
|
2070
2579
|
}
|
|
2071
2580
|
|
|
2072
|
-
// src/adapter/canvas-
|
|
2073
|
-
var
|
|
2581
|
+
// src/adapter/canvas-surface.ts
|
|
2582
|
+
var _CanvasSurface = class {
|
|
2074
2583
|
static isHTMLCanvas(canvas) {
|
|
2075
2584
|
return typeof HTMLCanvasElement !== "undefined" && canvas instanceof HTMLCanvasElement;
|
|
2076
2585
|
}
|
|
@@ -2106,11 +2615,7 @@ or create a device with the 'debug: true' prop.`;
|
|
|
2106
2615
|
drawingBufferHeight;
|
|
2107
2616
|
/** Resolves when the canvas is initialized, i.e. when the ResizeObserver has updated the pixel size */
|
|
2108
2617
|
_initializedResolvers = withResolvers();
|
|
2109
|
-
|
|
2110
|
-
_resizeObserver;
|
|
2111
|
-
/** IntersectionObserver to track canvas visibility changes */
|
|
2112
|
-
_intersectionObserver;
|
|
2113
|
-
_observeDevicePixelRatioTimeout = null;
|
|
2618
|
+
_canvasObserver;
|
|
2114
2619
|
/** Position of the canvas in the document, updated by a timer */
|
|
2115
2620
|
_position = [0, 0];
|
|
2116
2621
|
/** Whether this canvas context has been destroyed */
|
|
@@ -2121,7 +2626,7 @@ or create a device with the 'debug: true' prop.`;
|
|
|
2121
2626
|
return `${this[Symbol.toStringTag]}(${this.id})`;
|
|
2122
2627
|
}
|
|
2123
2628
|
constructor(props) {
|
|
2124
|
-
this.props = { ...
|
|
2629
|
+
this.props = { ..._CanvasSurface.defaultProps, ...props };
|
|
2125
2630
|
props = this.props;
|
|
2126
2631
|
this.initialized = this._initializedResolvers.promise;
|
|
2127
2632
|
if (!isBrowser()) {
|
|
@@ -2133,11 +2638,11 @@ or create a device with the 'debug: true' prop.`;
|
|
|
2133
2638
|
} else {
|
|
2134
2639
|
this.canvas = props.canvas;
|
|
2135
2640
|
}
|
|
2136
|
-
if (
|
|
2641
|
+
if (_CanvasSurface.isHTMLCanvas(this.canvas)) {
|
|
2137
2642
|
this.id = props.id || this.canvas.id;
|
|
2138
2643
|
this.type = "html-canvas";
|
|
2139
2644
|
this.htmlCanvas = this.canvas;
|
|
2140
|
-
} else if (
|
|
2645
|
+
} else if (_CanvasSurface.isOffscreenCanvas(this.canvas)) {
|
|
2141
2646
|
this.id = props.id || "offscreen-canvas";
|
|
2142
2647
|
this.type = "offscreen-canvas";
|
|
2143
2648
|
this.offscreenCanvas = this.canvas;
|
|
@@ -2153,33 +2658,20 @@ or create a device with the 'debug: true' prop.`;
|
|
|
2153
2658
|
this.drawingBufferHeight = this.canvas.height;
|
|
2154
2659
|
this.devicePixelRatio = globalThis.devicePixelRatio || 1;
|
|
2155
2660
|
this._position = [0, 0];
|
|
2156
|
-
|
|
2157
|
-
this.
|
|
2158
|
-
|
|
2159
|
-
)
|
|
2160
|
-
this.
|
|
2161
|
-
|
|
2162
|
-
|
|
2163
|
-
|
|
2164
|
-
} catch {
|
|
2165
|
-
this._resizeObserver.observe(this.canvas, { box: "content-box" });
|
|
2166
|
-
}
|
|
2167
|
-
this._observeDevicePixelRatioTimeout = setTimeout(() => this._observeDevicePixelRatio(), 0);
|
|
2168
|
-
if (this.props.trackPosition) {
|
|
2169
|
-
this._trackPosition();
|
|
2170
|
-
}
|
|
2171
|
-
}
|
|
2661
|
+
this._canvasObserver = new CanvasObserver({
|
|
2662
|
+
canvas: this.htmlCanvas,
|
|
2663
|
+
trackPosition: this.props.trackPosition,
|
|
2664
|
+
onResize: (entries) => this._handleResize(entries),
|
|
2665
|
+
onIntersection: (entries) => this._handleIntersection(entries),
|
|
2666
|
+
onDevicePixelRatioChange: () => this._observeDevicePixelRatio(),
|
|
2667
|
+
onPositionChange: () => this.updatePosition()
|
|
2668
|
+
});
|
|
2172
2669
|
}
|
|
2173
2670
|
destroy() {
|
|
2174
2671
|
if (!this.destroyed) {
|
|
2175
2672
|
this.destroyed = true;
|
|
2176
|
-
|
|
2177
|
-
clearTimeout(this._observeDevicePixelRatioTimeout);
|
|
2178
|
-
this._observeDevicePixelRatioTimeout = null;
|
|
2179
|
-
}
|
|
2673
|
+
this._stopObservers();
|
|
2180
2674
|
this.device = null;
|
|
2181
|
-
this._resizeObserver?.disconnect();
|
|
2182
|
-
this._intersectionObserver?.disconnect();
|
|
2183
2675
|
}
|
|
2184
2676
|
}
|
|
2185
2677
|
setProps(props) {
|
|
@@ -2194,41 +2686,22 @@ or create a device with the 'debug: true' prop.`;
|
|
|
2194
2686
|
this._resizeDrawingBufferIfNeeded();
|
|
2195
2687
|
return this._getCurrentFramebuffer(options);
|
|
2196
2688
|
}
|
|
2197
|
-
// SIZE METHODS
|
|
2198
|
-
/**
|
|
2199
|
-
* Returns the size covered by the canvas in CSS pixels
|
|
2200
|
-
* @note This can be different from the actual device pixel size of a canvas due to DPR scaling, and rounding to integer pixels
|
|
2201
|
-
* @note This is independent of the canvas' internal drawing buffer size (.width, .height).
|
|
2202
|
-
*/
|
|
2203
2689
|
getCSSSize() {
|
|
2204
2690
|
return [this.cssWidth, this.cssHeight];
|
|
2205
2691
|
}
|
|
2206
2692
|
getPosition() {
|
|
2207
2693
|
return this._position;
|
|
2208
2694
|
}
|
|
2209
|
-
/**
|
|
2210
|
-
* Returns the size covered by the canvas in actual device pixels.
|
|
2211
|
-
* @note This can be different from the 'CSS' size of a canvas due to DPR scaling, and rounding to integer pixels
|
|
2212
|
-
* @note This is independent of the canvas' internal drawing buffer size (.width, .height).
|
|
2213
|
-
*/
|
|
2214
2695
|
getDevicePixelSize() {
|
|
2215
2696
|
return [this.devicePixelWidth, this.devicePixelHeight];
|
|
2216
2697
|
}
|
|
2217
|
-
/** Get the drawing buffer size (number of pixels GPU is rendering into, can be different from CSS size) */
|
|
2218
2698
|
getDrawingBufferSize() {
|
|
2219
2699
|
return [this.drawingBufferWidth, this.drawingBufferHeight];
|
|
2220
2700
|
}
|
|
2221
|
-
/** Returns the biggest allowed framebuffer size. @todo Allow the application to limit this? */
|
|
2222
2701
|
getMaxDrawingBufferSize() {
|
|
2223
2702
|
const maxTextureDimension = this.device.limits.maxTextureDimension2D;
|
|
2224
2703
|
return [maxTextureDimension, maxTextureDimension];
|
|
2225
2704
|
}
|
|
2226
|
-
/**
|
|
2227
|
-
* Update the canvas drawing buffer size.
|
|
2228
|
-
* @note - Called automatically if props.autoResize is true.
|
|
2229
|
-
* @note - Defers update of drawing buffer size until framebuffer is requested to avoid flicker
|
|
2230
|
-
* (resizing clears the drawing buffer)!
|
|
2231
|
-
*/
|
|
2232
2705
|
setDrawingBufferSize(width, height) {
|
|
2233
2706
|
width = Math.floor(width);
|
|
2234
2707
|
height = Math.floor(height);
|
|
@@ -2239,19 +2712,10 @@ or create a device with the 'debug: true' prop.`;
|
|
|
2239
2712
|
this.drawingBufferHeight = height;
|
|
2240
2713
|
this._needsDrawingBufferResize = true;
|
|
2241
2714
|
}
|
|
2242
|
-
/**
|
|
2243
|
-
* Returns the current DPR (number of physical pixels per CSS pixel), if props.useDevicePixels is true
|
|
2244
|
-
* @note This can be a fractional (non-integer) number, e.g. when the user zooms in the browser.
|
|
2245
|
-
* @note This function handles the non-HTML canvas cases
|
|
2246
|
-
*/
|
|
2247
2715
|
getDevicePixelRatio() {
|
|
2248
|
-
const
|
|
2249
|
-
return
|
|
2716
|
+
const devicePixelRatio2 = typeof window !== "undefined" && window.devicePixelRatio;
|
|
2717
|
+
return devicePixelRatio2 || 1;
|
|
2250
2718
|
}
|
|
2251
|
-
// DEPRECATED METHODS
|
|
2252
|
-
/**
|
|
2253
|
-
* Maps CSS pixel position to device pixel position
|
|
2254
|
-
*/
|
|
2255
2719
|
cssToDevicePixels(cssPixel, yInvert = true) {
|
|
2256
2720
|
const ratio = this.cssToDeviceRatio();
|
|
2257
2721
|
const [width, height] = this.getDrawingBufferSize();
|
|
@@ -2261,10 +2725,10 @@ or create a device with the 'debug: true' prop.`;
|
|
|
2261
2725
|
getPixelSize() {
|
|
2262
2726
|
return this.getDevicePixelSize();
|
|
2263
2727
|
}
|
|
2264
|
-
/** @deprecated
|
|
2728
|
+
/** @deprecated Use the current drawing buffer size for projection setup. */
|
|
2265
2729
|
getAspect() {
|
|
2266
|
-
const [width, height] = this.
|
|
2267
|
-
return width / height;
|
|
2730
|
+
const [width, height] = this.getDrawingBufferSize();
|
|
2731
|
+
return width > 0 && height > 0 ? width / height : 1;
|
|
2268
2732
|
}
|
|
2269
2733
|
/** @deprecated Returns multiplier need to convert CSS size to Device size */
|
|
2270
2734
|
cssToDeviceRatio() {
|
|
@@ -2280,17 +2744,36 @@ or create a device with the 'debug: true' prop.`;
|
|
|
2280
2744
|
resize(size) {
|
|
2281
2745
|
this.setDrawingBufferSize(size.width, size.height);
|
|
2282
2746
|
}
|
|
2283
|
-
// IMPLEMENTATION
|
|
2284
|
-
/**
|
|
2285
|
-
* Allows subclass constructor to override the canvas id for auto created canvases.
|
|
2286
|
-
* This can really help when debugging DOM in apps that create multiple devices
|
|
2287
|
-
*/
|
|
2288
2747
|
_setAutoCreatedCanvasId(id) {
|
|
2289
2748
|
if (this.htmlCanvas?.id === "lumagl-auto-created-canvas") {
|
|
2290
2749
|
this.htmlCanvas.id = id;
|
|
2291
2750
|
}
|
|
2292
2751
|
}
|
|
2293
|
-
/**
|
|
2752
|
+
/**
|
|
2753
|
+
* Starts DOM observation after the derived context and its device are fully initialized.
|
|
2754
|
+
*
|
|
2755
|
+
* `CanvasSurface` construction runs before subclasses can assign `this.device`, and the
|
|
2756
|
+
* default WebGL canvas context is created before `WebGLDevice` has initialized `limits`,
|
|
2757
|
+
* `features`, and the rest of its runtime state. Deferring observer startup avoids early
|
|
2758
|
+
* `ResizeObserver` and DPR callbacks running against a partially initialized device.
|
|
2759
|
+
*/
|
|
2760
|
+
_startObservers() {
|
|
2761
|
+
if (this.destroyed) {
|
|
2762
|
+
return;
|
|
2763
|
+
}
|
|
2764
|
+
this._canvasObserver.start();
|
|
2765
|
+
}
|
|
2766
|
+
/**
|
|
2767
|
+
* Stops all DOM observation and timers associated with a canvas surface.
|
|
2768
|
+
*
|
|
2769
|
+
* This pairs with `_startObservers()` so teardown uses the same lifecycle whether a context is
|
|
2770
|
+
* explicitly destroyed, abandoned during device reuse, or temporarily has not started observing
|
|
2771
|
+
* yet. Centralizing shutdown here keeps resize/DPR/position watchers from surviving past the
|
|
2772
|
+
* lifetime of the owning device.
|
|
2773
|
+
*/
|
|
2774
|
+
_stopObservers() {
|
|
2775
|
+
this._canvasObserver.stop();
|
|
2776
|
+
}
|
|
2294
2777
|
_handleIntersection(entries) {
|
|
2295
2778
|
if (this.destroyed) {
|
|
2296
2779
|
return;
|
|
@@ -2305,11 +2788,6 @@ or create a device with the 'debug: true' prop.`;
|
|
|
2305
2788
|
this.device.props.onVisibilityChange(this);
|
|
2306
2789
|
}
|
|
2307
2790
|
}
|
|
2308
|
-
/**
|
|
2309
|
-
* Reacts to an observed resize by using the most accurate pixel size information the browser can provide
|
|
2310
|
-
* @see https://web.dev/articles/device-pixel-content-box
|
|
2311
|
-
* @see https://webgpufundamentals.org/webgpu/lessons/webgpu-resizing-the-canvas.html
|
|
2312
|
-
*/
|
|
2313
2791
|
_handleResize(entries) {
|
|
2314
2792
|
if (this.destroyed) {
|
|
2315
2793
|
return;
|
|
@@ -2330,12 +2808,14 @@ or create a device with the 'debug: true' prop.`;
|
|
|
2330
2808
|
this._updateDrawingBufferSize();
|
|
2331
2809
|
this.device.props.onResize(this, { oldPixelSize });
|
|
2332
2810
|
}
|
|
2333
|
-
/** Initiate a deferred update for the canvas drawing buffer size */
|
|
2334
2811
|
_updateDrawingBufferSize() {
|
|
2335
2812
|
if (this.props.autoResize) {
|
|
2336
2813
|
if (typeof this.props.useDevicePixels === "number") {
|
|
2337
|
-
const
|
|
2338
|
-
this.setDrawingBufferSize(
|
|
2814
|
+
const devicePixelRatio2 = this.props.useDevicePixels;
|
|
2815
|
+
this.setDrawingBufferSize(
|
|
2816
|
+
this.cssWidth * devicePixelRatio2,
|
|
2817
|
+
this.cssHeight * devicePixelRatio2
|
|
2818
|
+
);
|
|
2339
2819
|
} else if (this.props.useDevicePixels) {
|
|
2340
2820
|
this.setDrawingBufferSize(this.devicePixelWidth, this.devicePixelHeight);
|
|
2341
2821
|
} else {
|
|
@@ -2346,7 +2826,6 @@ or create a device with the 'debug: true' prop.`;
|
|
|
2346
2826
|
this.isInitialized = true;
|
|
2347
2827
|
this.updatePosition();
|
|
2348
2828
|
}
|
|
2349
|
-
/** Perform a deferred resize of the drawing buffer if needed */
|
|
2350
2829
|
_resizeDrawingBufferIfNeeded() {
|
|
2351
2830
|
if (this._needsDrawingBufferResize) {
|
|
2352
2831
|
this._needsDrawingBufferResize = false;
|
|
@@ -2358,36 +2837,17 @@ or create a device with the 'debug: true' prop.`;
|
|
|
2358
2837
|
}
|
|
2359
2838
|
}
|
|
2360
2839
|
}
|
|
2361
|
-
/** Monitor DPR changes */
|
|
2362
2840
|
_observeDevicePixelRatio() {
|
|
2363
|
-
if (this.destroyed) {
|
|
2841
|
+
if (this.destroyed || !this._canvasObserver.started) {
|
|
2364
2842
|
return;
|
|
2365
2843
|
}
|
|
2366
2844
|
const oldRatio = this.devicePixelRatio;
|
|
2367
2845
|
this.devicePixelRatio = window.devicePixelRatio;
|
|
2368
2846
|
this.updatePosition();
|
|
2369
|
-
this.device.props.onDevicePixelRatioChange?.(this, {
|
|
2370
|
-
|
|
2371
|
-
|
|
2372
|
-
() => this._observeDevicePixelRatio(),
|
|
2373
|
-
{ once: true }
|
|
2374
|
-
);
|
|
2375
|
-
}
|
|
2376
|
-
/** Start tracking positions with a timer */
|
|
2377
|
-
_trackPosition(intervalMs = 100) {
|
|
2378
|
-
const intervalId = setInterval(() => {
|
|
2379
|
-
if (this.destroyed) {
|
|
2380
|
-
clearInterval(intervalId);
|
|
2381
|
-
} else {
|
|
2382
|
-
this.updatePosition();
|
|
2383
|
-
}
|
|
2384
|
-
}, intervalMs);
|
|
2847
|
+
this.device.props.onDevicePixelRatioChange?.(this, {
|
|
2848
|
+
oldRatio
|
|
2849
|
+
});
|
|
2385
2850
|
}
|
|
2386
|
-
/**
|
|
2387
|
-
* Calculated the absolute position of the canvas
|
|
2388
|
-
* @note - getBoundingClientRect() is normally cheap but can be expensive
|
|
2389
|
-
* if called before browser has finished a reflow. Should not be the case here.
|
|
2390
|
-
*/
|
|
2391
2851
|
updatePosition() {
|
|
2392
2852
|
if (this.destroyed) {
|
|
2393
2853
|
return;
|
|
@@ -2400,13 +2860,15 @@ or create a device with the 'debug: true' prop.`;
|
|
|
2400
2860
|
if (positionChanged) {
|
|
2401
2861
|
const oldPosition = this._position;
|
|
2402
2862
|
this._position = position;
|
|
2403
|
-
this.device.props.onPositionChange?.(this, {
|
|
2863
|
+
this.device.props.onPositionChange?.(this, {
|
|
2864
|
+
oldPosition
|
|
2865
|
+
});
|
|
2404
2866
|
}
|
|
2405
2867
|
}
|
|
2406
2868
|
}
|
|
2407
2869
|
};
|
|
2408
|
-
var
|
|
2409
|
-
__publicField(
|
|
2870
|
+
var CanvasSurface = _CanvasSurface;
|
|
2871
|
+
__publicField(CanvasSurface, "defaultProps", {
|
|
2410
2872
|
id: void 0,
|
|
2411
2873
|
canvas: null,
|
|
2412
2874
|
width: 800,
|
|
@@ -2434,7 +2896,7 @@ or create a device with the 'debug: true' prop.`;
|
|
|
2434
2896
|
}
|
|
2435
2897
|
function getCanvasFromDOM(canvasId) {
|
|
2436
2898
|
const canvas = document.getElementById(canvasId);
|
|
2437
|
-
if (!
|
|
2899
|
+
if (!CanvasSurface.isHTMLCanvas(canvas)) {
|
|
2438
2900
|
throw new Error("Object is not a canvas element");
|
|
2439
2901
|
}
|
|
2440
2902
|
return canvas;
|
|
@@ -2458,33 +2920,40 @@ or create a device with the 'debug: true' prop.`;
|
|
|
2458
2920
|
const point = pixel;
|
|
2459
2921
|
const x = scaleX(point[0], ratio, width);
|
|
2460
2922
|
let y = scaleY(point[1], ratio, height, yInvert);
|
|
2461
|
-
let
|
|
2462
|
-
const xHigh =
|
|
2463
|
-
|
|
2923
|
+
let temporary = scaleX(point[0] + 1, ratio, width);
|
|
2924
|
+
const xHigh = temporary === width - 1 ? temporary : temporary - 1;
|
|
2925
|
+
temporary = scaleY(point[1] + 1, ratio, height, yInvert);
|
|
2464
2926
|
let yHigh;
|
|
2465
2927
|
if (yInvert) {
|
|
2466
|
-
|
|
2928
|
+
temporary = temporary === 0 ? temporary : temporary + 1;
|
|
2467
2929
|
yHigh = y;
|
|
2468
|
-
y =
|
|
2930
|
+
y = temporary;
|
|
2469
2931
|
} else {
|
|
2470
|
-
yHigh =
|
|
2932
|
+
yHigh = temporary === height - 1 ? temporary : temporary - 1;
|
|
2471
2933
|
}
|
|
2472
2934
|
return {
|
|
2473
2935
|
x,
|
|
2474
2936
|
y,
|
|
2475
|
-
// when ratio < 1, current css pixel and next css pixel may point to same device pixel, set width/height to 1 in those cases.
|
|
2476
2937
|
width: Math.max(xHigh - x + 1, 1),
|
|
2477
2938
|
height: Math.max(yHigh - y + 1, 1)
|
|
2478
2939
|
};
|
|
2479
2940
|
}
|
|
2480
2941
|
function scaleX(x, ratio, width) {
|
|
2481
|
-
|
|
2482
|
-
return r;
|
|
2942
|
+
return Math.min(Math.round(x * ratio), width - 1);
|
|
2483
2943
|
}
|
|
2484
2944
|
function scaleY(y, ratio, height, yInvert) {
|
|
2485
2945
|
return yInvert ? Math.max(0, height - 1 - Math.round(y * ratio)) : Math.min(Math.round(y * ratio), height - 1);
|
|
2486
2946
|
}
|
|
2487
2947
|
|
|
2948
|
+
// src/adapter/canvas-context.ts
|
|
2949
|
+
var CanvasContext = class extends CanvasSurface {
|
|
2950
|
+
};
|
|
2951
|
+
__publicField(CanvasContext, "defaultProps", CanvasSurface.defaultProps);
|
|
2952
|
+
|
|
2953
|
+
// src/adapter/presentation-context.ts
|
|
2954
|
+
var PresentationContext = class extends CanvasSurface {
|
|
2955
|
+
};
|
|
2956
|
+
|
|
2488
2957
|
// src/adapter/resources/sampler.ts
|
|
2489
2958
|
var _Sampler = class extends Resource {
|
|
2490
2959
|
get [Symbol.toStringTag]() {
|
|
@@ -2539,6 +3008,8 @@ or create a device with the 'debug: true' prop.`;
|
|
|
2539
3008
|
depth;
|
|
2540
3009
|
/** mip levels in this texture */
|
|
2541
3010
|
mipLevels;
|
|
3011
|
+
/** sample count */
|
|
3012
|
+
samples;
|
|
2542
3013
|
/** Rows are multiples of this length, padded with extra bytes if needed */
|
|
2543
3014
|
byteAlignment;
|
|
2544
3015
|
/** The ready promise is always resolved. It is provided for type compatibility with DynamicTexture. */
|
|
@@ -2564,6 +3035,7 @@ or create a device with the 'debug: true' prop.`;
|
|
|
2564
3035
|
this.height = this.props.height;
|
|
2565
3036
|
this.depth = this.props.depth;
|
|
2566
3037
|
this.mipLevels = this.props.mipLevels;
|
|
3038
|
+
this.samples = this.props.samples || 1;
|
|
2567
3039
|
if (this.dimension === "cube") {
|
|
2568
3040
|
this.depth = 6;
|
|
2569
3041
|
}
|
|
@@ -2597,9 +3069,25 @@ or create a device with the 'debug: true' prop.`;
|
|
|
2597
3069
|
setSampler(sampler) {
|
|
2598
3070
|
this.sampler = sampler instanceof Sampler ? sampler : this.device.createSampler(sampler);
|
|
2599
3071
|
}
|
|
3072
|
+
/**
|
|
3073
|
+
* Copy raw image data (bytes) into the texture.
|
|
3074
|
+
*
|
|
3075
|
+
* @note Deprecated compatibility wrapper over {@link writeData}.
|
|
3076
|
+
* @note Uses the same layout defaults and alignment rules as {@link writeData}.
|
|
3077
|
+
* @note Tightly packed CPU uploads can omit `bytesPerRow` and `rowsPerImage`.
|
|
3078
|
+
* @note If the CPU source rows are padded, pass explicit `bytesPerRow` and `rowsPerImage`.
|
|
3079
|
+
* @deprecated Use writeData()
|
|
3080
|
+
*/
|
|
3081
|
+
copyImageData(options) {
|
|
3082
|
+
const { data, depth, ...writeOptions } = options;
|
|
3083
|
+
this.writeData(data, {
|
|
3084
|
+
...writeOptions,
|
|
3085
|
+
depthOrArrayLayers: writeOptions.depthOrArrayLayers ?? depth
|
|
3086
|
+
});
|
|
3087
|
+
}
|
|
2600
3088
|
/**
|
|
2601
3089
|
* Calculates the memory layout of the texture, required when reading and writing data.
|
|
2602
|
-
* @return the
|
|
3090
|
+
* @return the backend-aligned linear layout, in particular bytesPerRow which includes any required padding for buffer copy/read paths
|
|
2603
3091
|
*/
|
|
2604
3092
|
computeMemoryLayout(options_ = {}) {
|
|
2605
3093
|
const options = this._normalizeTextureReadOptions(options_);
|
|
@@ -2618,9 +3106,11 @@ or create a device with the 'debug: true' prop.`;
|
|
|
2618
3106
|
* @returns A Buffer containing the texture data.
|
|
2619
3107
|
*
|
|
2620
3108
|
* @note The memory layout of the texture data is determined by the texture format and dimensions.
|
|
2621
|
-
* @note The application can call Texture.computeMemoryLayout() to compute the layout.
|
|
3109
|
+
* @note The application can call Texture.computeMemoryLayout() to compute the backend-aligned layout.
|
|
2622
3110
|
* @note The application can call Buffer.readAsync()
|
|
2623
3111
|
* @note If not supplied a buffer will be created and the application needs to call Buffer.destroy
|
|
3112
|
+
* @note On WebGPU this corresponds to a texture-to-buffer copy and uses buffer-copy alignment rules.
|
|
3113
|
+
* @note On WebGL, luma.gl emulates the same logical readback behavior.
|
|
2624
3114
|
*/
|
|
2625
3115
|
readBuffer(options, buffer) {
|
|
2626
3116
|
throw new Error("readBuffer not implemented");
|
|
@@ -2636,10 +3126,14 @@ or create a device with the 'debug: true' prop.`;
|
|
|
2636
3126
|
throw new Error("readBuffer not implemented");
|
|
2637
3127
|
}
|
|
2638
3128
|
/**
|
|
2639
|
-
* Writes
|
|
3129
|
+
* Writes a GPU Buffer into a texture.
|
|
2640
3130
|
*
|
|
3131
|
+
* @param buffer - Source GPU buffer.
|
|
3132
|
+
* @param options - Destination subresource, extent, and source layout options.
|
|
2641
3133
|
* @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.
|
|
3134
|
+
* @note The application can call Texture.computeMemoryLayout() to compute the backend-aligned layout.
|
|
3135
|
+
* @note On WebGPU this corresponds to a buffer-to-texture copy and uses buffer-copy alignment rules.
|
|
3136
|
+
* @note On WebGL, luma.gl emulates the same destination and layout semantics.
|
|
2643
3137
|
*/
|
|
2644
3138
|
writeBuffer(buffer, options) {
|
|
2645
3139
|
throw new Error("readBuffer not implemented");
|
|
@@ -2647,8 +3141,11 @@ or create a device with the 'debug: true' prop.`;
|
|
|
2647
3141
|
/**
|
|
2648
3142
|
* Writes an array buffer into a texture.
|
|
2649
3143
|
*
|
|
2650
|
-
* @
|
|
2651
|
-
* @
|
|
3144
|
+
* @param data - Source texel data.
|
|
3145
|
+
* @param options - Destination subresource, extent, and source layout options.
|
|
3146
|
+
* @note If `bytesPerRow` and `rowsPerImage` are omitted, luma.gl computes a tightly packed CPU-memory layout for the requested region.
|
|
3147
|
+
* @note On WebGPU this corresponds to `GPUQueue.writeTexture()` and does not implicitly pad rows to 256 bytes.
|
|
3148
|
+
* @note On WebGL, padded CPU data is supported via the same `bytesPerRow` and `rowsPerImage` options.
|
|
2652
3149
|
*/
|
|
2653
3150
|
writeData(data, options) {
|
|
2654
3151
|
throw new Error("readBuffer not implemented");
|
|
@@ -2711,37 +3208,166 @@ or create a device with the 'debug: true' prop.`;
|
|
|
2711
3208
|
}
|
|
2712
3209
|
}
|
|
2713
3210
|
_normalizeCopyImageDataOptions(options_) {
|
|
2714
|
-
const {
|
|
2715
|
-
const options = {
|
|
2716
|
-
|
|
2717
|
-
|
|
2718
|
-
|
|
2719
|
-
}
|
|
2720
|
-
options.bytesPerRow = options_.bytesPerRow || width * (info.bytesPerPixel || 4);
|
|
2721
|
-
options.rowsPerImage = options_.rowsPerImage || height;
|
|
2722
|
-
return options;
|
|
3211
|
+
const { data, depth, ...writeOptions } = options_;
|
|
3212
|
+
const options = this._normalizeTextureWriteOptions({
|
|
3213
|
+
...writeOptions,
|
|
3214
|
+
depthOrArrayLayers: writeOptions.depthOrArrayLayers ?? depth
|
|
3215
|
+
});
|
|
3216
|
+
return { data, depth: options.depthOrArrayLayers, ...options };
|
|
2723
3217
|
}
|
|
2724
3218
|
_normalizeCopyExternalImageOptions(options_) {
|
|
3219
|
+
const optionsWithoutUndefined = _Texture._omitUndefined(options_);
|
|
3220
|
+
const mipLevel = optionsWithoutUndefined.mipLevel ?? 0;
|
|
3221
|
+
const mipLevelSize = this._getMipLevelSize(mipLevel);
|
|
2725
3222
|
const size = this.device.getExternalImageSize(options_.image);
|
|
2726
|
-
const options = {
|
|
2727
|
-
|
|
2728
|
-
|
|
3223
|
+
const options = {
|
|
3224
|
+
..._Texture.defaultCopyExternalImageOptions,
|
|
3225
|
+
...mipLevelSize,
|
|
3226
|
+
...size,
|
|
3227
|
+
...optionsWithoutUndefined
|
|
3228
|
+
};
|
|
3229
|
+
options.width = Math.min(options.width, mipLevelSize.width - options.x);
|
|
3230
|
+
options.height = Math.min(options.height, mipLevelSize.height - options.y);
|
|
3231
|
+
options.depth = Math.min(options.depth, mipLevelSize.depthOrArrayLayers - options.z);
|
|
2729
3232
|
return options;
|
|
2730
3233
|
}
|
|
2731
3234
|
_normalizeTextureReadOptions(options_) {
|
|
2732
|
-
const
|
|
2733
|
-
const
|
|
2734
|
-
|
|
2735
|
-
options
|
|
3235
|
+
const optionsWithoutUndefined = _Texture._omitUndefined(options_);
|
|
3236
|
+
const mipLevel = optionsWithoutUndefined.mipLevel ?? 0;
|
|
3237
|
+
const mipLevelSize = this._getMipLevelSize(mipLevel);
|
|
3238
|
+
const options = {
|
|
3239
|
+
..._Texture.defaultTextureReadOptions,
|
|
3240
|
+
...mipLevelSize,
|
|
3241
|
+
...optionsWithoutUndefined
|
|
3242
|
+
};
|
|
3243
|
+
options.width = Math.min(options.width, mipLevelSize.width - options.x);
|
|
3244
|
+
options.height = Math.min(options.height, mipLevelSize.height - options.y);
|
|
3245
|
+
options.depthOrArrayLayers = Math.min(
|
|
3246
|
+
options.depthOrArrayLayers,
|
|
3247
|
+
mipLevelSize.depthOrArrayLayers - options.z
|
|
3248
|
+
);
|
|
2736
3249
|
return options;
|
|
2737
3250
|
}
|
|
3251
|
+
/**
|
|
3252
|
+
* Normalizes a texture read request and validates the color-only readback contract used by the
|
|
3253
|
+
* current texture read APIs. Supported dimensions are `2d`, `cube`, `cube-array`,
|
|
3254
|
+
* `2d-array`, and `3d`.
|
|
3255
|
+
*
|
|
3256
|
+
* @throws if the texture format, aspect, or dimension is not supported by the first-pass
|
|
3257
|
+
* color-read implementation.
|
|
3258
|
+
*/
|
|
3259
|
+
_getSupportedColorReadOptions(options_) {
|
|
3260
|
+
const options = this._normalizeTextureReadOptions(options_);
|
|
3261
|
+
const formatInfo = textureFormatDecoder.getInfo(this.format);
|
|
3262
|
+
this._validateColorReadAspect(options);
|
|
3263
|
+
this._validateColorReadFormat(formatInfo);
|
|
3264
|
+
switch (this.dimension) {
|
|
3265
|
+
case "2d":
|
|
3266
|
+
case "cube":
|
|
3267
|
+
case "cube-array":
|
|
3268
|
+
case "2d-array":
|
|
3269
|
+
case "3d":
|
|
3270
|
+
return options;
|
|
3271
|
+
default:
|
|
3272
|
+
throw new Error(`${this} color readback does not support ${this.dimension} textures`);
|
|
3273
|
+
}
|
|
3274
|
+
}
|
|
3275
|
+
/** Validates that a read request targets the full color aspect of the texture. */
|
|
3276
|
+
_validateColorReadAspect(options) {
|
|
3277
|
+
if (options.aspect !== "all") {
|
|
3278
|
+
throw new Error(`${this} color readback only supports aspect 'all'`);
|
|
3279
|
+
}
|
|
3280
|
+
}
|
|
3281
|
+
/** Validates that a read request targets an uncompressed color-renderable texture format. */
|
|
3282
|
+
_validateColorReadFormat(formatInfo) {
|
|
3283
|
+
if (formatInfo.compressed) {
|
|
3284
|
+
throw new Error(
|
|
3285
|
+
`${this} color readback does not support compressed formats (${this.format})`
|
|
3286
|
+
);
|
|
3287
|
+
}
|
|
3288
|
+
switch (formatInfo.attachment) {
|
|
3289
|
+
case "color":
|
|
3290
|
+
return;
|
|
3291
|
+
case "depth":
|
|
3292
|
+
throw new Error(`${this} color readback does not support depth formats (${this.format})`);
|
|
3293
|
+
case "stencil":
|
|
3294
|
+
throw new Error(`${this} color readback does not support stencil formats (${this.format})`);
|
|
3295
|
+
case "depth-stencil":
|
|
3296
|
+
throw new Error(
|
|
3297
|
+
`${this} color readback does not support depth-stencil formats (${this.format})`
|
|
3298
|
+
);
|
|
3299
|
+
default:
|
|
3300
|
+
throw new Error(`${this} color readback does not support format ${this.format}`);
|
|
3301
|
+
}
|
|
3302
|
+
}
|
|
2738
3303
|
_normalizeTextureWriteOptions(options_) {
|
|
2739
|
-
const
|
|
2740
|
-
const
|
|
2741
|
-
|
|
2742
|
-
options
|
|
3304
|
+
const optionsWithoutUndefined = _Texture._omitUndefined(options_);
|
|
3305
|
+
const mipLevel = optionsWithoutUndefined.mipLevel ?? 0;
|
|
3306
|
+
const mipLevelSize = this._getMipLevelSize(mipLevel);
|
|
3307
|
+
const options = {
|
|
3308
|
+
..._Texture.defaultTextureWriteOptions,
|
|
3309
|
+
...mipLevelSize,
|
|
3310
|
+
...optionsWithoutUndefined
|
|
3311
|
+
};
|
|
3312
|
+
options.width = Math.min(options.width, mipLevelSize.width - options.x);
|
|
3313
|
+
options.height = Math.min(options.height, mipLevelSize.height - options.y);
|
|
3314
|
+
options.depthOrArrayLayers = Math.min(
|
|
3315
|
+
options.depthOrArrayLayers,
|
|
3316
|
+
mipLevelSize.depthOrArrayLayers - options.z
|
|
3317
|
+
);
|
|
3318
|
+
const layout = textureFormatDecoder.computeMemoryLayout({
|
|
3319
|
+
format: this.format,
|
|
3320
|
+
width: options.width,
|
|
3321
|
+
height: options.height,
|
|
3322
|
+
depth: options.depthOrArrayLayers,
|
|
3323
|
+
byteAlignment: this.byteAlignment
|
|
3324
|
+
});
|
|
3325
|
+
const minimumBytesPerRow = layout.bytesPerPixel * options.width;
|
|
3326
|
+
options.bytesPerRow = optionsWithoutUndefined.bytesPerRow ?? layout.bytesPerRow;
|
|
3327
|
+
options.rowsPerImage = optionsWithoutUndefined.rowsPerImage ?? options.height;
|
|
3328
|
+
if (options.bytesPerRow < minimumBytesPerRow) {
|
|
3329
|
+
throw new Error(
|
|
3330
|
+
`bytesPerRow (${options.bytesPerRow}) must be at least ${minimumBytesPerRow} for ${this.format}`
|
|
3331
|
+
);
|
|
3332
|
+
}
|
|
3333
|
+
if (options.rowsPerImage < options.height) {
|
|
3334
|
+
throw new Error(
|
|
3335
|
+
`rowsPerImage (${options.rowsPerImage}) must be at least ${options.height} for ${this.format}`
|
|
3336
|
+
);
|
|
3337
|
+
}
|
|
3338
|
+
const bytesPerPixel = this.device.getTextureFormatInfo(this.format).bytesPerPixel;
|
|
3339
|
+
if (bytesPerPixel && options.bytesPerRow % bytesPerPixel !== 0) {
|
|
3340
|
+
throw new Error(
|
|
3341
|
+
`bytesPerRow (${options.bytesPerRow}) must be a multiple of bytesPerPixel (${bytesPerPixel}) for ${this.format}`
|
|
3342
|
+
);
|
|
3343
|
+
}
|
|
2743
3344
|
return options;
|
|
2744
3345
|
}
|
|
3346
|
+
_getMipLevelSize(mipLevel) {
|
|
3347
|
+
const width = Math.max(1, this.width >> mipLevel);
|
|
3348
|
+
const height = this.baseDimension === "1d" ? 1 : Math.max(1, this.height >> mipLevel);
|
|
3349
|
+
const depthOrArrayLayers = this.dimension === "3d" ? Math.max(1, this.depth >> mipLevel) : this.depth;
|
|
3350
|
+
return { width, height, depthOrArrayLayers };
|
|
3351
|
+
}
|
|
3352
|
+
getAllocatedByteLength() {
|
|
3353
|
+
let allocatedByteLength = 0;
|
|
3354
|
+
for (let mipLevel = 0; mipLevel < this.mipLevels; mipLevel++) {
|
|
3355
|
+
const { width, height, depthOrArrayLayers } = this._getMipLevelSize(mipLevel);
|
|
3356
|
+
allocatedByteLength += textureFormatDecoder.computeMemoryLayout({
|
|
3357
|
+
format: this.format,
|
|
3358
|
+
width,
|
|
3359
|
+
height,
|
|
3360
|
+
depth: depthOrArrayLayers,
|
|
3361
|
+
byteAlignment: 1
|
|
3362
|
+
}).byteLength;
|
|
3363
|
+
}
|
|
3364
|
+
return allocatedByteLength * this.samples;
|
|
3365
|
+
}
|
|
3366
|
+
static _omitUndefined(options) {
|
|
3367
|
+
return Object.fromEntries(
|
|
3368
|
+
Object.entries(options).filter(([, value]) => value !== void 0)
|
|
3369
|
+
);
|
|
3370
|
+
}
|
|
2745
3371
|
};
|
|
2746
3372
|
var Texture = _Texture;
|
|
2747
3373
|
/** The texture can be bound for use as a sampled texture in a shader */
|
|
@@ -2777,6 +3403,10 @@ or create a device with the 'debug: true' prop.`;
|
|
|
2777
3403
|
byteOffset: 0,
|
|
2778
3404
|
bytesPerRow: void 0,
|
|
2779
3405
|
rowsPerImage: void 0,
|
|
3406
|
+
width: void 0,
|
|
3407
|
+
height: void 0,
|
|
3408
|
+
depthOrArrayLayers: void 0,
|
|
3409
|
+
depth: 1,
|
|
2780
3410
|
mipLevel: 0,
|
|
2781
3411
|
x: 0,
|
|
2782
3412
|
y: 0,
|
|
@@ -2810,6 +3440,19 @@ or create a device with the 'debug: true' prop.`;
|
|
|
2810
3440
|
mipLevel: 0,
|
|
2811
3441
|
aspect: "all"
|
|
2812
3442
|
});
|
|
3443
|
+
__publicField(Texture, "defaultTextureWriteOptions", {
|
|
3444
|
+
byteOffset: 0,
|
|
3445
|
+
bytesPerRow: void 0,
|
|
3446
|
+
rowsPerImage: void 0,
|
|
3447
|
+
x: 0,
|
|
3448
|
+
y: 0,
|
|
3449
|
+
z: 0,
|
|
3450
|
+
width: void 0,
|
|
3451
|
+
height: void 0,
|
|
3452
|
+
depthOrArrayLayers: 1,
|
|
3453
|
+
mipLevel: 0,
|
|
3454
|
+
aspect: "all"
|
|
3455
|
+
});
|
|
2813
3456
|
|
|
2814
3457
|
// src/adapter/resources/texture-view.ts
|
|
2815
3458
|
var _TextureView = class extends Resource {
|
|
@@ -3188,10 +3831,21 @@ ${numberedLines}${positionIndicator}${message.type.toUpperCase()}: ${message.mes
|
|
|
3188
3831
|
linkStatus = "pending";
|
|
3189
3832
|
/** The hash of the pipeline */
|
|
3190
3833
|
hash = "";
|
|
3834
|
+
/** Optional shared backend implementation */
|
|
3835
|
+
sharedRenderPipeline = null;
|
|
3836
|
+
/** Whether shader or pipeline compilation/linking is still in progress */
|
|
3837
|
+
get isPending() {
|
|
3838
|
+
return this.linkStatus === "pending" || this.vs.compilationStatus === "pending" || this.fs?.compilationStatus === "pending";
|
|
3839
|
+
}
|
|
3840
|
+
/** Whether shader or pipeline compilation/linking has failed */
|
|
3841
|
+
get isErrored() {
|
|
3842
|
+
return this.linkStatus === "error" || this.vs.compilationStatus === "error" || this.fs?.compilationStatus === "error";
|
|
3843
|
+
}
|
|
3191
3844
|
constructor(device, props) {
|
|
3192
3845
|
super(device, props, _RenderPipeline.defaultProps);
|
|
3193
3846
|
this.shaderLayout = this.props.shaderLayout;
|
|
3194
3847
|
this.bufferLayout = this.props.bufferLayout || [];
|
|
3848
|
+
this.sharedRenderPipeline = this.props._sharedRenderPipeline || null;
|
|
3195
3849
|
}
|
|
3196
3850
|
};
|
|
3197
3851
|
var RenderPipeline = _RenderPipeline;
|
|
@@ -3209,10 +3863,30 @@ ${numberedLines}${positionIndicator}${message.type.toUpperCase()}: ${message.mes
|
|
|
3209
3863
|
colorAttachmentFormats: void 0,
|
|
3210
3864
|
depthStencilAttachmentFormat: void 0,
|
|
3211
3865
|
parameters: {},
|
|
3212
|
-
|
|
3213
|
-
|
|
3866
|
+
varyings: void 0,
|
|
3867
|
+
bufferMode: void 0,
|
|
3868
|
+
disableWarnings: false,
|
|
3869
|
+
_sharedRenderPipeline: void 0,
|
|
3870
|
+
bindings: void 0
|
|
3214
3871
|
});
|
|
3215
3872
|
|
|
3873
|
+
// src/adapter/resources/shared-render-pipeline.ts
|
|
3874
|
+
var SharedRenderPipeline = class extends Resource {
|
|
3875
|
+
get [Symbol.toStringTag]() {
|
|
3876
|
+
return "SharedRenderPipeline";
|
|
3877
|
+
}
|
|
3878
|
+
constructor(device, props) {
|
|
3879
|
+
super(device, props, {
|
|
3880
|
+
...Resource.defaultProps,
|
|
3881
|
+
handle: void 0,
|
|
3882
|
+
vs: void 0,
|
|
3883
|
+
fs: void 0,
|
|
3884
|
+
varyings: void 0,
|
|
3885
|
+
bufferMode: void 0
|
|
3886
|
+
});
|
|
3887
|
+
}
|
|
3888
|
+
};
|
|
3889
|
+
|
|
3216
3890
|
// src/adapter/resources/render-pass.ts
|
|
3217
3891
|
var _RenderPass = class extends Resource {
|
|
3218
3892
|
get [Symbol.toStringTag]() {
|
|
@@ -3295,8 +3969,69 @@ ${numberedLines}${positionIndicator}${message.type.toUpperCase()}: ${message.mes
|
|
|
3295
3969
|
get [Symbol.toStringTag]() {
|
|
3296
3970
|
return "CommandEncoder";
|
|
3297
3971
|
}
|
|
3972
|
+
_timeProfilingQuerySet = null;
|
|
3973
|
+
_timeProfilingSlotCount = 0;
|
|
3974
|
+
_gpuTimeMs;
|
|
3298
3975
|
constructor(device, props) {
|
|
3299
3976
|
super(device, props, _CommandEncoder.defaultProps);
|
|
3977
|
+
this._timeProfilingQuerySet = props.timeProfilingQuerySet ?? null;
|
|
3978
|
+
this._timeProfilingSlotCount = 0;
|
|
3979
|
+
this._gpuTimeMs = void 0;
|
|
3980
|
+
}
|
|
3981
|
+
/**
|
|
3982
|
+
* Reads all resolved timestamp pairs on the current profiler query set and caches the sum
|
|
3983
|
+
* as milliseconds on this encoder.
|
|
3984
|
+
*/
|
|
3985
|
+
async resolveTimeProfilingQuerySet() {
|
|
3986
|
+
this._gpuTimeMs = void 0;
|
|
3987
|
+
if (!this._timeProfilingQuerySet) {
|
|
3988
|
+
return;
|
|
3989
|
+
}
|
|
3990
|
+
const pairCount = Math.floor(this._timeProfilingSlotCount / 2);
|
|
3991
|
+
if (pairCount <= 0) {
|
|
3992
|
+
return;
|
|
3993
|
+
}
|
|
3994
|
+
const queryCount = pairCount * 2;
|
|
3995
|
+
const results = await this._timeProfilingQuerySet.readResults({
|
|
3996
|
+
firstQuery: 0,
|
|
3997
|
+
queryCount
|
|
3998
|
+
});
|
|
3999
|
+
let totalDurationNanoseconds = 0n;
|
|
4000
|
+
for (let queryIndex = 0; queryIndex < queryCount; queryIndex += 2) {
|
|
4001
|
+
totalDurationNanoseconds += results[queryIndex + 1] - results[queryIndex];
|
|
4002
|
+
}
|
|
4003
|
+
this._gpuTimeMs = Number(totalDurationNanoseconds) / 1e6;
|
|
4004
|
+
}
|
|
4005
|
+
/** Returns the number of query slots consumed by automatic pass profiling on this encoder. */
|
|
4006
|
+
getTimeProfilingSlotCount() {
|
|
4007
|
+
return this._timeProfilingSlotCount;
|
|
4008
|
+
}
|
|
4009
|
+
getTimeProfilingQuerySet() {
|
|
4010
|
+
return this._timeProfilingQuerySet;
|
|
4011
|
+
}
|
|
4012
|
+
/** Internal helper for auto-assigning timestamp slots to render/compute passes on this encoder. */
|
|
4013
|
+
_applyTimeProfilingToPassProps(props) {
|
|
4014
|
+
const passProps = props || {};
|
|
4015
|
+
if (!this._supportsTimestampQueries() || !this._timeProfilingQuerySet) {
|
|
4016
|
+
return passProps;
|
|
4017
|
+
}
|
|
4018
|
+
if (passProps.timestampQuerySet !== void 0 || passProps.beginTimestampIndex !== void 0 || passProps.endTimestampIndex !== void 0) {
|
|
4019
|
+
return passProps;
|
|
4020
|
+
}
|
|
4021
|
+
const beginTimestampIndex = this._timeProfilingSlotCount;
|
|
4022
|
+
if (beginTimestampIndex + 1 >= this._timeProfilingQuerySet.props.count) {
|
|
4023
|
+
return passProps;
|
|
4024
|
+
}
|
|
4025
|
+
this._timeProfilingSlotCount += 2;
|
|
4026
|
+
return {
|
|
4027
|
+
...passProps,
|
|
4028
|
+
timestampQuerySet: this._timeProfilingQuerySet,
|
|
4029
|
+
beginTimestampIndex,
|
|
4030
|
+
endTimestampIndex: beginTimestampIndex + 1
|
|
4031
|
+
};
|
|
4032
|
+
}
|
|
4033
|
+
_supportsTimestampQueries() {
|
|
4034
|
+
return this.device.features.has("timestamp-query");
|
|
3300
4035
|
}
|
|
3301
4036
|
};
|
|
3302
4037
|
var CommandEncoder = _CommandEncoder;
|
|
@@ -3305,7 +4040,8 @@ ${numberedLines}${positionIndicator}${message.type.toUpperCase()}: ${message.mes
|
|
|
3305
4040
|
// beginComputePass(optional GPUComputePassDescriptor descriptor = {}): GPUComputePassEncoder;
|
|
3306
4041
|
__publicField(CommandEncoder, "defaultProps", {
|
|
3307
4042
|
...Resource.defaultProps,
|
|
3308
|
-
measureExecutionTime: void 0
|
|
4043
|
+
measureExecutionTime: void 0,
|
|
4044
|
+
timeProfilingQuerySet: void 0
|
|
3309
4045
|
});
|
|
3310
4046
|
|
|
3311
4047
|
// src/adapter/resources/command-buffer.ts
|
|
@@ -3324,11 +4060,20 @@ ${numberedLines}${positionIndicator}${message.type.toUpperCase()}: ${message.mes
|
|
|
3324
4060
|
|
|
3325
4061
|
// src/shadertypes/data-types/decode-shader-types.ts
|
|
3326
4062
|
function getVariableShaderTypeInfo(format) {
|
|
3327
|
-
const
|
|
4063
|
+
const resolvedFormat = resolveVariableShaderTypeAlias(format);
|
|
4064
|
+
const decoded = UNIFORM_FORMATS[resolvedFormat];
|
|
4065
|
+
if (!decoded) {
|
|
4066
|
+
throw new Error(`Unsupported variable shader type: ${format}`);
|
|
4067
|
+
}
|
|
3328
4068
|
return decoded;
|
|
3329
4069
|
}
|
|
3330
4070
|
function getAttributeShaderTypeInfo(attributeType) {
|
|
3331
|
-
const
|
|
4071
|
+
const resolvedAttributeType = resolveAttributeShaderTypeAlias(attributeType);
|
|
4072
|
+
const decoded = TYPE_INFO[resolvedAttributeType];
|
|
4073
|
+
if (!decoded) {
|
|
4074
|
+
throw new Error(`Unsupported attribute shader type: ${attributeType}`);
|
|
4075
|
+
}
|
|
4076
|
+
const [primitiveType, components] = decoded;
|
|
3332
4077
|
const integer = primitiveType === "i32" || primitiveType === "u32";
|
|
3333
4078
|
const signed = primitiveType !== "u32";
|
|
3334
4079
|
const byteLength = PRIMITIVE_TYPE_SIZES[primitiveType] * components;
|
|
@@ -3340,6 +4085,12 @@ ${numberedLines}${positionIndicator}${message.type.toUpperCase()}: ${message.mes
|
|
|
3340
4085
|
signed
|
|
3341
4086
|
};
|
|
3342
4087
|
}
|
|
4088
|
+
function resolveAttributeShaderTypeAlias(alias) {
|
|
4089
|
+
return WGSL_ATTRIBUTE_TYPE_ALIAS_MAP[alias] || alias;
|
|
4090
|
+
}
|
|
4091
|
+
function resolveVariableShaderTypeAlias(alias) {
|
|
4092
|
+
return WGSL_VARIABLE_TYPE_ALIAS_MAP[alias] || alias;
|
|
4093
|
+
}
|
|
3343
4094
|
var PRIMITIVE_TYPE_SIZES = {
|
|
3344
4095
|
f32: 4,
|
|
3345
4096
|
f16: 2,
|
|
@@ -3664,7 +4415,9 @@ ${numberedLines}${positionIndicator}${message.type.toUpperCase()}: ${message.mes
|
|
|
3664
4415
|
|
|
3665
4416
|
// src/adapter/resources/fence.ts
|
|
3666
4417
|
var _Fence = class extends Resource {
|
|
3667
|
-
[Symbol.toStringTag]
|
|
4418
|
+
get [Symbol.toStringTag]() {
|
|
4419
|
+
return "Fence";
|
|
4420
|
+
}
|
|
3668
4421
|
constructor(device, props = {}) {
|
|
3669
4422
|
super(device, props, _Fence.defaultProps);
|
|
3670
4423
|
}
|
|
@@ -3824,20 +4577,26 @@ ${numberedLines}${positionIndicator}${message.type.toUpperCase()}: ${message.mes
|
|
|
3824
4577
|
}
|
|
3825
4578
|
|
|
3826
4579
|
// src/utils/array-equal.ts
|
|
4580
|
+
var MAX_ELEMENTWISE_ARRAY_COMPARE_LENGTH = 128;
|
|
3827
4581
|
function arrayEqual(a, b, limit = 16) {
|
|
3828
|
-
if (a
|
|
3829
|
-
return
|
|
4582
|
+
if (a === b) {
|
|
4583
|
+
return true;
|
|
3830
4584
|
}
|
|
3831
4585
|
const arrayA = a;
|
|
3832
4586
|
const arrayB = b;
|
|
3833
|
-
if (!isNumberArray(arrayA)) {
|
|
4587
|
+
if (!isNumberArray(arrayA) || !isNumberArray(arrayB)) {
|
|
3834
4588
|
return false;
|
|
3835
4589
|
}
|
|
3836
|
-
if (
|
|
3837
|
-
|
|
3838
|
-
|
|
3839
|
-
|
|
3840
|
-
|
|
4590
|
+
if (arrayA.length !== arrayB.length) {
|
|
4591
|
+
return false;
|
|
4592
|
+
}
|
|
4593
|
+
const maxCompareLength = Math.min(limit, MAX_ELEMENTWISE_ARRAY_COMPARE_LENGTH);
|
|
4594
|
+
if (arrayA.length > maxCompareLength) {
|
|
4595
|
+
return false;
|
|
4596
|
+
}
|
|
4597
|
+
for (let i = 0; i < arrayA.length; ++i) {
|
|
4598
|
+
if (arrayB[i] !== arrayA[i]) {
|
|
4599
|
+
return false;
|
|
3841
4600
|
}
|
|
3842
4601
|
}
|
|
3843
4602
|
return true;
|