Skip to main content

viewport_lib/renderer/
paths.rs

1use super::{FrameData, SceneEffects, ViewportId, ViewportRenderer};
2
3/// Token returned by `prepare_scene` and required by `prepare_viewport`.
4///
5/// Enforces call ordering at compile time: `prepare_viewport` cannot be called
6/// without a token from a prior `prepare_scene` in the same frame. A single
7/// token may be borrowed multiple times in the same frame to prepare multiple
8/// viewports over a shared scene.
9pub struct ScenePreparedToken {
10    _private: (),
11}
12
13/// Rendering path for applications that own the window loop and wgpu encoder.
14///
15/// Obtained from [`ViewportRenderer::owned`]. The renderer encodes all GPU work
16/// and returns a [`wgpu::CommandBuffer`] for the caller to submit.
17///
18/// Use this with winit, raw wgpu, or any setup where you control the encoder.
19pub struct OwnedPath<'r> {
20    pub(super) renderer: &'r mut ViewportRenderer,
21}
22
23/// Rendering path for framework callbacks that provide a render pass.
24///
25/// Obtained from [`ViewportRenderer::pass`]. Prepare encodes pre-pass work
26/// and returns command buffers to submit before the surface pass. Paint draws
27/// into the caller-provided render pass.
28///
29/// Use this with eframe (`CallbackTrait`), iced, or any framework that hands
30/// you a render pass. For the eframe `paint` callback where only a `&` reference
31/// to the renderer is available, use [`ViewportRenderer::pass_view`] instead.
32pub struct PassPath<'r> {
33    pub(super) renderer: &'r mut ViewportRenderer,
34}
35
36/// Read-only paint view returned by [`ViewportRenderer::pass_view`].
37///
38/// Identical to [`PassPath`] but constructed from a shared reference, making it
39/// usable in framework paint callbacks where only `&` access to the renderer is
40/// available (e.g. eframe's `CallbackTrait::paint`).
41pub struct PassView<'r> {
42    pub(super) renderer: &'r ViewportRenderer,
43}
44
45impl<'r> OwnedPath<'r> {
46    /// Render a single viewport. Runs prepare internally and returns a command buffer to submit.
47    pub fn render(
48        &mut self,
49        device: &wgpu::Device,
50        queue: &wgpu::Queue,
51        output_view: &wgpu::TextureView,
52        frame: &FrameData,
53    ) -> wgpu::CommandBuffer {
54        self.renderer.render(device, queue, output_view, frame)
55    }
56
57    /// Multi-viewport: upload scene-level GPU data shared across all viewports.
58    ///
59    /// Call once per frame before any `prepare_viewport` or `render_viewport` calls.
60    /// Returns a [`ScenePreparedToken`] that must be passed to each `prepare_viewport`
61    /// call in the same frame. The token may be borrowed multiple times for multi-viewport scenes.
62    pub fn prepare_scene(
63        &mut self,
64        device: &wgpu::Device,
65        queue: &wgpu::Queue,
66        frame: &FrameData,
67        scene_effects: &SceneEffects<'_>,
68    ) -> ScenePreparedToken {
69        self.renderer.prepare_scene(device, queue, frame, scene_effects);
70        ScenePreparedToken { _private: () }
71    }
72
73    /// Multi-viewport: upload per-viewport GPU data for `id`.
74    ///
75    /// Call after `prepare_scene` and before `render_viewport`. The `_token` parameter
76    /// is a borrow of the [`ScenePreparedToken`] returned by `prepare_scene`; it enforces
77    /// that `prepare_scene` has been called earlier in the same frame.
78    pub fn prepare_viewport(
79        &mut self,
80        device: &wgpu::Device,
81        queue: &wgpu::Queue,
82        _token: &ScenePreparedToken,
83        id: ViewportId,
84        frame: &FrameData,
85    ) {
86        self.renderer.prepare_viewport(device, queue, id, frame);
87    }
88
89    /// Multi-viewport: encode draw calls for `id` into its own command buffer.
90    /// Call after `prepare_scene` and `prepare_viewport` for this id.
91    pub fn render_viewport(
92        &mut self,
93        device: &wgpu::Device,
94        queue: &wgpu::Queue,
95        output_view: &wgpu::TextureView,
96        id: ViewportId,
97        frame: &FrameData,
98    ) -> wgpu::CommandBuffer {
99        self.renderer.render_viewport(device, queue, output_view, id, frame)
100    }
101}
102
103impl<'r> PassPath<'r> {
104    /// Single viewport: upload uniforms and encode any HDR pre-pass work.
105    ///
106    /// Returns command buffers that must be submitted before the surface render
107    /// pass begins. Returns an empty vec for LDR with no dynamic resolution.
108    pub fn prepare(
109        &mut self,
110        device: &wgpu::Device,
111        queue: &wgpu::Queue,
112        frame: &FrameData,
113    ) -> Vec<wgpu::CommandBuffer> {
114        self.renderer.prepare_callback(device, queue, frame)
115    }
116
117    /// Single viewport: issue draw calls into `render_pass`.
118    ///
119    /// Call after `prepare` for the same frame. Dispatches to the HDR blit,
120    /// dynamic-resolution blit, or direct draw based on which path `prepare`
121    /// activated. The render pass is expected to have a depth-stencil attachment,
122    /// as provided by eframe and most GUI frameworks.
123    pub fn paint<'rp>(&self, render_pass: &mut wgpu::RenderPass<'rp>, frame: &FrameData) {
124        self.renderer.paint_callback(render_pass, frame);
125    }
126
127    /// Multi-viewport: upload scene-level GPU data shared across all viewports.
128    ///
129    /// Call once per frame before any `prepare_viewport` calls. Returns a
130    /// [`ScenePreparedToken`] that must be passed to each `prepare_viewport` call
131    /// in the same frame. The token may be borrowed multiple times for multi-viewport scenes.
132    pub fn prepare_scene(
133        &mut self,
134        device: &wgpu::Device,
135        queue: &wgpu::Queue,
136        frame: &FrameData,
137        scene_effects: &SceneEffects<'_>,
138    ) -> ScenePreparedToken {
139        self.renderer.prepare_scene(device, queue, frame, scene_effects);
140        ScenePreparedToken { _private: () }
141    }
142
143    /// Multi-viewport: upload per-viewport GPU data for `id`.
144    ///
145    /// Call after `prepare_scene` and before `paint_viewport` or `prepare_hdr_viewport`.
146    /// The `_token` parameter is a borrow of the [`ScenePreparedToken`] returned by
147    /// `prepare_scene`; it enforces that `prepare_scene` has been called earlier in the same frame.
148    pub fn prepare_viewport(
149        &mut self,
150        device: &wgpu::Device,
151        queue: &wgpu::Queue,
152        _token: &ScenePreparedToken,
153        id: ViewportId,
154        frame: &FrameData,
155    ) {
156        self.renderer.prepare_viewport(device, queue, id, frame);
157    }
158
159    /// Multi-viewport: issue draw calls for `id` into `render_pass`.
160    ///
161    /// Set the render pass viewport and scissor rect to the correct region
162    /// before calling. Call after `prepare_scene` and `prepare_viewport`.
163    pub fn paint_viewport<'rp>(
164        &self,
165        render_pass: &mut wgpu::RenderPass<'rp>,
166        id: ViewportId,
167        frame: &FrameData,
168    ) {
169        self.renderer.paint_viewport_to(render_pass, id, frame);
170    }
171
172    /// Multi-viewport HDR: encode the full HDR pipeline for `id` into an intermediate texture.
173    ///
174    /// Call after `prepare_scene` and `prepare_viewport` for this viewport. Returns a
175    /// `CommandBuffer` that eframe must submit before the egui render pass begins.
176    ///
177    /// Call [`PassView::paint_hdr_blit`] from `CallbackTrait::paint` to composite the
178    /// result into the egui render pass. Set the render pass viewport and scissor rect first.
179    pub fn prepare_hdr_viewport(
180        &mut self,
181        device: &wgpu::Device,
182        queue: &wgpu::Queue,
183        id: ViewportId,
184        frame: &FrameData,
185    ) -> wgpu::CommandBuffer {
186        self.renderer.prepare_hdr_callback_viewport(device, queue, id, frame)
187    }
188}
189
190impl<'r> PassView<'r> {
191    /// Single viewport: issue draw calls into `render_pass`.
192    pub fn paint<'rp>(&self, render_pass: &mut wgpu::RenderPass<'rp>, frame: &FrameData) {
193        self.renderer.paint_callback(render_pass, frame);
194    }
195
196    /// Multi-viewport: issue draw calls for `id` into `render_pass`.
197    pub fn paint_viewport<'rp>(
198        &self,
199        render_pass: &mut wgpu::RenderPass<'rp>,
200        id: ViewportId,
201        frame: &FrameData,
202    ) {
203        self.renderer.paint_viewport_to(render_pass, id, frame);
204    }
205
206    /// Multi-viewport HDR: blit the intermediate texture for `frame`'s viewport into `render_pass`.
207    ///
208    /// Call after [`PassPath::prepare_hdr_viewport`] for the same viewport. Set the render
209    /// pass viewport and scissor rect to the correct region before calling.
210    ///
211    /// The render pass must have a `Depth24PlusStencil8` depth-stencil attachment (as eframe
212    /// callbacks always do). For render passes without a depth attachment (e.g. a plain winit
213    /// blit pass), use [`paint_hdr_blit_no_ds`](Self::paint_hdr_blit_no_ds) instead.
214    pub fn paint_hdr_blit<'rp>(&self, render_pass: &mut wgpu::RenderPass<'rp>, frame: &FrameData) {
215        self.renderer.paint_hdr_blit(render_pass, frame);
216    }
217
218    /// Like [`paint_hdr_blit`] but for render passes without a depth-stencil attachment.
219    ///
220    /// Use this when you create the blit render pass yourself (e.g. winit) and the pass
221    /// has no depth attachment. The resulting blit is identical; only the pipeline variant
222    /// differs to match the render pass format.
223    pub fn paint_hdr_blit_no_ds<'rp>(&self, render_pass: &mut wgpu::RenderPass<'rp>, frame: &FrameData) {
224        self.renderer.paint_hdr_blit_no_ds(render_pass, frame);
225    }
226}