rafx_framework/render_features/jobs/extract/
extract_job.rs

1use super::RenderObjectInstance;
2use crate::render_features::render_features_prelude::*;
3use std::marker::PhantomData;
4use std::ops::Range;
5
6/// An `ExtractJob` implements the `RenderFeatureExtractJob` trait by wrapping an instance
7/// of an `ExtractJobEntryPoints` type defined at compile-time. The `ExtractJob` contains
8/// the frame packet and presents the correct context (like `ExtractPerFrameContext`) to each
9/// entry point defined in `ExtractJobEntryPoints`.
10pub struct ExtractJob<'extract, ExtractJobEntryPointsT: ExtractJobEntryPoints<'extract>> {
11    inner: ExtractJobEntryPointsT,
12    extract_context: RenderJobExtractContext<'extract>,
13    frame_packet: Option<Box<FramePacket<ExtractJobEntryPointsT::FramePacketDataT>>>,
14    #[allow(dead_code)]
15    debug_constants: &'static RenderFeatureDebugConstants,
16    _phantom: (PhantomData<&'extract ()>,),
17}
18
19impl<'extract, ExtractJobEntryPointsT: 'extract + ExtractJobEntryPoints<'extract>>
20    ExtractJob<'extract, ExtractJobEntryPointsT>
21{
22    pub fn new(
23        inner: ExtractJobEntryPointsT,
24        extract_context: &RenderJobExtractContext<'extract>,
25        frame_packet: Box<FramePacket<ExtractJobEntryPointsT::FramePacketDataT>>,
26    ) -> Self {
27        let debug_constants = inner.feature_debug_constants();
28        Self {
29            inner,
30            extract_context: extract_context.clone(),
31            frame_packet: Some(frame_packet),
32            debug_constants,
33            _phantom: Default::default(),
34        }
35    }
36
37    fn frame_packet(&self) -> &Option<Box<FramePacket<ExtractJobEntryPointsT::FramePacketDataT>>> {
38        &self.frame_packet
39    }
40
41    fn view_packets(&self) -> &Vec<ViewPacket<ExtractJobEntryPointsT::FramePacketDataT>> {
42        &self.frame_packet.as_ref().unwrap().view_packets()
43    }
44
45    fn render_object_instances(&self) -> &Vec<RenderObjectInstance> {
46        &self
47            .frame_packet
48            .as_ref()
49            .unwrap()
50            .render_object_instances()
51    }
52
53    fn force_to_extract_lifetime(
54        &self,
55        inner: &ExtractJobEntryPointsT,
56    ) -> &'extract ExtractJobEntryPointsT {
57        unsafe {
58            // SAFETY: The 'extract lifetime added here is already required by the ExtractJobEntryPointsT.
59            // This transmute is just avoiding the need to proliferate even _more_ 'extract lifetimes through
60            // _every single function_.
61            std::mem::transmute::<_, &'extract ExtractJobEntryPointsT>(inner)
62        }
63    }
64}
65
66impl<'extract, ExtractJobEntryPointsT: 'extract + ExtractJobEntryPoints<'extract>>
67    RenderFeatureExtractJob<'extract> for ExtractJob<'extract, ExtractJobEntryPointsT>
68{
69    fn begin_per_frame_extract(&self) {
70        profiling::scope!(self.debug_constants.begin_per_frame_extract);
71
72        let context =
73            ExtractPerFrameContext::new(&self.extract_context, self.frame_packet.as_ref().unwrap());
74        self.inner.begin_per_frame_extract(&context);
75    }
76
77    fn extract_render_object_instance(
78        &self,
79        visibility_resource: &VisibilityResource,
80        range: Range<usize>,
81    ) {
82        if range.is_empty() {
83            return;
84        }
85
86        let mut job_context = {
87            let inner = self.force_to_extract_lifetime(&self.inner);
88            inner.new_render_object_instance_job_context()
89        };
90
91        if job_context.is_none() {
92            return;
93        }
94
95        profiling::scope!(self.debug_constants.extract_render_object_instance);
96
97        let job_context = job_context.as_mut().unwrap();
98        let frame_packet = self.frame_packet.as_ref().unwrap();
99        for id in range {
100            let context = ExtractRenderObjectInstanceContext::new(
101                &self.extract_context,
102                frame_packet,
103                visibility_resource,
104                id,
105            );
106            self.inner
107                .extract_render_object_instance(job_context, &context);
108        }
109    }
110
111    fn view_packet(
112        &self,
113        view_index: ViewFrameIndex,
114    ) -> &dyn RenderFeatureViewPacket {
115        self.frame_packet()
116            .as_ref()
117            .unwrap()
118            .render_feature_view_packet(view_index)
119    }
120
121    fn extract_render_object_instance_per_view(
122        &self,
123        view_packet: &dyn RenderFeatureViewPacket,
124        visibility_resource: &VisibilityResource,
125        range: Range<usize>,
126    ) {
127        if range.is_empty() {
128            return;
129        }
130
131        let mut job_context = {
132            let inner = self.force_to_extract_lifetime(&self.inner);
133            inner.new_render_object_instance_per_view_job_context()
134        };
135
136        if job_context.is_none() {
137            return;
138        }
139
140        profiling::scope!(self.debug_constants.extract_render_object_instance_per_view);
141
142        let job_context = job_context.as_mut().unwrap();
143        let frame_packet = self.frame_packet.as_ref().unwrap();
144        let view_packet: &ViewPacket<ExtractJobEntryPointsT::FramePacketDataT> =
145            view_packet.as_concrete();
146
147        for id in range {
148            let context = ExtractRenderObjectInstancePerViewContext::new(
149                &self.extract_context,
150                frame_packet,
151                view_packet,
152                visibility_resource,
153                id,
154            );
155            self.inner
156                .extract_render_object_instance_per_view(job_context, &context);
157        }
158    }
159
160    fn end_per_view_extract(
161        &self,
162        view_packet: &dyn RenderFeatureViewPacket,
163    ) {
164        profiling::scope!(self.debug_constants.end_per_view_extract);
165
166        let view_packet: &ViewPacket<ExtractJobEntryPointsT::FramePacketDataT> =
167            view_packet.as_concrete();
168
169        let context = ExtractPerViewContext::new(
170            &self.extract_context,
171            self.frame_packet.as_ref().unwrap(),
172            view_packet,
173        );
174        self.inner.end_per_view_extract(&context);
175    }
176
177    fn end_per_frame_extract(&self) {
178        profiling::scope!(self.debug_constants.end_per_frame_extract);
179
180        let context =
181            ExtractPerFrameContext::new(&self.extract_context, self.frame_packet.as_ref().unwrap());
182        self.inner.end_per_frame_extract(&context);
183    }
184
185    fn num_views(&self) -> usize {
186        self.view_packets().len()
187    }
188
189    fn num_render_object_instances(&self) -> usize {
190        self.render_object_instances().len()
191    }
192
193    fn take_frame_packet(&mut self) -> Box<dyn RenderFeatureFramePacket> {
194        std::mem::take(&mut self.frame_packet).unwrap()
195    }
196
197    fn feature_debug_constants(&self) -> &'static RenderFeatureDebugConstants {
198        self.inner.feature_debug_constants()
199    }
200
201    fn feature_index(&self) -> RenderFeatureIndex {
202        self.inner.feature_index()
203    }
204}