rafx_framework/render_features/
render_views.rs

1use crate::render_features::registry::MAX_RENDER_FEATURE_COUNT;
2use crate::render_features::{
3    RenderFeature, RenderFeatureFlag, RenderFeatureFlagMask, RenderFeatureIndex, RenderFeatureMask,
4    RenderPhase, RenderPhaseIndex, RenderPhaseMask, ViewFrameIndex,
5};
6use crate::visibility::ViewFrustumArc;
7use glam::{Mat4, Vec3};
8use rafx_visibility::{DepthRange, Projection};
9use std::mem::MaybeUninit;
10use std::sync::atomic::Ordering;
11use std::sync::atomic::{AtomicI32, AtomicU32};
12use std::sync::Arc;
13
14pub type RenderViewIndex = u32;
15pub type RenderViewCount = u32;
16
17pub struct RenderViewSet {
18    view_count: AtomicU32,
19    frame_index: usize,
20}
21
22impl RenderViewSet {
23    pub fn new(frame_index: usize) -> Self {
24        RenderViewSet {
25            view_count: Default::default(),
26            frame_index,
27        }
28    }
29
30    pub fn create_view(
31        &self,
32        view_frustum: ViewFrustumArc,
33        eye_position: Vec3,
34        view: Mat4,
35        proj: Mat4,
36        extents: (u32, u32),
37        depth_range: RenderViewDepthRange,
38        render_phase_mask: RenderPhaseMask,
39        render_feature_mask: RenderFeatureMask,
40        render_feature_flag_mask: RenderFeatureFlagMask,
41        debug_name: String,
42    ) -> RenderView {
43        let view_index = self.view_count.fetch_add(1, Ordering::Release);
44        RenderView::new(
45            view_frustum,
46            view_index,
47            eye_position,
48            view,
49            proj,
50            extents,
51            depth_range,
52            render_phase_mask,
53            render_feature_mask,
54            render_feature_flag_mask,
55            debug_name,
56            self.frame_index,
57        )
58    }
59
60    pub fn view_count(&self) -> RenderViewCount {
61        self.view_count.load(Ordering::Acquire)
62    }
63}
64
65////////////////// Views //////////////////
66pub struct RenderViewInner {
67    view_frustum: ViewFrustumArc,
68    eye_position: Vec3,
69    view: Mat4,
70    proj: Mat4,
71    view_proj: Mat4,
72    view_dir: Vec3,
73    view_index: RenderViewIndex,
74    view_frame_indices: [AtomicI32; MAX_RENDER_FEATURE_COUNT as usize],
75    // XY of the plane in screen coordinates, the size the framebuffer would be for 1:1
76    extents: (u32, u32),
77    depth_range: RenderViewDepthRange,
78    render_phase_mask: RenderPhaseMask,
79    render_feature_mask: RenderFeatureMask,
80    render_feature_flag_mask: RenderFeatureFlagMask,
81    debug_name: String,
82    frame_index: usize,
83}
84
85#[derive(Clone)]
86pub struct RenderViewDepthRange {
87    pub near: f32,
88    pub far: Option<f32>, // If none, it's an infinite projection
89    pub reversed: bool,
90}
91
92impl RenderViewDepthRange {
93    pub fn new(
94        near: f32,
95        far: f32,
96    ) -> Self {
97        RenderViewDepthRange {
98            near,
99            far: Some(far),
100            reversed: false,
101        }
102    }
103
104    pub fn from_projection(projection: &Projection) -> Self {
105        let near = projection.near_distance();
106        let far = projection.far_distance();
107        match projection.depth_range() {
108            DepthRange::Normal => RenderViewDepthRange::new(near, far),
109            DepthRange::Infinite => RenderViewDepthRange::new_infinite(near),
110            DepthRange::Reverse => RenderViewDepthRange::new_reverse(near, far),
111            DepthRange::InfiniteReverse => RenderViewDepthRange::new_infinite_reverse(near),
112        }
113    }
114
115    pub fn new_infinite(near: f32) -> Self {
116        RenderViewDepthRange {
117            near,
118            far: None,
119            reversed: false,
120        }
121    }
122
123    pub fn new_reverse(
124        near: f32,
125        far: f32,
126    ) -> Self {
127        RenderViewDepthRange {
128            near,
129            far: Some(far),
130            reversed: true,
131        }
132    }
133
134    pub fn new_infinite_reverse(near: f32) -> Self {
135        RenderViewDepthRange {
136            near,
137            far: None,
138            reversed: true,
139        }
140    }
141
142    // If the view is a reversed view, return the values reversed. This is handy for cases where
143    // the math works nicely by flipping the near/far for a reverse.
144    pub fn planes_after_reverse(&self) -> (Option<f32>, Option<f32>) {
145        if self.reversed {
146            (self.far, Some(self.near))
147        } else {
148            (Some(self.near), self.far)
149        }
150    }
151
152    pub fn finite_planes_after_reverse(&self) -> Option<(f32, f32)> {
153        if self.reversed {
154            Some((self.far?, self.near))
155        } else {
156            Some((self.near, self.far?))
157        }
158    }
159
160    pub fn planes_before_reverse(&self) -> (f32, Option<f32>) {
161        (self.near, self.far)
162    }
163}
164
165// This creates a `[AtomicI32; MAX_RENDER_FEATURE_COUNT as usize]` where all values are -1.
166fn init_view_frame_indices() -> [AtomicI32; MAX_RENDER_FEATURE_COUNT as usize] {
167    let mut view_count_by_feature: [MaybeUninit<AtomicI32>; MAX_RENDER_FEATURE_COUNT as usize] =
168        unsafe { MaybeUninit::uninit().assume_init() };
169
170    for data in &mut view_count_by_feature {
171        data.write(AtomicI32::new(-1));
172    }
173
174    unsafe { std::mem::transmute(view_count_by_feature) }
175}
176
177/// The `Renderer` processes `RenderView`s during the execution of the `RenderGraph`. Each
178/// `RenderView` is associated with a specific `ViewFrustum` in the game world. The `RenderView`
179/// may be registered for specific `RenderFeature`s by a `RenderFeatureMask` or `RenderPhase`s by
180/// the `RenderPhaseMask`. If a `RenderView` is not registered for a `RenderFeature` or `RenderPhase`
181/// then it will not be processed by that feature or phase.
182#[derive(Clone)]
183pub struct RenderView {
184    inner: Arc<RenderViewInner>,
185}
186
187impl RenderView {
188    // Exposed publically as it's used downstream and want to make sure the logic stays in sync
189    pub fn view_mat4_to_view_dir(view: &glam::Mat4) -> glam::Vec3 {
190        glam::Vec3::new(view.x_axis.z, view.y_axis.z, view.z_axis.z) * -1.0
191    }
192
193    pub fn new(
194        view_frustum: ViewFrustumArc,
195        view_index: RenderViewIndex,
196        eye_position: Vec3,
197        view: Mat4,
198        proj: Mat4,
199        extents: (u32, u32),
200        depth_range: RenderViewDepthRange,
201        render_phase_mask: RenderPhaseMask,
202        render_feature_mask: RenderFeatureMask,
203        render_feature_flag_mask: RenderFeatureFlagMask,
204        debug_name: String,
205        frame_index: usize,
206    ) -> RenderView {
207        let view_dir = Self::view_mat4_to_view_dir(&view);
208
209        let inner = RenderViewInner {
210            view_frustum,
211            eye_position,
212            view,
213            proj,
214            view_proj: proj * view,
215            view_dir,
216            view_index,
217            view_frame_indices: init_view_frame_indices(),
218            extents,
219            depth_range,
220            render_phase_mask,
221            render_feature_mask,
222            render_feature_flag_mask,
223            debug_name,
224            frame_index,
225        };
226
227        RenderView {
228            inner: Arc::new(inner),
229        }
230    }
231
232    pub fn frame_index(&self) -> usize {
233        self.inner.frame_index
234    }
235
236    pub fn view_frustum(&self) -> ViewFrustumArc {
237        self.inner.view_frustum.clone()
238    }
239
240    pub fn eye_position(&self) -> Vec3 {
241        self.inner.eye_position
242    }
243
244    pub fn view_dir(&self) -> Vec3 {
245        self.inner.view_dir
246    }
247
248    pub fn view_matrix(&self) -> Mat4 {
249        self.inner.view
250    }
251
252    pub fn projection_matrix(&self) -> Mat4 {
253        self.inner.proj
254    }
255
256    pub fn view_proj(&self) -> Mat4 {
257        self.inner.view_proj
258    }
259
260    pub fn view_index(&self) -> RenderViewIndex {
261        self.inner.view_index
262    }
263
264    pub fn set_view_frame_index(
265        &self,
266        feature_index: RenderFeatureIndex,
267        view_frame_index: ViewFrameIndex,
268    ) {
269        let old_view_frame_index = self.inner.view_frame_indices[feature_index as usize]
270            .swap(view_frame_index as i32, Ordering::Relaxed);
271        assert!(old_view_frame_index == -1);
272    }
273
274    pub fn view_frame_index(
275        &self,
276        feature_index: RenderFeatureIndex,
277    ) -> Option<ViewFrameIndex> {
278        let view_frame_index =
279            self.inner.view_frame_indices[feature_index as usize].load(Ordering::Relaxed);
280        if view_frame_index != -1 {
281            Some(view_frame_index as ViewFrameIndex)
282        } else {
283            None
284        }
285    }
286
287    pub fn extents(&self) -> (u32, u32) {
288        self.inner.extents
289    }
290
291    pub fn extents_vec2(&self) -> glam::Vec2 {
292        glam::Vec2::new(self.inner.extents.0 as f32, self.inner.extents.1 as f32)
293    }
294
295    pub fn extents_width(&self) -> u32 {
296        self.inner.extents.0
297    }
298
299    pub fn extents_height(&self) -> u32 {
300        self.inner.extents.1
301    }
302
303    pub fn depth_range(&self) -> &RenderViewDepthRange {
304        &self.inner.depth_range
305    }
306
307    pub fn debug_name(&self) -> &str {
308        &self.inner.debug_name
309    }
310
311    pub fn phase_is_relevant<RenderPhaseT: RenderPhase>(&self) -> bool {
312        self.inner.render_phase_mask.is_included::<RenderPhaseT>()
313    }
314
315    pub fn phase_index_is_relevant(
316        &self,
317        phase_index: RenderPhaseIndex,
318    ) -> bool {
319        self.inner.render_phase_mask.is_included_index(phase_index)
320    }
321
322    pub fn render_phase_mask(&self) -> RenderPhaseMask {
323        self.inner.render_phase_mask
324    }
325
326    pub fn feature_is_relevant<RenderFeatureT: RenderFeature>(&self) -> bool {
327        self.inner
328            .render_feature_mask
329            .is_included::<RenderFeatureT>()
330    }
331
332    pub fn feature_index_is_relevant(
333        &self,
334        feature_index: RenderFeatureIndex,
335    ) -> bool {
336        self.inner
337            .render_feature_mask
338            .is_included_index(feature_index)
339    }
340
341    pub fn render_feature_mask(&self) -> RenderFeatureMask {
342        self.inner.render_feature_mask
343    }
344
345    pub fn is_relevant<RenderPhaseT: RenderPhase, RenderFeatureT: RenderFeature>(&self) -> bool {
346        self.phase_is_relevant::<RenderPhaseT>() && self.feature_is_relevant::<RenderFeatureT>()
347    }
348
349    pub fn index_is_relevant(
350        &self,
351        phase_index: RenderPhaseIndex,
352        feature_index: RenderFeatureIndex,
353    ) -> bool {
354        self.phase_index_is_relevant(phase_index) && self.feature_index_is_relevant(feature_index)
355    }
356
357    pub fn feature_flag_is_relevant<RenderFeatureFlagT: RenderFeatureFlag>(&self) -> bool {
358        self.inner
359            .render_feature_flag_mask
360            .is_included::<RenderFeatureFlagT>()
361    }
362
363    pub fn feature_flag_index_is_relevant(
364        &self,
365        feature_flag_index: RenderFeatureIndex,
366    ) -> bool {
367        self.inner
368            .render_feature_flag_mask
369            .is_included_index(feature_flag_index)
370    }
371
372    pub fn render_feature_flag_mask(&self) -> RenderFeatureFlagMask {
373        self.inner.render_feature_flag_mask
374    }
375}