mirror of
https://github.com/emilk/egui.git
synced 2026-09-02 06:40:06 -04:00
WGPU implementation
This commit is contained in:
@@ -1518,6 +1518,9 @@ pub use glow_integration::run_glow;
|
|||||||
mod wgpu_integration {
|
mod wgpu_integration {
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
|
use egui::ViewportRender;
|
||||||
|
use winit::window::ResizeDirection;
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
/// State that is initialized when the application is first starts running via
|
/// State that is initialized when the application is first starts running via
|
||||||
@@ -1527,6 +1530,17 @@ mod wgpu_integration {
|
|||||||
painter: egui_wgpu::winit::Painter,
|
painter: egui_wgpu::winit::Painter,
|
||||||
integration: epi_integration::EpiIntegration,
|
integration: epi_integration::EpiIntegration,
|
||||||
app: Box<dyn epi::App>,
|
app: Box<dyn epi::App>,
|
||||||
|
windows: HashMap<
|
||||||
|
u64,
|
||||||
|
(
|
||||||
|
Option<winit::window::Window>,
|
||||||
|
Option<egui_winit::State>,
|
||||||
|
Option<Arc<Box<ViewportRender>>>,
|
||||||
|
u64,
|
||||||
|
ViewportBuilder,
|
||||||
|
),
|
||||||
|
>,
|
||||||
|
windows_id: HashMap<winit::window::WindowId, u64>,
|
||||||
}
|
}
|
||||||
|
|
||||||
struct WgpuWinitApp {
|
struct WgpuWinitApp {
|
||||||
@@ -1538,7 +1552,6 @@ mod wgpu_integration {
|
|||||||
|
|
||||||
/// Window surface state that's initialized when the app starts running via a Resumed event
|
/// Window surface state that's initialized when the app starts running via a Resumed event
|
||||||
/// and on Android will also be destroyed if the application is paused.
|
/// and on Android will also be destroyed if the application is paused.
|
||||||
window: Option<winit::window::Window>,
|
|
||||||
is_focused: bool,
|
is_focused: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1560,7 +1573,6 @@ mod wgpu_integration {
|
|||||||
app_name: app_name.to_owned(),
|
app_name: app_name.to_owned(),
|
||||||
native_options,
|
native_options,
|
||||||
running: None,
|
running: None,
|
||||||
window: None,
|
|
||||||
app_creator: Some(app_creator),
|
app_creator: Some(app_creator),
|
||||||
is_focused: true,
|
is_focused: true,
|
||||||
}
|
}
|
||||||
@@ -1571,23 +1583,38 @@ mod wgpu_integration {
|
|||||||
storage: Option<&dyn epi::Storage>,
|
storage: Option<&dyn epi::Storage>,
|
||||||
title: &str,
|
title: &str,
|
||||||
native_options: &NativeOptions,
|
native_options: &NativeOptions,
|
||||||
) -> std::result::Result<winit::window::Window, winit::error::OsError> {
|
) -> std::result::Result<(winit::window::Window, ViewportBuilder), winit::error::OsError>
|
||||||
|
{
|
||||||
let window_settings = epi_integration::load_window_settings(storage);
|
let window_settings = epi_integration::load_window_settings(storage);
|
||||||
let window_builder =
|
let window_builder =
|
||||||
epi_integration::window_builder(event_loop, title, native_options, window_settings);
|
epi_integration::window_builder(event_loop, title, native_options, window_settings);
|
||||||
let window = create_winit_window_builder(&window_builder).build(event_loop)?;
|
let window = create_winit_window_builder(&window_builder).build(event_loop)?;
|
||||||
epi_integration::apply_native_options_to_window(&window, native_options);
|
epi_integration::apply_native_options_to_window(&window, native_options);
|
||||||
Ok(window)
|
Ok((window, window_builder))
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(unsafe_code)]
|
fn build_windows(&mut self, event_loop: &EventLoopWindowTarget<UserEvent>) {
|
||||||
fn set_window(
|
let Some(running) = &mut self.running else {return};
|
||||||
&mut self,
|
|
||||||
window: winit::window::Window,
|
for (id, (window, state, _, _, builder)) in running.windows.iter_mut() {
|
||||||
) -> std::result::Result<(), egui_wgpu::WgpuError> {
|
if window.is_none() {
|
||||||
self.window = Some(window);
|
if let Ok(new_window) = create_winit_window_builder(&builder).build(event_loop)
|
||||||
|
{
|
||||||
|
running.windows_id.insert(new_window.id(), *id);
|
||||||
|
|
||||||
|
pollster::block_on(running.painter.set_window(*id, Some(&new_window)));
|
||||||
|
*window = Some(new_window);
|
||||||
|
*state = Some(egui_winit::State::new(event_loop));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_window(&mut self, id: u64) -> std::result::Result<(), egui_wgpu::WgpuError> {
|
||||||
if let Some(running) = &mut self.running {
|
if let Some(running) = &mut self.running {
|
||||||
pollster::block_on(running.painter.set_window(self.window.as_ref()))?;
|
if let Some((window, _, _, _, _)) = running.windows.get(&id) {
|
||||||
|
pollster::block_on(running.painter.set_window(id, window.as_ref().map(|w| w)))?;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@@ -1595,8 +1622,8 @@ mod wgpu_integration {
|
|||||||
#[allow(unsafe_code)]
|
#[allow(unsafe_code)]
|
||||||
#[cfg(target_os = "android")]
|
#[cfg(target_os = "android")]
|
||||||
fn drop_window(&mut self) -> std::result::Result<(), egui_wgpu::WgpuError> {
|
fn drop_window(&mut self) -> std::result::Result<(), egui_wgpu::WgpuError> {
|
||||||
self.window = None;
|
|
||||||
if let Some(running) = &mut self.running {
|
if let Some(running) = &mut self.running {
|
||||||
|
running.windows.remove(&0);
|
||||||
pollster::block_on(running.painter.set_window(None))?;
|
pollster::block_on(running.painter.set_window(None))?;
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
@@ -1607,99 +1634,104 @@ mod wgpu_integration {
|
|||||||
event_loop: &EventLoopWindowTarget<UserEvent>,
|
event_loop: &EventLoopWindowTarget<UserEvent>,
|
||||||
storage: Option<Box<dyn epi::Storage>>,
|
storage: Option<Box<dyn epi::Storage>>,
|
||||||
window: winit::window::Window,
|
window: winit::window::Window,
|
||||||
|
builder: ViewportBuilder,
|
||||||
) -> std::result::Result<(), egui_wgpu::WgpuError> {
|
) -> std::result::Result<(), egui_wgpu::WgpuError> {
|
||||||
unimplemented!();
|
#[allow(unsafe_code, unused_mut, unused_unsafe)]
|
||||||
// #[allow(unsafe_code, unused_mut, unused_unsafe)]
|
let mut painter = egui_wgpu::winit::Painter::new(
|
||||||
// let mut painter = egui_wgpu::winit::Painter::new(
|
self.native_options.wgpu_options.clone(),
|
||||||
// self.native_options.wgpu_options.clone(),
|
self.native_options.multisampling.max(1) as _,
|
||||||
// self.native_options.multisampling.max(1) as _,
|
egui_wgpu::depth_format_from_bits(
|
||||||
// egui_wgpu::depth_format_from_bits(
|
self.native_options.depth_buffer,
|
||||||
// self.native_options.depth_buffer,
|
self.native_options.stencil_buffer,
|
||||||
// self.native_options.stencil_buffer,
|
),
|
||||||
// ),
|
self.native_options.transparent,
|
||||||
// self.native_options.transparent,
|
);
|
||||||
// );
|
pollster::block_on(painter.set_window(0, Some(&window)))?;
|
||||||
// pollster::block_on(painter.set_window(Some(&window)))?;
|
|
||||||
|
|
||||||
// let wgpu_render_state = painter.render_state();
|
let wgpu_render_state = painter.render_state();
|
||||||
|
|
||||||
// let system_theme = system_theme(&window, &self.native_options);
|
let system_theme = system_theme(&window, &self.native_options);
|
||||||
// let mut integration = epi_integration::EpiIntegration::new(
|
let mut integration = epi_integration::EpiIntegration::new(
|
||||||
// event_loop,
|
event_loop,
|
||||||
// painter.max_texture_side().unwrap_or(2048),
|
painter.max_texture_side().unwrap_or(2048),
|
||||||
// &window,
|
&window,
|
||||||
// system_theme,
|
system_theme,
|
||||||
// &self.app_name,
|
&self.app_name,
|
||||||
// &self.native_options,
|
&self.native_options,
|
||||||
// storage,
|
storage,
|
||||||
// #[cfg(feature = "glow")]
|
#[cfg(feature = "glow")]
|
||||||
// None,
|
None,
|
||||||
// wgpu_render_state.clone(),
|
wgpu_render_state.clone(),
|
||||||
// );
|
);
|
||||||
// #[cfg(feature = "accesskit")]
|
|
||||||
// {
|
|
||||||
// integration.init_accesskit(&window, self.repaint_proxy.lock().unwrap().clone());
|
|
||||||
// }
|
|
||||||
// let theme = system_theme.unwrap_or(self.native_options.default_theme);
|
|
||||||
// integration.egui_ctx.set_visuals(theme.egui_visuals());
|
|
||||||
|
|
||||||
// window.set_ime_allowed(true);
|
let mut state = egui_winit::State::new(event_loop);
|
||||||
|
#[cfg(feature = "accesskit")]
|
||||||
|
{
|
||||||
|
integration.init_accesskit(
|
||||||
|
&mut state,
|
||||||
|
&window,
|
||||||
|
self.repaint_proxy.lock().unwrap().clone(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
let theme = system_theme.unwrap_or(self.native_options.default_theme);
|
||||||
|
integration.egui_ctx.set_visuals(theme.egui_visuals());
|
||||||
|
|
||||||
// {
|
window.set_ime_allowed(true);
|
||||||
// let event_loop_proxy = self.repaint_proxy.clone();
|
|
||||||
|
|
||||||
// // !!! TODO !!!
|
{
|
||||||
// // Need a better way to redraw all the windows idependent of one eachother
|
let event_loop_proxy = self.repaint_proxy.clone();
|
||||||
|
|
||||||
// integration
|
integration
|
||||||
// .egui_ctx
|
.egui_ctx
|
||||||
// .set_request_repaint_callback(move |info| {
|
.set_request_repaint_callback(move |info| {
|
||||||
// log::trace!("request_repaint_callback: {info:?}");
|
log::trace!("request_repaint_callback: {info:?}");
|
||||||
// let when = Instant::now() + info.after;
|
let when = Instant::now() + info.after;
|
||||||
// let frame_nr = info.current_frame_nr;
|
let frame_nr = info.current_frame_nr;
|
||||||
|
|
||||||
// // !!! WARNING !!!
|
event_loop_proxy
|
||||||
// // This will only work for 10 windows
|
.lock()
|
||||||
|
.unwrap()
|
||||||
|
.send_event(UserEvent::RequestRepaint {
|
||||||
|
when,
|
||||||
|
frame_nr,
|
||||||
|
window_id: info.window_id,
|
||||||
|
})
|
||||||
|
.ok();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
// for i in 0..10 {
|
let app_creator = std::mem::take(&mut self.app_creator)
|
||||||
// event_loop_proxy
|
.expect("Single-use AppCreator has unexpectedly already been taken");
|
||||||
// .lock()
|
let mut app = app_creator(&epi::CreationContext {
|
||||||
// .unwrap()
|
egui_ctx: integration.egui_ctx.clone(),
|
||||||
// .send_event(UserEvent::RequestRepaint {
|
integration_info: integration.frame.info(),
|
||||||
// when,
|
storage: integration.frame.storage(),
|
||||||
// frame_nr,
|
#[cfg(feature = "glow")]
|
||||||
// window_id: i,
|
gl: None,
|
||||||
// })
|
wgpu_render_state,
|
||||||
// .ok();
|
raw_display_handle: window.raw_display_handle(),
|
||||||
// }
|
raw_window_handle: window.raw_window_handle(),
|
||||||
// });
|
});
|
||||||
// }
|
|
||||||
|
|
||||||
// let app_creator = std::mem::take(&mut self.app_creator)
|
if app.warm_up_enabled() {
|
||||||
// .expect("Single-use AppCreator has unexpectedly already been taken");
|
integration.warm_up(app.as_mut(), &window, &mut state);
|
||||||
// let mut app = app_creator(&epi::CreationContext {
|
}
|
||||||
// egui_ctx: integration.egui_ctx.clone(),
|
|
||||||
// integration_info: integration.frame.info(),
|
|
||||||
// storage: integration.frame.storage(),
|
|
||||||
// #[cfg(feature = "glow")]
|
|
||||||
// gl: None,
|
|
||||||
// wgpu_render_state,
|
|
||||||
// raw_display_handle: window.raw_display_handle(),
|
|
||||||
// raw_window_handle: window.raw_window_handle(),
|
|
||||||
// });
|
|
||||||
|
|
||||||
// if app.warm_up_enabled() {
|
let mut windows_id = HashMap::default();
|
||||||
// integration.warm_up(app.as_mut(), &window);
|
windows_id.insert(window.id(), 0);
|
||||||
// }
|
|
||||||
|
|
||||||
// self.running = Some(WgpuWinitRunning {
|
let mut windows = HashMap::default();
|
||||||
// painter,
|
windows.insert(0, (Some(window), Some(state), None, 0, builder));
|
||||||
// integration,
|
|
||||||
// app,
|
|
||||||
// });
|
|
||||||
// self.window = Some(window);
|
|
||||||
|
|
||||||
// Ok(())
|
self.running = Some(WgpuWinitRunning {
|
||||||
|
painter,
|
||||||
|
integration,
|
||||||
|
app,
|
||||||
|
windows,
|
||||||
|
windows_id,
|
||||||
|
});
|
||||||
|
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1718,20 +1750,28 @@ mod wgpu_integration {
|
|||||||
self.running.as_ref().map(|r| &r.integration)
|
self.running.as_ref().map(|r| &r.integration)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn window(&self, _: winit::window::WindowId) -> Option<&winit::window::Window> {
|
fn window(&self, window_id: winit::window::WindowId) -> Option<&winit::window::Window> {
|
||||||
self.window.as_ref()
|
self.running
|
||||||
|
.as_ref()
|
||||||
|
.map(|r| r.windows_id.get(&window_id).map(|id| r.windows.get(id)))
|
||||||
|
.flatten()
|
||||||
|
.flatten()
|
||||||
|
.map(|w| w.0.as_ref().map(|w| w))
|
||||||
|
.flatten()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_window_winit_id(&self, id: u64) -> Option<winit::window::WindowId> {
|
fn get_window_winit_id(&self, id: u64) -> Option<winit::window::WindowId> {
|
||||||
if id == 0 {
|
self.running
|
||||||
return self.window.as_ref().map(|w| w.id());
|
.as_ref()
|
||||||
}
|
.map(|r| r.windows.get(&id))
|
||||||
None
|
.flatten()
|
||||||
|
.map(|w| w.0.as_ref().map(|w| w.id()))
|
||||||
|
.flatten()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn save_and_destroy(&mut self) {
|
fn save_and_destroy(&mut self) {
|
||||||
if let Some(mut running) = self.running.take() {
|
if let Some(mut running) = self.running.take() {
|
||||||
if let Some(window) = &self.window {
|
if let Some((Some(window), _, _, _, _)) = running.windows.get(&0) {
|
||||||
running.integration.save(running.app.as_mut(), window);
|
running.integration.save(running.app.as_mut(), window);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1746,80 +1786,172 @@ mod wgpu_integration {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn run_ui_and_paint(&mut self, window_id: winit::window::WindowId) -> Vec<EventResult> {
|
fn run_ui_and_paint(&mut self, window_id: winit::window::WindowId) -> Vec<EventResult> {
|
||||||
// !!! WARNING !!!
|
if let Some(running) = &mut self.running {
|
||||||
// Nothing is implemented for WGPU
|
#[cfg(feature = "puffin")]
|
||||||
|
puffin::GlobalProfiler::lock().new_frame();
|
||||||
|
crate::profile_scope!("frame");
|
||||||
|
|
||||||
unimplemented!("Multiples windows in wgpu is not implemented");
|
let WgpuWinitRunning {
|
||||||
// if let (Some(running), Some(window)) = (&mut self.running, &self.window) {
|
app,
|
||||||
// #[cfg(feature = "puffin")]
|
integration,
|
||||||
// puffin::GlobalProfiler::lock().new_frame();
|
painter,
|
||||||
// crate::profile_scope!("frame");
|
windows,
|
||||||
|
windows_id,
|
||||||
|
} = running;
|
||||||
|
|
||||||
// let WgpuWinitRunning {
|
let egui::FullOutput {
|
||||||
// app,
|
platform_output,
|
||||||
// integration,
|
repaint_after,
|
||||||
// painter,
|
textures_delta,
|
||||||
// } = running;
|
shapes,
|
||||||
|
mut viewports,
|
||||||
|
viewport_commands,
|
||||||
|
};
|
||||||
|
{
|
||||||
|
let Some((viewport_id, (Some(window), Some(state), render, parent_viewport_id, _))) = windows_id.get(&window_id).map(|id|(windows.get_mut(id).map(|w|(*id, w)))).flatten() else{return vec![]};
|
||||||
|
integration.egui_ctx.set_current_viewport_id(viewport_id);
|
||||||
|
|
||||||
// let egui::FullOutput {
|
pollster::block_on(painter.set_window(viewport_id, Some(&window)));
|
||||||
// platform_output,
|
|
||||||
// repaint_after,
|
|
||||||
// textures_delta,
|
|
||||||
// shapes,
|
|
||||||
// } = integration.update(app.as_mut(), window);
|
|
||||||
|
|
||||||
// integration.handle_platform_output(window, platform_output);
|
egui::FullOutput {
|
||||||
|
platform_output,
|
||||||
|
repaint_after,
|
||||||
|
textures_delta,
|
||||||
|
shapes,
|
||||||
|
viewports,
|
||||||
|
viewport_commands,
|
||||||
|
} = integration.update(
|
||||||
|
app.as_mut(),
|
||||||
|
window,
|
||||||
|
state,
|
||||||
|
render.clone(),
|
||||||
|
viewport_id,
|
||||||
|
*parent_viewport_id,
|
||||||
|
);
|
||||||
|
|
||||||
// let clipped_primitives = {
|
integration.handle_platform_output(window, platform_output, state);
|
||||||
// crate::profile_scope!("tessellate");
|
|
||||||
// integration.egui_ctx.tessellate(shapes)
|
|
||||||
// };
|
|
||||||
|
|
||||||
// let screenshot_requested = &mut integration.frame.output.screenshot_requested;
|
let clipped_primitives = {
|
||||||
|
crate::profile_scope!("tessellate");
|
||||||
|
integration.egui_ctx.tessellate(shapes)
|
||||||
|
};
|
||||||
|
|
||||||
// let screenshot = painter.paint_and_update_textures(
|
let screenshot_requested = &mut integration.frame.output.screenshot_requested;
|
||||||
// integration.egui_ctx.pixels_per_point(),
|
|
||||||
// app.clear_color(&integration.egui_ctx.style().visuals),
|
|
||||||
// &clipped_primitives,
|
|
||||||
// &textures_delta,
|
|
||||||
// *screenshot_requested,
|
|
||||||
// );
|
|
||||||
// *screenshot_requested = false;
|
|
||||||
// integration.frame.screenshot.set(screenshot);
|
|
||||||
|
|
||||||
// integration.post_rendering(app.as_mut(), window);
|
let screenshot = painter.paint_and_update_textures(
|
||||||
// integration.post_present(window);
|
viewport_id,
|
||||||
|
integration.egui_ctx.pixels_per_point(),
|
||||||
|
app.clear_color(&integration.egui_ctx.style().visuals),
|
||||||
|
&clipped_primitives,
|
||||||
|
&textures_delta,
|
||||||
|
*screenshot_requested,
|
||||||
|
);
|
||||||
|
*screenshot_requested = false;
|
||||||
|
integration.frame.screenshot.set(screenshot);
|
||||||
|
|
||||||
// let control_flow = if integration.should_close() {
|
integration.post_rendering(app.as_mut(), window);
|
||||||
// EventResult::Exit
|
integration.post_present(window);
|
||||||
// } else if repaint_after.is_zero() {
|
}
|
||||||
// EventResult::RepaintNext
|
|
||||||
// } else if let Some(repaint_after_instant) =
|
|
||||||
// std::time::Instant::now().checked_add(repaint_after)
|
|
||||||
// {
|
|
||||||
// // if repaint_after is something huge and can't be added to Instant,
|
|
||||||
// // we will use `ControlFlow::Wait` instead.
|
|
||||||
// // technically, this might lead to some weird corner cases where the user *WANTS*
|
|
||||||
// // winit to use `WaitUntil(MAX_INSTANT)` explicitly. they can roll their own
|
|
||||||
// // egui backend impl i guess.
|
|
||||||
// EventResult::RepaintAt(repaint_after_instant)
|
|
||||||
// } else {
|
|
||||||
// EventResult::Wait
|
|
||||||
// };
|
|
||||||
|
|
||||||
// integration.maybe_autosave(app.as_mut(), window);
|
let mut active_viewports_ids = vec![0];
|
||||||
|
|
||||||
// if window.is_minimized() == Some(true) {
|
viewports.retain_mut(|(id, parent, builder, render)| {
|
||||||
// // On Mac, a minimized Window uses up all CPU:
|
if let Some(w) = windows.get_mut(id) {
|
||||||
// // https://github.com/emilk/egui/issues/325
|
w.2 = Some(render.clone());
|
||||||
// crate::profile_scope!("bg_sleep");
|
w.3 = *parent;
|
||||||
// std::thread::sleep(std::time::Duration::from_millis(10));
|
active_viewports_ids.push(*id);
|
||||||
// }
|
return false;
|
||||||
|
} else {
|
||||||
|
true
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
// control_flow
|
for (id, parent, builder, render) in viewports {
|
||||||
// } else {
|
windows.insert(id, (None, None, Some(render), parent, builder));
|
||||||
// EventResult::Wait
|
active_viewports_ids.push(id);
|
||||||
// }
|
}
|
||||||
|
|
||||||
|
// TODO Make this more efficient
|
||||||
|
for (id, command) in viewport_commands {
|
||||||
|
if let Some(window) = windows.get(&id) {
|
||||||
|
if let Some(win) = &window.0 {
|
||||||
|
match command {
|
||||||
|
egui::window::ViewportCommand::Drag => {
|
||||||
|
// if this is not checked on x11 the input will be permanently taken until the app is killed!
|
||||||
|
// if let Some(focus) = self.is_focused {
|
||||||
|
// if focus == id {
|
||||||
|
win.drag_window();
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
egui::window::ViewportCommand::InnerSize(width, height) => {
|
||||||
|
win.set_inner_size(winit::dpi::PhysicalSize::new(
|
||||||
|
width, height,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
egui::window::ViewportCommand::Resize(top, bottom, right, left) => {
|
||||||
|
win.drag_resize_window(match (top, bottom, right, left) {
|
||||||
|
(true, false, false, false) => ResizeDirection::North,
|
||||||
|
(false, true, false, false) => ResizeDirection::South,
|
||||||
|
(false, false, true, false) => ResizeDirection::East,
|
||||||
|
(false, false, false, true) => ResizeDirection::West,
|
||||||
|
(true, false, true, false) => ResizeDirection::NorthEast,
|
||||||
|
(false, true, true, false) => ResizeDirection::SouthEast,
|
||||||
|
(true, false, false, true) => ResizeDirection::NorthWest,
|
||||||
|
(false, true, false, true) => ResizeDirection::SouthWest,
|
||||||
|
_ => ResizeDirection::East,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
windows.retain(|id, _| active_viewports_ids.contains(id));
|
||||||
|
windows_id.retain(|_, id| active_viewports_ids.contains(id));
|
||||||
|
|
||||||
|
let mut control_flow = vec![EventResult::Wait];
|
||||||
|
for repaint_after in repaint_after {
|
||||||
|
control_flow.push(if integration.should_close() {
|
||||||
|
EventResult::Exit
|
||||||
|
} else if repaint_after.1.is_zero() {
|
||||||
|
if let Some((Some(window_id), _, _, _, _)) = windows.get(&repaint_after.0) {
|
||||||
|
EventResult::RepaintNext(window_id.id())
|
||||||
|
} else {
|
||||||
|
EventResult::Wait
|
||||||
|
}
|
||||||
|
} else if let Some(repaint_after_instant) =
|
||||||
|
std::time::Instant::now().checked_add(repaint_after.1)
|
||||||
|
{
|
||||||
|
// if repaint_after is something huge and can't be added to Instant,
|
||||||
|
// we will use `ControlFlow::Wait` instead.
|
||||||
|
// technically, this might lead to some weird corner cases where the user *WANTS*
|
||||||
|
// winit to use `WaitUntil(MAX_INSTANT)` explicitly. they can roll their own
|
||||||
|
// egui backend impl i guess.
|
||||||
|
if let Some((Some(window_id), _, _, _, _)) = windows.get(&repaint_after.0) {
|
||||||
|
EventResult::RepaintAt(window_id.id(), repaint_after_instant)
|
||||||
|
} else {
|
||||||
|
EventResult::Wait
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
EventResult::Wait
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
let Some((viewport_id, (Some(window), Some(state), render, parent_viewport_id, _))) = windows_id.get(&window_id).map(|id|(windows.get_mut(id).map(|w|(*id, w)))).flatten() else{return vec![]};
|
||||||
|
integration.maybe_autosave(app.as_mut(), window);
|
||||||
|
|
||||||
|
if window.is_minimized() == Some(true) {
|
||||||
|
// On Mac, a minimized Window uses up all CPU:
|
||||||
|
// https://github.com/emilk/egui/issues/325
|
||||||
|
crate::profile_scope!("bg_sleep");
|
||||||
|
std::thread::sleep(std::time::Duration::from_millis(10));
|
||||||
|
}
|
||||||
|
|
||||||
|
control_flow
|
||||||
|
} else {
|
||||||
|
vec![EventResult::Wait]
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn on_event(
|
fn on_event(
|
||||||
@@ -1827,132 +1959,179 @@ mod wgpu_integration {
|
|||||||
event_loop: &EventLoopWindowTarget<UserEvent>,
|
event_loop: &EventLoopWindowTarget<UserEvent>,
|
||||||
event: &winit::event::Event<'_, UserEvent>,
|
event: &winit::event::Event<'_, UserEvent>,
|
||||||
) -> Result<EventResult> {
|
) -> Result<EventResult> {
|
||||||
// !!! WARNING !!!
|
self.build_windows(event_loop);
|
||||||
|
Ok(match event {
|
||||||
|
winit::event::Event::Resumed => {
|
||||||
|
if let Some(running) = &self.running {
|
||||||
|
if running.windows.get(&0).is_none() {
|
||||||
|
let window = Self::create_window(
|
||||||
|
event_loop,
|
||||||
|
running.integration.frame.storage(),
|
||||||
|
&self.app_name,
|
||||||
|
&self.native_options,
|
||||||
|
)?;
|
||||||
|
self.set_window(0)?;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
let storage = epi_integration::create_storage(
|
||||||
|
self.native_options
|
||||||
|
.app_id
|
||||||
|
.as_ref()
|
||||||
|
.unwrap_or(&self.app_name),
|
||||||
|
);
|
||||||
|
let (window, builder) = Self::create_window(
|
||||||
|
event_loop,
|
||||||
|
storage.as_deref(),
|
||||||
|
&self.app_name,
|
||||||
|
&self.native_options,
|
||||||
|
)?;
|
||||||
|
self.init_run_state(event_loop, storage, window, builder)?;
|
||||||
|
}
|
||||||
|
EventResult::RepaintNow(
|
||||||
|
self.running
|
||||||
|
.as_ref()
|
||||||
|
.unwrap()
|
||||||
|
.windows
|
||||||
|
.get(&0)
|
||||||
|
.unwrap()
|
||||||
|
.0
|
||||||
|
.as_ref()
|
||||||
|
.unwrap()
|
||||||
|
.id(),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
winit::event::Event::Suspended => {
|
||||||
|
#[cfg(target_os = "android")]
|
||||||
|
self.drop_window()?;
|
||||||
|
EventResult::Wait
|
||||||
|
}
|
||||||
|
|
||||||
unimplemented!("Multiples windows is not implemented for WGPU");
|
winit::event::Event::WindowEvent { event, window_id } => {
|
||||||
|
if let Some(running) = &mut self.running {
|
||||||
|
// On Windows, if a window is resized by the user, it should repaint synchronously, inside the
|
||||||
|
// event handler.
|
||||||
|
//
|
||||||
|
// If this is not done, the compositor will assume that the window does not want to redraw,
|
||||||
|
// and continue ahead.
|
||||||
|
//
|
||||||
|
// In eframe's case, that causes the window to rapidly flicker, as it struggles to deliver
|
||||||
|
// new frames to the compositor in time.
|
||||||
|
//
|
||||||
|
// The flickering is technically glutin or glow's fault, but we should be responding properly
|
||||||
|
// to resizes anyway, as doing so avoids dropping frames.
|
||||||
|
//
|
||||||
|
// See: https://github.com/emilk/egui/issues/903
|
||||||
|
let mut repaint_asap = false;
|
||||||
|
|
||||||
// Ok(match event {
|
match &event {
|
||||||
// winit::event::Event::Resumed => {
|
winit::event::WindowEvent::Focused(new_focused) => {
|
||||||
// if let Some(running) = &self.running {
|
self.is_focused = *new_focused;
|
||||||
// if self.window.is_none() {
|
}
|
||||||
// let window = Self::create_window(
|
winit::event::WindowEvent::Resized(physical_size) => {
|
||||||
// event_loop,
|
repaint_asap = true;
|
||||||
// running.integration.frame.storage(),
|
|
||||||
// &self.app_name,
|
|
||||||
// &self.native_options,
|
|
||||||
// )?;
|
|
||||||
// self.set_window(window)?;
|
|
||||||
// }
|
|
||||||
// } else {
|
|
||||||
// let storage = epi_integration::create_storage(
|
|
||||||
// self.native_options
|
|
||||||
// .app_id
|
|
||||||
// .as_ref()
|
|
||||||
// .unwrap_or(&self.app_name),
|
|
||||||
// );
|
|
||||||
// let window = Self::create_window(
|
|
||||||
// event_loop,
|
|
||||||
// storage.as_deref(),
|
|
||||||
// &self.app_name,
|
|
||||||
// &self.native_options,
|
|
||||||
// )?;
|
|
||||||
// self.init_run_state(event_loop, storage, window)?;
|
|
||||||
// }
|
|
||||||
// EventResult::RepaintNow
|
|
||||||
// }
|
|
||||||
// winit::event::Event::Suspended => {
|
|
||||||
// #[cfg(target_os = "android")]
|
|
||||||
// self.drop_window()?;
|
|
||||||
// EventResult::Wait
|
|
||||||
// }
|
|
||||||
|
|
||||||
// winit::event::Event::WindowEvent { event, .. } => {
|
// Resize with 0 width and height is used by winit to signal a minimize event on Windows.
|
||||||
// if let Some(running) = &mut self.running {
|
// See: https://github.com/rust-windowing/winit/issues/208
|
||||||
// // On Windows, if a window is resized by the user, it should repaint synchronously, inside the
|
// This solves an issue where the app would panic when minimizing on Windows.
|
||||||
// // event handler.
|
if let Some(viewport_id) =
|
||||||
// //
|
running.windows_id.get(window_id).cloned()
|
||||||
// // If this is not done, the compositor will assume that the window does not want to redraw,
|
{
|
||||||
// // and continue ahead.
|
if physical_size.width > 0 && physical_size.height > 0 {
|
||||||
// //
|
running.painter.on_window_resized(
|
||||||
// // In eframe's case, that causes the window to rapidly flicker, as it struggles to deliver
|
viewport_id,
|
||||||
// // new frames to the compositor in time.
|
physical_size.width,
|
||||||
// //
|
physical_size.height,
|
||||||
// // The flickering is technically glutin or glow's fault, but we should be responding properly
|
);
|
||||||
// // to resizes anyway, as doing so avoids dropping frames.
|
}
|
||||||
// //
|
}
|
||||||
// // See: https://github.com/emilk/egui/issues/903
|
}
|
||||||
// let mut repaint_asap = false;
|
winit::event::WindowEvent::ScaleFactorChanged {
|
||||||
|
new_inner_size,
|
||||||
|
..
|
||||||
|
} => {
|
||||||
|
if let Some(viewport_id) =
|
||||||
|
running.windows_id.get(window_id).cloned()
|
||||||
|
{
|
||||||
|
repaint_asap = true;
|
||||||
|
running.painter.on_window_resized(
|
||||||
|
viewport_id,
|
||||||
|
new_inner_size.width,
|
||||||
|
new_inner_size.height,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
winit::event::WindowEvent::CloseRequested
|
||||||
|
if running.integration.should_close() =>
|
||||||
|
{
|
||||||
|
log::debug!("Received WindowEvent::CloseRequested");
|
||||||
|
return Ok(EventResult::Exit);
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
};
|
||||||
|
|
||||||
// match &event {
|
let event_response =
|
||||||
// winit::event::WindowEvent::Focused(new_focused) => {
|
if let Some((id, (Some(window), Some(state), _, _, _))) = running
|
||||||
// self.is_focused = *new_focused;
|
.windows_id
|
||||||
// }
|
.get(window_id)
|
||||||
// winit::event::WindowEvent::Resized(physical_size) => {
|
.map(|id| running.windows.get_mut(id).map(|w| (*id, w)))
|
||||||
// repaint_asap = true;
|
.flatten()
|
||||||
|
{
|
||||||
|
Some(running.integration.on_event(
|
||||||
|
running.app.as_mut(),
|
||||||
|
event,
|
||||||
|
window_id,
|
||||||
|
state,
|
||||||
|
id,
|
||||||
|
))
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
};
|
||||||
|
|
||||||
// // Resize with 0 width and height is used by winit to signal a minimize event on Windows.
|
if running.integration.should_close() {
|
||||||
// // See: https://github.com/rust-windowing/winit/issues/208
|
EventResult::Exit
|
||||||
// // This solves an issue where the app would panic when minimizing on Windows.
|
} else if let Some(event_response) = event_response {
|
||||||
// if physical_size.width > 0 && physical_size.height > 0 {
|
if event_response.repaint {
|
||||||
// running.painter.on_window_resized(
|
if repaint_asap {
|
||||||
// physical_size.width,
|
EventResult::RepaintNow(*window_id)
|
||||||
// physical_size.height,
|
} else {
|
||||||
// );
|
EventResult::RepaintNext(*window_id)
|
||||||
// }
|
}
|
||||||
// }
|
} else {
|
||||||
// winit::event::WindowEvent::ScaleFactorChanged {
|
EventResult::Wait
|
||||||
// new_inner_size,
|
}
|
||||||
// ..
|
} else {
|
||||||
// } => {
|
EventResult::Wait
|
||||||
// repaint_asap = true;
|
}
|
||||||
// running
|
} else {
|
||||||
// .painter
|
EventResult::Wait
|
||||||
// .on_window_resized(new_inner_size.width, new_inner_size.height);
|
}
|
||||||
// }
|
}
|
||||||
// winit::event::WindowEvent::CloseRequested
|
#[cfg(feature = "accesskit")]
|
||||||
// if running.integration.should_close() =>
|
winit::event::Event::UserEvent(UserEvent::AccessKitActionRequest(
|
||||||
// {
|
accesskit_winit::ActionRequestEvent { request, window_id },
|
||||||
// log::debug!("Received WindowEvent::CloseRequested");
|
)) => {
|
||||||
// return Ok(EventResult::Exit);
|
if let Some(running) = &mut self.running {
|
||||||
// }
|
if let Some((_, Some(state), _, _, _)) = running
|
||||||
// _ => {}
|
.windows_id
|
||||||
// };
|
.get(window_id)
|
||||||
|
.map(|id| running.windows.get_mut(id))
|
||||||
// let event_response =
|
.flatten()
|
||||||
// running.integration.on_event(running.app.as_mut(), event);
|
{
|
||||||
// if running.integration.should_close() {
|
running.integration.on_accesskit_action_request(
|
||||||
// EventResult::Exit
|
request.clone(),
|
||||||
// } else if event_response.repaint {
|
window_id,
|
||||||
// if repaint_asap {
|
state,
|
||||||
// EventResult::RepaintNow
|
);
|
||||||
// } else {
|
}
|
||||||
// EventResult::RepaintNext
|
// As a form of user input, accessibility actions should
|
||||||
// }
|
// lead to a repaint.
|
||||||
// } else {
|
EventResult::RepaintNext(*window_id)
|
||||||
// EventResult::Wait
|
} else {
|
||||||
// }
|
EventResult::Wait
|
||||||
// } else {
|
}
|
||||||
// EventResult::Wait
|
}
|
||||||
// }
|
_ => EventResult::Wait,
|
||||||
// }
|
})
|
||||||
// #[cfg(feature = "accesskit")]
|
|
||||||
// winit::event::Event::UserEvent(UserEvent::AccessKitActionRequest(
|
|
||||||
// accesskit_winit::ActionRequestEvent { request, .. },
|
|
||||||
// )) => {
|
|
||||||
// if let Some(running) = &mut self.running {
|
|
||||||
// running
|
|
||||||
// .integration
|
|
||||||
// .on_accesskit_action_request(request.clone());
|
|
||||||
// // As a form of user input, accessibility actions should
|
|
||||||
// // lead to a repaint.
|
|
||||||
// EventResult::RepaintNext
|
|
||||||
// } else {
|
|
||||||
// EventResult::Wait
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// _ => EventResult::Wait,
|
|
||||||
// })
|
|
||||||
//
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_window_id(&self, id: &winit::window::WindowId) -> Option<u64> {
|
fn get_window_id(&self, id: &winit::window::WindowId) -> Option<u64> {
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
|
use epaint::ahash::HashMap;
|
||||||
|
|
||||||
use crate::{renderer, RenderState, SurfaceErrorAction, WgpuConfiguration};
|
use crate::{renderer, RenderState, SurfaceErrorAction, WgpuConfiguration};
|
||||||
|
|
||||||
struct SurfaceState {
|
struct SurfaceState {
|
||||||
@@ -83,7 +85,7 @@ pub struct Painter {
|
|||||||
|
|
||||||
instance: wgpu::Instance,
|
instance: wgpu::Instance,
|
||||||
render_state: Option<RenderState>,
|
render_state: Option<RenderState>,
|
||||||
surface_state: Option<SurfaceState>,
|
surfaces: HashMap<u64, SurfaceState>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Painter {
|
impl Painter {
|
||||||
@@ -120,7 +122,7 @@ impl Painter {
|
|||||||
|
|
||||||
instance,
|
instance,
|
||||||
render_state: None,
|
render_state: None,
|
||||||
surface_state: None,
|
surfaces: HashMap::default(),
|
||||||
msaa_texture_view: None,
|
msaa_texture_view: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -185,60 +187,72 @@ impl Painter {
|
|||||||
/// If the provided wgpu configuration does not match an available device.
|
/// If the provided wgpu configuration does not match an available device.
|
||||||
pub async fn set_window(
|
pub async fn set_window(
|
||||||
&mut self,
|
&mut self,
|
||||||
|
viewport_id: u64,
|
||||||
window: Option<&winit::window::Window>,
|
window: Option<&winit::window::Window>,
|
||||||
) -> Result<(), crate::WgpuError> {
|
) -> Result<(), crate::WgpuError> {
|
||||||
match window {
|
match window {
|
||||||
Some(window) => {
|
Some(window) => {
|
||||||
let surface = unsafe { self.instance.create_surface(&window)? };
|
|
||||||
|
|
||||||
let render_state = if let Some(render_state) = &self.render_state {
|
|
||||||
render_state
|
|
||||||
} else {
|
|
||||||
let render_state = RenderState::create(
|
|
||||||
&self.configuration,
|
|
||||||
&self.instance,
|
|
||||||
&surface,
|
|
||||||
self.depth_format,
|
|
||||||
self.msaa_samples,
|
|
||||||
)
|
|
||||||
.await?;
|
|
||||||
self.render_state.get_or_insert(render_state)
|
|
||||||
};
|
|
||||||
|
|
||||||
let alpha_mode = if self.support_transparent_backbuffer {
|
|
||||||
let supported_alpha_modes =
|
|
||||||
surface.get_capabilities(&render_state.adapter).alpha_modes;
|
|
||||||
|
|
||||||
// Prefer pre multiplied over post multiplied!
|
|
||||||
if supported_alpha_modes.contains(&wgpu::CompositeAlphaMode::PreMultiplied) {
|
|
||||||
wgpu::CompositeAlphaMode::PreMultiplied
|
|
||||||
} else if supported_alpha_modes
|
|
||||||
.contains(&wgpu::CompositeAlphaMode::PostMultiplied)
|
|
||||||
{
|
|
||||||
wgpu::CompositeAlphaMode::PostMultiplied
|
|
||||||
} else {
|
|
||||||
log::warn!("Transparent window was requested, but the active wgpu surface does not support a `CompositeAlphaMode` with transparency.");
|
|
||||||
wgpu::CompositeAlphaMode::Auto
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
wgpu::CompositeAlphaMode::Auto
|
|
||||||
};
|
|
||||||
|
|
||||||
let supports_screenshot =
|
|
||||||
!matches!(render_state.adapter.get_info().backend, wgpu::Backend::Gl);
|
|
||||||
|
|
||||||
let size = window.inner_size();
|
let size = window.inner_size();
|
||||||
self.surface_state = Some(SurfaceState {
|
if self.surfaces.get(&viewport_id).is_none() {
|
||||||
surface,
|
let surface = unsafe { self.instance.create_surface(&window)? };
|
||||||
width: size.width,
|
|
||||||
height: size.height,
|
let render_state = if let Some(render_state) = &self.render_state {
|
||||||
alpha_mode,
|
render_state
|
||||||
supports_screenshot,
|
} else {
|
||||||
});
|
let render_state = RenderState::create(
|
||||||
self.resize_and_generate_depth_texture_view_and_msaa_view(size.width, size.height);
|
&self.configuration,
|
||||||
|
&self.instance,
|
||||||
|
&surface,
|
||||||
|
self.depth_format,
|
||||||
|
self.msaa_samples,
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
|
self.render_state.get_or_insert(render_state)
|
||||||
|
};
|
||||||
|
|
||||||
|
let alpha_mode = if self.support_transparent_backbuffer {
|
||||||
|
let supported_alpha_modes =
|
||||||
|
surface.get_capabilities(&render_state.adapter).alpha_modes;
|
||||||
|
|
||||||
|
// Prefer pre multiplied over post multiplied!
|
||||||
|
if supported_alpha_modes.contains(&wgpu::CompositeAlphaMode::PreMultiplied)
|
||||||
|
{
|
||||||
|
wgpu::CompositeAlphaMode::PreMultiplied
|
||||||
|
} else if supported_alpha_modes
|
||||||
|
.contains(&wgpu::CompositeAlphaMode::PostMultiplied)
|
||||||
|
{
|
||||||
|
wgpu::CompositeAlphaMode::PostMultiplied
|
||||||
|
} else {
|
||||||
|
log::warn!("Transparent window was requested, but the active wgpu surface does not support a `CompositeAlphaMode` with transparency.");
|
||||||
|
wgpu::CompositeAlphaMode::Auto
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
wgpu::CompositeAlphaMode::Auto
|
||||||
|
};
|
||||||
|
|
||||||
|
let supports_screenshot =
|
||||||
|
!matches!(render_state.adapter.get_info().backend, wgpu::Backend::Gl);
|
||||||
|
|
||||||
|
self.surfaces.insert(
|
||||||
|
viewport_id,
|
||||||
|
SurfaceState {
|
||||||
|
surface,
|
||||||
|
width: size.width,
|
||||||
|
height: size.height,
|
||||||
|
alpha_mode,
|
||||||
|
supports_screenshot,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
self.resize_and_generate_depth_texture_view_and_msaa_view(
|
||||||
|
viewport_id,
|
||||||
|
size.width,
|
||||||
|
size.height,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
None => {
|
None => {
|
||||||
self.surface_state = None;
|
log::warn!("All surfaces was deleted!");
|
||||||
|
self.surfaces.clear();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
@@ -257,11 +271,12 @@ impl Painter {
|
|||||||
|
|
||||||
fn resize_and_generate_depth_texture_view_and_msaa_view(
|
fn resize_and_generate_depth_texture_view_and_msaa_view(
|
||||||
&mut self,
|
&mut self,
|
||||||
|
viewport_id: u64,
|
||||||
width_in_pixels: u32,
|
width_in_pixels: u32,
|
||||||
height_in_pixels: u32,
|
height_in_pixels: u32,
|
||||||
) {
|
) {
|
||||||
let render_state = self.render_state.as_ref().unwrap();
|
let render_state = self.render_state.as_ref().unwrap();
|
||||||
let surface_state = self.surface_state.as_mut().unwrap();
|
let surface_state = self.surfaces.get_mut(&viewport_id).unwrap();
|
||||||
|
|
||||||
surface_state.width = width_in_pixels;
|
surface_state.width = width_in_pixels;
|
||||||
surface_state.height = height_in_pixels;
|
surface_state.height = height_in_pixels;
|
||||||
@@ -314,9 +329,15 @@ impl Painter {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn on_window_resized(&mut self, width_in_pixels: u32, height_in_pixels: u32) {
|
pub fn on_window_resized(
|
||||||
if self.surface_state.is_some() {
|
&mut self,
|
||||||
|
viewport_id: u64,
|
||||||
|
width_in_pixels: u32,
|
||||||
|
height_in_pixels: u32,
|
||||||
|
) {
|
||||||
|
if self.surfaces.get(&viewport_id).is_some() {
|
||||||
self.resize_and_generate_depth_texture_view_and_msaa_view(
|
self.resize_and_generate_depth_texture_view_and_msaa_view(
|
||||||
|
viewport_id,
|
||||||
width_in_pixels,
|
width_in_pixels,
|
||||||
height_in_pixels,
|
height_in_pixels,
|
||||||
);
|
);
|
||||||
@@ -427,6 +448,7 @@ impl Painter {
|
|||||||
// Returns a vector with the frame's pixel data if it was requested.
|
// Returns a vector with the frame's pixel data if it was requested.
|
||||||
pub fn paint_and_update_textures(
|
pub fn paint_and_update_textures(
|
||||||
&mut self,
|
&mut self,
|
||||||
|
viewport_id: u64,
|
||||||
pixels_per_point: f32,
|
pixels_per_point: f32,
|
||||||
clear_color: [f32; 4],
|
clear_color: [f32; 4],
|
||||||
clipped_primitives: &[epaint::ClippedPrimitive],
|
clipped_primitives: &[epaint::ClippedPrimitive],
|
||||||
@@ -436,7 +458,7 @@ impl Painter {
|
|||||||
crate::profile_function!();
|
crate::profile_function!();
|
||||||
|
|
||||||
let render_state = self.render_state.as_mut()?;
|
let render_state = self.render_state.as_mut()?;
|
||||||
let surface_state = self.surface_state.as_ref()?;
|
let surface_state = self.surfaces.get(&viewport_id)?;
|
||||||
|
|
||||||
let output_frame = {
|
let output_frame = {
|
||||||
crate::profile_scope!("get_current_texture");
|
crate::profile_scope!("get_current_texture");
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ use eframe::{
|
|||||||
egui_wgpu::wgpu::util::DeviceExt,
|
egui_wgpu::wgpu::util::DeviceExt,
|
||||||
egui_wgpu::{self, wgpu},
|
egui_wgpu::{self, wgpu},
|
||||||
};
|
};
|
||||||
|
use egui::ViewportRender;
|
||||||
|
|
||||||
pub struct Custom3d {
|
pub struct Custom3d {
|
||||||
angle: f32,
|
angle: f32,
|
||||||
@@ -96,7 +97,16 @@ impl Custom3d {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl eframe::App for Custom3d {
|
impl eframe::App for Custom3d {
|
||||||
fn update(&mut self, ctx: &egui::Context, _frame: &mut eframe::Frame) {
|
fn update(
|
||||||
|
&mut self,
|
||||||
|
ctx: &egui::Context,
|
||||||
|
frame: &mut eframe::Frame,
|
||||||
|
render: Option<&ViewportRender>,
|
||||||
|
) {
|
||||||
|
if let Some(render) = render {
|
||||||
|
render(ctx, frame.viewport_id(), frame.parent_viewport_id());
|
||||||
|
return;
|
||||||
|
}
|
||||||
egui::CentralPanel::default().show(ctx, |ui| {
|
egui::CentralPanel::default().show(ctx, |ui| {
|
||||||
egui::ScrollArea::both()
|
egui::ScrollArea::both()
|
||||||
.auto_shrink([false; 2])
|
.auto_shrink([false; 2])
|
||||||
|
|||||||
@@ -9,5 +9,5 @@ publish = false
|
|||||||
|
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
eframe = { path = "../../crates/eframe" }
|
eframe = { path = "../../crates/eframe", features = ["wgpu"] }
|
||||||
env_logger = "0.10"
|
env_logger = "0.10"
|
||||||
|
|||||||
@@ -9,7 +9,10 @@ fn main() {
|
|||||||
|
|
||||||
eframe::run_simple_native(
|
eframe::run_simple_native(
|
||||||
"Viewports Examples",
|
"Viewports Examples",
|
||||||
NativeOptions::default(),
|
NativeOptions {
|
||||||
|
renderer: eframe::Renderer::Wgpu,
|
||||||
|
..NativeOptions::default()
|
||||||
|
},
|
||||||
move |ctx, _frame| {
|
move |ctx, _frame| {
|
||||||
egui::CentralPanel::default().show(ctx, |ui| {
|
egui::CentralPanel::default().show(ctx, |ui| {
|
||||||
ui.label(format!("Frame: {}", ui.ctx().frame_nr()));
|
ui.label(format!("Frame: {}", ui.ctx().frame_nr()));
|
||||||
|
|||||||
Reference in New Issue
Block a user