wgui: introduce SharedContext to share between Contexts

This commit is contained in:
galister
2025-06-25 21:06:05 +09:00
parent 44b6da8967
commit 158562031f
5 changed files with 363 additions and 322 deletions

View File

@@ -8,24 +8,25 @@ use tracing_subscriber::layer::SubscriberExt;
use tracing_subscriber::util::SubscriberInitExt; use tracing_subscriber::util::SubscriberInitExt;
use vulkan::init_window; use vulkan::init_window;
use vulkano::{ use vulkano::{
Validated, VulkanError, Validated, VulkanError,
command_buffer::CommandBufferUsage, command_buffer::CommandBufferUsage,
format::Format, format::Format,
image::{ImageUsage, view::ImageView}, image::{ImageUsage, view::ImageView},
swapchain::{ swapchain::{
Surface, SurfaceInfo, Swapchain, SwapchainCreateInfo, SwapchainPresentInfo, acquire_next_image, Surface, SurfaceInfo, Swapchain, SwapchainCreateInfo, SwapchainPresentInfo,
}, acquire_next_image,
sync::GpuFuture, },
sync::GpuFuture,
}; };
use wgui::{ use wgui::{
event::{MouseButton, MouseDownEvent, MouseMotionEvent, MouseUpEvent, MouseWheelEvent}, event::{MouseButton, MouseDownEvent, MouseMotionEvent, MouseUpEvent, MouseWheelEvent},
gfx::WGfx, gfx::WGfx,
renderer_vk::{self}, renderer_vk::{self},
}; };
use winit::{ use winit::{
event::{ElementState, Event, MouseScrollDelta, WindowEvent}, event::{ElementState, Event, MouseScrollDelta, WindowEvent},
event_loop::ControlFlow, event_loop::ControlFlow,
keyboard::{KeyCode, PhysicalKey}, keyboard::{KeyCode, PhysicalKey},
}; };
use crate::testbed::{testbed_dashboard::TestbedDashboard, testbed_generic::TestbedGeneric}; use crate::testbed::{testbed_dashboard::TestbedDashboard, testbed_generic::TestbedGeneric};
@@ -37,304 +38,312 @@ mod timestep;
mod vulkan; mod vulkan;
fn init_logging() { fn init_logging() {
tracing_subscriber::registry() tracing_subscriber::registry()
.with( .with(
tracing_subscriber::fmt::layer() tracing_subscriber::fmt::layer()
.pretty() .pretty()
.with_writer(std::io::stderr), .with_writer(std::io::stderr),
) )
.with( .with(
/* read RUST_LOG env var */ /* read RUST_LOG env var */
EnvFilter::builder() EnvFilter::builder()
.with_default_directive(LevelFilter::DEBUG.into()) .with_default_directive(LevelFilter::DEBUG.into())
.from_env_lossy(), .from_env_lossy(),
) )
.init(); .init();
} }
fn load_testbed() -> anyhow::Result<Box<dyn Testbed>> { fn load_testbed() -> anyhow::Result<Box<dyn Testbed>> {
let name = std::env::var("TESTBED").unwrap_or_default(); let name = std::env::var("TESTBED").unwrap_or_default();
Ok(match name.as_str() { Ok(match name.as_str() {
"dashboard" => Box::new(TestbedDashboard::new()?), "dashboard" => Box::new(TestbedDashboard::new()?),
"" => Box::new(TestbedGeneric::new()?), "" => Box::new(TestbedGeneric::new()?),
_ => Box::new(TestbedAny::new(&name)?), _ => Box::new(TestbedAny::new(&name)?),
}) })
} }
fn main() -> Result<(), Box<dyn std::error::Error>> { fn main() -> Result<(), Box<dyn std::error::Error>> {
init_logging(); init_logging();
let (gfx, event_loop, window, surface) = init_window()?; let (gfx, event_loop, window, surface) = init_window()?;
let inner_size = window.inner_size(); let inner_size = window.inner_size();
let mut swapchain_size = [inner_size.width, inner_size.height]; let mut swapchain_size = [inner_size.width, inner_size.height];
let mut swapchain_create_info = let mut swapchain_create_info =
swapchain_create_info(&gfx, gfx.surface_format, surface.clone(), swapchain_size); swapchain_create_info(&gfx, gfx.surface_format, surface.clone(), swapchain_size);
let (mut swapchain, mut images) = { let (mut swapchain, mut images) = {
let (swapchain, images) = Swapchain::new( let (swapchain, images) = Swapchain::new(
gfx.device.clone(), gfx.device.clone(),
surface.clone(), surface.clone(),
swapchain_create_info.clone(), swapchain_create_info.clone(),
)?; )?;
let image_views = images let image_views = images
.into_iter() .into_iter()
.map(|image| ImageView::new_default(image).unwrap()) .map(|image| ImageView::new_default(image).unwrap())
.collect::<Vec<_>>(); .collect::<Vec<_>>();
(swapchain, image_views) (swapchain, image_views)
}; };
let mut recreate = false; let mut recreate = false;
let mut last_draw = std::time::Instant::now(); let mut last_draw = std::time::Instant::now();
let mut scale = window.scale_factor() as f32; let mut scale = window.scale_factor() as f32;
let mut testbed = load_testbed()?; let mut testbed = load_testbed()?;
let mut mouse = Vec2::ZERO; let mut mouse = Vec2::ZERO;
let mut render_context = let mut shared_context = renderer_vk::context::SharedContext::new(gfx.clone())?;
renderer_vk::context::Context::new(gfx.clone(), gfx.surface_format, scale)?; let mut render_context = renderer_vk::context::Context::new(&mut shared_context, scale)?;
render_context.update_viewport(swapchain_size, scale)?; render_context.update_viewport(&mut shared_context, swapchain_size, scale)?;
println!("new swapchain_size: {swapchain_size:?}"); println!("new swapchain_size: {swapchain_size:?}");
let mut profiler = profiler::Profiler::new(100); let mut profiler = profiler::Profiler::new(100);
let mut frame_index: u64 = 0; let mut frame_index: u64 = 0;
let mut timestep = Timestep::new(); let mut timestep = Timestep::new();
timestep.set_tps(60.0); timestep.set_tps(60.0);
#[allow(deprecated)] #[allow(deprecated)]
event_loop.run(move |event, elwt| { event_loop.run(move |event, elwt| {
elwt.set_control_flow(ControlFlow::Poll); elwt.set_control_flow(ControlFlow::Poll);
match event { match event {
Event::WindowEvent { Event::WindowEvent {
event: WindowEvent::MouseWheel { delta, .. }, event: WindowEvent::MouseWheel { delta, .. },
.. ..
} => match delta { } => match delta {
MouseScrollDelta::LineDelta(x, y) => testbed MouseScrollDelta::LineDelta(x, y) => testbed
.layout() .layout()
.push_event(&wgui::event::Event::MouseWheel(MouseWheelEvent { .push_event(&wgui::event::Event::MouseWheel(MouseWheelEvent {
shift: Vec2::new(x, y), shift: Vec2::new(x, y),
pos: mouse / scale, pos: mouse / scale,
device: 0, device: 0,
})) }))
.unwrap(), .unwrap(),
MouseScrollDelta::PixelDelta(pos) => testbed MouseScrollDelta::PixelDelta(pos) => testbed
.layout() .layout()
.push_event(&wgui::event::Event::MouseWheel(MouseWheelEvent { .push_event(&wgui::event::Event::MouseWheel(MouseWheelEvent {
shift: Vec2::new(pos.x as f32 / 5.0, pos.y as f32 / 5.0), shift: Vec2::new(pos.x as f32 / 5.0, pos.y as f32 / 5.0),
pos: mouse / scale, pos: mouse / scale,
device: 0, device: 0,
})) }))
.unwrap(), .unwrap(),
}, },
Event::WindowEvent { Event::WindowEvent {
event: WindowEvent::MouseInput { state, button, .. }, event: WindowEvent::MouseInput { state, button, .. },
.. ..
} => { } => {
if matches!(button, winit::event::MouseButton::Left) { if matches!(button, winit::event::MouseButton::Left) {
if matches!(state, winit::event::ElementState::Pressed) { if matches!(state, winit::event::ElementState::Pressed) {
testbed testbed
.layout() .layout()
.push_event(&wgui::event::Event::MouseDown(MouseDownEvent { .push_event(&wgui::event::Event::MouseDown(MouseDownEvent {
pos: mouse / scale, pos: mouse / scale,
button: MouseButton::Left, button: MouseButton::Left,
device: 0, device: 0,
})) }))
.unwrap(); .unwrap();
} else { } else {
testbed testbed
.layout() .layout()
.push_event(&wgui::event::Event::MouseUp(MouseUpEvent { .push_event(&wgui::event::Event::MouseUp(MouseUpEvent {
pos: mouse / scale, pos: mouse / scale,
button: MouseButton::Left, button: MouseButton::Left,
device: 0, device: 0,
})) }))
.unwrap(); .unwrap();
} }
} }
} }
Event::WindowEvent { Event::WindowEvent {
event: WindowEvent::CursorMoved { position, .. }, event: WindowEvent::CursorMoved { position, .. },
.. ..
} => { } => {
mouse = vec2(position.x as _, position.y as _); mouse = vec2(position.x as _, position.y as _);
testbed testbed
.layout() .layout()
.push_event(&wgui::event::Event::MouseMotion(MouseMotionEvent { .push_event(&wgui::event::Event::MouseMotion(MouseMotionEvent {
pos: mouse / scale, pos: mouse / scale,
device: 0, device: 0,
})) }))
.unwrap(); .unwrap();
} }
Event::WindowEvent { Event::WindowEvent {
event: WindowEvent::KeyboardInput { event, .. }, event: WindowEvent::KeyboardInput { event, .. },
.. ..
} => { } => {
if event.state == ElementState::Pressed { if event.state == ElementState::Pressed {
if event.physical_key == PhysicalKey::Code(KeyCode::Equal) { if event.physical_key == PhysicalKey::Code(KeyCode::Equal) {
scale *= 1.25; scale *= 1.25;
render_context render_context
.update_viewport(swapchain_size, scale) .update_viewport(&mut shared_context, swapchain_size, scale)
.unwrap(); .unwrap();
} }
if event.physical_key == PhysicalKey::Code(KeyCode::Minus) { if event.physical_key == PhysicalKey::Code(KeyCode::Minus) {
scale *= 0.75; scale *= 0.75;
render_context render_context
.update_viewport(swapchain_size, scale) .update_viewport(&mut shared_context, swapchain_size, scale)
.unwrap(); .unwrap();
} }
} }
} }
Event::WindowEvent { Event::WindowEvent {
event: WindowEvent::CloseRequested, event: WindowEvent::CloseRequested,
.. ..
} => { } => {
elwt.exit(); elwt.exit();
} }
Event::WindowEvent { Event::WindowEvent {
event: WindowEvent::Resized(_), event: WindowEvent::Resized(_),
.. ..
} => { } => {
recreate = true; recreate = true;
} }
Event::WindowEvent { Event::WindowEvent {
event: WindowEvent::RedrawRequested, event: WindowEvent::RedrawRequested,
.. ..
} => { } => {
if recreate { if recreate {
let inner_size = window.inner_size(); let inner_size = window.inner_size();
swapchain_size = [inner_size.width, inner_size.height]; swapchain_size = [inner_size.width, inner_size.height];
swapchain_create_info.image_extent = swapchain_size; swapchain_create_info.image_extent = swapchain_size;
(swapchain, images) = { (swapchain, images) = {
let (swapchain, images) = swapchain.recreate(swapchain_create_info.clone()).unwrap(); let (swapchain, images) =
swapchain.recreate(swapchain_create_info.clone()).unwrap();
let image_views = images let image_views = images
.into_iter() .into_iter()
.map(|image| ImageView::new_default(image).unwrap()) .map(|image| ImageView::new_default(image).unwrap())
.collect::<Vec<_>>(); .collect::<Vec<_>>();
(swapchain, image_views) (swapchain, image_views)
}; };
render_context render_context
.update_viewport(swapchain_size, scale) .update_viewport(&mut shared_context, swapchain_size, scale)
.unwrap(); .unwrap();
println!("new swapchain_size: {swapchain_size:?}"); println!("new swapchain_size: {swapchain_size:?}");
recreate = false; recreate = false;
window.request_redraw(); window.request_redraw();
} }
while timestep.on_tick() { while timestep.on_tick() {
testbed.layout().tick().unwrap(); testbed.layout().tick().unwrap();
} }
testbed testbed
.update( .update(
(swapchain_size[0] as f32 / scale) as _, (swapchain_size[0] as f32 / scale) as _,
(swapchain_size[1] as f32 / scale) as _, (swapchain_size[1] as f32 / scale) as _,
timestep.alpha, timestep.alpha,
) )
.unwrap(); .unwrap();
if !render_context.dirty && !testbed.layout().check_toggle_needs_redraw() { if !render_context.dirty && !testbed.layout().check_toggle_needs_redraw() {
// no need to redraw // no need to redraw
std::thread::sleep(std::time::Duration::from_millis(5)); // dirty fix to prevent cpu burning precious cycles doing a busy loop std::thread::sleep(std::time::Duration::from_millis(5)); // dirty fix to prevent cpu burning precious cycles doing a busy loop
return; return;
} }
log::trace!("drawing frame {}", frame_index); log::trace!("drawing frame {}", frame_index);
frame_index += 1; frame_index += 1;
profiler.start(); profiler.start();
{ {
let (image_index, _, acquire_future) = let (image_index, _, acquire_future) = match acquire_next_image(
match acquire_next_image(swapchain.clone(), None).map_err(Validated::unwrap) { swapchain.clone(),
Ok(r) => r, None,
Err(VulkanError::OutOfDate) => { )
recreate = true; .map_err(Validated::unwrap)
return; {
} Ok(r) => r,
Err(e) => panic!("failed to acquire next image: {e}"), Err(VulkanError::OutOfDate) => {
}; recreate = true;
return;
}
Err(e) => panic!("failed to acquire next image: {e}"),
};
let tgt = images[image_index as usize].clone(); let tgt = images[image_index as usize].clone();
last_draw = std::time::Instant::now(); last_draw = std::time::Instant::now();
let mut cmd_buf = gfx let mut cmd_buf = gfx
.create_gfx_command_buffer(CommandBufferUsage::OneTimeSubmit) .create_gfx_command_buffer(CommandBufferUsage::OneTimeSubmit)
.unwrap(); .unwrap();
cmd_buf.begin_rendering(tgt).unwrap(); cmd_buf.begin_rendering(tgt).unwrap();
let primitives = wgui::drawing::draw(testbed.layout()).unwrap(); let primitives = wgui::drawing::draw(testbed.layout()).unwrap();
render_context render_context
.draw(&gfx, &mut cmd_buf, &primitives) .draw(&mut shared_context, &mut cmd_buf, &primitives)
.unwrap(); .unwrap();
cmd_buf.end_rendering().unwrap(); cmd_buf.end_rendering().unwrap();
let cmd_buf = cmd_buf.build().unwrap(); let cmd_buf = cmd_buf.build().unwrap();
acquire_future acquire_future
.then_execute(gfx.queue_gfx.clone(), cmd_buf) .then_execute(gfx.queue_gfx.clone(), cmd_buf)
.unwrap() .unwrap()
.then_swapchain_present( .then_swapchain_present(
gfx.queue_gfx.clone(), gfx.queue_gfx.clone(),
SwapchainPresentInfo::swapchain_image_index(swapchain.clone(), image_index), SwapchainPresentInfo::swapchain_image_index(
) swapchain.clone(),
.then_signal_fence_and_flush() image_index,
.unwrap() ),
.wait(None) )
.unwrap(); .then_signal_fence_and_flush()
} .unwrap()
.wait(None)
.unwrap();
}
profiler.end(); profiler.end();
} }
Event::AboutToWait => { Event::AboutToWait => {
if last_draw.elapsed().as_millis() > 16 { if last_draw.elapsed().as_millis() > 16 {
window.request_redraw(); window.request_redraw();
} }
} }
_ => (), _ => (),
} }
})?; })?;
Ok(()) Ok(())
} }
fn swapchain_create_info( fn swapchain_create_info(
graphics: &WGfx, graphics: &WGfx,
format: Format, format: Format,
surface: Arc<Surface>, surface: Arc<Surface>,
extent: [u32; 2], extent: [u32; 2],
) -> SwapchainCreateInfo { ) -> SwapchainCreateInfo {
let surface_capabilities = graphics let surface_capabilities = graphics
.device .device
.physical_device() .physical_device()
.surface_capabilities(&surface, SurfaceInfo::default()) .surface_capabilities(&surface, SurfaceInfo::default())
.unwrap(); // want panic .unwrap(); // want panic
SwapchainCreateInfo { SwapchainCreateInfo {
min_image_count: surface_capabilities.min_image_count.max(2), min_image_count: surface_capabilities.min_image_count.max(2),
image_format: format, image_format: format,
image_extent: extent, image_extent: extent,
image_usage: ImageUsage::COLOR_ATTACHMENT, image_usage: ImageUsage::COLOR_ATTACHMENT,
composite_alpha: surface_capabilities composite_alpha: surface_capabilities
.supported_composite_alpha .supported_composite_alpha
.into_iter() .into_iter()
.next() .next()
.unwrap(), // want panic .unwrap(), // want panic
..Default::default() ..Default::default()
} }
} }

View File

@@ -2,6 +2,7 @@ use std::{cell::RefCell, rc::Rc, sync::Arc};
use cosmic_text::Buffer; use cosmic_text::Buffer;
use glam::{Mat4, Vec2, Vec3}; use glam::{Mat4, Vec2, Vec3};
use slotmap::{SlotMap, new_key_type};
use crate::{ use crate::{
drawing, drawing,
@@ -70,48 +71,81 @@ impl RendererPass<'_> {
} }
} }
pub struct Context { new_key_type! {
viewport: Viewport, struct SharedContextKey;
text_atlas: TextAtlas, }
pub struct SharedContext {
gfx: Arc<WGfx>,
atlas_map: SlotMap<SharedContextKey, SharedAtlas>,
rect_pipeline: RectPipeline, rect_pipeline: RectPipeline,
text_pipeline: TextPipeline, text_pipeline: TextPipeline,
}
impl SharedContext {
pub fn new(gfx: Arc<WGfx>) -> anyhow::Result<Self> {
let rect_pipeline = RectPipeline::new(gfx.clone(), gfx.surface_format)?;
let text_pipeline = TextPipeline::new(gfx.clone(), gfx.surface_format)?;
Ok(Self {
gfx,
atlas_map: SlotMap::with_key(),
rect_pipeline,
text_pipeline,
})
}
fn atlas_for_pixel_scale(&mut self, pixel_scale: f32) -> anyhow::Result<SharedContextKey> {
for (key, atlas) in self.atlas_map.iter() {
if (atlas.pixel_scale - pixel_scale).abs() < f32::EPSILON {
return Ok(key);
}
}
log::debug!("Initializing SharedAtlas for pixel scale {pixel_scale:.1}");
let text_atlas = TextAtlas::new(self.text_pipeline.clone())?;
Ok(self.atlas_map.insert(SharedAtlas {
text_atlas,
pixel_scale,
}))
}
}
pub struct SharedAtlas {
text_atlas: TextAtlas,
pixel_scale: f32, pixel_scale: f32,
}
pub struct Context {
viewport: Viewport,
shared_ctx_key: SharedContextKey,
pub dirty: bool, pub dirty: bool,
pixel_scale: f32,
empty_text: Rc<RefCell<Buffer>>, empty_text: Rc<RefCell<Buffer>>,
} }
impl Context { impl Context {
pub fn new( pub fn new(shared: &mut SharedContext, pixel_scale: f32) -> anyhow::Result<Self> {
gfx: Arc<WGfx>, let viewport = Viewport::new(shared.gfx.clone())?;
native_format: vulkano::format::Format, let shared_ctx_key = shared.atlas_for_pixel_scale(pixel_scale)?;
pixel_scale: f32,
) -> anyhow::Result<Self> {
let rect_pipeline = RectPipeline::new(gfx.clone(), native_format)?;
let text_pipeline = TextPipeline::new(gfx.clone(), native_format)?;
let viewport = Viewport::new(gfx.clone())?;
let text_atlas = TextAtlas::new(text_pipeline.clone())?;
Ok(Self { Ok(Self {
viewport, viewport,
text_atlas, shared_ctx_key,
rect_pipeline,
text_pipeline,
pixel_scale, pixel_scale,
dirty: true, dirty: true,
empty_text: Rc::new(RefCell::new(Buffer::new_empty(DEFAULT_METRICS))), empty_text: Rc::new(RefCell::new(Buffer::new_empty(DEFAULT_METRICS))),
}) })
} }
pub fn regen(&mut self) -> anyhow::Result<()> { pub fn update_viewport(
self.text_atlas = TextAtlas::new(self.text_pipeline.clone())?; &mut self,
self.dirty = true; shared: &mut SharedContext,
Ok(()) resolution: [u32; 2],
} pixel_scale: f32,
) -> anyhow::Result<()> {
pub fn update_viewport(&mut self, resolution: [u32; 2], pixel_scale: f32) -> anyhow::Result<()> { if (self.pixel_scale - pixel_scale).abs() < f32::EPSILON {
if self.pixel_scale != pixel_scale {
self.pixel_scale = pixel_scale; self.pixel_scale = pixel_scale;
self.regen()?; self.shared_ctx_key = shared.atlas_for_pixel_scale(pixel_scale)?;
} }
if self.viewport.resolution() != resolution { if self.viewport.resolution() != resolution {
@@ -143,34 +177,20 @@ impl Context {
Ok(()) Ok(())
} }
fn new_pass(&mut self, passes: &mut Vec<RendererPass>) -> anyhow::Result<()> {
passes.push(RendererPass::new(
&mut self.text_atlas,
self.rect_pipeline.clone(),
)?);
Ok(())
}
fn submit_pass(
&mut self,
gfx: &Arc<WGfx>,
cmd_buf: &mut GfxCommandBuffer,
pass: &mut RendererPass,
) -> anyhow::Result<()> {
pass.submit(gfx, &mut self.viewport, cmd_buf, &mut self.text_atlas)?;
Ok(())
}
pub fn draw( pub fn draw(
&mut self, &mut self,
gfx: &Arc<WGfx>, shared: &mut SharedContext,
cmd_buf: &mut GfxCommandBuffer, cmd_buf: &mut GfxCommandBuffer,
primitives: &[drawing::RenderPrimitive], primitives: &[drawing::RenderPrimitive],
) -> anyhow::Result<()> { ) -> anyhow::Result<()> {
self.dirty = false; self.dirty = false;
let mut passes = Vec::<RendererPass>::new();
self.new_pass(&mut passes)?; let atlas = shared.atlas_map.get_mut(self.shared_ctx_key).unwrap();
let mut passes = vec![RendererPass::new(
&mut atlas.text_atlas,
shared.rect_pipeline.clone(),
)?];
for primitive in primitives.iter() { for primitive in primitives.iter() {
let pass = passes.last_mut().unwrap(); // always safe let pass = passes.last_mut().unwrap(); // always safe
@@ -214,7 +234,12 @@ impl Context {
} }
let pass = passes.last_mut().unwrap(); let pass = passes.last_mut().unwrap();
self.submit_pass(gfx, cmd_buf, pass)?; pass.submit(
&shared.gfx,
&mut self.viewport,
cmd_buf,
&mut atlas.text_atlas,
)?;
Ok(()) Ok(())
} }

View File

@@ -33,11 +33,11 @@ pub struct GuiPanel {
} }
impl GuiPanel { impl GuiPanel {
pub fn new_from_template(app: &AppState, path: &str) -> anyhow::Result<Self> { pub fn new_from_template(app: &mut AppState, path: &str) -> anyhow::Result<Self> {
let (layout, _state) = let (layout, _state) =
wgui::parser::new_layout_from_assets(Box::new(gui::asset::GuiAsset {}), path)?; wgui::parser::new_layout_from_assets(Box::new(gui::asset::GuiAsset {}), path)?;
let context = WguiContext::new(app.gfx.clone(), app.gfx.surface_format, 1.0)?; let context = WguiContext::new(&mut app.wgui_shared, 1.0)?;
let mut timestep = Timestep::new(); let mut timestep = Timestep::new();
timestep.set_tps(60.0); timestep.set_tps(60.0);
@@ -48,9 +48,9 @@ impl GuiPanel {
}) })
} }
pub fn new_blank(app: &AppState) -> anyhow::Result<Self> { pub fn new_blank(app: &mut AppState) -> anyhow::Result<Self> {
let layout = Layout::new(Box::new(GuiAsset {}))?; let layout = Layout::new(Box::new(GuiAsset {}))?;
let context = WguiContext::new(app.gfx.clone(), app.gfx.surface_format, 1.0)?; let context = WguiContext::new(&mut app.wgui_shared, 1.0)?;
let mut timestep = Timestep::new(); let mut timestep = Timestep::new();
timestep.set_tps(60.0); timestep.set_tps(60.0);
@@ -177,7 +177,8 @@ impl OverlayRenderer for GuiPanel {
buf: &mut CommandBuffers, buf: &mut CommandBuffers,
_alpha: f32, _alpha: f32,
) -> anyhow::Result<bool> { ) -> anyhow::Result<bool> {
self.context.update_viewport(tgt.extent_u32arr(), 1.0)?; self.context
.update_viewport(&mut app.wgui_shared, tgt.extent_u32arr(), 1.0)?;
self.layout.update(MAX_SIZE_VEC2, self.timestep.alpha)?; self.layout.update(MAX_SIZE_VEC2, self.timestep.alpha)?;
let mut cmd_buf = app let mut cmd_buf = app
@@ -187,7 +188,8 @@ impl OverlayRenderer for GuiPanel {
cmd_buf.begin_rendering(tgt)?; cmd_buf.begin_rendering(tgt)?;
let primitives = wgui::drawing::draw(&self.layout)?; let primitives = wgui::drawing::draw(&self.layout)?;
self.context.draw(&app.gfx, &mut cmd_buf, &primitives)?; self.context
.draw(&mut app.wgui_shared, &mut cmd_buf, &primitives)?;
cmd_buf.end_rendering()?; cmd_buf.end_rendering()?;
buf.push(cmd_buf.build()?); buf.push(cmd_buf.build()?);

View File

@@ -31,7 +31,7 @@ const PIXELS_PER_UNIT: f32 = 80.;
#[allow(clippy::too_many_lines, clippy::significant_drop_tightening)] #[allow(clippy::too_many_lines, clippy::significant_drop_tightening)]
pub fn create_keyboard<O>( pub fn create_keyboard<O>(
app: &AppState, app: &mut AppState,
mut keymap: Option<XkbKeymap>, mut keymap: Option<XkbKeymap>,
) -> anyhow::Result<OverlayData<O>> ) -> anyhow::Result<OverlayData<O>>
where where

View File

@@ -4,7 +4,7 @@ use serde::{Deserialize, Serialize};
use smallvec::{SmallVec, smallvec}; use smallvec::{SmallVec, smallvec};
use std::sync::Arc; use std::sync::Arc;
use vulkano::image::view::ImageView; use vulkano::image::view::ImageView;
use wgui::gfx::WGfx; use wgui::{gfx::WGfx, renderer_vk::context::SharedContext as WSharedContext};
#[cfg(feature = "wayvr")] #[cfg(feature = "wayvr")]
use { use {
@@ -34,6 +34,8 @@ pub struct AppState {
pub hid_provider: HidWrapper, pub hid_provider: HidWrapper,
pub audio_provider: AudioOutput, pub audio_provider: AudioOutput,
pub wgui_shared: WSharedContext,
pub input_state: InputState, pub input_state: InputState,
pub screens: SmallVec<[ScreenMeta; 8]>, pub screens: SmallVec<[ScreenMeta; 8]>,
pub anchor: Affine3A, pub anchor: Affine3A,
@@ -71,6 +73,8 @@ impl AppState {
include_bytes!("res/557297.wav"), include_bytes!("res/557297.wav"),
); );
let wgui_shared = WSharedContext::new(gfx.clone())?;
Ok(Self { Ok(Self {
session, session,
tasks, tasks,
@@ -78,6 +82,7 @@ impl AppState {
gfx_extras, gfx_extras,
hid_provider: HidWrapper::new(), hid_provider: HidWrapper::new(),
audio_provider: AudioOutput::new(), audio_provider: AudioOutput::new(),
wgui_shared,
input_state: InputState::new(), input_state: InputState::new(),
screens: smallvec![], screens: smallvec![],
anchor: Affine3A::IDENTITY, anchor: Affine3A::IDENTITY,