@woosh/meep-engine 2.73.0 → 2.75.0

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.
Files changed (48) hide show
  1. package/build/bundle-worker-image-decoder.js +1 -1
  2. package/build/meep.cjs +185 -189
  3. package/build/meep.min.js +1 -1
  4. package/build/meep.module.js +185 -189
  5. package/package.json +1 -1
  6. package/src/core/binary/UINT32_MAX.js +5 -0
  7. package/src/core/bvh2/bvh3/BVH.js +44 -2
  8. package/src/core/bvh2/bvh3/BVH.spec.js +45 -0
  9. package/src/core/bvh2/bvh3/build_triangle_morton_codes.js +73 -0
  10. package/src/core/bvh2/bvh3/ebvh_build_for_geometry_morton.js +5 -101
  11. package/src/core/bvh2/bvh3/ebvh_build_hierarchy.js +59 -0
  12. package/src/core/bvh2/bvh3/query/bvh_query_user_data_nearest_to_point.js +31 -32
  13. package/src/core/bvh2/bvh3/query/bvh_query_user_data_nearest_to_point.spec.js +64 -0
  14. package/src/core/collection/SCRATCH_UINT32_TRAVERSAL_STACK.js +1 -0
  15. package/src/core/geom/3d/aabb/aabb3_signed_distance_sqr_to_point.js +1 -0
  16. package/src/core/geom/3d/aabb/aabb3_unsigned_distance_sqr_to_point.js +36 -0
  17. package/src/core/process/worker/OnDemandWorkerManager.js +5 -1
  18. package/src/engine/asset/loaders/ArrayBufferLoader.js +13 -15
  19. package/src/engine/asset/loaders/image/ImageDecoderWorker.js +1 -1
  20. package/src/engine/asset/loaders/image/ImageRGBADataLoader.js +5 -7
  21. package/src/engine/asset/loaders/image/codec/NativeImageDecoder.js +2 -1
  22. package/src/engine/asset/loaders/image/codec/ThreadedImageDecoder.js +5 -6
  23. package/src/engine/asset/loaders/image/png/PNG.js +339 -332
  24. package/src/engine/asset/loaders/image/png/PNGReader.js +77 -30
  25. package/src/engine/asset/loaders/image/png/prototypePNG.js +13 -4
  26. package/src/engine/graphics/generate_halton_jitter.js +21 -0
  27. package/src/engine/graphics/render/buffer/simple-fx/taa/TemporalSupersamplingRenderPlugin.js +3 -20
  28. package/src/engine/graphics/texture/virtual/v2/PageTexture.js +335 -0
  29. package/src/engine/graphics/texture/virtual/v2/ResidentTileTexture.js +46 -0
  30. package/src/engine/graphics/texture/virtual/v2/{TileLoader.js → VirtualTextureTileLoader.js} +33 -13
  31. package/src/engine/graphics/texture/virtual/v2/{UsageMetadata.js → VirtualTextureUsage.js} +68 -22
  32. package/src/engine/graphics/texture/virtual/v2/{VirtualTextureManager.js → VirtualTextureUsageUpdater.js} +66 -9
  33. package/src/engine/graphics/texture/virtual/v2/debug/ResidencyDebugView.js +70 -0
  34. package/src/engine/graphics/texture/virtual/v2/debug/UsageDebugView.js +63 -0
  35. package/src/engine/graphics/texture/virtual/v2/{UsagePyramidDebugView.js → debug/UsagePyramidDebugView.js} +31 -40
  36. package/src/engine/graphics/texture/virtual/v2/prototype.js +98 -54
  37. package/src/engine/graphics/texture/virtual/v2/{TextureTile.js → tile/VirtualTextureTile.js} +3 -3
  38. package/src/engine/graphics/texture/virtual/v2/tile/compose_finger_print.js +23 -0
  39. package/src/engine/graphics/texture/virtual/v2/tile/compose_tile_address.js +26 -0
  40. package/src/engine/graphics/texture/virtual/v2/tile/decompose_finger_print.js +12 -0
  41. package/src/engine/graphics/texture/virtual/v2/tile/finger_print_to_tile_address.js +16 -0
  42. package/src/engine/graphics/texture/virtual/v2/{tile_index_to_finger_print.js → tile/tile_address_to_finger_print.js} +7 -3
  43. package/src/view/CSS_ABSOLUTE_POSITIONING.js +5 -0
  44. package/src/engine/graphics/texture/virtual/v2/SparseTexture.js +0 -182
  45. package/src/engine/graphics/texture/virtual/v2/UsageDebugView.js +0 -64
  46. package/src/engine/graphics/texture/virtual/v2/compose_finger_print.js +0 -13
  47. package/src/engine/graphics/texture/virtual/v2/finger_print_to_tile_index.js +0 -37
  48. /package/src/engine/graphics/texture/virtual/v2/{ShaderUsage.js → VirtualTextureUsageShader.js} +0 -0
@@ -3,24 +3,37 @@ import { arrayQuickSort } from "../../../../../core/collection/array/arrayQuickS
3
3
  import Signal from "../../../../../core/events/signal/Signal.js";
4
4
  import { AssetManager } from "../../../../asset/AssetManager.js";
5
5
  import { GameAssetType } from "../../../../asset/GameAssetType.js";
6
- import { compose_finger_print } from "./compose_finger_print.js";
7
- import { decompose_finger_print } from "./finger_print_to_tile_index.js";
8
- import { TextureTile } from "./TextureTile.js";
9
-
10
- export class TileLoader {
6
+ import { compose_finger_print } from "./tile/compose_finger_print.js";
7
+ import { decompose_finger_print } from "./tile/decompose_finger_print.js";
8
+ import { VirtualTextureTile } from "./tile/VirtualTextureTile.js";
9
+
10
+ /**
11
+ * Facilitates prioritized queueing and loading of individual texture tiles
12
+ */
13
+ export class VirtualTextureTileLoader {
11
14
  /**
12
15
  * Where the tiles are stored
13
16
  * @type {string}
14
17
  */
15
18
  #root_path = "";
16
19
 
20
+ set path(v) {
21
+ this.#root_path = v;
22
+ }
23
+
24
+ /**
25
+ * When queue gets larger than this, we start discarding elements
26
+ * @type {number}
27
+ */
28
+ queue_limit = Infinity;
29
+
17
30
  /**
18
31
  *
19
32
  * @type {AssetManager}
20
33
  */
21
34
  #asset_manager = null;
22
35
 
23
- set asset_manager(v){
36
+ set asset_manager(v) {
24
37
  this.#asset_manager = v;
25
38
  }
26
39
 
@@ -49,7 +62,7 @@ export class TileLoader {
49
62
  */
50
63
  on = {
51
64
  /**
52
- * @type {Signal<TextureTile>}
65
+ * @type {Signal<VirtualTextureTile>}
53
66
  */
54
67
  loaded: new Signal()
55
68
  };
@@ -95,7 +108,6 @@ export class TileLoader {
95
108
  return false;
96
109
  }
97
110
 
98
- // TODO limit queue size, if the queue grows too large we may end up with completely irrelevant tiles being loaded minutes after they were actually relevant
99
111
  if (this.#queue_add(fingerprint) === false) {
100
112
  return false;
101
113
  }
@@ -118,7 +130,7 @@ export class TileLoader {
118
130
 
119
131
  /**
120
132
  *
121
- * @param {UsageMetadata} usage
133
+ * @param {VirtualTextureUsage} usage
122
134
  */
123
135
  #sort_queue_by_usage(usage) {
124
136
 
@@ -138,10 +150,16 @@ export class TileLoader {
138
150
 
139
151
  /**
140
152
  *
141
- * @param {UsageMetadata} usage
153
+ * @param {VirtualTextureUsage} usage
142
154
  */
143
155
  update_usage(usage) {
144
156
  this.#sort_queue_by_usage(usage);
157
+
158
+ // truncate the queue if necessary
159
+ const queue_overflow = this.#queue.length - this.queue_limit;
160
+ if (queue_overflow > 0) {
161
+ this.#queue.splice(this.queue_limit, queue_overflow);
162
+ }
145
163
  }
146
164
 
147
165
  /**
@@ -165,7 +183,7 @@ export class TileLoader {
165
183
  */
166
184
  #prod() {
167
185
  while (this.#in_flight.length < this.#concurrency && this.#queue.length > 0) {
168
- const fingerprint = this.#queue.pop();
186
+ const fingerprint = this.#queue[0];
169
187
  const { mip, x, y } = decompose_finger_print(fingerprint);
170
188
 
171
189
  this.#load(mip, x, y);
@@ -177,7 +195,7 @@ export class TileLoader {
177
195
  * @param {number} mip
178
196
  * @param {number} x
179
197
  * @param {number} y
180
- * @returns {Promise<TextureTile>}
198
+ * @returns {Promise<VirtualTextureTile>}
181
199
  */
182
200
  #load(mip, x, y) {
183
201
  const file_name = this.#build_file_name(mip, x, y);
@@ -191,7 +209,7 @@ export class TileLoader {
191
209
 
192
210
  const sampler = asset.create();
193
211
 
194
- const tile = new TextureTile();
212
+ const tile = new VirtualTextureTile();
195
213
 
196
214
 
197
215
  tile.data = sampler;
@@ -201,6 +219,8 @@ export class TileLoader {
201
219
 
202
220
 
203
221
  return tile;
222
+ }, (reason) => {
223
+ console.error(`Failed to load tile ${file_name}, reason:${reason}`);
204
224
  })
205
225
  .finally(() => {
206
226
 
@@ -1,9 +1,21 @@
1
- import { compose_finger_print } from "./compose_finger_print.js";
2
- import { finger_print_to_tile_index } from "./finger_print_to_tile_index.js";
1
+ import { arrayQuickSort } from "../../../../../core/collection/array/arrayQuickSort.js";
2
+ import { compose_tile_address } from "./tile/compose_tile_address.js";
3
+ import { finger_print_to_tile_address } from "./tile/finger_print_to_tile_address.js";
3
4
 
4
- export class UsageMetadata {
5
+
6
+ export class VirtualTextureUsage {
5
7
 
6
8
  #counts_intrinsic = new Uint32Array(0);
9
+ /**
10
+ * Stores indices of tiles with usage > 0
11
+ * @type {Uint32Array}
12
+ */
13
+ #occupancy = new Uint32Array(0);
14
+ /**
15
+ * Points at the end of the occupancy list
16
+ * @type {number}
17
+ */
18
+ #occupancy_cursor = 0;
7
19
 
8
20
  get counts() {
9
21
  return this.#counts_intrinsic;
@@ -11,6 +23,7 @@ export class UsageMetadata {
11
23
 
12
24
  #max_mip_level = 0;
13
25
 
26
+
14
27
  set max_mip_level(v) {
15
28
  this.#max_mip_level = v;
16
29
 
@@ -21,14 +34,21 @@ export class UsageMetadata {
21
34
  return this.#max_mip_level;
22
35
  }
23
36
 
37
+
38
+ get occupancy() {
39
+ return this.#occupancy;
40
+ }
41
+
42
+ get occupancy_count() {
43
+ return this.#occupancy_cursor;
44
+ }
45
+
24
46
  /**
25
47
  *
26
48
  */
27
49
  #ensureCapacity() {
28
50
 
29
- const finger_print = compose_finger_print(this.#max_mip_level + 1, 0, 0);
30
-
31
- const size = finger_print_to_tile_index(finger_print);
51
+ const size = compose_tile_address(this.#max_mip_level + 1, 0, 0);
32
52
 
33
53
  if (this.#counts_intrinsic.length >= size) {
34
54
  // already large enough
@@ -36,12 +56,7 @@ export class UsageMetadata {
36
56
  }
37
57
 
38
58
  this.#counts_intrinsic = new Uint32Array(size);
39
- }
40
-
41
- #getIndexBy(mip, x, y) {
42
- const finger_print = compose_finger_print(mip, x, y);
43
-
44
- return finger_print_to_tile_index(finger_print);
59
+ this.#occupancy = new Uint32Array(size);
45
60
  }
46
61
 
47
62
  /**
@@ -50,8 +65,7 @@ export class UsageMetadata {
50
65
  * @returns {number}
51
66
  */
52
67
  getCountByFingerprint(fingerprint) {
53
- const index = finger_print_to_tile_index(fingerprint);
54
-
68
+ const index = finger_print_to_tile_address(fingerprint);
55
69
 
56
70
  return this.#counts_intrinsic[index];
57
71
  }
@@ -64,13 +78,14 @@ export class UsageMetadata {
64
78
  * @returns {number}
65
79
  */
66
80
  getCountBy(mip, x, y) {
67
- const finger_print = compose_finger_print(mip, x, y);
81
+ const address = compose_tile_address(mip, x, y);
68
82
 
69
- return this.getCountByFingerprint(finger_print);
83
+ return this.#counts_intrinsic[address];
70
84
  }
71
85
 
72
86
  clear() {
73
87
  this.#counts_intrinsic.fill(0);
88
+ this.#occupancy_cursor = 0;
74
89
  }
75
90
 
76
91
  /**
@@ -81,7 +96,7 @@ export class UsageMetadata {
81
96
  promoteAncestors(bias = 1) {
82
97
 
83
98
  // traverse mip pyramid in reverse, so we can push counts to parents one level at a time
84
- for (let mip = this.#max_mip_level - 1; mip > 0; mip--) {
99
+ for (let mip = this.#max_mip_level; mip > 0; mip--) {
85
100
 
86
101
  const mip_resolution = 1 << mip;
87
102
 
@@ -99,7 +114,7 @@ export class UsageMetadata {
99
114
  const parent_x = x >>> 1;
100
115
  const parent_y = y >>> 1;
101
116
 
102
- const parent_index = this.#getIndexBy(parent_level, parent_x, parent_y);
117
+ const parent_index = compose_tile_address(parent_level, parent_x, parent_y);
103
118
 
104
119
  const parent_count = this.#counts_intrinsic[parent_index];
105
120
 
@@ -107,6 +122,10 @@ export class UsageMetadata {
107
122
 
108
123
  if (parent_count < expected_count) {
109
124
  this.#counts_intrinsic[parent_index] = expected_count;
125
+
126
+ if (parent_count === 0) {
127
+ this.#append_to_occupancy(parent_index);
128
+ }
110
129
  }
111
130
 
112
131
  }
@@ -115,6 +134,26 @@ export class UsageMetadata {
115
134
  }
116
135
  }
117
136
 
137
+ /**
138
+ *
139
+ * @param {number} address
140
+ */
141
+ #append_to_occupancy(address) {
142
+ this.#occupancy[this.#occupancy_cursor] = address;
143
+ this.#occupancy_cursor++;
144
+ }
145
+
146
+ /**
147
+ * Sort occupancy list in descending order
148
+ */
149
+ sortOccupancy() {
150
+ arrayQuickSort(
151
+ this.#occupancy,
152
+ (index) => -this.#counts_intrinsic[index], null,
153
+ 0, this.#occupancy_cursor - 1
154
+ );
155
+ }
156
+
118
157
 
119
158
  /**
120
159
  *
@@ -125,7 +164,9 @@ export class UsageMetadata {
125
164
 
126
165
  const data_size = data.length;
127
166
 
128
- this.#ensureCapacity(data_size >> 2);
167
+ this.#ensureCapacity();
168
+
169
+ const counts = this.#counts_intrinsic;
129
170
 
130
171
  for (let offset = 0; offset < data_size; offset += 4) {
131
172
 
@@ -142,11 +183,16 @@ export class UsageMetadata {
142
183
  const tile_x = data[offset + 1] & max_tile_value;
143
184
  const tile_y = data[offset + 2] & max_tile_value;
144
185
 
145
- const finger_print = compose_finger_print(mip_level, tile_x, tile_y);
186
+ const tile_address = compose_tile_address(mip_level, tile_x, tile_y);
187
+
188
+ const previous_count = counts[tile_address];
146
189
 
147
- const index0 = finger_print_to_tile_index(finger_print);
190
+ if (previous_count === 0) {
191
+ // first occurrence, mark occupancy
192
+ this.#append_to_occupancy(tile_address);
193
+ }
148
194
 
149
- this.#counts_intrinsic[index0]++;
195
+ counts[tile_address] = previous_count + 1;
150
196
  }
151
197
 
152
198
  }
@@ -1,5 +1,6 @@
1
1
  import {
2
2
  ClampToEdgeWrapping,
3
+ DoubleSide,
3
4
  GLSL3,
4
5
  Matrix4,
5
6
  NearestFilter,
@@ -12,12 +13,14 @@ import {
12
13
  WebGLRenderTarget
13
14
  } from "three";
14
15
  import { assert } from "../../../../../core/assert.js";
16
+ import { array_copy } from "../../../../../core/collection/array/array_copy.js";
15
17
  import { clamp } from "../../../../../core/math/clamp.js";
16
18
  import { max2 } from "../../../../../core/math/max2.js";
19
+ import { generate_halton_jitter } from "../../../generate_halton_jitter.js";
17
20
  import { renderScreenSpace } from "../../../render/utils/renderScreenSpace.js";
18
21
  import { Sampler2D } from "../../sampler/Sampler2D.js";
19
- import { fragment, vertex } from "./ShaderUsage.js";
20
- import { UsageMetadata } from "./UsageMetadata.js";
22
+ import { VirtualTextureUsage } from "./VirtualTextureUsage.js";
23
+ import { fragment, vertex } from "./VirtualTextureUsageShader.js";
21
24
 
22
25
  const usage_material_uniforms = {
23
26
  "u_mt_params": { value: new Vector2(0.1, 1) },
@@ -38,6 +41,7 @@ const usage_material = new RawShaderMaterial({
38
41
  uniforms: usage_material_uniforms,
39
42
  vertexShader: vertex(),
40
43
  fragmentShader: fragment(),
44
+ side: DoubleSide,
41
45
  glslVersion: GLSL3
42
46
 
43
47
  });
@@ -65,7 +69,24 @@ const clear_usage_material = new RawShaderMaterial({
65
69
  glslVersion: GLSL3
66
70
  });
67
71
 
68
- export class VirtualTextureManager {
72
+ const scratch_matrix = new Float32Array(16);
73
+
74
+ export class VirtualTextureUsageUpdater {
75
+
76
+ #frame_index = 0;
77
+
78
+ /**
79
+ * In order to avoid aliasing due to the fact that we render at a lower resolution, we move the camera slightly each frame to sweep across texels in-between
80
+ * @type {Float32Array}
81
+ */
82
+ #frame_jitter_offsets = new Float32Array([0, 0]);
83
+ #frame_jitter_samples = 1;
84
+ #frame_jitter_enabled = false;
85
+
86
+ #initialize_frame_jitter() {
87
+ this.#frame_jitter_samples = this.#usage_resolution_scale;
88
+ this.#frame_jitter_offsets = generate_halton_jitter(this.#frame_jitter_samples);
89
+ }
69
90
 
70
91
  #usage_buffer = new WebGLRenderTarget(1, 1, {
71
92
  wrapT: ClampToEdgeWrapping,
@@ -90,7 +111,7 @@ export class VirtualTextureManager {
90
111
  */
91
112
  #usage_resolution_scale = 32;
92
113
 
93
- #usage_metadata = new UsageMetadata();
114
+ #usage_metadata = new VirtualTextureUsage();
94
115
 
95
116
  #texture_id = 3;
96
117
  #texture_resolution = 65536;
@@ -115,6 +136,7 @@ export class VirtualTextureManager {
115
136
  */
116
137
  #usage_texture_bias = 0.1;
117
138
 
139
+
118
140
  /**
119
141
  *
120
142
  * @param {number} resolution
@@ -150,6 +172,7 @@ export class VirtualTextureManager {
150
172
 
151
173
  constructor() {
152
174
  this.#initialize_usage_uniforms();
175
+ this.#initialize_frame_jitter();
153
176
  }
154
177
 
155
178
  #initialize_usage_uniforms() {
@@ -208,6 +231,28 @@ export class VirtualTextureManager {
208
231
 
209
232
  }
210
233
 
234
+ #prepareUsageUniforms(camera) {
235
+
236
+ const uniforms = usage_material.uniforms;
237
+ const usage_buffer = this.#usage_buffer;
238
+ const camera_projection_matrix = camera.projectionMatrix.elements;
239
+
240
+ if (this.#frame_jitter_enabled) {
241
+ // apply jitter to projection matrix
242
+ const jitter_index = this.#frame_index % this.#frame_jitter_samples;
243
+
244
+ const jitter_offset_x = this.#frame_jitter_offsets[jitter_index * 2];
245
+ const jitter_offset_y = this.#frame_jitter_offsets[jitter_index * 2 + 1];
246
+
247
+ camera_projection_matrix[8] = jitter_offset_x / usage_buffer.width;
248
+ camera_projection_matrix[9] = jitter_offset_y / usage_buffer.height;
249
+ }
250
+
251
+
252
+ uniforms.modelViewMatrix.value.multiplyMatrices(camera.matrixWorldInverse, camera.matrixWorld);
253
+ uniforms.projectionMatrix.value.copy(camera.projectionMatrix);
254
+ }
255
+
211
256
  /**
212
257
  *
213
258
  * @param {WebGLRenderer} renderer
@@ -218,37 +263,49 @@ export class VirtualTextureManager {
218
263
 
219
264
  const usage_buffer = this.#usage_buffer;
220
265
 
221
- const uniforms = usage_material.uniforms;
222
266
 
223
- uniforms.modelViewMatrix.value.multiplyMatrices(camera.matrixWorldInverse, camera.matrixWorld);
224
- uniforms.projectionMatrix.value.copy(camera.projectionMatrix);
267
+ const camera_projection_matrix = camera.projectionMatrix.elements;
225
268
 
226
269
  // remember existing state
227
270
  const _old_render_target = renderer.getRenderTarget();
228
271
  const _auto_clear = renderer.autoClear;
229
-
272
+ array_copy(camera_projection_matrix, 0, scratch_matrix, 0, 16);
230
273
  const _old_material = scene.overrideMaterial;
274
+ const _old_camera_matrix_update = camera.matrixAutoUpdate;
275
+
276
+ camera.matrixAutoUpdate = false;
231
277
 
232
278
  renderer.autoClear = false;
233
279
  renderer.setRenderTarget(usage_buffer);
234
- scene.overrideMaterial = usage_material;
235
280
 
236
281
  // clear out usage texture
237
282
  renderScreenSpace(renderer, clear_usage_material);
238
283
 
239
284
  renderer.clearDepth();
240
285
 
286
+ scene.overrideMaterial = usage_material;
287
+
288
+ this.#prepareUsageUniforms(camera);
289
+
241
290
  renderer.render(scene, camera);
242
291
 
243
292
  scene.overrideMaterial = _old_material;
244
293
 
245
294
  renderer.readRenderTargetPixels(usage_buffer, 0, 0, usage_buffer.width, usage_buffer.height, this.#usage_pixel_data.data);
246
295
 
296
+ // restore state
247
297
  renderer.setRenderTarget(_old_render_target);
248
298
  renderer.autoClear = _auto_clear;
299
+ array_copy(scratch_matrix, 0, camera_projection_matrix, 0, 16);
249
300
 
301
+ camera.matrixAutoUpdate = _old_camera_matrix_update;
302
+
303
+ //
250
304
  this.#usage_metadata.fromTexture(this.#usage_pixel_data.data);
251
305
  this.#usage_metadata.promoteAncestors(1);
306
+ this.#usage_metadata.sortOccupancy();
307
+
308
+ this.#frame_index++;
252
309
  }
253
310
 
254
311
  dispose() {
@@ -0,0 +1,70 @@
1
+ import { CSS_ABSOLUTE_POSITIONING } from "../../../../../../view/CSS_ABSOLUTE_POSITIONING.js";
2
+ import { CanvasView } from "../../../../../../view/elements/CanvasView.js";
3
+ import EmptyView from "../../../../../../view/elements/EmptyView.js";
4
+ import { sampler2d_write_to_canvas_raw } from "../../../sampler/sampler2d_write_to_canvas_raw.js";
5
+
6
+ export class ResidencyDebugView extends EmptyView {
7
+ /**
8
+ *
9
+ * @type {PageTexture|null}
10
+ */
11
+ texture = null;
12
+
13
+ #canvas = new CanvasView();
14
+
15
+ #previous_residency = new Uint32Array(1024);
16
+
17
+ constructor() {
18
+ super({
19
+ css: {
20
+ position: "absolute",
21
+ boxShadow: "0 0 8px black",
22
+ background: "black"
23
+ }
24
+ });
25
+
26
+ this.#canvas.css(CSS_ABSOLUTE_POSITIONING);
27
+
28
+ this.addChild(this.#canvas);
29
+
30
+ this.#previous_residency.fill(-1);
31
+ }
32
+
33
+ update() {
34
+
35
+ const t = this.texture;
36
+ if (t === null) {
37
+ return;
38
+ }
39
+
40
+ const canvas = this.#canvas;
41
+ canvas.size.readFromArray(t.page_texture_resolution);
42
+
43
+ this.size.copy(canvas.size);
44
+
45
+ const residentTiles = t.resident_tiles;
46
+
47
+ const temp = new CanvasView();
48
+ const tile_resolution = t.tile_resolution;
49
+ temp.size.setScalar(tile_resolution);
50
+
51
+ const tile_columns = t.page_texture_resolution[0] / tile_resolution;
52
+
53
+ for (let i = 0; i < residentTiles.length; i++) {
54
+ const tile = residentTiles[i];
55
+
56
+ const page_slot = tile.page_slot;
57
+ if (this.#previous_residency[page_slot] === tile.finder_print) {
58
+ continue;
59
+ }
60
+
61
+ sampler2d_write_to_canvas_raw(tile.data, temp.el);
62
+ const column = page_slot % tile_columns;
63
+ const row = (page_slot / tile_columns) | 0;
64
+
65
+ canvas.context2d.drawImage(temp.el, 0, 0, tile_resolution, tile_resolution, tile_resolution * column, tile_resolution * row, tile_resolution, tile_resolution);
66
+
67
+ this.#previous_residency[page_slot] = tile.finder_print;
68
+ }
69
+ }
70
+ }
@@ -0,0 +1,63 @@
1
+ import LabelView from "../../../../../../view/common/LabelView.js";
2
+ import EmptyView from "../../../../../../view/elements/EmptyView.js";
3
+ import { decompose_finger_print } from "../tile/decompose_finger_print.js";
4
+ import { tile_address_to_finger_print } from "../tile/tile_address_to_finger_print.js";
5
+
6
+ export class UsageDebugView extends EmptyView {
7
+ #tileCount = new LabelView("")
8
+ #tiles = new EmptyView();
9
+ #mip_levels = 0;
10
+
11
+
12
+ constructor(opt) {
13
+ super(opt);
14
+
15
+ this.addChild(this.#tileCount);
16
+ this.addChild(this.#tiles);
17
+
18
+ this.css({
19
+ position: "absolute",
20
+ left: "0",
21
+ top: "0",
22
+ background: "rgba(255,255,255,0.5)",
23
+ fontFamily: "monospace",
24
+ fontSize: "10px"
25
+ });
26
+ }
27
+
28
+ set mip_levels(v) {
29
+ this.#mip_levels = v;
30
+ }
31
+
32
+ /**
33
+ *
34
+ * @param {VirtualTextureUsage} usage
35
+ */
36
+ set usage(usage) {
37
+
38
+
39
+ this.#tiles.removeAllChildren();
40
+
41
+ const occupancy = usage.occupancy;
42
+ const occupancyCount = usage.occupancy_count;
43
+
44
+ for (let i = 0; i < occupancyCount; i++) {
45
+ const occupancy_index = occupancy[i];
46
+ const fingerPrint = tile_address_to_finger_print(occupancy_index);
47
+
48
+ const count = usage.getCountByFingerprint(fingerPrint);
49
+
50
+ if (count <= 0) {
51
+ continue;
52
+ }
53
+
54
+ const { mip, x, y } = decompose_finger_print(fingerPrint);
55
+
56
+ this.#tiles.addChild(new LabelView(`ID: ${0} Level: ${mip} X: ${x} Y: ${y} USAGE: ${count}`));
57
+ }
58
+
59
+ this.#tileCount.updateText(`Tile Count: ${occupancyCount}`);
60
+ }
61
+
62
+
63
+ }