use super::passes;
impl super::WgpuRenderer {
pub(super) fn ensure_camera_viewport(
&mut self,
camera_entity: freecs::Entity,
width: u32,
height: u32,
) -> Option<egui::TextureId> {
if let Some(viewport) = self.camera_viewports.get(&camera_entity)
&& viewport.size == (width, height)
{
return Some(viewport.texture_id);
}
let existing_texture_id = self
.camera_viewports
.get(&camera_entity)
.map(|viewport| viewport.texture_id);
let texture = self.device.create_texture(&wgpu::TextureDescriptor {
label: Some(&format!("Viewport Texture (Camera {})", camera_entity.id)),
size: wgpu::Extent3d {
width,
height,
depth_or_array_layers: 1,
},
mip_level_count: 1,
sample_count: 1,
dimension: wgpu::TextureDimension::D2,
format: self.surface_format,
usage: wgpu::TextureUsages::TEXTURE_BINDING | wgpu::TextureUsages::RENDER_ATTACHMENT,
view_formats: &[],
});
let view = texture.create_view(&wgpu::TextureViewDescriptor::default());
let texture_id = if let Some(egui_pass) = self.graph.get_pass_mut("egui_pass")
&& let Some(egui_pass) =
(egui_pass as &mut dyn std::any::Any).downcast_mut::<passes::EguiPass>()
{
if let Some(existing_id) = existing_texture_id {
egui_pass.update_native_texture(&self.device, existing_id, &view);
existing_id
} else {
egui_pass.register_texture(&self.device, &view)
}
} else {
return None;
};
self.camera_viewports.insert(
camera_entity,
super::CameraViewport {
texture,
view,
texture_id,
size: (width, height),
},
);
Some(texture_id)
}
pub(super) fn prepare_egui_pass(
&mut self,
ui_output: &egui::FullOutput,
ui_primitives: &[egui::ClippedPrimitive],
) {
if let Some(egui_pass) = self.graph.get_pass_mut("egui_pass")
&& let Some(egui_pass) =
(egui_pass as &mut dyn std::any::Any).downcast_mut::<passes::EguiPass>()
{
egui_pass.update_textures(&self.device, &self.queue, &ui_output.textures_delta);
}
let screen_descriptor = egui_wgpu::ScreenDescriptor {
size_in_pixels: [self.surface_config.width, self.surface_config.height],
pixels_per_point: ui_output.pixels_per_point,
};
if let Some(egui_pass) = self.graph.get_pass_mut("egui_pass")
&& let Some(egui_pass) =
(egui_pass as &mut dyn std::any::Any).downcast_mut::<passes::EguiPass>()
{
egui_pass.set_screen_descriptor(screen_descriptor);
egui_pass.set_paint_jobs(ui_primitives.to_vec());
}
}
pub(super) fn render_egui_to_secondary_surface_impl(
&mut self,
id: usize,
ui_output: Option<egui::FullOutput>,
ui_primitives: Option<Vec<egui::ClippedPrimitive>>,
) -> Result<(), Box<dyn std::error::Error>> {
let Some(secondary) = self.secondary_surfaces.get_mut(&id) else {
return Ok(());
};
let Some(egui_renderer) = secondary.egui_renderer.as_mut() else {
return Ok(());
};
if let Some(egui::FullOutput {
ref textures_delta, ..
}) = ui_output
{
for (texture_id, image_delta) in &textures_delta.set {
egui_renderer.update_texture(&self.device, &self.queue, *texture_id, image_delta);
}
for texture_id in &textures_delta.free {
egui_renderer.free_texture(texture_id);
}
}
let width = secondary.width;
let height = secondary.height;
if let Some(ref paint_jobs) = ui_primitives {
let pixels_per_point = ui_output
.as_ref()
.map(|output| output.pixels_per_point)
.unwrap_or(1.0);
let screen_descriptor = egui_wgpu::ScreenDescriptor {
size_in_pixels: [width, height],
pixels_per_point,
};
let mut encoder = self
.device
.create_command_encoder(&wgpu::CommandEncoderDescriptor {
label: Some("Secondary Egui Prepare Encoder"),
});
egui_renderer.update_buffers(
&self.device,
&self.queue,
&mut encoder,
paint_jobs,
&screen_descriptor,
);
self.queue.submit(std::iter::once(encoder.finish()));
let surface_texture = match secondary.surface.get_current_texture() {
wgpu::CurrentSurfaceTexture::Success(frame)
| wgpu::CurrentSurfaceTexture::Suboptimal(frame) => frame,
wgpu::CurrentSurfaceTexture::Outdated => {
secondary.surface.configure(&self.device, &secondary.config);
match secondary.surface.get_current_texture() {
wgpu::CurrentSurfaceTexture::Success(frame)
| wgpu::CurrentSurfaceTexture::Suboptimal(frame) => frame,
other => {
panic!("Failed to get surface texture after reconfiguration: {other:?}")
}
}
}
_ => {
return Ok(());
}
};
let surface_view = surface_texture
.texture
.create_view(&wgpu::TextureViewDescriptor::default());
if secondary.egui_depth_size != (width, height)
|| secondary.egui_depth_texture.is_none()
{
let depth_texture = self.device.create_texture(&wgpu::TextureDescriptor {
label: Some("Secondary Egui Depth Texture"),
size: wgpu::Extent3d {
width,
height,
depth_or_array_layers: 1,
},
mip_level_count: 1,
sample_count: 1,
dimension: wgpu::TextureDimension::D2,
format: wgpu::TextureFormat::Depth32Float,
usage: wgpu::TextureUsages::RENDER_ATTACHMENT,
view_formats: &[],
});
let depth_view = depth_texture.create_view(&wgpu::TextureViewDescriptor::default());
secondary.egui_depth_texture = Some(depth_texture);
secondary.egui_depth_view = Some(depth_view);
secondary.egui_depth_size = (width, height);
}
let depth_stencil_attachment = secondary.egui_depth_view.as_ref().map(|view| {
wgpu::RenderPassDepthStencilAttachment {
view,
depth_ops: Some(wgpu::Operations {
load: wgpu::LoadOp::Clear(1.0),
store: wgpu::StoreOp::Discard,
}),
stencil_ops: None,
}
});
let mut encoder = self
.device
.create_command_encoder(&wgpu::CommandEncoderDescriptor {
label: Some("Secondary Egui Render Encoder"),
});
egui_renderer.render(
&mut encoder
.begin_render_pass(&wgpu::RenderPassDescriptor {
label: Some("Secondary Egui Pass"),
color_attachments: &[Some(wgpu::RenderPassColorAttachment {
view: &surface_view,
resolve_target: None,
ops: wgpu::Operations {
load: wgpu::LoadOp::Clear(wgpu::Color {
r: 0.1,
g: 0.1,
b: 0.1,
a: 1.0,
}),
store: wgpu::StoreOp::Store,
},
depth_slice: None,
})],
depth_stencil_attachment,
timestamp_writes: None,
occlusion_query_set: None,
multiview_mask: None,
})
.forget_lifetime(),
paint_jobs,
&screen_descriptor,
);
self.queue.submit(std::iter::once(encoder.finish()));
surface_texture.present();
}
Ok(())
}
pub(super) fn initialize_secondary_egui_impl(&mut self, id: usize) {
if let Some(secondary) = self.secondary_surfaces.get_mut(&id) {
let renderer = egui_wgpu::Renderer::new(
&self.device,
secondary.format,
egui_wgpu::RendererOptions {
depth_stencil_format: Some(wgpu::TextureFormat::Depth32Float),
msaa_samples: 1,
..Default::default()
},
);
secondary.egui_renderer = Some(renderer);
}
}
}