@woosh/meep-engine 3.31.0 → 3.33.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.
- package/build/bundle-worker-terrain.js +1 -1
- package/package.json +1 -1
- package/src/core/collection/table/RowFirstTable.d.ts +8 -0
- package/src/core/collection/table/RowFirstTable.d.ts.map +1 -1
- package/src/core/collection/table/RowFirstTable.js +40 -11
- package/src/engine/graphics/ecs/sprite/Sprite.d.ts +3 -0
- package/src/engine/graphics/ecs/sprite/Sprite.d.ts.map +1 -1
- package/src/engine/graphics/ecs/sprite/Sprite.js +3 -0
- package/src/engine/graphics/ecs/sprite/SpriteSystemPE.d.ts +3 -0
- package/src/engine/graphics/ecs/sprite/SpriteSystemPE.d.ts.map +1 -1
- package/src/engine/graphics/ecs/sprite/SpriteSystemPE.js +3 -0
- package/src/engine/graphics3/DebugDrawSystem.d.ts.map +1 -1
- package/src/engine/graphics3/DebugDrawSystem.js +6 -2
- package/src/engine/graphics3/PathDisplaySystem.d.ts.map +1 -1
- package/src/engine/graphics3/PathDisplaySystem.js +311 -307
- package/src/engine/physics/fluid/ecs/FluidObstacleSystem.d.ts +4 -4
- package/src/shade/RENDERER_CONTRACT.md +15 -2
- package/src/shade/device/IMMEDIATE_DATA_PLAN_2026_08_28.md +5 -0
- package/src/shade/device/ShadeGPUCommandContext.d.ts +15 -2
- package/src/shade/device/ShadeGPUCommandContext.d.ts.map +1 -1
- package/src/shade/device/ShadeGPUCommandContext.js +154 -25
- package/src/shade/device/mock/SoftwareGPURenderPassEncoder.d.ts +20 -3
- package/src/shade/device/mock/SoftwareGPURenderPassEncoder.d.ts.map +1 -1
- package/src/shade/device/mock/SoftwareGPURenderPassEncoder.js +21 -3
- package/src/shade/renderer/GraphicsContext.d.ts +20 -1
- package/src/shade/renderer/GraphicsContext.d.ts.map +1 -1
- package/src/shade/renderer/GraphicsContext.js +105 -52
- package/src/shade/renderer/Renderer.d.ts +19 -4
- package/src/shade/renderer/Renderer.d.ts.map +1 -1
- package/src/shade/renderer/Renderer.js +113 -2
- package/src/shade/renderer/animation/GPUAnimationManager.d.ts +10 -7
- package/src/shade/renderer/animation/GPUAnimationManager.d.ts.map +1 -1
- package/src/shade/renderer/animation/GPUAnimationManager.js +147 -45
- package/src/shade/renderer/buffer/GPUBufferReadbackAllocator.d.ts +6 -5
- package/src/shade/renderer/buffer/GPUBufferReadbackAllocator.d.ts.map +1 -1
- package/src/shade/renderer/buffer/GPUBufferReadbackAllocator.js +241 -240
- package/src/shade/renderer/buffer/GPUBufferStagingAllocator.d.ts +62 -2
- package/src/shade/renderer/buffer/GPUBufferStagingAllocator.d.ts.map +1 -1
- package/src/shade/renderer/buffer/GPUBufferStagingAllocator.js +306 -38
- package/src/shade/renderer/buffer/GPUBufferUploadAllocator.d.ts +60 -0
- package/src/shade/renderer/buffer/GPUBufferUploadAllocator.d.ts.map +1 -0
- package/src/shade/renderer/buffer/GPUBufferUploadAllocator.js +202 -0
- package/src/shade/renderer/buffer/GPUUploadBlock.d.ts +68 -0
- package/src/shade/renderer/buffer/GPUUploadBlock.d.ts.map +1 -0
- package/src/shade/renderer/buffer/GPUUploadBlock.js +97 -0
- package/src/shade/renderer/dynamic/DynamicMeshAVBOITChannel.d.ts +2 -1
- package/src/shade/renderer/dynamic/DynamicMeshAVBOITChannel.d.ts.map +1 -1
- package/src/shade/renderer/dynamic/DynamicMeshAVBOITChannel.js +19 -17
- package/src/shade/renderer/dynamic/GPUDynamicMeshDrawList.d.ts +70 -0
- package/src/shade/renderer/dynamic/GPUDynamicMeshDrawList.d.ts.map +1 -0
- package/src/shade/renderer/dynamic/GPUDynamicMeshDrawList.js +257 -0
- package/src/shade/renderer/dynamic/GPUDynamicMeshRenderer.d.ts +20 -7
- package/src/shade/renderer/dynamic/GPUDynamicMeshRenderer.d.ts.map +1 -1
- package/src/shade/renderer/dynamic/GPUDynamicMeshRenderer.js +39 -41
- package/src/shade/renderer/dynamic/GPUDynamicMeshResidency.d.ts +6 -20
- package/src/shade/renderer/dynamic/GPUDynamicMeshResidency.d.ts.map +1 -1
- package/src/shade/renderer/dynamic/GPUDynamicMeshResidency.js +42 -36
- package/src/shade/renderer/dynamic/chunk_dynamic_mesh_avboit_vertex.d.ts +2 -1
- package/src/shade/renderer/dynamic/chunk_dynamic_mesh_avboit_vertex.d.ts.map +1 -1
- package/src/shade/renderer/dynamic/chunk_dynamic_mesh_avboit_vertex.js +4 -3
- package/src/shade/renderer/dynamic/chunk_dynamic_mesh_vertex.d.ts +4 -3
- package/src/shade/renderer/dynamic/chunk_dynamic_mesh_vertex.d.ts.map +1 -1
- package/src/shade/renderer/dynamic/chunk_dynamic_mesh_vertex.js +7 -4
- package/src/shade/renderer/dynamic/graph_dynamic_mesh_avboit.d.ts +14 -15
- package/src/shade/renderer/dynamic/graph_dynamic_mesh_avboit.d.ts.map +1 -1
- package/src/shade/renderer/dynamic/graph_dynamic_mesh_avboit.js +49 -83
- package/src/shade/renderer/dynamic/shader_dynamic_mesh.d.ts +19 -3
- package/src/shade/renderer/dynamic/shader_dynamic_mesh.d.ts.map +1 -1
- package/src/shade/renderer/dynamic/shader_dynamic_mesh.js +26 -6
- package/src/shade/renderer/dynamic/shader_dynamic_mesh_avboit_draw.d.ts +2 -1
- package/src/shade/renderer/dynamic/shader_dynamic_mesh_avboit_draw.d.ts.map +1 -1
- package/src/shade/renderer/dynamic/shader_dynamic_mesh_avboit_draw.js +12 -6
- package/src/shade/renderer/dynamic/shader_dynamic_mesh_avboit_splat.d.ts +3 -2
- package/src/shade/renderer/dynamic/shader_dynamic_mesh_avboit_splat.d.ts.map +1 -1
- package/src/shade/renderer/dynamic/shader_dynamic_mesh_avboit_splat.js +21 -13
- package/src/shade/renderer/geometry/meshlet/build/meshoptimizer/geometry_to_meshlets_meshoptimizer.d.ts +5 -0
- package/src/shade/renderer/geometry/meshlet/build/meshoptimizer/geometry_to_meshlets_meshoptimizer.d.ts.map +1 -1
- package/src/shade/renderer/geometry/meshlet/build/meshoptimizer/geometry_to_meshlets_meshoptimizer.js +19 -0
- package/src/shade/renderer/loader/gltf/tiny-gltf.d.ts +1 -1
- package/src/shade/renderer/postprocess/nss/NSS.d.ts +1 -1
- package/src/shade/renderer/rasterize/bucket/rasterization_has_opaque_bucket.d.ts +3 -1
- package/src/shade/renderer/rasterize/bucket/rasterization_has_opaque_bucket.d.ts.map +1 -1
- package/src/shade/renderer/rasterize/bucket/rasterization_has_opaque_bucket.js +3 -1
- package/src/shade/renderer/rasterize/expand/bucket/mesh/shader_instances_rasterization_bucket_sort.d.ts.map +1 -1
- package/src/shade/renderer/rasterize/expand/bucket/mesh/shader_instances_rasterization_bucket_sort.js +134 -88
- package/src/shade/renderer/rasterize/expand/bucket/meshlet/shader_meshlets_rasterization_bucket_sort.d.ts.map +1 -1
- package/src/shade/renderer/rasterize/expand/bucket/meshlet/shader_meshlets_rasterization_bucket_sort.js +57 -26
- package/src/shade/renderer/rasterize/fast/graph_rasterize_scene_fast.d.ts.map +1 -1
- package/src/shade/renderer/rasterize/fast/graph_rasterize_scene_fast.js +28 -20
- package/src/shade/renderer/rasterize/graph_clear_raster_targets.d.ts +38 -0
- package/src/shade/renderer/rasterize/graph_clear_raster_targets.d.ts.map +1 -0
- package/src/shade/renderer/rasterize/graph_clear_raster_targets.js +105 -0
- package/src/shade/renderer/rasterize/native/avboit/AVBOIT_LEDGER.md +20 -0
- package/src/shade/renderer/rasterize/standard/graph_rasterize_partial_opaque.d.ts +1 -1
- package/src/shade/renderer/rasterize/standard/graph_rasterize_partial_opaque.d.ts.map +1 -1
- package/src/shade/renderer/rasterize/standard/graph_rasterize_partial_opaque.js +21 -1
- package/src/shade/renderer/rasterize/standard/graph_rasterize_scene.d.ts.map +1 -1
- package/src/shade/renderer/rasterize/standard/graph_rasterize_scene.js +12 -20
- package/src/shade/renderer/shader/graph/graph_import_typed_buffer.d.ts +2 -1
- package/src/shade/renderer/shader/graph/graph_import_typed_buffer.d.ts.map +1 -1
- package/src/shade/renderer/shader/graph/graph_import_typed_buffer.js +15 -28
- package/src/shade/renderer/shader/type/serde/write_gpu_typed_buffer.d.ts.map +1 -1
- package/src/shade/renderer/shader/type/serde/write_gpu_typed_buffer.js +8 -1
- package/src/core/geom/3d/atlas/atlas_bench_lib.d.ts +0 -73
- package/src/core/geom/3d/atlas/atlas_bench_lib.d.ts.map +0 -1
- package/src/engine/graphics3/terrain/GPUTerrainSplatRenderer.d.ts +0 -59
- package/src/engine/graphics3/terrain/GPUTerrainSplatRenderer.d.ts.map +0 -1
- package/src/engine/graphics3/terrain/pack_terrain_row_table.d.ts +0 -22
- package/src/engine/graphics3/terrain/pack_terrain_row_table.d.ts.map +0 -1
- package/src/engine/graphics3/terrain/shader_terrain_splat.d.ts +0 -26
- package/src/engine/graphics3/terrain/shader_terrain_splat.d.ts.map +0 -1
- package/src/shade/renderer/animation/ANIMATION_BOUND_TRACK_GROUP_STRUCT.d.ts +0 -25
- package/src/shade/renderer/animation/ANIMATION_BOUND_TRACK_GROUP_STRUCT.d.ts.map +0 -1
- package/src/shade/renderer/animation/ANIMATION_KEYFRAME_BLOCK_STRUCT.d.ts +0 -26
- package/src/shade/renderer/animation/ANIMATION_KEYFRAME_BLOCK_STRUCT.d.ts.map +0 -1
- package/src/shade/renderer/animation/ANIMATION_SKIN_JOINT_BLOCK_STRUCT.d.ts +0 -29
- package/src/shade/renderer/animation/ANIMATION_SKIN_JOINT_BLOCK_STRUCT.d.ts.map +0 -1
|
@@ -1,89 +1,135 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
10
|
-
import {
|
|
11
|
-
import {
|
|
12
|
-
import {
|
|
13
|
-
import {
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
resources
|
|
27
|
-
|
|
28
|
-
.addStorageBuffer("
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
.addStorageBuffer("
|
|
33
|
-
.addStorageBuffer("
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
1
|
+
import { assert } from "../../../../../../core/assert.js";
|
|
2
|
+
import { u32 } from "../../../../shader/type/WEBGPU_WGSL_PRIMITIVE_TYPES.js";
|
|
3
|
+
import { WebGPUArray } from "../../../../shader/type/WebGPUArray.js";
|
|
4
|
+
import { WebGPUStruct } from "../../../../shader/type/WebGPUStruct.js";
|
|
5
|
+
import { COLLECTION_U32_STRUCT_READ } from "../../../../gpu_primitive/COLLECTION_U32_STRUCT_READ.js";
|
|
6
|
+
import { MATERIAL_METADATA_STRUCT } from "../../../../material/MATERIAL_METADATA_STRUCT.js";
|
|
7
|
+
import { chunk_scene_database_access } from "../../../../scene/chunk_scene_database_access.js";
|
|
8
|
+
import { CodeChunk } from "../../../../shader/compiler/CodeChunk.js";
|
|
9
|
+
import { COMPUTE_SHADER_DEFAULT_GROUP_SIZE } from "../../../../shader/COMPUTE_SHADER_DEFAULT_GROUP_SIZE.js";
|
|
10
|
+
import { ComputeShader } from "../../../../shader/ComputeShader.js";
|
|
11
|
+
import { ShaderResourceSetDescriptor } from "../../../../shader/resource/ShaderResourceSetDescriptor.js";
|
|
12
|
+
import { chunk_rasterization_material_bucket } from "../chunk_rasterization_material_bucket.js";
|
|
13
|
+
import { RASTERIZATION_BUCKET_LIMIT } from "../RASTERIZATION_BUCKET_LIMIT.js";
|
|
14
|
+
import {
|
|
15
|
+
RASTERIZATION_BUCKET_SORT_OUTPUT_HEADER_STRUCT_WRITE
|
|
16
|
+
} from "../RASTERIZATION_BUCKET_SORT_OUTPUT_HEADER_STRUCT_WRITE.js";
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
export const RASTERIZATION_BUCKET_SORT_OUTPUT_STRUCT_WRITE = WebGPUStruct.from({
|
|
20
|
+
headers: RASTERIZATION_BUCKET_SORT_OUTPUT_HEADER_STRUCT_WRITE,
|
|
21
|
+
elements: WebGPUArray.u32
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
const OFFSETS_TYPE = WebGPUArray.from(u32, RASTERIZATION_BUCKET_LIMIT);
|
|
25
|
+
|
|
26
|
+
const resources = new ShaderResourceSetDescriptor();
|
|
27
|
+
resources.createGroup()
|
|
28
|
+
.addStorageBuffer("scene_database", WebGPUArray.from(u32))
|
|
29
|
+
.addStorageBuffer("materials", WebGPUArray.from(MATERIAL_METADATA_STRUCT))
|
|
30
|
+
|
|
31
|
+
resources.createGroup()
|
|
32
|
+
.addStorageBuffer("input", COLLECTION_U32_STRUCT_READ)
|
|
33
|
+
.addStorageBuffer("offsets", OFFSETS_TYPE)
|
|
34
|
+
.addStorageBuffer("output", RASTERIZATION_BUCKET_SORT_OUTPUT_STRUCT_WRITE, true)
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
const GROUP_SIZE = COMPUTE_SHADER_DEFAULT_GROUP_SIZE;
|
|
38
|
+
|
|
39
|
+
// one lane per bucket makes the workgroup's claims
|
|
40
|
+
assert.lessThanOrEqual(RASTERIZATION_BUCKET_LIMIT, GROUP_SIZE);
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Every element used to claim its slot with an `atomicAdd(&output.headers[bucket].count, 1u)` of
|
|
44
|
+
* its own. The address comes from the material, so nothing aggregated it, and every survivor of a
|
|
45
|
+
* view queued on its bucket's one counter: 0.47-0.80 ns a survivor, the largest non-raster pass of
|
|
46
|
+
* a view.
|
|
47
|
+
*
|
|
48
|
+
* Instead each lane ranks itself within its workgroup, in workgroup memory, and one lane per bucket
|
|
49
|
+
* claims the workgroup's whole run with a single global atomic. Measured on a 4090 against
|
|
50
|
+
* aggregating per subgroup (a ballot per bit of the bucket index, one atomic per bucket a wave
|
|
51
|
+
* holds), at 2M rows: 62 against 63 us for 1.48M elements of one bucket, 13 against 22 us for
|
|
52
|
+
* the main view's 774K, and 62 against 107 us for the 1.48M with six buckets to a wave. Waves on
|
|
53
|
+
* mixed content hold several buckets, and a workgroup claims each of them a quarter as often.
|
|
54
|
+
*/
|
|
55
|
+
const body = CodeChunk.from(
|
|
56
|
+
//language=WGSL
|
|
57
|
+
`
|
|
58
|
+
var<workgroup> wg_count: array<atomic<u32>, ${RASTERIZATION_BUCKET_LIMIT}>;
|
|
59
|
+
var<workgroup> wg_base: array<u32, ${RASTERIZATION_BUCKET_LIMIT}>;
|
|
60
|
+
|
|
61
|
+
@compute @workgroup_size(${GROUP_SIZE})
|
|
62
|
+
fn main(
|
|
63
|
+
@builtin(global_invocation_id) global_id : vec3<u32>,
|
|
64
|
+
@builtin(local_invocation_index) local_index : u32,
|
|
65
|
+
){
|
|
66
|
+
|
|
67
|
+
let index = global_id.x;
|
|
68
|
+
|
|
69
|
+
let input_size = min(input.count, arrayLength(&input.elements));
|
|
70
|
+
|
|
71
|
+
// a lane past the input does not return: every lane of the workgroup has to reach the barriers
|
|
72
|
+
let valid = index < input_size;
|
|
73
|
+
|
|
74
|
+
var mesh_index = 0u;
|
|
75
|
+
var bucket_index = 0u;
|
|
76
|
+
var rank = 0u;
|
|
77
|
+
|
|
78
|
+
if(valid){
|
|
79
|
+
mesh_index = input.elements[index];
|
|
80
|
+
|
|
81
|
+
let mesh = scene_read_mesh(&scene_database, mesh_index);
|
|
82
|
+
|
|
83
|
+
let material = materials[mesh.material];
|
|
84
|
+
|
|
85
|
+
bucket_index = rasterization_material_bucket(
|
|
86
|
+
material.transparency_mode,
|
|
87
|
+
material.draw_mode,
|
|
88
|
+
material.draw_side
|
|
89
|
+
);
|
|
90
|
+
|
|
91
|
+
// this element's place in the workgroup's run of its bucket
|
|
92
|
+
rank = atomicAdd(&wg_count[bucket_index], 1u);
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
workgroupBarrier();
|
|
96
|
+
|
|
97
|
+
// one lane per bucket claims the workgroup's whole run with one atomic
|
|
98
|
+
if(local_index < ${RASTERIZATION_BUCKET_LIMIT}u){
|
|
99
|
+
let run_length = atomicLoad(&wg_count[local_index]);
|
|
100
|
+
|
|
101
|
+
if(run_length > 0u){
|
|
102
|
+
let run_offset = atomicAdd(&output.headers[local_index].count, run_length);
|
|
103
|
+
|
|
104
|
+
if(run_offset == 0u){
|
|
105
|
+
// first element in bucket, write offset as well
|
|
106
|
+
output.headers[local_index].offset = offsets[local_index];
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
wg_base[local_index] = run_offset;
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
workgroupBarrier();
|
|
114
|
+
|
|
115
|
+
if(valid){
|
|
116
|
+
let output_offset = offsets[bucket_index] + wg_base[bucket_index] + rank;
|
|
117
|
+
|
|
118
|
+
if(output_offset < arrayLength(&output.elements)){
|
|
119
|
+
// guard against out-of-bounds access
|
|
120
|
+
output.elements[output_offset] = mesh_index;
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
}
|
|
125
|
+
`, [
|
|
126
|
+
chunk_rasterization_material_bucket,
|
|
127
|
+
chunk_scene_database_access,
|
|
128
|
+
]
|
|
129
|
+
);
|
|
130
|
+
|
|
131
|
+
export const shader_instances_rasterization_bucket_sort = ComputeShader.from({
|
|
132
|
+
label: 'Rasterization bucket sort',
|
|
133
|
+
resources,
|
|
134
|
+
body,
|
|
89
135
|
})
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"shader_meshlets_rasterization_bucket_sort.d.ts","sourceRoot":"","sources":["../../../../../../../../src/shade/renderer/rasterize/expand/bucket/meshlet/shader_meshlets_rasterization_bucket_sort.js"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"shader_meshlets_rasterization_bucket_sort.d.ts","sourceRoot":"","sources":["../../../../../../../../src/shade/renderer/rasterize/expand/bucket/meshlet/shader_meshlets_rasterization_bucket_sort.js"],"names":[],"mappings":"AA0HA,sEAIE;8BApH4B,qCAAqC"}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { assert } from "../../../../../../core/assert.js";
|
|
1
2
|
import { u32 } from "../../../../shader/type/WEBGPU_WGSL_PRIMITIVE_TYPES.js";
|
|
2
3
|
import { WebGPUArray } from "../../../../shader/type/WebGPUArray.js";
|
|
3
4
|
import { WebGPUStruct } from "../../../../shader/type/WebGPUStruct.js";
|
|
@@ -33,52 +34,82 @@ resources.createGroup()
|
|
|
33
34
|
.addStorageBuffer("output", RASTERIZATION_MESHLET_BUCKET_SORT_OUTPUT_STRUCT_WRITE, true)
|
|
34
35
|
|
|
35
36
|
|
|
37
|
+
const GROUP_SIZE = COMPUTE_SHADER_DEFAULT_GROUP_SIZE;
|
|
38
|
+
|
|
39
|
+
// one lane per bucket makes the workgroup's claims
|
|
40
|
+
assert.lessThanOrEqual(RASTERIZATION_BUCKET_LIMIT, GROUP_SIZE);
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* The meshlet twin of {@link shader_instances_rasterization_bucket_sort}: the same workgroup
|
|
44
|
+
* histogram, for the same reason.
|
|
45
|
+
*/
|
|
36
46
|
const body = CodeChunk.from(
|
|
37
47
|
//language=WGSL
|
|
38
48
|
`
|
|
39
|
-
|
|
49
|
+
var<workgroup> wg_count: array<atomic<u32>, ${RASTERIZATION_BUCKET_LIMIT}>;
|
|
50
|
+
var<workgroup> wg_base: array<u32, ${RASTERIZATION_BUCKET_LIMIT}>;
|
|
51
|
+
|
|
52
|
+
@compute @workgroup_size(${GROUP_SIZE})
|
|
40
53
|
fn main(
|
|
41
54
|
@builtin(workgroup_id) workgroup_id : vec3<u32>,
|
|
42
55
|
@builtin(local_invocation_index) local_index : u32,
|
|
43
56
|
){
|
|
44
|
-
|
|
57
|
+
|
|
45
58
|
// folded dispatch — see IndirectComputeCommandBuildPass
|
|
46
|
-
let index = folded_workgroup_index(workgroup_id) * ${
|
|
59
|
+
let index = folded_workgroup_index(workgroup_id) * ${GROUP_SIZE}u + local_index;
|
|
47
60
|
|
|
48
61
|
let input_size = min(input.count, arrayLength(&input.elements));
|
|
49
62
|
|
|
50
|
-
|
|
51
|
-
|
|
63
|
+
// a lane past the input does not return: every lane of the workgroup has to reach the barriers
|
|
64
|
+
let valid = index < input_size;
|
|
65
|
+
|
|
66
|
+
var bucket_index = 0u;
|
|
67
|
+
var rank = 0u;
|
|
68
|
+
|
|
69
|
+
if(valid){
|
|
70
|
+
let mesh_index = input.elements[index].mesh;
|
|
71
|
+
|
|
72
|
+
let mesh = scene_read_mesh(&scene_database, mesh_index);
|
|
73
|
+
|
|
74
|
+
let material = materials[mesh.material];
|
|
75
|
+
|
|
76
|
+
bucket_index = rasterization_material_bucket(
|
|
77
|
+
material.transparency_mode,
|
|
78
|
+
material.draw_mode,
|
|
79
|
+
material.draw_side
|
|
80
|
+
);
|
|
81
|
+
|
|
82
|
+
// this element's place in the workgroup's run of its bucket
|
|
83
|
+
rank = atomicAdd(&wg_count[bucket_index], 1u);
|
|
52
84
|
}
|
|
53
85
|
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
let mesh_index = meshlet_def.mesh;
|
|
57
|
-
|
|
58
|
-
let mesh = scene_read_mesh(&scene_database, mesh_index);
|
|
59
|
-
|
|
60
|
-
let material = materials[mesh.material];
|
|
86
|
+
workgroupBarrier();
|
|
61
87
|
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
material.draw_side
|
|
66
|
-
);
|
|
88
|
+
// one lane per bucket claims the workgroup's whole run with one atomic
|
|
89
|
+
if(local_index < ${RASTERIZATION_BUCKET_LIMIT}u){
|
|
90
|
+
let run_length = atomicLoad(&wg_count[local_index]);
|
|
67
91
|
|
|
68
|
-
|
|
92
|
+
if(run_length > 0u){
|
|
93
|
+
let run_offset = atomicAdd(&output.headers[local_index].count, run_length);
|
|
69
94
|
|
|
70
|
-
|
|
95
|
+
if(run_offset == 0u){
|
|
96
|
+
// first element in bucket, write offset as well
|
|
97
|
+
output.headers[local_index].offset = offsets[local_index];
|
|
98
|
+
}
|
|
71
99
|
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
output.headers[bucket_index].offset = bucket_offset;
|
|
100
|
+
wg_base[local_index] = run_offset;
|
|
101
|
+
}
|
|
75
102
|
}
|
|
76
103
|
|
|
77
|
-
|
|
104
|
+
workgroupBarrier();
|
|
105
|
+
|
|
106
|
+
if(valid){
|
|
107
|
+
let output_offset = offsets[bucket_index] + wg_base[bucket_index] + rank;
|
|
78
108
|
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
109
|
+
if(output_offset < arrayLength(&output.elements)){
|
|
110
|
+
// guard against out-of-bounds access
|
|
111
|
+
output.elements[output_offset] = input.elements[index];
|
|
112
|
+
}
|
|
82
113
|
}
|
|
83
114
|
|
|
84
115
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"graph_rasterize_scene_fast.d.ts","sourceRoot":"","sources":["../../../../../../src/shade/renderer/rasterize/fast/graph_rasterize_scene_fast.js"],"names":[],"mappings":"AAoBA;;;;;;;;;;GAUG;AACH;;;;;;;IAFa;IAAC,YAAY,EAAE,MAAM,CAAC;IAAC,aAAa,EAAE,MAAM,EAAE,CAAA;CAAC,
|
|
1
|
+
{"version":3,"file":"graph_rasterize_scene_fast.d.ts","sourceRoot":"","sources":["../../../../../../src/shade/renderer/rasterize/fast/graph_rasterize_scene_fast.js"],"names":[],"mappings":"AAoBA;;;;;;;;;;GAUG;AACH;;;;;;;IAFa;IAAC,YAAY,EAAE,MAAM,CAAC;IAAC,aAAa,EAAE,MAAM,EAAE,CAAA;CAAC,CAkK3D;AAED;;;;;;;;;;;;;;;;;;;GAmBG;AACH;IAJ+B,KAAK;IACC,GAAG;IACA,MAAM;SA8C7C"}
|
|
@@ -13,8 +13,8 @@ import { graph_vgeo_expand_if_enabled } from "../../geometry/virtual/runtime/gra
|
|
|
13
13
|
import { RasterizationCollectionType } from "../expand/RasterizationCollectionType.js";
|
|
14
14
|
import { construct_primitive_state } from "../bucket/construct_primitive_state.js";
|
|
15
15
|
import { rasterization_opaque_buckets } from "../bucket/rasterization_opaque_buckets.js";
|
|
16
|
-
import { rasterization_has_opaque_bucket } from "../bucket/rasterization_has_opaque_bucket.js";
|
|
17
16
|
import { graph_mesh_frustum_cull } from "../compute/graph_mesh_frustum_cull.js";
|
|
17
|
+
import { graph_clear_raster_targets } from "../graph_clear_raster_targets.js";
|
|
18
18
|
import { graph_rasterize_meshes_alpha_tested } from "../native/graph_rasterize_meshes_alpha_tested.js";
|
|
19
19
|
import { graph_extract_meshes_from_bucket } from "./graph_extract_meshes_from_bucket.js";
|
|
20
20
|
|
|
@@ -122,29 +122,39 @@ export function graph_rasterize_scene_fast_raw({
|
|
|
122
122
|
is_first_draw = false;
|
|
123
123
|
}
|
|
124
124
|
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
let targets_cleared = rasterization_has_opaque_bucket(active_buckets);
|
|
125
|
+
if (is_first_draw) {
|
|
126
|
+
/*
|
|
127
|
+
No opaque bucket, so no draw above cleared the target, and the rectangle holds whatever was
|
|
128
|
+
there before: in the atlas, the shadow of whatever was in the scene then; in a point light's
|
|
129
|
+
cube, which is a pooled transient, whatever the pool's last user left. The clear goes in the
|
|
130
|
+
first draw's place, and everything after this loads.
|
|
131
|
+
*/
|
|
132
|
+
const cleared = graph_clear_raster_targets({
|
|
133
|
+
graph,
|
|
134
|
+
depth: target_depth,
|
|
135
|
+
color_targets: targets_color,
|
|
136
|
+
pass_descriptor: job.opaque_pass,
|
|
137
|
+
viewport,
|
|
138
|
+
});
|
|
140
139
|
|
|
140
|
+
target_depth = cleared.depth;
|
|
141
|
+
targets_color = cleared.color_targets;
|
|
142
|
+
}
|
|
141
143
|
|
|
144
|
+
// alpha-tested: reuse the existing native pass but skip HZB filtering by passing hzb=-1
|
|
145
|
+
if (job.alpha_tested_pass !== undefined) {
|
|
146
|
+
/*
|
|
147
|
+
Both alpha-tested passes load, never clear: the targets were cleared above, by the first
|
|
148
|
+
opaque draw or in its place. The clear used to be handed to the first alpha-tested draw, which
|
|
149
|
+
left a scene with neither kind of draw — nothing in it, or only transparent surfaces — with
|
|
150
|
+
nothing clearing at all.
|
|
151
|
+
*/
|
|
142
152
|
const alpha_tested_front = graph_rasterize_meshes_alpha_tested({
|
|
143
153
|
graph,
|
|
144
154
|
buckets: gr_render_buckets,
|
|
145
155
|
view_ctx: view_ctx,
|
|
146
156
|
render_pass_descriptor: job.alpha_tested_pass,
|
|
147
|
-
clear_target:
|
|
157
|
+
clear_target: false,
|
|
148
158
|
side: ShadeDrawSide.Front,
|
|
149
159
|
cull_policy: job.cull_policy,
|
|
150
160
|
limits,
|
|
@@ -157,14 +167,13 @@ export function graph_rasterize_scene_fast_raw({
|
|
|
157
167
|
|
|
158
168
|
target_depth = alpha_tested_front.depth;
|
|
159
169
|
targets_color = alpha_tested_front.color_targets;
|
|
160
|
-
targets_cleared = targets_cleared || alpha_tested_front.executed;
|
|
161
170
|
|
|
162
171
|
const alpha_tested_double = graph_rasterize_meshes_alpha_tested({
|
|
163
172
|
graph,
|
|
164
173
|
buckets: gr_render_buckets,
|
|
165
174
|
view_ctx: view_ctx,
|
|
166
175
|
render_pass_descriptor: job.alpha_tested_pass,
|
|
167
|
-
clear_target:
|
|
176
|
+
clear_target: false,
|
|
168
177
|
side: ShadeDrawSide.Double,
|
|
169
178
|
cull_policy: job.cull_policy,
|
|
170
179
|
limits,
|
|
@@ -177,7 +186,6 @@ export function graph_rasterize_scene_fast_raw({
|
|
|
177
186
|
|
|
178
187
|
target_depth = alpha_tested_double.depth;
|
|
179
188
|
targets_color = alpha_tested_double.color_targets;
|
|
180
|
-
targets_cleared = targets_cleared || alpha_tested_double.executed;
|
|
181
189
|
}
|
|
182
190
|
|
|
183
191
|
return {target_depth, targets_color};
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Clear a rasterization's targets to what its first draw would have cleared them to, for a
|
|
3
|
+
* rasterization that has no first draw.
|
|
4
|
+
*
|
|
5
|
+
* A rasterization clears its targets through the `loadOp` of its first draw, which is its first opaque
|
|
6
|
+
* bucket's; everything after that loads. A scene with no opaque bucket has no such draw, and a scene
|
|
7
|
+
* with nothing in it has no draw at all — and no target starts a frame empty, so the frame then reads
|
|
8
|
+
* whatever it last held. The renderer's own targets outlive the frame: a mesh taken out of the scene
|
|
9
|
+
* stays in them, and so does the depth an extension wrote over the scene after the rasterizer was done.
|
|
10
|
+
* A graph transient comes out of a pool holding whatever its last user left, which is what a point
|
|
11
|
+
* light's cube faces are. This takes that draw's place.
|
|
12
|
+
*
|
|
13
|
+
* The clear values are the pass descriptor's own, so what the targets hold afterwards is exactly what
|
|
14
|
+
* the draw's clear would have left. A viewport short of the whole target fills that rectangle alone —
|
|
15
|
+
* shadow maps share an atlas, and a clear load op would erase every other map in it.
|
|
16
|
+
*
|
|
17
|
+
* @param {object} options
|
|
18
|
+
* @param {FrameGraph} options.graph
|
|
19
|
+
* @param {number} options.depth depth texture resource ID
|
|
20
|
+
* @param {number[]} options.color_targets colour texture resource IDs, in the order of the pass
|
|
21
|
+
* descriptor's colour attachments
|
|
22
|
+
* @param {RenderPassDescriptor} options.pass_descriptor the pass whose first draw this stands in for;
|
|
23
|
+
* the clear values are read off it
|
|
24
|
+
* @param {number[]} [options.viewport] [x, y, width, height]; a width or height of -1 runs to the edge of
|
|
25
|
+
* the target, and [0, 0, -1, -1] is the whole target
|
|
26
|
+
* @returns {{depth: number, color_targets: number[]}} the depth and colour handles, cleared
|
|
27
|
+
*/
|
|
28
|
+
export function graph_clear_raster_targets({ graph, depth, color_targets, pass_descriptor, viewport, }: {
|
|
29
|
+
graph: FrameGraph;
|
|
30
|
+
depth: number;
|
|
31
|
+
color_targets: number[];
|
|
32
|
+
pass_descriptor: RenderPassDescriptor;
|
|
33
|
+
viewport?: number[];
|
|
34
|
+
}): {
|
|
35
|
+
depth: number;
|
|
36
|
+
color_targets: number[];
|
|
37
|
+
};
|
|
38
|
+
//# sourceMappingURL=graph_clear_raster_targets.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"graph_clear_raster_targets.d.ts","sourceRoot":"","sources":["../../../../../src/shade/renderer/rasterize/graph_clear_raster_targets.js"],"names":[],"mappings":"AAGA;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH;IAV+B,KAAK;IACT,KAAK,EAArB,MAAM;IACY,aAAa,EAA/B,MAAM,EAAE;IAEsB,eAAe;IAE1B,QAAQ,GAA3B,MAAM,EAAE;IAEN;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,aAAa,EAAE,MAAM,EAAE,CAAA;CAAC,CA4EpD"}
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
import { assert } from "../../../core/assert.js";
|
|
2
|
+
import { texture_fill_rectangle } from "../texture/util/texture_fill_rectangle.js";
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Clear a rasterization's targets to what its first draw would have cleared them to, for a
|
|
6
|
+
* rasterization that has no first draw.
|
|
7
|
+
*
|
|
8
|
+
* A rasterization clears its targets through the `loadOp` of its first draw, which is its first opaque
|
|
9
|
+
* bucket's; everything after that loads. A scene with no opaque bucket has no such draw, and a scene
|
|
10
|
+
* with nothing in it has no draw at all — and no target starts a frame empty, so the frame then reads
|
|
11
|
+
* whatever it last held. The renderer's own targets outlive the frame: a mesh taken out of the scene
|
|
12
|
+
* stays in them, and so does the depth an extension wrote over the scene after the rasterizer was done.
|
|
13
|
+
* A graph transient comes out of a pool holding whatever its last user left, which is what a point
|
|
14
|
+
* light's cube faces are. This takes that draw's place.
|
|
15
|
+
*
|
|
16
|
+
* The clear values are the pass descriptor's own, so what the targets hold afterwards is exactly what
|
|
17
|
+
* the draw's clear would have left. A viewport short of the whole target fills that rectangle alone —
|
|
18
|
+
* shadow maps share an atlas, and a clear load op would erase every other map in it.
|
|
19
|
+
*
|
|
20
|
+
* @param {object} options
|
|
21
|
+
* @param {FrameGraph} options.graph
|
|
22
|
+
* @param {number} options.depth depth texture resource ID
|
|
23
|
+
* @param {number[]} options.color_targets colour texture resource IDs, in the order of the pass
|
|
24
|
+
* descriptor's colour attachments
|
|
25
|
+
* @param {RenderPassDescriptor} options.pass_descriptor the pass whose first draw this stands in for;
|
|
26
|
+
* the clear values are read off it
|
|
27
|
+
* @param {number[]} [options.viewport] [x, y, width, height]; a width or height of -1 runs to the edge of
|
|
28
|
+
* the target, and [0, 0, -1, -1] is the whole target
|
|
29
|
+
* @returns {{depth: number, color_targets: number[]}} the depth and colour handles, cleared
|
|
30
|
+
*/
|
|
31
|
+
export function graph_clear_raster_targets({
|
|
32
|
+
graph,
|
|
33
|
+
depth,
|
|
34
|
+
color_targets,
|
|
35
|
+
pass_descriptor,
|
|
36
|
+
viewport = [0, 0, -1, -1],
|
|
37
|
+
}) {
|
|
38
|
+
assert.defined(graph, 'graph');
|
|
39
|
+
assert.isNonNegativeInteger(depth, 'depth');
|
|
40
|
+
assert.isArray(color_targets, 'color_targets');
|
|
41
|
+
assert.equal(pass_descriptor.isRenderPassDescriptor, true, "pass_descriptor must be a RenderPassDescriptor");
|
|
42
|
+
assert.equal(color_targets.length, pass_descriptor.colorAttachments.length, 'one colour target per colour attachment of the pass');
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* @param data
|
|
46
|
+
* @param {FramePassResources} resources
|
|
47
|
+
* @param {GraphicsExecutionContext} context
|
|
48
|
+
*/
|
|
49
|
+
function execute(data, resources, context) {
|
|
50
|
+
const encoder = context.encoder;
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* @type {GPUTextureContext}
|
|
54
|
+
*/
|
|
55
|
+
const depth_texture = resources.get(data.depth);
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* @type {GPUTextureContext[]}
|
|
59
|
+
*/
|
|
60
|
+
const color_textures = data.color_targets.map(id => resources.get(id));
|
|
61
|
+
|
|
62
|
+
const x = viewport[0];
|
|
63
|
+
const y = viewport[1];
|
|
64
|
+
const width = viewport[2] >= 0 ? viewport[2] : depth_texture.width - x;
|
|
65
|
+
const height = viewport[3] >= 0 ? viewport[3] : depth_texture.height - y;
|
|
66
|
+
|
|
67
|
+
const is_whole_target = x === 0 && y === 0 && width === depth_texture.width && height === depth_texture.height;
|
|
68
|
+
|
|
69
|
+
if (is_whole_target) {
|
|
70
|
+
const gpu_descriptor = pass_descriptor.toGPU({
|
|
71
|
+
colorTargets: color_textures,
|
|
72
|
+
depthTarget: depth_texture,
|
|
73
|
+
loadOp: "clear",
|
|
74
|
+
storeOp: "store",
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
// not the draw's pipeline label: nothing is drawn
|
|
78
|
+
gpu_descriptor.label = "Clear rasterization targets";
|
|
79
|
+
|
|
80
|
+
encoder.beginRenderPass(gpu_descriptor).end();
|
|
81
|
+
|
|
82
|
+
return;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
const rectangle = [x, y, width, height];
|
|
86
|
+
|
|
87
|
+
for (let i = 0; i < color_textures.length; i++) {
|
|
88
|
+
texture_fill_rectangle(encoder, color_textures[i], rectangle, pass_descriptor.colorAttachments[i].clearValue);
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
texture_fill_rectangle(encoder, depth_texture, rectangle, [pass_descriptor.depthStencilAttachment.depthClearValue]);
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
const data = {};
|
|
95
|
+
|
|
96
|
+
const pass = graph.add("clear raster targets", data, execute);
|
|
97
|
+
|
|
98
|
+
data.depth = pass.write(depth);
|
|
99
|
+
data.color_targets = color_targets.map(pass.write, pass);
|
|
100
|
+
|
|
101
|
+
return {
|
|
102
|
+
depth: data.depth,
|
|
103
|
+
color_targets: data.color_targets,
|
|
104
|
+
};
|
|
105
|
+
}
|
|
@@ -887,3 +887,23 @@ reach — the dynamic-mesh directory, the orchestrator run with a real channel,
|
|
|
887
887
|
93 tests — passes, and the type check is at budget. On the Metal adapter, `@builtin(sample_mask)` and
|
|
888
888
|
`@interpolate(perspective, centroid)` compile and the multisampled pipeline builds; no uncaptured device
|
|
889
889
|
errors, including 240 frames of a live trail on a moving path, fading in and out.
|
|
890
|
+
|
|
891
|
+
## 25. A trail's draw constants go up once a frame — 2026-09-27
|
|
892
|
+
|
|
893
|
+
Entry 23 left each live mesh's constants built twice — a transient uniform and a bind group of its own
|
|
894
|
+
for the splat, and again for the draw — noted, not shaved. They are shaved here, as part of moving
|
|
895
|
+
every dynamic mesh's per-draw constants into a table (CHANGELOG, Unreleased, Rendering): the
|
|
896
|
+
occupancy, after its upload, writes the frame's `GPUDynamicMeshDrawList` — one transient storage
|
|
897
|
+
buffer and one write per 1,024 draws — and the splat and the draw both bind it and name their rows by
|
|
898
|
+
`first_instance`. The splat's layout is four groups now (constants, geometry, warp, volume), which is
|
|
899
|
+
WebGPU's default `maxBindGroups`.
|
|
900
|
+
|
|
901
|
+
**Measured** with 1,500 live meshes through the channel at 1280×720 on the RTX 4090, asserts
|
|
902
|
+
stripped, paired: 9.8–11.4 ms of CPU a frame to 2.0–2.5; 3,032 copies a frame to 34 and 7,624
|
|
903
|
+
`setBindGroup` to 3,131. The pictures after equal frame counts are bit-identical to before.
|
|
904
|
+
|
|
905
|
+
**Verified.** `DynamicMeshAVBOITChannel.draws.spec.js` checks the splat and the draw read each mesh's own
|
|
906
|
+
constants from one table, and fails with a draw pass that uploads its own copy (two tables).
|
|
907
|
+
`chunk_dynamic_mesh_vertex.spec.js` runs the shared AVBOIT vertex stage on the emulator and checks a
|
|
908
|
+
vertex is carried by the row its draw names. The other half of the item — the emptiness query and the
|
|
909
|
+
gather both walking the first live mesh's triangles — is left as it was.
|
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
* @param {Set<number>} active_buckets IDs of buckets that have any materials that are active.
|
|
13
13
|
* @param {number[]} [viewport] optional viewport definition, if not provided, will use the entire render target. Useful for drawing multiple views into the same render target.
|
|
14
14
|
* @param {Readonly<Record<number, GPUCullMode>>} [cull_policy] side→cullMode mapping; defaults to {@link CullPolicy.Standard}
|
|
15
|
-
* @returns {{instances_maybe:number, meshlets_maybe:number, depth:number, color_targets:number[]}} the "maybe visible" sets, and the depth and colour handles produced by the rasterization
|
|
15
|
+
* @returns {{instances_maybe:number, meshlets_maybe:number, depth:number, color_targets:number[]}} the "maybe visible" sets, and the depth and colour handles produced by the rasterization — cleared whether or not any bucket drew
|
|
16
16
|
*/
|
|
17
17
|
export function graph_rasterize_partial_opaque({ graph, buckets, view, render_pass_descriptor, limits, depth, raster_color_targets, hzb, viewport, active_buckets, cull_policy, }: FrameGraph): {
|
|
18
18
|
instances_maybe: number;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"graph_rasterize_partial_opaque.d.ts","sourceRoot":"","sources":["../../../../../../src/shade/renderer/rasterize/standard/graph_rasterize_partial_opaque.js"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"graph_rasterize_partial_opaque.d.ts","sourceRoot":"","sources":["../../../../../../src/shade/renderer/rasterize/standard/graph_rasterize_partial_opaque.js"],"names":[],"mappings":"AAyBA;;;;;;;;;;;;;;;GAeG;AACH,gMAFa;IAAC,eAAe,EAAC,MAAM,CAAC;IAAC,cAAc,EAAC,MAAM,CAAC;IAAC,KAAK,EAAC,MAAM,CAAC;IAAC,aAAa,EAAC,MAAM,EAAE,CAAA;CAAC,CAmNjG"}
|