wgui: introduce SharedContext to share between Contexts
This commit is contained in:
@@ -13,7 +13,8 @@ use vulkano::{
|
|||||||
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,
|
||||||
};
|
};
|
||||||
@@ -95,10 +96,10 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
|
|||||||
|
|
||||||
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);
|
||||||
@@ -180,14 +181,14 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
|
|||||||
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();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -215,7 +216,8 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
|
|||||||
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()
|
||||||
@@ -226,7 +228,7 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
|
|||||||
};
|
};
|
||||||
|
|
||||||
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:?}");
|
||||||
@@ -258,8 +260,12 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
|
|||||||
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(),
|
||||||
|
None,
|
||||||
|
)
|
||||||
|
.map_err(Validated::unwrap)
|
||||||
|
{
|
||||||
Ok(r) => r,
|
Ok(r) => r,
|
||||||
Err(VulkanError::OutOfDate) => {
|
Err(VulkanError::OutOfDate) => {
|
||||||
recreate = true;
|
recreate = true;
|
||||||
@@ -279,7 +285,7 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
|
|||||||
|
|
||||||
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();
|
||||||
@@ -291,7 +297,10 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
|
|||||||
.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(),
|
||||||
|
image_index,
|
||||||
|
),
|
||||||
)
|
)
|
||||||
.then_signal_fence_and_flush()
|
.then_signal_fence_and_flush()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
|
|||||||
@@ -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(())
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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()?);
|
||||||
|
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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,
|
||||||
|
|||||||
Reference in New Issue
Block a user