Skip to content

Commit 6d1183d

Browse files
committed
feat(renderer): namespace virtual visibility IDs
1 parent f2b71d6 commit 6d1183d

4 files changed

Lines changed: 166 additions & 51 deletions

File tree

native/shared/shaders/visibility_buffer/reconstruct.wgsl

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,16 @@
66
// a per-corner barycentric vertex stream.
77

88
const BLOOM_VISIBILITY_INVALID_DRAW_ID: u32 = 0xffffffffu;
9+
const BLOOM_VISIBILITY_VIRTUAL_DRAW_BIT: u32 = 0x80000000u;
10+
const BLOOM_VISIBILITY_DRAW_INDEX_MASK: u32 = 0x7fffffffu;
911
const BLOOM_VISIBILITY_FRONT_FACE_BIT: u32 = 0x80000000u;
1012
const BLOOM_VISIBILITY_PRIMITIVE_MASK: u32 = 0x7fffffffu;
1113

1214
struct BloomVisibilityRecord {
1315
draw_id: u32,
1416
primitive_id: u32,
1517
front_facing: bool,
18+
virtual_geometry: bool,
1619
};
1720

1821
fn bloom_visibility_valid(raw: vec2<u32>) -> bool {
@@ -21,9 +24,22 @@ fn bloom_visibility_valid(raw: vec2<u32>) -> bool {
2124

2225
fn bloom_decode_visibility(raw: vec2<u32>) -> BloomVisibilityRecord {
2326
return BloomVisibilityRecord(
24-
raw.x,
27+
raw.x & BLOOM_VISIBILITY_DRAW_INDEX_MASK,
2528
raw.y & BLOOM_VISIBILITY_PRIMITIVE_MASK,
2629
(raw.y & BLOOM_VISIBILITY_FRONT_FACE_BIT) != 0u,
30+
(raw.x & BLOOM_VISIBILITY_VIRTUAL_DRAW_BIT) != 0u,
31+
);
32+
}
33+
34+
fn bloom_encode_virtual_visibility(
35+
draw_index: u32,
36+
primitive_id: u32,
37+
front_facing: bool,
38+
) -> vec2<u32> {
39+
let face = select(0u, BLOOM_VISIBILITY_FRONT_FACE_BIT, front_facing);
40+
return vec2<u32>(
41+
BLOOM_VISIBILITY_VIRTUAL_DRAW_BIT | draw_index,
42+
primitive_id | face,
2743
);
2844
}
2945

native/shared/src/renderer/mod.rs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,7 @@ mod texture_store;
6969
mod transmitted_shadows;
7070
mod transparent_gi;
7171
pub(crate) mod visibility_buffer;
72+
mod visibility_ids;
7273
mod visibility_shading;
7374
mod vsm_gpu_casters;
7475
mod weighted_transparency;
@@ -113,6 +114,7 @@ use atmosphere_lut::{
113114
};
114115

115116
mod formats;
117+
pub(crate) use formats::DEPTH_FORMAT;
116118
#[cfg(not(target_arch = "wasm32"))]
117119
use formats::PROBE_OCT_SIZE;
118120
use formats::{
@@ -124,8 +126,8 @@ use formats::{
124126
create_ssao_rt, create_ssgi_rt, create_ssr_history_textures, create_ssr_rt, create_sss_rt,
125127
create_taa_textures, create_velocity_rt, create_wsrc_atlas, halton, probe_grid_dims,
126128
BLOOM_MIP_COUNT, CARD_ATLAS_SIZE, CARD_AXES_PER_MESH, CARD_MAX_SLOTS, CARD_SLOTS_PER_ROW,
127-
CARD_SLOT_SIZE, DEPTH_FORMAT, HDR_FORMAT, HIZ_FORMAT, HIZ_MIP_COUNT, MATERIAL_FORMAT,
128-
MESH_SDF_RES, PROBE_TILE_SIZE, SCENE_SDF_CLIPMAP_BIN_CELLS, SCENE_SDF_CLIPMAP_EXTENT,
129+
CARD_SLOT_SIZE, HDR_FORMAT, HIZ_FORMAT, HIZ_MIP_COUNT, MATERIAL_FORMAT, MESH_SDF_RES,
130+
PROBE_TILE_SIZE, SCENE_SDF_CLIPMAP_BIN_CELLS, SCENE_SDF_CLIPMAP_EXTENT,
129131
SCENE_SDF_CLIPMAP_LAYERS_PER_FRAME, SCENE_SDF_CLIPMAP_REBAKE_THRESHOLD, SCENE_SDF_CLIPMAP_RES,
130132
SSAO_FORMAT, VELOCITY_FORMAT, WSRC_CASCADE_COUNT, WSRC_CASCADE_EXTENTS, WSRC_GRID_RES,
131133
WSRC_REBAKE_THRESHOLD,

native/shared/src/renderer/visibility_buffer.rs

Lines changed: 11 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -5,52 +5,10 @@
55
//! use. The existing forward MRT remains authoritative until total frame cost
66
//! and image parity pass on every required capability tier.
77
8-
pub(crate) const VISIBILITY_FORMAT: wgpu::TextureFormat = wgpu::TextureFormat::Rg32Uint;
9-
pub(crate) const VISIBILITY_BYTES_PER_PIXEL: u64 = 8;
10-
pub(crate) const INVALID_DRAW_ID: u32 = u32::MAX;
11-
pub(crate) const FRONT_FACE_BIT: u32 = 1 << 31;
12-
pub(crate) const PRIMITIVE_ID_MASK: u32 = FRONT_FACE_BIT - 1;
13-
14-
/// One visibility-buffer texel. The second word reserves its high bit for the
15-
/// rasterized face orientation and leaves 31 bits for the primitive index.
16-
#[repr(C)]
17-
#[derive(Copy, Clone, Debug, Eq, PartialEq, bytemuck::Pod, bytemuck::Zeroable)]
18-
pub(crate) struct VisibilityRecord {
19-
pub draw_id: u32,
20-
pub primitive_and_face: u32,
21-
}
22-
23-
impl VisibilityRecord {
24-
pub(crate) const BACKGROUND: Self = Self {
25-
draw_id: INVALID_DRAW_ID,
26-
primitive_and_face: u32::MAX,
27-
};
28-
29-
pub(crate) const fn encode(
30-
draw_id: u32,
31-
primitive_id: u32,
32-
front_facing: bool,
33-
) -> Option<Self> {
34-
if draw_id == INVALID_DRAW_ID || primitive_id > PRIMITIVE_ID_MASK {
35-
return None;
36-
}
37-
Some(Self {
38-
draw_id,
39-
primitive_and_face: primitive_id | if front_facing { FRONT_FACE_BIT } else { 0 },
40-
})
41-
}
42-
43-
pub(crate) const fn decode(self) -> Option<(u32, u32, bool)> {
44-
if self.draw_id == INVALID_DRAW_ID {
45-
return None;
46-
}
47-
Some((
48-
self.draw_id,
49-
self.primitive_and_face & PRIMITIVE_ID_MASK,
50-
(self.primitive_and_face & FRONT_FACE_BIT) != 0,
51-
))
52-
}
53-
}
8+
pub(crate) use super::visibility_ids::{
9+
VisibilityDraw, VisibilityRecord, DRAW_INDEX_MASK, FRONT_FACE_BIT, INVALID_DRAW_ID,
10+
PRIMITIVE_ID_MASK, VIRTUAL_DRAW_BIT, VISIBILITY_BYTES_PER_PIXEL, VISIBILITY_FORMAT,
11+
};
5412

5513
/// Exact allocation size of the packed visibility target, excluding backend
5614
/// row/heap alignment that must be reported separately by the runtime A/B.
@@ -77,7 +35,9 @@ pub(crate) fn contract_json() -> String {
7735
concat!(
7836
"{{\"format\":\"{}\",\"bytes_per_pixel\":{},",
7937
"\"invalid_draw_id\":{},\"primitive_bits\":31,",
80-
"\"front_face_bits\":1,\"shipping_enabled\":false,",
38+
"\"front_face_bits\":1,\"draw_namespace_bits\":1,",
39+
"\"virtual_draw_bit\":{},\"draw_index_mask\":{},",
40+
"\"shipping_enabled\":false,",
8141
"\"required_feature\":\"primitive-index\",",
8242
"\"vertex_stride_bytes\":{},\"native_1080p_bytes\":{},",
8343
"\"reconstruction_wgsl_bytes\":{},\"geometry_wgsl_bytes\":{},",
@@ -86,6 +46,8 @@ pub(crate) fn contract_json() -> String {
8646
format_name,
8747
VISIBILITY_BYTES_PER_PIXEL,
8848
INVALID_DRAW_ID,
49+
VIRTUAL_DRAW_BIT,
50+
DRAW_INDEX_MASK,
8951
std::mem::size_of::<super::Vertex3D>(),
9052
target_bytes(1_920, 1_080).expect("1080p visibility allocation is bounded"),
9153
RECONSTRUCTION_WGSL.len(),
@@ -1202,13 +1164,14 @@ mod tests {
12021164
for (draw, primitive, front) in [
12031165
(0, 0, false),
12041166
(17, 42, true),
1205-
(u32::MAX - 1, PRIMITIVE_ID_MASK, false),
1167+
(DRAW_INDEX_MASK, PRIMITIVE_ID_MASK, false),
12061168
] {
12071169
let encoded = VisibilityRecord::encode(draw, primitive, front).unwrap();
12081170
assert_eq!(encoded.decode(), Some((draw, primitive, front)));
12091171
}
12101172
assert_eq!(VisibilityRecord::BACKGROUND.decode(), None);
12111173
assert_eq!(VisibilityRecord::encode(INVALID_DRAW_ID, 0, true), None);
1174+
assert_eq!(VisibilityRecord::encode(VIRTUAL_DRAW_BIT, 0, true), None);
12121175
assert_eq!(VisibilityRecord::encode(0, FRONT_FACE_BIT, true), None);
12131176
}
12141177

Lines changed: 134 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,134 @@
1+
//! Collision-free draw namespace for the shared packed visibility target.
2+
3+
pub(crate) const VISIBILITY_FORMAT: wgpu::TextureFormat = wgpu::TextureFormat::Rg32Uint;
4+
pub(crate) const VISIBILITY_BYTES_PER_PIXEL: u64 = 8;
5+
pub(crate) const INVALID_DRAW_ID: u32 = u32::MAX;
6+
pub(crate) const VIRTUAL_DRAW_BIT: u32 = 1 << 31;
7+
pub(crate) const DRAW_INDEX_MASK: u32 = VIRTUAL_DRAW_BIT - 1;
8+
pub(crate) const FRONT_FACE_BIT: u32 = 1 << 31;
9+
pub(crate) const PRIMITIVE_ID_MASK: u32 = FRONT_FACE_BIT - 1;
10+
const MAX_VIRTUAL_DRAW_INDEX: u32 = DRAW_INDEX_MASK - 1;
11+
12+
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
13+
pub(crate) enum VisibilityDraw {
14+
Compatibility(u32),
15+
Virtual(u32),
16+
}
17+
18+
/// One `Rg32Uint` texel. Draw bit 31 selects compatibility or virtual
19+
/// geometry; primitive bit 31 independently carries raster face orientation.
20+
#[repr(C)]
21+
#[derive(Copy, Clone, Debug, Eq, PartialEq, bytemuck::Pod, bytemuck::Zeroable)]
22+
pub(crate) struct VisibilityRecord {
23+
pub draw_id: u32,
24+
pub primitive_and_face: u32,
25+
}
26+
27+
impl VisibilityRecord {
28+
pub(crate) const BACKGROUND: Self = Self {
29+
draw_id: INVALID_DRAW_ID,
30+
primitive_and_face: u32::MAX,
31+
};
32+
33+
pub(crate) const fn encode(
34+
draw_id: u32,
35+
primitive_id: u32,
36+
front_facing: bool,
37+
) -> Option<Self> {
38+
Self::encode_draw(
39+
VisibilityDraw::Compatibility(draw_id),
40+
primitive_id,
41+
front_facing,
42+
)
43+
}
44+
45+
pub(crate) const fn encode_virtual(
46+
draw_index: u32,
47+
primitive_id: u32,
48+
front_facing: bool,
49+
) -> Option<Self> {
50+
Self::encode_draw(
51+
VisibilityDraw::Virtual(draw_index),
52+
primitive_id,
53+
front_facing,
54+
)
55+
}
56+
57+
pub(crate) const fn encode_draw(
58+
draw: VisibilityDraw,
59+
primitive_id: u32,
60+
front_facing: bool,
61+
) -> Option<Self> {
62+
if primitive_id > PRIMITIVE_ID_MASK {
63+
return None;
64+
}
65+
let draw_id = match draw {
66+
VisibilityDraw::Compatibility(index) if index <= DRAW_INDEX_MASK => index,
67+
VisibilityDraw::Virtual(index) if index <= MAX_VIRTUAL_DRAW_INDEX => {
68+
VIRTUAL_DRAW_BIT | index
69+
}
70+
_ => return None,
71+
};
72+
Some(Self {
73+
draw_id,
74+
primitive_and_face: primitive_id | if front_facing { FRONT_FACE_BIT } else { 0 },
75+
})
76+
}
77+
78+
pub(crate) const fn decode(self) -> Option<(u32, u32, bool)> {
79+
if self.draw_id == INVALID_DRAW_ID {
80+
return None;
81+
}
82+
Some((
83+
self.draw_id,
84+
self.primitive_and_face & PRIMITIVE_ID_MASK,
85+
(self.primitive_and_face & FRONT_FACE_BIT) != 0,
86+
))
87+
}
88+
89+
pub(crate) const fn decode_draw(self) -> Option<(VisibilityDraw, u32, bool)> {
90+
let (_, primitive, front) = match self.decode() {
91+
Some(decoded) => decoded,
92+
None => return None,
93+
};
94+
let draw = if self.draw_id & VIRTUAL_DRAW_BIT == 0 {
95+
VisibilityDraw::Compatibility(self.draw_id)
96+
} else {
97+
VisibilityDraw::Virtual(self.draw_id & DRAW_INDEX_MASK)
98+
};
99+
Some((draw, primitive, front))
100+
}
101+
}
102+
103+
#[cfg(test)]
104+
mod tests {
105+
use super::*;
106+
107+
#[test]
108+
fn compatibility_and_virtual_draws_never_alias_or_hit_background() {
109+
let compatibility =
110+
VisibilityRecord::encode(DRAW_INDEX_MASK, PRIMITIVE_ID_MASK, false).unwrap();
111+
let virtual_draw =
112+
VisibilityRecord::encode_virtual(MAX_VIRTUAL_DRAW_INDEX, 19, true).unwrap();
113+
assert_eq!(
114+
compatibility.decode_draw(),
115+
Some((
116+
VisibilityDraw::Compatibility(DRAW_INDEX_MASK),
117+
PRIMITIVE_ID_MASK,
118+
false,
119+
))
120+
);
121+
assert_eq!(
122+
virtual_draw.decode_draw(),
123+
Some((VisibilityDraw::Virtual(MAX_VIRTUAL_DRAW_INDEX), 19, true,))
124+
);
125+
assert_ne!(compatibility.draw_id, virtual_draw.draw_id);
126+
assert_ne!(virtual_draw.draw_id, INVALID_DRAW_ID);
127+
assert_eq!(VisibilityRecord::BACKGROUND.decode_draw(), None);
128+
assert_eq!(VisibilityRecord::encode(VIRTUAL_DRAW_BIT, 0, true), None);
129+
assert_eq!(
130+
VisibilityRecord::encode_virtual(DRAW_INDEX_MASK, 0, true),
131+
None
132+
);
133+
}
134+
}

0 commit comments

Comments
 (0)