You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Hi there, community! I am currently integrating egui to my wgpu game using the official examples, via the egui-wgpu and egui-winit crates. Running the egui_demo_lib application with all the subwindows open takes ~120ms (--release, most of the time is taken by running the application itself, so I assume layouting and such), compared to the browser number of ~13ms.
Why such a performance difference? Have I skipped something? Here is the renderer implementation I have stripped from the official examples:
use anyhow::Result;use bevy_ecs::{
prelude::resource_changed,
schedule::{IntoSystemConfigs,Schedule},
system::{Res,ResMut,Resource},
world::World,};use wgpu::TextureFormat;usecrate::gpu::GpuContext;usesuper::present::FrameBuffer;pubfnsetup_ui(world:&mutWorld,schedule:&mutSchedule) -> Result<()>{let gpu = world
.get_resource::<GpuContext>().ok_or_else(|| anyhow::anyhow!("GpuContext resource not found"))?;let pipeline = EguiRenderer::new(&gpu.device,TextureFormat::Rgba16Float,None,1,&gpu.window,);let app = egui_demo_lib::DemoWindows::default();let ui = EguiState{renderer: pipeline,
app,};
world.insert_resource(ui);
schedule.add_systems(frame_buffer_changed_system.run_if(resource_changed::<FrameBuffer>));Ok(())}pubfnframe_buffer_changed_system(frame_buffer:Res<FrameBuffer>,gpu:Res<GpuContext>,mutpipeline:ResMut<EguiState>,){let new_size = gpu.window.inner_size();let new_scale = gpu.window.scale_factor();}// =============================== UI RESOURCE ===============================#[derive(Resource)]pubstructEguiState{pub(crate)renderer:EguiRenderer,pub(crate)app: egui_demo_lib::DemoWindows,}unsafeimplSendforEguiState{}unsafeimplSyncforEguiState{}implEguiState{pubfnrun_app(&mutself){self.app.ui(&self.renderer.context());}}// =============================== RENDERER ===============================use egui::Context;use egui_wgpu::wgpu::{CommandEncoder,Device,Queue,StoreOp,TextureView};use egui_wgpu::{wgpu,Renderer,ScreenDescriptor};use egui_winit::{EventResponse,State};use winit::event::WindowEvent;use winit::window::Window;pubstructEguiRenderer{state:State,renderer:Renderer,frame_started:bool,}implEguiRenderer{pubfncontext(&self) -> &Context{self.state.egui_ctx()}pubfnnew(device:&Device,output_color_format:TextureFormat,output_depth_format:Option<TextureFormat>,msaa_samples:u32,window:&Window,) -> EguiRenderer{let egui_context = Context::default();
egui_extras::install_image_loaders(&egui_context);let egui_state = egui_winit::State::new(
egui_context,
egui::viewport::ViewportId::ROOT,&window,Some(window.scale_factor()asf32),None,Some(2*1024),// default dimension is 2048);let egui_renderer = Renderer::new(
device,
output_color_format,
output_depth_format,
msaa_samples,true,);EguiRenderer{state: egui_state,renderer: egui_renderer,frame_started:false,}}pubfnhandle_input(&mutself,window:&Window,event:&WindowEvent) -> EventResponse{self.state.on_window_event(window, event)}pubfnppp(&mutself,v:f32){self.context().set_pixels_per_point(v);}pubfnbegin_frame(&mutself,window:&Window){let raw_input = self.state.take_egui_input(window);self.state.egui_ctx().begin_pass(raw_input);self.frame_started = true;}pubfnend_frame_and_draw(&mutself,device:&Device,queue:&Queue,encoder:&mutCommandEncoder,window:&Window,window_surface_view:&TextureView,screen_descriptor:ScreenDescriptor,){if !self.frame_started{panic!("begin_frame must be called before end_frame_and_draw can be called!");}self.ppp(screen_descriptor.pixels_per_point);let full_output = self.state.egui_ctx().end_pass();self.state.handle_platform_output(window, full_output.platform_output);let tris = self.state.egui_ctx().tessellate(full_output.shapes,self.state.egui_ctx().pixels_per_point());for(id, image_delta)in&full_output.textures_delta.set{self.renderer.update_texture(device, queue,*id, image_delta);}self.renderer.update_buffers(device, queue, encoder,&tris,&screen_descriptor);let rpass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor{color_attachments:&[Some(wgpu::RenderPassColorAttachment{view: window_surface_view,resolve_target:None,ops: egui_wgpu::wgpu::Operations{load: egui_wgpu::wgpu::LoadOp::Load,store:StoreOp::Store,},})],depth_stencil_attachment:None,timestamp_writes:None,label:Some("egui main render pass"),occlusion_query_set:None,});self.renderer.render(&mut rpass.forget_lifetime(),&tris,&screen_descriptor);for x in&full_output.textures_delta.free{self.renderer.free_texture(x)}self.frame_started = false;}}
// UIlet _guard = tracing_tracy::client::Client::running().expect("client must be running").non_continuous_frame(frame_name!("ui"));
ui.renderer.begin_frame(&gpu.window);// most CPU time is taken
ui.run_app();// ...herelet frame_buffer_size = frame_buffer.texture.texture.size();let screen_descriptor = ScreenDescriptor{size_in_pixels:[frame_buffer_size.width, frame_buffer_size.height],pixels_per_point: gpu.window.scale_factor()asf32,};
ui.renderer.end_frame_and_draw(&gpu.device,&gpu.queue,&mut encoder,&gpu.window,&frame_buffer.texture.view,
screen_descriptor,);drop(_guard);
I really, really want to use egui for the UI in the game, but current performance I am getting is not feasible, unfortunately.
Some additional info:
checked via RenderDoc, rendering itself takes only 0.8ms, so it's purely CPU time, not GPU
once again, narrowing down has shown that 90% of that time is spent in the egui_demo_lib itself
I have compared how the official demo does things and it uses the egui_demo_lib in the same way
I have both running in "continuous" mode
events are fed to the app as soon as they arrive via winit
reacted with thumbs up emoji reacted with thumbs down emoji reacted with laugh emoji reacted with hooray emoji reacted with confused emoji reacted with heart emoji reacted with rocket emoji reacted with eyes emoji
-
Hi there, community! I am currently integrating
egui
to mywgpu
game using the official examples, via theegui-wgpu
andegui-winit
crates. Running theegui_demo_lib
application with all the subwindows open takes ~120ms (--release
, most of the time is taken by running the application itself, so I assume layouting and such), compared to the browser number of ~13ms.Why such a performance difference? Have I skipped something? Here is the renderer implementation I have stripped from the official examples:
I really, really want to use
egui
for the UI in the game, but current performance I am getting is not feasible, unfortunately.Some additional info:
egui_demo_lib
itselfegui_demo_lib
in the same waywinit
In advance, great thanks for the help!
Beta Was this translation helpful? Give feedback.
All reactions