Skip to main content

pfx_editor_viewport/
live.rs

1use std::collections::BTreeMap;
2
3use egui::TextureId;
4use pfx_gpu::{Gpu, wgpu};
5use pfx_live::demand::{Limits, Need, Next};
6use pfx_live::renderer::{Exposure, Renderer};
7use pfx_live::scene::{Override, Staged};
8use pfx_load::scene::{Camera, Scene, SceneDiff};
9
10pub const FORMAT: wgpu::TextureFormat = wgpu::TextureFormat::Rgba8UnormSrgb;
11pub const SHOWN: wgpu::TextureFormat = wgpu::TextureFormat::Rgba8Unorm;
12pub const IN_FLIGHT: u64 = 1;
13
14#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
15pub struct Drawn {
16    pub drew: bool,
17    pub picked: Option<u32>,
18    pub awaiting: bool,
19}
20
21struct Surface {
22    texture: wgpu::Texture,
23    view: wgpu::TextureView,
24    shown: wgpu::TextureView,
25}
26
27fn surface(gpu: &Gpu, size: [u32; 2]) -> Surface {
28    let texture = gpu.device.create_texture(&wgpu::TextureDescriptor {
29        label: Some("editor viewport"),
30        size: wgpu::Extent3d {
31            width: size[0],
32            height: size[1],
33            depth_or_array_layers: 1,
34        },
35        mip_level_count: 1,
36        sample_count: 1,
37        dimension: wgpu::TextureDimension::D2,
38        format: FORMAT,
39        usage: wgpu::TextureUsages::RENDER_ATTACHMENT
40            | wgpu::TextureUsages::TEXTURE_BINDING
41            | wgpu::TextureUsages::COPY_SRC
42            | wgpu::TextureUsages::COPY_DST,
43        view_formats: &[SHOWN],
44    });
45    let view = texture.create_view(&wgpu::TextureViewDescriptor::default());
46    let shown = texture.create_view(&wgpu::TextureViewDescriptor {
47        format: Some(SHOWN),
48        ..wgpu::TextureViewDescriptor::default()
49    });
50    Surface {
51        texture,
52        view,
53        shown,
54    }
55}
56
57pub struct Live {
58    gpu: Gpu,
59    renderer: Renderer,
60    staged: Staged,
61    scene: Scene,
62    revision: u64,
63    camera: Camera,
64    surface: Surface,
65    id: TextureId,
66    size: [u32; 2],
67    awaiting: bool,
68    drawn: u64,
69}
70
71fn aspect(size: [u32; 2]) -> f32 {
72    size[0].max(1) as f32 / size[1].max(1) as f32
73}
74
75impl Live {
76    pub fn new(
77        gpu: &Gpu,
78        egui: &mut egui_wgpu::Renderer,
79        scene: &Scene,
80        revision: u64,
81        camera: Camera,
82        size: [u32; 2],
83    ) -> Result<Live, String> {
84        let mut renderer = Renderer::new_with_output_format(gpu.clone(), size[0], size[1], FORMAT)
85            .map_err(|error| format!("the live renderer could not start: {error}"))?;
86        renderer.set_exposure(Exposure::Fixed(1.0))?;
87        renderer.set_frames_on_demand(Some(Limits::default()))?;
88        let mut shown = scene.clone();
89        shown.camera = Some(camera);
90        let staged = renderer.stage(&shown)?;
91        renderer.wait_sky()?;
92        renderer.set_lens(staged.lens(aspect(size)));
93        let surface = surface(gpu, size);
94        let id =
95            egui.register_native_texture(&gpu.device, &surface.shown, wgpu::FilterMode::Nearest);
96        Ok(Live {
97            gpu: gpu.clone(),
98            renderer,
99            staged,
100            scene: shown,
101            revision,
102            camera,
103            surface,
104            id,
105            size,
106            awaiting: false,
107            drawn: 0,
108        })
109    }
110
111    pub fn texture(&self) -> TextureId {
112        self.id
113    }
114
115    pub fn size(&self) -> [u32; 2] {
116        self.size
117    }
118
119    pub fn revision(&self) -> u64 {
120        self.revision
121    }
122
123    pub fn drawn(&self) -> u64 {
124        self.drawn
125    }
126
127    pub fn staged(&self) -> &Staged {
128        &self.staged
129    }
130
131    pub fn image(&self) -> &wgpu::Texture {
132        &self.surface.texture
133    }
134
135    pub fn resize(
136        &mut self,
137        egui: &mut egui_wgpu::Renderer,
138        size: [u32; 2],
139    ) -> Result<bool, String> {
140        if size == self.size {
141            return Ok(false);
142        }
143        self.renderer.resize(size[0], size[1])?;
144        self.surface = surface(&self.gpu, size);
145        egui.update_egui_texture_from_wgpu_texture(
146            &self.gpu.device,
147            &self.surface.shown,
148            wgpu::FilterMode::Nearest,
149            self.id,
150        );
151        self.size = size;
152        self.renderer.set_lens(self.staged.lens(aspect(size)));
153        Ok(true)
154    }
155
156    pub fn show(&mut self, scene: &Scene, revision: u64) -> Result<(), String> {
157        let mut next = scene.clone();
158        next.camera = self.scene.camera;
159        let diff = self.scene.diff(&next);
160        self.staged.apply(&mut self.renderer, &next, &diff)?;
161        self.scene = next;
162        self.revision = revision;
163        Ok(())
164    }
165
166    pub fn look(&mut self, camera: Camera) -> Result<(), String> {
167        if self.camera == camera {
168            return Ok(());
169        }
170        self.scene.camera = Some(camera);
171        let diff = SceneDiff {
172            camera: true,
173            ..SceneDiff::default()
174        };
175        self.staged.apply(&mut self.renderer, &self.scene, &diff)?;
176        self.renderer.set_lens(self.staged.lens(aspect(self.size)));
177        self.camera = camera;
178        Ok(())
179    }
180
181    pub fn overrides(&mut self, wanted: &BTreeMap<String, Override>) {
182        let gone: Vec<String> = self
183            .staged
184            .overrides()
185            .keys()
186            .filter(|name| !wanted.contains_key(*name))
187            .cloned()
188            .collect();
189        for name in gone {
190            self.staged.clear_override(&name);
191        }
192        for (name, change) in wanted {
193            if self.staged.overrides().get(name) != Some(change) {
194                self.staged.set_override(name, *change);
195            }
196        }
197    }
198
199    pub fn gpu_ms(&self) -> Option<f64> {
200        self.renderer
201            .timings()
202            .filter(|timings| !timings.passes.is_empty())
203            .map(|timings| timings.passes.iter().map(|t| t.milliseconds).sum())
204    }
205
206    pub fn drops(&self) -> u64 {
207        let drops = self.renderer.timing_drops();
208        drops.ring + drops.late
209    }
210
211    pub fn draw(&mut self, pick: Option<[u32; 2]>) -> Result<Drawn, String> {
212        let mut drawn = Drawn::default();
213        if self.awaiting
214            && let Some(picked) = self.renderer.picked()
215        {
216            self.awaiting = false;
217            drawn.picked = Some(picked.id);
218        }
219        let size = self.size;
220        let finish = self.staged.finish();
221        let frame = self.staged.frame(aspect(size), 0.0, 0);
222        let next = Next::new(&frame.scene, &frame.text, &frame.effects, finish);
223        if let Some([x, y]) = pick {
224            self.renderer.pick(x.min(size[0] - 1), y.min(size[1] - 1))?;
225            self.renderer
226                .render_needed(&next, &Need::Full, &self.surface.view)?;
227            match self.renderer.picked() {
228                Some(picked) => drawn.picked = Some(picked.id),
229                None => self.awaiting = true,
230            }
231            drawn.drew = true;
232        } else {
233            let need = self.renderer.frame_needed(&next);
234            if need.draws() {
235                if self.renderer.frames_in_flight() >= IN_FLIGHT {
236                    self.renderer.wait_frames(IN_FLIGHT - 1)?;
237                }
238                self.renderer
239                    .submit_needed(&next, &need, &self.surface.view)?;
240                drawn.drew = true;
241            }
242        }
243        if drawn.drew {
244            self.drawn += 1;
245        }
246        drawn.awaiting = self.awaiting;
247        Ok(drawn)
248    }
249}