steamvr poc works

This commit is contained in:
galister
2024-01-23 16:43:17 +01:00
parent 6cfbc6ffcd
commit 51160f97fe
12 changed files with 817 additions and 376 deletions

106
Cargo.lock generated
View File

@@ -293,7 +293,7 @@ dependencies = [
"futures-lite 2.1.0", "futures-lite 2.1.0",
"parking", "parking",
"polling 3.3.1", "polling 3.3.1",
"rustix 0.38.26", "rustix 0.38.28",
"slab", "slab",
"tracing", "tracing",
"windows-sys 0.52.0", "windows-sys 0.52.0",
@@ -332,7 +332,7 @@ dependencies = [
"cfg-if", "cfg-if",
"event-listener 3.1.0", "event-listener 3.1.0",
"futures-lite 1.13.0", "futures-lite 1.13.0",
"rustix 0.38.26", "rustix 0.38.28",
"windows-sys 0.48.0", "windows-sys 0.48.0",
] ]
@@ -359,7 +359,7 @@ dependencies = [
"cfg-if", "cfg-if",
"futures-core", "futures-core",
"futures-io", "futures-io",
"rustix 0.38.26", "rustix 0.38.28",
"signal-hook-registry", "signal-hook-registry",
"slab", "slab",
"windows-sys 0.48.0", "windows-sys 0.48.0",
@@ -1794,7 +1794,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cb0889898416213fab133e1d33a0e5858a48177452750691bde3666d0fdbaf8b" checksum = "cb0889898416213fab133e1d33a0e5858a48177452750691bde3666d0fdbaf8b"
dependencies = [ dependencies = [
"hermit-abi 0.3.3", "hermit-abi 0.3.3",
"rustix 0.38.26", "rustix 0.38.28",
"windows-sys 0.48.0", "windows-sys 0.48.0",
] ]
@@ -1818,9 +1818,9 @@ dependencies = [
[[package]] [[package]]
name = "itoa" name = "itoa"
version = "1.0.9" version = "1.0.10"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "af150ab688ff2122fcef229be89cb50dd66af9e01a4ff320cc137eecc9bacc38" checksum = "b1a46d1a171d865aa5f83f92695765caa047a9b4cbae2cbf37dbd613a793fd4c"
[[package]] [[package]]
name = "jni" name = "jni"
@@ -2101,9 +2101,9 @@ dependencies = [
[[package]] [[package]]
name = "mio" name = "mio"
version = "0.8.9" version = "0.8.10"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3dce281c5e46beae905d4de1870d8b1509a9142b62eedf18b443b011ca8343d0" checksum = "8f3d0b296e374a4e6f3c7b0a1f5a51d748a0d34c85e7dc48fc3fa9a87657fe09"
dependencies = [ dependencies = [
"libc", "libc",
"log", "log",
@@ -2328,9 +2328,9 @@ dependencies = [
[[package]] [[package]]
name = "once_cell" name = "once_cell"
version = "1.18.0" version = "1.19.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d" checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92"
[[package]] [[package]]
name = "orbclient" name = "orbclient"
@@ -2520,7 +2520,7 @@ dependencies = [
"cfg-if", "cfg-if",
"concurrent-queue", "concurrent-queue",
"pin-project-lite", "pin-project-lite",
"rustix 0.38.26", "rustix 0.38.28",
"tracing", "tracing",
"windows-sys 0.52.0", "windows-sys 0.52.0",
] ]
@@ -2593,6 +2593,15 @@ dependencies = [
"memchr", "memchr",
] ]
[[package]]
name = "quick-xml"
version = "0.30.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "eff6510e86862b57b210fd8cbe8ed3f0d7d600b9c2863cd4549a2e033c66e956"
dependencies = [
"memchr",
]
[[package]] [[package]]
name = "quote" name = "quote"
version = "1.0.33" version = "1.0.33"
@@ -2747,9 +2756,9 @@ dependencies = [
[[package]] [[package]]
name = "rustix" name = "rustix"
version = "0.38.26" version = "0.38.28"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9470c4bf8246c8daf25f9598dca807fb6510347b1e1cfa55749113850c79d88a" checksum = "72e572a5e8ca657d7366229cdde4bd14c4eb5499a9573d4d366fe1b599daa316"
dependencies = [ dependencies = [
"bitflags 2.4.1", "bitflags 2.4.1",
"errno", "errno",
@@ -2774,9 +2783,9 @@ dependencies = [
[[package]] [[package]]
name = "ryu" name = "ryu"
version = "1.0.15" version = "1.0.16"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1ad4cc8da4ef723ed60bced201181d83791ad433213d8c24efffda1eec85d741" checksum = "f98d2aa92eebf49b69786be48e4477826b256916e84a57ff2a4f21923b48eb4c"
[[package]] [[package]]
name = "same-file" name = "same-file"
@@ -3115,7 +3124,7 @@ dependencies = [
"cfg-if", "cfg-if",
"fastrand 2.0.1", "fastrand 2.0.1",
"redox_syscall 0.4.1", "redox_syscall 0.4.1",
"rustix 0.38.26", "rustix 0.38.28",
"windows-sys 0.48.0", "windows-sys 0.48.0",
] ]
@@ -3298,9 +3307,9 @@ dependencies = [
[[package]] [[package]]
name = "unicode-bidi" name = "unicode-bidi"
version = "0.3.13" version = "0.3.14"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "92888ba5573ff080736b3648696b70cafad7d250551175acbaa4e0385b3e1460" checksum = "6f2528f27a9eb2b21e69c95319b30bd0efd85d09c379741b0f78ea1d86be2416"
[[package]] [[package]]
name = "unicode-ident" name = "unicode-ident"
@@ -3373,18 +3382,18 @@ checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
[[package]] [[package]]
name = "vk-parse" name = "vk-parse"
version = "0.8.0" version = "0.12.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4c6a0bda9bbe6b9e50e6456c80aa8fe4cca3b21e4311a1130c41e4915ec2e32a" checksum = "81086c28be67a8759cd80cbb3c8f7b520e0874605fc5eb74d5a1c9c2d1878e79"
dependencies = [ dependencies = [
"xml-rs", "xml-rs",
] ]
[[package]] [[package]]
name = "vulkano" name = "vulkano"
version = "0.33.0" version = "0.34.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1e1f15eeb9d93a05eb3c237332a10806eac1eb82444e54485bfcc1859c483c23" checksum = "70f4278f76307b3c388679234b397b4f90de29cdba53873c26b624ed82653d75"
dependencies = [ dependencies = [
"ahash", "ahash",
"ash", "ash",
@@ -3393,13 +3402,14 @@ dependencies = [
"crossbeam-queue", "crossbeam-queue",
"half", "half",
"heck", "heck",
"indexmap 1.9.3", "indexmap 2.1.0",
"libloading 0.7.4", "libloading 0.8.1",
"objc", "objc",
"once_cell", "once_cell",
"parking_lot", "parking_lot",
"proc-macro2", "proc-macro2",
"quote", "quote",
"raw-window-handle",
"regex", "regex",
"serde", "serde",
"serde_json", "serde_json",
@@ -3411,9 +3421,9 @@ dependencies = [
[[package]] [[package]]
name = "vulkano-macros" name = "vulkano-macros"
version = "0.33.0" version = "0.34.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "895b8a2cac1e7650d2d0552f2392da0970a358515ac11a34adaf19bfdc771b98" checksum = "52be622d364272fd77e298e7f68e8547ae66e7687cb86eb85335412cee7e3965"
dependencies = [ dependencies = [
"proc-macro-crate", "proc-macro-crate",
"proc-macro2", "proc-macro2",
@@ -3423,36 +3433,35 @@ dependencies = [
[[package]] [[package]]
name = "vulkano-shaders" name = "vulkano-shaders"
version = "0.33.0" version = "0.34.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5f8cf18e9becbc6d39f1c39e26bcf69546c93989553eb5748cd734a8a697a6e5" checksum = "d1f63401297565d74afb96e9add12587d8e46235140cee325a8eb6ba4602f4ee"
dependencies = [ dependencies = [
"ahash", "ahash",
"heck", "heck",
"proc-macro2", "proc-macro2",
"quote", "quote",
"shaderc", "shaderc",
"syn 1.0.109", "syn 2.0.39",
"vulkano", "vulkano",
] ]
[[package]] [[package]]
name = "vulkano-util" name = "vulkano-util"
version = "0.33.0" version = "0.34.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a71b6df05a391161c1baec645a918437c2949d3494bf74c8358fde291d37f5f4" checksum = "ff1f96a4055a8362c8fa77a17c01da184c6412961cd9572110533ff89e6669a7"
dependencies = [ dependencies = [
"ahash", "ahash",
"vulkano", "vulkano",
"vulkano-win",
"winit", "winit",
] ]
[[package]] [[package]]
name = "vulkano-win" name = "vulkano-win"
version = "0.33.0" version = "0.34.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "666c77efe5ea82837781961a6bcd957ee2e926777e8de0005f580335d6eaefe7" checksum = "b26c66e8600327823c15184e096eab37a7491d2f3f52b4956c21d84594fb0183"
dependencies = [ dependencies = [
"core-graphics-types", "core-graphics-types",
"objc", "objc",
@@ -3682,7 +3691,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b9b873b257fbc32ec909c0eb80dea312076a67014e65e245f5eb69a6b8ab330e" checksum = "b9b873b257fbc32ec909c0eb80dea312076a67014e65e245f5eb69a6b8ab330e"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quick-xml", "quick-xml 0.28.2",
"quote", "quote",
] ]
@@ -3727,7 +3736,7 @@ dependencies = [
"either", "either",
"home", "home",
"once_cell", "once_cell",
"rustix 0.38.26", "rustix 0.38.28",
] ]
[[package]] [[package]]
@@ -4014,9 +4023,9 @@ dependencies = [
[[package]] [[package]]
name = "winnow" name = "winnow"
version = "0.5.22" version = "0.5.26"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "40460c13b1e9b107cfc9ede71232f204c36250bbf6f9c78515e2e27ead3122a7" checksum = "b67b5f0a4e7a27a64c651977932b9dc5667ca7fc31ac44b03ed37a0cf42fdfff"
dependencies = [ dependencies = [
"memchr", "memchr",
] ]
@@ -4090,23 +4099,20 @@ dependencies = [
[[package]] [[package]]
name = "xcb" name = "xcb"
version = "1.2.2" version = "1.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fb3acf6b0945550d37d3a683b8f7de9d9f66b2c14dc390313b34d7ac6f1b4089" checksum = "5d27b37e69b8c05bfadcd968eb1a4fe27c9c52565b727f88512f43b89567e262"
dependencies = [ dependencies = [
"bitflags 1.3.2", "bitflags 1.3.2",
"libc", "libc",
"quick-xml", "quick-xml 0.30.0",
] ]
[[package]] [[package]]
name = "xcursor" name = "xcursor"
version = "0.3.4" version = "0.3.5"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "463705a63313cd4301184381c5e8042f0a7e9b4bb63653f216311d4ae74690b7" checksum = "6a0ccd7b4a5345edfcd0c3535718a4e9ff7798ffc536bb5b5a0e26ff84732911"
dependencies = [
"nom",
]
[[package]] [[package]]
name = "xdg-home" name = "xdg-home"
@@ -4220,18 +4226,18 @@ dependencies = [
[[package]] [[package]]
name = "zerocopy" name = "zerocopy"
version = "0.7.28" version = "0.7.30"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7d6f15f7ade05d2a4935e34a457b936c23dc70a05cc1d97133dc99e7a3fe0f0e" checksum = "306dca4455518f1f31635ec308b6b3e4eb1b11758cefafc782827d0aa7acb5c7"
dependencies = [ dependencies = [
"zerocopy-derive", "zerocopy-derive",
] ]
[[package]] [[package]]
name = "zerocopy-derive" name = "zerocopy-derive"
version = "0.7.28" version = "0.7.30"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dbbad221e3f78500350ecbd7dfa4e63ef945c05f4c61cb7f4d3f84cd0bba649b" checksum = "be912bf68235a88fbefd1b73415cb218405958d1655b2ece9035a19920bdf6ba"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",

View File

@@ -35,10 +35,10 @@ serde_yaml = "0.9.25"
smallvec = "1.11.0" smallvec = "1.11.0"
strum = { version = "0.25.0", features = ["derive"] } strum = { version = "0.25.0", features = ["derive"] }
tinyvec = "1.6.0" tinyvec = "1.6.0"
vulkano = { version = "0.33.0", features = ["serde"] } vulkano = { version = "0.34.1", features = ["serde"] }
vulkano-shaders = "0.33.0" vulkano-shaders = "0.34.0"
vulkano-util = "0.33.0" vulkano-util = "0.34.1"
vulkano-win = "0.33.0" vulkano-win = "0.34.0"
winit = "0.28.6" winit = "0.28.6"
wlx-capture = { path = "../wlx-capture" } wlx-capture = { path = "../wlx-capture" }

View File

@@ -39,11 +39,11 @@ where
get_screens_x11() get_screens_x11()
}; };
let watch = create_watch::<T>(&app, &screens); //let watch = create_watch::<T>(&app, &screens);
overlays.insert(watch.state.id, watch); //overlays.insert(watch.state.id, watch);
let keyboard = create_keyboard(&app); //let keyboard = create_keyboard(&app);
overlays.insert(keyboard.state.id, keyboard); //overlays.insert(keyboard.state.id, keyboard);
let mut first = true; let mut first = true;
for mut screen in screens { for mut screen in screens {

View File

@@ -8,7 +8,7 @@ use ovr_overlay::overlay::OverlayManager;
use vulkano::command_buffer::CommandBufferUsage; use vulkano::command_buffer::CommandBufferUsage;
use vulkano::format::Format; use vulkano::format::Format;
use vulkano::image::view::ImageView; use vulkano::image::view::ImageView;
use vulkano::image::{ImageAccess, ImageLayout, ImageViewAbstract, ImmutableImage}; use vulkano::image::ImageLayout;
use crate::backend::overlay::{OverlayData, OverlayRenderer, OverlayState, SplitOverlayBackend}; use crate::backend::overlay::{OverlayData, OverlayRenderer, OverlayState, SplitOverlayBackend};
use crate::graphics::WlxGraphics; use crate::graphics::WlxGraphics;
@@ -20,7 +20,7 @@ static AUTO_INCREMENT: AtomicUsize = AtomicUsize::new(1);
pub(super) struct LinePool { pub(super) struct LinePool {
lines: IdMap<usize, OverlayData<OpenVrOverlayData>>, lines: IdMap<usize, OverlayData<OpenVrOverlayData>>,
view: Arc<ImageView<ImmutableImage>>, view: Arc<ImageView>,
} }
impl LinePool { impl LinePool {
@@ -34,7 +34,7 @@ impl LinePool {
graphics graphics
.transition_layout( .transition_layout(
texture.inner().image.clone(), texture.clone(),
ImageLayout::ShaderReadOnlyOptimal, ImageLayout::ShaderReadOnlyOptimal,
ImageLayout::TransferSrcOptimal, ImageLayout::TransferSrcOptimal,
) )
@@ -116,7 +116,7 @@ impl LinePool {
} }
struct StaticRenderer { struct StaticRenderer {
view: Arc<ImageView<ImmutableImage>>, view: Arc<ImageView>,
} }
impl OverlayRenderer for StaticRenderer { impl OverlayRenderer for StaticRenderer {
@@ -124,7 +124,7 @@ impl OverlayRenderer for StaticRenderer {
fn pause(&mut self, _app: &mut AppState) {} fn pause(&mut self, _app: &mut AppState) {}
fn resume(&mut self, _app: &mut AppState) {} fn resume(&mut self, _app: &mut AppState) {}
fn render(&mut self, _app: &mut AppState) {} fn render(&mut self, _app: &mut AppState) {}
fn view(&mut self) -> Option<Arc<dyn ImageViewAbstract>> { fn view(&mut self) -> Option<Arc<ImageView>> {
Some(self.view.clone()) Some(self.view.clone())
} }
} }

View File

@@ -4,7 +4,7 @@ use ovr_overlay::{
pose::Matrix3x4, pose::Matrix3x4,
sys::{ETrackingUniverseOrigin, VRVulkanTextureData_t}, sys::{ETrackingUniverseOrigin, VRVulkanTextureData_t},
}; };
use vulkano::{image::ImageAccess, Handle, VulkanObject}; use vulkano::{Handle, VulkanObject};
use crate::{ use crate::{
backend::overlay::{OverlayData, RelativeTo}, backend::overlay::{OverlayData, RelativeTo},
@@ -195,7 +195,7 @@ impl OverlayData<OpenVrOverlayData> {
return; return;
}; };
let image = view.image().inner().image.clone(); let image = view.image().clone();
let raw_image = image.handle().as_raw(); let raw_image = image.handle().as_raw();
@@ -205,17 +205,14 @@ impl OverlayData<OpenVrOverlayData> {
} }
} }
let Some(format) = image.format() else { let dimensions = image.extent();
panic!("{}: Image format is None", self.state.name); let format = image.format();
};
let dimensions = image.dimensions();
let mut texture = VRVulkanTextureData_t { let mut texture = VRVulkanTextureData_t {
m_nImage: raw_image, m_nImage: raw_image,
m_nFormat: format as _, m_nFormat: format as _,
m_nWidth: dimensions.width(), m_nWidth: dimensions[0],
m_nHeight: dimensions.height(), m_nHeight: dimensions[1],
m_nSampleCount: image.samples() as u32, m_nSampleCount: image.samples() as u32,
m_pDevice: graphics.device.handle().as_raw() as *mut _, m_pDevice: graphics.device.handle().as_raw() as *mut _,
m_pPhysicalDevice: graphics.device.physical_device().handle().as_raw() as *mut _, m_pPhysicalDevice: graphics.device.physical_device().handle().as_raw() as *mut _,
@@ -224,8 +221,9 @@ impl OverlayData<OpenVrOverlayData> {
m_nQueueFamilyIndex: graphics.queue.queue_family_index(), m_nQueueFamilyIndex: graphics.queue.queue_family_index(),
}; };
log::debug!( log::info!(
"UploadTex: {:?}, {}x{}, {:?}", "{}: UploadTex {:?}, {}x{}, {:?}",
self.state.name,
format, format,
texture.m_nWidth, texture.m_nWidth,
texture.m_nHeight, texture.m_nHeight,
@@ -234,5 +232,6 @@ impl OverlayData<OpenVrOverlayData> {
if let Err(e) = overlay.set_image_vulkan(handle, &mut texture) { if let Err(e) = overlay.set_image_vulkan(handle, &mut texture) {
panic!("Failed to set overlay texture: {}", e); panic!("Failed to set overlay texture: {}", e);
} }
log::info!("{}: Uploaded texture", self.state.name);
} }
} }

View File

@@ -7,7 +7,7 @@ use std::{
}; };
use glam::{Affine2, Affine3A, Mat3A, Quat, Vec3, Vec3A}; use glam::{Affine2, Affine3A, Mat3A, Quat, Vec3, Vec3A};
use vulkano::image::ImageViewAbstract; use vulkano::image::view::ImageView;
use crate::state::AppState; use crate::state::AppState;
@@ -134,7 +134,7 @@ where
pub fn render(&mut self, app: &mut AppState) { pub fn render(&mut self, app: &mut AppState) {
self.backend.render(app); self.backend.render(app);
} }
pub fn view(&mut self) -> Option<Arc<dyn ImageViewAbstract>> { pub fn view(&mut self) -> Option<Arc<ImageView>> {
self.backend.view() self.backend.view()
} }
} }
@@ -144,7 +144,7 @@ pub trait OverlayRenderer {
fn pause(&mut self, app: &mut AppState); fn pause(&mut self, app: &mut AppState);
fn resume(&mut self, app: &mut AppState); fn resume(&mut self, app: &mut AppState);
fn render(&mut self, app: &mut AppState); fn render(&mut self, app: &mut AppState);
fn view(&mut self) -> Option<Arc<dyn ImageViewAbstract>>; fn view(&mut self) -> Option<Arc<ImageView>>;
} }
pub struct FallbackRenderer; pub struct FallbackRenderer;
@@ -154,7 +154,7 @@ impl OverlayRenderer for FallbackRenderer {
fn pause(&mut self, _app: &mut AppState) {} fn pause(&mut self, _app: &mut AppState) {}
fn resume(&mut self, _app: &mut AppState) {} fn resume(&mut self, _app: &mut AppState) {}
fn render(&mut self, _app: &mut AppState) {} fn render(&mut self, _app: &mut AppState) {}
fn view(&mut self) -> Option<Arc<dyn ImageViewAbstract>> { fn view(&mut self) -> Option<Arc<ImageView>> {
None None
} }
} }
@@ -196,7 +196,7 @@ impl OverlayRenderer for SplitOverlayBackend {
fn render(&mut self, app: &mut AppState) { fn render(&mut self, app: &mut AppState) {
self.renderer.render(app); self.renderer.render(app);
} }
fn view(&mut self) -> Option<Arc<dyn ImageViewAbstract>> { fn view(&mut self) -> Option<Arc<ImageView>> {
self.renderer.view() self.renderer.view()
} }
} }

View File

@@ -1,22 +1,26 @@
use std::{error::Error, io::Cursor, slice::Iter, sync::Arc}; use std::{
error::Error,
io::Cursor,
os::fd::{FromRawFd, IntoRawFd},
slice::Iter,
sync::Arc,
};
use ash::vk::SubmitInfo; use ash::vk::SubmitInfo;
use smallvec::smallvec; use smallvec::{smallvec, SmallVec};
use vulkano::{ use vulkano::{
buffer::{ buffer::{
allocator::{SubbufferAllocator, SubbufferAllocatorCreateInfo}, allocator::{SubbufferAllocator, SubbufferAllocatorCreateInfo},
Buffer, BufferContents, BufferCreateInfo, BufferUsage, Subbuffer, Buffer, BufferContents, BufferCreateInfo, BufferUsage, Subbuffer,
}, },
command_buffer::{ command_buffer::{
allocator::{ allocator::{StandardCommandBufferAllocator, StandardCommandBufferAllocatorCreateInfo},
CommandBufferAllocator, CommandBufferBuilderAlloc, StandardCommandBufferAllocator,
},
sys::{CommandBufferBeginInfo, UnsafeCommandBufferBuilder}, sys::{CommandBufferBeginInfo, UnsafeCommandBufferBuilder},
AutoCommandBufferBuilder, CommandBufferExecFuture, CommandBufferInheritanceInfo, AutoCommandBufferBuilder, CommandBufferExecFuture, CommandBufferInheritanceInfo,
CommandBufferInheritanceRenderPassType, CommandBufferInheritanceRenderingInfo, CommandBufferInheritanceRenderPassInfo, CommandBufferInheritanceRenderPassType,
CommandBufferLevel, CommandBufferUsage, PrimaryAutoCommandBuffer, CommandBufferLevel, CommandBufferUsage, CopyBufferToImageInfo, PrimaryAutoCommandBuffer,
PrimaryCommandBufferAbstract, RenderingAttachmentInfo, RenderingInfo, PrimaryCommandBufferAbstract, RenderPassBeginInfo, SecondaryAutoCommandBuffer,
SecondaryAutoCommandBuffer, SubpassContents, SubpassBeginInfo, SubpassContents, SubpassEndInfo,
}, },
descriptor_set::{ descriptor_set::{
allocator::StandardDescriptorSetAllocator, PersistentDescriptorSet, WriteDescriptorSet, allocator::StandardDescriptorSetAllocator, PersistentDescriptorSet, WriteDescriptorSet,
@@ -27,33 +31,47 @@ use vulkano::{
}, },
format::Format, format::Format,
image::{ image::{
sys::Image, AttachmentImage, ImageCreateFlags, ImageDimensions, ImageError, ImageLayout, sampler::{Filter, Sampler, SamplerAddressMode, SamplerCreateInfo},
ImageUsage, ImageViewAbstract, ImmutableImage, MipmapsCount, StorageImage, SubresourceData, sys::RawImage,
SwapchainImage, view::ImageView,
Image, ImageCreateInfo, ImageLayout, ImageTiling, ImageType, ImageUsage, SampleCount,
SubresourceLayout,
},
instance::{Instance, InstanceCreateFlags, InstanceCreateInfo, InstanceExtensions},
memory::{
allocator::{
AllocationCreateInfo, MemoryAllocator, MemoryTypeFilter, StandardMemoryAllocator,
},
DedicatedAllocation, DeviceMemory, ExternalMemoryHandleType, ExternalMemoryHandleTypes,
MemoryAllocateInfo, MemoryImportInfo, ResourceMemory,
}, },
instance::{Instance, InstanceCreateInfo, InstanceExtensions},
memory::allocator::{AllocationCreateInfo, MemoryUsage, StandardMemoryAllocator},
pipeline::{ pipeline::{
graphics::{ graphics::{
color_blend::{AttachmentBlend, ColorBlendState}, color_blend::{AttachmentBlend, ColorBlendAttachmentState, ColorBlendState},
input_assembly::InputAssemblyState, input_assembly::InputAssemblyState,
render_pass::PipelineRenderingCreateInfo, multisample::MultisampleState,
vertex_input::Vertex, rasterization::RasterizationState,
vertex_input::{Vertex, VertexDefinition},
viewport::{Viewport, ViewportState}, viewport::{Viewport, ViewportState},
GraphicsPipelineCreateInfo,
}, },
GraphicsPipeline, Pipeline, PipelineBindPoint, layout::PipelineDescriptorSetLayoutCreateInfo,
DynamicState, GraphicsPipeline, Pipeline, PipelineBindPoint, PipelineLayout,
PipelineShaderStageCreateInfo,
},
render_pass::{
AttachmentDescription, AttachmentLoadOp, AttachmentReference, AttachmentStoreOp,
Framebuffer, FramebufferCreateInfo, RenderPass, RenderPassCreateInfo, Subpass,
SubpassDescription,
}, },
render_pass::{LoadOp, StoreOp},
sampler::{Filter, Sampler, SamplerAddressMode, SamplerCreateInfo},
shader::ShaderModule, shader::ShaderModule,
swapchain::{CompositeAlpha, Surface, Swapchain, SwapchainCreateInfo}, swapchain::{CompositeAlpha, Surface, Swapchain, SwapchainCreateInfo},
sync::{ sync::{
fence::Fence, future::NowFuture, AccessFlags, DependencyInfo, GpuFuture, fence::Fence, future::NowFuture, AccessFlags, DependencyInfo, GpuFuture,
ImageMemoryBarrier, PipelineStages, ImageMemoryBarrier, PipelineStages,
}, },
Version, VulkanLibrary, VulkanObject, DeviceSize, VulkanLibrary, VulkanObject,
}; };
use vulkano_win::VkSurfaceBuild;
use winit::{ use winit::{
event_loop::EventLoop, event_loop::EventLoop,
window::{Window, WindowBuilder}, window::{Window, WindowBuilder},
@@ -98,8 +116,11 @@ impl WlxGraphics {
#[cfg(not(debug_assertions))] #[cfg(not(debug_assertions))]
let layers = vec![]; let layers = vec![];
// TODO headless
let event_loop = EventLoop::new();
let library_extensions = Surface::required_extensions(&event_loop);
let library = VulkanLibrary::new().unwrap(); let library = VulkanLibrary::new().unwrap();
let library_extensions = vulkano_win::required_extensions(&library);
let required_extensions = library_extensions.union(&vk_instance_extensions); let required_extensions = library_extensions.union(&vk_instance_extensions);
log::debug!("Instance exts for app: {:?}", &required_extensions); log::debug!("Instance exts for app: {:?}", &required_extensions);
@@ -108,9 +129,9 @@ impl WlxGraphics {
let instance = Instance::new( let instance = Instance::new(
library, library,
InstanceCreateInfo { InstanceCreateInfo {
flags: InstanceCreateFlags::ENUMERATE_PORTABILITY,
enabled_extensions: required_extensions, enabled_extensions: required_extensions,
enabled_layers: layers, enabled_layers: layers,
enumerate_portability: true,
..Default::default() ..Default::default()
}, },
) )
@@ -128,17 +149,15 @@ impl WlxGraphics {
log::debug!("Device exts for app: {:?}", &device_extensions); log::debug!("Device exts for app: {:?}", &device_extensions);
// TODO headless // TODO headless
let event_loop = EventLoop::new(); let window = Arc::new(WindowBuilder::new().build(&event_loop).unwrap());
let surface = WindowBuilder::new() let surface = Surface::from_window(instance.clone(), window.clone()).unwrap();
.build_vk_surface(&event_loop, instance.clone())
.unwrap();
let (physical_device, my_extensions, queue_family_index) = instance let (physical_device, my_extensions, queue_family_index) = instance
.enumerate_physical_devices() .enumerate_physical_devices()
.unwrap() .unwrap()
.filter(|p| { //.filter(|p| {
p.api_version() >= Version::V1_3 || p.supported_extensions().khr_dynamic_rendering // p.api_version() >= Version::V1_3 || p.supported_extensions().khr_dynamic_rendering
}) //})
.filter_map(|p| { .filter_map(|p| {
let runtime_extensions = vk_device_extensions_fn(&p); let runtime_extensions = vk_device_extensions_fn(&p);
log::debug!( log::debug!(
@@ -178,9 +197,9 @@ impl WlxGraphics {
physical_device.properties().device_name, physical_device.properties().device_name,
); );
if physical_device.api_version() < Version::V1_3 { //if physical_device.api_version() < Version::V1_3 {
device_extensions.khr_dynamic_rendering = true; // device_extensions.khr_dynamic_rendering = true;
} //}
let (device, mut queues) = Device::new( let (device, mut queues) = Device::new(
physical_device, physical_device,
@@ -203,11 +222,16 @@ impl WlxGraphics {
let memory_allocator = Arc::new(StandardMemoryAllocator::new_default(device.clone())); let memory_allocator = Arc::new(StandardMemoryAllocator::new_default(device.clone()));
let command_buffer_allocator = Arc::new(StandardCommandBufferAllocator::new( let command_buffer_allocator = Arc::new(StandardCommandBufferAllocator::new(
device.clone(),
StandardCommandBufferAllocatorCreateInfo {
secondary_buffer_count: 32,
..Default::default()
},
));
let descriptor_set_allocator = Arc::new(StandardDescriptorSetAllocator::new(
device.clone(), device.clone(),
Default::default(), Default::default(),
)); ));
let descriptor_set_allocator =
Arc::new(StandardDescriptorSetAllocator::new(device.clone()));
let vertices = [ let vertices = [
Vert2Uv { Vert2Uv {
@@ -228,13 +252,14 @@ impl WlxGraphics {
}, },
]; ];
let quad_verts = Buffer::from_iter( let quad_verts = Buffer::from_iter(
&memory_allocator, memory_allocator.clone(),
BufferCreateInfo { BufferCreateInfo {
usage: BufferUsage::VERTEX_BUFFER, usage: BufferUsage::VERTEX_BUFFER,
..Default::default() ..Default::default()
}, },
AllocationCreateInfo { AllocationCreateInfo {
usage: MemoryUsage::Upload, memory_type_filter: MemoryTypeFilter::PREFER_DEVICE
| MemoryTypeFilter::HOST_SEQUENTIAL_WRITE,
..Default::default() ..Default::default()
}, },
vertices.into_iter(), vertices.into_iter(),
@@ -242,13 +267,14 @@ impl WlxGraphics {
.unwrap(); .unwrap();
let quad_indices = Buffer::from_iter( let quad_indices = Buffer::from_iter(
&memory_allocator, memory_allocator.clone(),
BufferCreateInfo { BufferCreateInfo {
usage: BufferUsage::INDEX_BUFFER, usage: BufferUsage::INDEX_BUFFER,
..Default::default() ..Default::default()
}, },
AllocationCreateInfo { AllocationCreateInfo {
usage: MemoryUsage::Upload, memory_type_filter: MemoryTypeFilter::PREFER_DEVICE
| MemoryTypeFilter::HOST_SEQUENTIAL_WRITE,
..Default::default() ..Default::default()
}, },
INDICES.iter().cloned(), INDICES.iter().cloned(),
@@ -271,10 +297,7 @@ impl WlxGraphics {
} }
#[allow(dead_code)] #[allow(dead_code)]
pub fn create_swapchain( pub fn create_swapchain(&self, format: Option<Format>) -> (Arc<Swapchain>, Vec<Arc<Image>>) {
&self,
format: Option<Format>,
) -> (Arc<Swapchain>, Vec<Arc<SwapchainImage>>) {
let (min_image_count, composite_alpha, image_format) = if let Some(format) = format { let (min_image_count, composite_alpha, image_format) = if let Some(format) = format {
(1, CompositeAlpha::Opaque, format) (1, CompositeAlpha::Opaque, format)
} else { } else {
@@ -314,7 +337,7 @@ impl WlxGraphics {
self.surface.clone(), self.surface.clone(),
SwapchainCreateInfo { SwapchainCreateInfo {
min_image_count, min_image_count,
image_format: Some(image_format), image_format,
image_extent: window.inner_size().into(), image_extent: window.inner_size().into(),
image_usage: ImageUsage::COLOR_ATTACHMENT, image_usage: ImageUsage::COLOR_ATTACHMENT,
composite_alpha, composite_alpha,
@@ -370,13 +393,14 @@ impl WlxGraphics {
T: BufferContents + Clone, T: BufferContents + Clone,
{ {
Buffer::from_iter( Buffer::from_iter(
&self.memory_allocator, self.memory_allocator.clone(),
BufferCreateInfo { BufferCreateInfo {
usage, usage,
..Default::default() ..Default::default()
}, },
AllocationCreateInfo { AllocationCreateInfo {
usage: MemoryUsage::Upload, memory_type_filter: MemoryTypeFilter::PREFER_HOST
| MemoryTypeFilter::HOST_SEQUENTIAL_WRITE,
..Default::default() ..Default::default()
}, },
contents.cloned(), contents.cloned(),
@@ -384,12 +408,8 @@ impl WlxGraphics {
.unwrap() .unwrap()
} }
pub fn dmabuf_texture(&self, frame: DmabufFrame) -> Result<Arc<StorageImage>, ImageError> { pub fn dmabuf_texture(&self, frame: DmabufFrame) -> Option<Arc<Image>> {
let dimensions = ImageDimensions::Dim2d { let extent = [frame.format.width, frame.format.height, 1];
width: frame.format.width,
height: frame.format.height,
array_layers: 1,
};
let format = match frame.format.fourcc { let format = match frame.format.fourcc {
DRM_FORMAT_ABGR8888 => Format::R8G8B8A8_UNORM, DRM_FORMAT_ABGR8888 => Format::R8G8B8A8_UNORM,
@@ -399,60 +419,145 @@ impl WlxGraphics {
_ => panic!("Unsupported dmabuf format {:x}", frame.format.fourcc), _ => panic!("Unsupported dmabuf format {:x}", frame.format.fourcc),
}; };
let planes = frame let layouts: Vec<SubresourceLayout> = (0..frame.num_planes)
.planes .into_iter()
.iter() .map(|i| {
.take(frame.num_planes) let plane = &frame.planes[i];
.filter_map(|plane| { SubresourceLayout {
let Some(fd) = plane.fd else {
return None;
};
Some(SubresourceData {
fd,
offset: plane.offset as _, offset: plane.offset as _,
size: 0,
row_pitch: plane.stride as _, row_pitch: plane.stride as _,
}) array_pitch: None,
depth_pitch: None,
}
}) })
.collect(); .collect();
StorageImage::new_from_dma_buf_fd( let external_memory_handle_types = ExternalMemoryHandleTypes::DMA_BUF;
&self.memory_allocator,
self.device.clone(),
dimensions,
format,
ImageUsage::SAMPLED | ImageUsage::TRANSFER_SRC,
ImageCreateFlags::empty(),
[self.queue.queue_family_index()],
planes,
frame.format.modifier,
)
}
pub fn render_texture(&self, width: u32, height: u32, format: Format) -> Arc<AttachmentImage> { let image = RawImage::new(
let tex = AttachmentImage::with_usage( self.device.clone(),
&self.memory_allocator, ImageCreateInfo {
[width, height], image_type: ImageType::Dim2d,
format, format,
ImageUsage::SAMPLED | ImageUsage::TRANSFER_SRC | ImageUsage::COLOR_ATTACHMENT, extent,
usage: ImageUsage::SAMPLED | ImageUsage::TRANSFER_SRC,
external_memory_handle_types,
tiling: ImageTiling::DrmFormatModifier,
drm_format_modifiers: vec![frame.format.modifier],
drm_format_modifier_plane_layouts: layouts,
..Default::default()
},
) )
.unwrap(); .unwrap();
tex let requirements = image.memory_requirements()[0];
let memory_type_index = self
.memory_allocator
.find_memory_type_index(
requirements.memory_type_bits,
MemoryTypeFilter::PREFER_DEVICE,
)
.unwrap();
debug_assert!(self.device.enabled_extensions().khr_external_memory_fd);
debug_assert!(self.device.enabled_extensions().khr_external_memory);
debug_assert!(self.device.enabled_extensions().ext_external_memory_dma_buf);
let memory = unsafe {
if frame.num_planes != 1 {
log::error!("Unsupported number of DMA-buf planes: {}", frame.num_planes);
return None;
}
let Some(fd) = frame.planes[0].fd else {
log::error!("DMA-buf plane has no FD");
return None;
};
let file = std::fs::File::from_raw_fd(fd);
let new_file = file.try_clone().unwrap();
file.into_raw_fd();
DeviceMemory::import(
self.device.clone(),
MemoryAllocateInfo {
allocation_size: requirements.layout.size(),
memory_type_index,
dedicated_allocation: Some(DedicatedAllocation::Image(&image)),
..Default::default()
},
MemoryImportInfo::Fd {
file: new_file,
handle_type: ExternalMemoryHandleType::DmaBuf,
},
)
.unwrap()
};
let allocations: SmallVec<[ResourceMemory; 1]> =
smallvec![ResourceMemory::new_dedicated(memory)];
if let Some(image) = image.bind_memory(allocations).ok() {
Some(Arc::new(image))
} else {
None
}
}
pub fn render_texture(&self, width: u32, height: u32, format: Format) -> Arc<Image> {
Image::new(
self.memory_allocator.clone(),
ImageCreateInfo {
image_type: ImageType::Dim2d,
format,
extent: [width, height, 1],
usage: ImageUsage::TRANSFER_SRC
| ImageUsage::SAMPLED
| ImageUsage::COLOR_ATTACHMENT,
..Default::default()
},
AllocationCreateInfo::default(),
)
.unwrap()
} }
pub fn create_pipeline( pub fn create_pipeline(
self: &Arc<Self>, self: &Arc<Self>,
render_target: Arc<ImageView>,
vert: Arc<ShaderModule>, vert: Arc<ShaderModule>,
frag: Arc<ShaderModule>, frag: Arc<ShaderModule>,
format: Format, format: Format,
) -> Arc<WlxPipeline> { ) -> Arc<WlxPipeline> {
Arc::new(WlxPipeline::new(self.clone(), vert, frag, format)) Arc::new(WlxPipeline::new(
render_target,
self.clone(),
vert,
frag,
format,
))
} }
pub fn create_command_buffer( pub fn create_pipeline_with_layouts(
self: &Arc<Self>, self: &Arc<Self>,
usage: CommandBufferUsage, render_target: Arc<ImageView>,
) -> WlxCommandBuffer<PrimaryAutoCommandBuffer> { vert: Arc<ShaderModule>,
frag: Arc<ShaderModule>,
format: Format,
initial_layout: ImageLayout,
final_layout: ImageLayout,
) -> Arc<WlxPipeline> {
Arc::new(WlxPipeline::new_with_layout(
render_target,
self.clone(),
vert,
frag,
format,
initial_layout,
final_layout,
))
}
pub fn create_command_buffer(self: &Arc<Self>, usage: CommandBufferUsage) -> WlxCommandBuffer {
let command_buffer = AutoCommandBufferBuilder::primary( let command_buffer = AutoCommandBufferBuilder::primary(
&self.command_buffer_allocator, &self.command_buffer_allocator,
self.queue.queue_family_index(), self.queue.queue_family_index(),
@@ -482,31 +587,25 @@ impl WlxGraphics {
..ImageMemoryBarrier::image(image) ..ImageMemoryBarrier::image(image)
}; };
let builder_alloc = self
.command_buffer_allocator
.allocate(
self.queue.queue_family_index(),
CommandBufferLevel::Primary,
1,
)
.unwrap()
.next()
.unwrap();
let command_buffer = unsafe { let command_buffer = unsafe {
let mut builder = UnsafeCommandBufferBuilder::new( let mut builder = UnsafeCommandBufferBuilder::new(
&builder_alloc.inner(), &self.command_buffer_allocator,
self.queue.queue_family_index(),
CommandBufferLevel::Primary,
CommandBufferBeginInfo { CommandBufferBeginInfo {
usage: CommandBufferUsage::OneTimeSubmit, usage: CommandBufferUsage::OneTimeSubmit,
inheritance_info: None,
..Default::default() ..Default::default()
}, },
) )
.unwrap(); .unwrap();
builder.pipeline_barrier(&DependencyInfo { builder
image_memory_barriers: smallvec![barrier], .pipeline_barrier(&DependencyInfo {
..Default::default() image_memory_barriers: smallvec![barrier],
}); ..Default::default()
})
.unwrap();
builder.build().unwrap() builder.build().unwrap()
}; };
@@ -535,24 +634,27 @@ impl WlxGraphics {
} }
} }
pub struct WlxCommandBuffer<T> { pub struct WlxCommandBuffer {
graphics: Arc<WlxGraphics>, graphics: Arc<WlxGraphics>,
command_buffer: AutoCommandBufferBuilder<T, Arc<StandardCommandBufferAllocator>>, command_buffer: AutoCommandBufferBuilder<
PrimaryAutoCommandBuffer<Arc<StandardCommandBufferAllocator>>,
Arc<StandardCommandBufferAllocator>,
>,
} }
impl<T> WlxCommandBuffer<T> { impl WlxCommandBuffer {
pub fn begin(mut self, render_target: Arc<dyn ImageViewAbstract>) -> Self { pub fn begin_render_pass(mut self, pipeline: &WlxPipeline) -> Self {
self.command_buffer self.command_buffer
.begin_rendering(RenderingInfo { .begin_render_pass(
contents: SubpassContents::SecondaryCommandBuffers, RenderPassBeginInfo {
color_attachments: vec![Some(RenderingAttachmentInfo { clear_values: vec![Some([0.0, 0.0, 0.0, 1.0].into())],
load_op: LoadOp::Clear, ..RenderPassBeginInfo::framebuffer(pipeline.framebuffer.clone())
store_op: StoreOp::Store, },
clear_value: Some([0.0, 0.0, 0.0, 0.0].into()), SubpassBeginInfo {
..RenderingAttachmentInfo::image_view(render_target.clone()) contents: SubpassContents::SecondaryCommandBuffers,
})], ..Default::default()
..Default::default() },
}) )
.unwrap(); .unwrap();
self self
} }
@@ -571,26 +673,46 @@ impl<T> WlxCommandBuffer<T> {
height: u32, height: u32,
format: Format, format: Format,
data: Vec<u8>, data: Vec<u8>,
) -> Arc<ImmutableImage> { ) -> Arc<Image> {
let dimensions = ImageDimensions::Dim2d { let image = Image::new(
width, self.graphics.memory_allocator.clone(),
height, ImageCreateInfo {
array_layers: 1, image_type: ImageType::Dim2d,
}; format,
extent: [width, height, 1],
ImmutableImage::from_iter( usage: ImageUsage::TRANSFER_DST | ImageUsage::TRANSFER_SRC | ImageUsage::SAMPLED,
&self.graphics.memory_allocator, ..Default::default()
data, },
dimensions, AllocationCreateInfo::default(),
MipmapsCount::Log2, // required for TRANSFER_SRC
format,
&mut self.command_buffer,
) )
.unwrap() .unwrap();
let buffer: Subbuffer<[u8]> = Buffer::new_slice(
self.graphics.memory_allocator.clone(),
BufferCreateInfo {
usage: BufferUsage::TRANSFER_SRC,
..Default::default()
},
AllocationCreateInfo {
memory_type_filter: MemoryTypeFilter::PREFER_HOST
| MemoryTypeFilter::HOST_SEQUENTIAL_WRITE,
..Default::default()
},
data.len() as DeviceSize,
)
.unwrap();
buffer.write().unwrap().copy_from_slice(data.as_slice());
self.command_buffer
.copy_buffer_to_image(CopyBufferToImageInfo::buffer_image(buffer, image.clone()))
.unwrap();
image
} }
#[allow(dead_code)] #[allow(dead_code)]
pub fn texture2d_png(&mut self, bytes: Vec<u8>) -> Arc<ImmutableImage> { pub fn texture2d_png(&mut self, bytes: Vec<u8>) -> Arc<Image> {
let cursor = Cursor::new(bytes); let cursor = Cursor::new(bytes);
let decoder = png::Decoder::new(cursor); let decoder = png::Decoder::new(cursor);
let mut reader = decoder.read_info().unwrap(); let mut reader = decoder.read_info().unwrap();
@@ -604,13 +726,15 @@ impl<T> WlxCommandBuffer<T> {
} }
} }
impl WlxCommandBuffer<PrimaryAutoCommandBuffer> { impl WlxCommandBuffer {
pub fn end_render(mut self) -> Self { pub fn end_render_pass(mut self) -> Self {
self.command_buffer.end_rendering().unwrap(); self.command_buffer
.end_render_pass(SubpassEndInfo::default())
.unwrap();
self self
} }
pub fn build(self) -> PrimaryAutoCommandBuffer { pub fn build(self) -> Arc<PrimaryAutoCommandBuffer<Arc<StandardCommandBufferAllocator>>> {
self.command_buffer.build().unwrap() self.command_buffer.build().unwrap()
} }
@@ -629,11 +753,79 @@ impl WlxCommandBuffer<PrimaryAutoCommandBuffer> {
pub struct WlxPipeline { pub struct WlxPipeline {
pub graphics: Arc<WlxGraphics>, pub graphics: Arc<WlxGraphics>,
pub pipeline: Arc<GraphicsPipeline>, pub pipeline: Arc<GraphicsPipeline>,
pub render_pass: Arc<RenderPass>,
pub framebuffer: Arc<Framebuffer>,
pub view: Arc<ImageView>,
pub format: Format, pub format: Format,
} }
impl WlxPipeline { impl WlxPipeline {
fn new( fn new(
render_target: Arc<ImageView>,
graphics: Arc<WlxGraphics>,
vert: Arc<ShaderModule>,
frag: Arc<ShaderModule>,
format: Format,
) -> Self {
let render_pass = vulkano::single_pass_renderpass!(
graphics.device.clone(),
attachments: {
color: {
format: format,
samples: 1,
load_op: Clear,
store_op: Store,
},
},
pass: {
color: [color],
depth_stencil: {},
},
)
.unwrap();
Self::new_from_pass(render_target, render_pass, graphics, vert, frag, format)
}
fn new_with_layout(
render_target: Arc<ImageView>,
graphics: Arc<WlxGraphics>,
vert: Arc<ShaderModule>,
frag: Arc<ShaderModule>,
format: Format,
initial_layout: ImageLayout,
final_layout: ImageLayout,
) -> Self {
let render_pass_description = RenderPassCreateInfo {
attachments: vec![AttachmentDescription {
format: format,
samples: SampleCount::Sample1,
load_op: AttachmentLoadOp::Clear,
store_op: AttachmentStoreOp::Store,
initial_layout,
final_layout,
..Default::default()
}],
subpasses: vec![SubpassDescription {
color_attachments: vec![Some(AttachmentReference {
attachment: 0,
layout: ImageLayout::ColorAttachmentOptimal,
..Default::default()
})],
..Default::default()
}],
..Default::default()
};
let render_pass =
RenderPass::new(graphics.device.clone(), render_pass_description).unwrap();
Self::new_from_pass(render_target, render_pass, graphics, vert, frag, format)
}
fn new_from_pass(
render_target: Arc<ImageView>,
render_pass: Arc<RenderPass>,
graphics: Arc<WlxGraphics>, graphics: Arc<WlxGraphics>,
vert: Arc<ShaderModule>, vert: Arc<ShaderModule>,
frag: Arc<ShaderModule>, frag: Arc<ShaderModule>,
@@ -641,24 +833,64 @@ impl WlxPipeline {
) -> Self { ) -> Self {
let vep = vert.entry_point("main").unwrap(); let vep = vert.entry_point("main").unwrap();
let fep = frag.entry_point("main").unwrap(); let fep = frag.entry_point("main").unwrap();
let pipeline = GraphicsPipeline::start()
.render_pass(PipelineRenderingCreateInfo { let vertex_input_state = Vert2Uv::per_vertex()
color_attachment_formats: vec![Some(format)], .definition(&vep.info().input_interface)
..Default::default()
})
.color_blend_state(ColorBlendState::default().blend(AttachmentBlend::alpha()))
.vertex_input_state(Vert2Uv::per_vertex())
.input_assembly_state(InputAssemblyState::new())
.vertex_shader(vep, ())
.viewport_state(ViewportState::viewport_dynamic_scissor_irrelevant())
.fragment_shader(fep, ())
.build(graphics.device.clone())
.unwrap(); .unwrap();
let stages = smallvec![
PipelineShaderStageCreateInfo::new(vep),
PipelineShaderStageCreateInfo::new(fep),
];
let layout = PipelineLayout::new(
graphics.device.clone(),
PipelineDescriptorSetLayoutCreateInfo::from_stages(&stages)
.into_pipeline_layout_create_info(graphics.device.clone())
.unwrap(),
)
.unwrap();
let framebuffer = Framebuffer::new(
render_pass.clone(),
FramebufferCreateInfo {
attachments: vec![render_target.clone()],
..Default::default()
},
)
.unwrap();
let pipeline = GraphicsPipeline::new(
graphics.device.clone(),
None,
GraphicsPipelineCreateInfo {
stages,
vertex_input_state: Some(vertex_input_state),
input_assembly_state: Some(InputAssemblyState::default()),
viewport_state: Some(ViewportState::default()),
color_blend_state: Some(ColorBlendState {
attachments: vec![ColorBlendAttachmentState {
blend: Some(AttachmentBlend::alpha()),
..Default::default()
}],
..Default::default()
}),
rasterization_state: Some(RasterizationState::default()),
multisample_state: Some(MultisampleState::default()),
dynamic_state: [DynamicState::Viewport].into_iter().collect(),
subpass: Some(Subpass::from(render_pass.clone(), 0).unwrap().into()),
..GraphicsPipelineCreateInfo::layout(layout)
},
)
.unwrap();
Self { Self {
graphics, graphics,
pipeline, pipeline,
format, format,
render_pass,
framebuffer,
view: render_target,
} }
} }
@@ -669,7 +901,7 @@ impl WlxPipeline {
pub fn uniform_sampler( pub fn uniform_sampler(
&self, &self,
set: usize, set: usize,
texture: Arc<dyn ImageViewAbstract>, texture: Arc<ImageView>,
filter: Filter, filter: Filter,
) -> Arc<PersistentDescriptorSet> { ) -> Arc<PersistentDescriptorSet> {
let sampler = Sampler::new( let sampler = Sampler::new(
@@ -689,6 +921,7 @@ impl WlxPipeline {
&self.graphics.descriptor_set_allocator, &self.graphics.descriptor_set_allocator,
layout.clone(), layout.clone(),
[WriteDescriptorSet::image_view_sampler(0, texture, sampler)], [WriteDescriptorSet::image_view_sampler(0, texture, sampler)],
[],
) )
.unwrap() .unwrap()
} }
@@ -701,6 +934,8 @@ impl WlxPipeline {
self.graphics.memory_allocator.clone(), self.graphics.memory_allocator.clone(),
SubbufferAllocatorCreateInfo { SubbufferAllocatorCreateInfo {
buffer_usage: BufferUsage::UNIFORM_BUFFER, buffer_usage: BufferUsage::UNIFORM_BUFFER,
memory_type_filter: MemoryTypeFilter::PREFER_DEVICE
| MemoryTypeFilter::HOST_SEQUENTIAL_WRITE,
..Default::default() ..Default::default()
}, },
); );
@@ -716,6 +951,7 @@ impl WlxPipeline {
&self.graphics.descriptor_set_allocator, &self.graphics.descriptor_set_allocator,
layout.clone(), layout.clone(),
[WriteDescriptorSet::buffer(0, uniform_buffer_subbuffer)], [WriteDescriptorSet::buffer(0, uniform_buffer_subbuffer)],
[],
) )
.unwrap() .unwrap()
} }
@@ -743,7 +979,7 @@ pub struct WlxPass {
vertex_buffer: Subbuffer<[Vert2Uv]>, vertex_buffer: Subbuffer<[Vert2Uv]>,
index_buffer: Subbuffer<[u16]>, index_buffer: Subbuffer<[u16]>,
descriptor_sets: Vec<Arc<PersistentDescriptorSet>>, descriptor_sets: Vec<Arc<PersistentDescriptorSet>>,
pub command_buffer: Arc<SecondaryAutoCommandBuffer>, pub command_buffer: Arc<SecondaryAutoCommandBuffer<Arc<StandardCommandBufferAllocator>>>,
} }
impl WlxPass { impl WlxPass {
@@ -755,9 +991,9 @@ impl WlxPass {
descriptor_sets: Vec<Arc<PersistentDescriptorSet>>, descriptor_sets: Vec<Arc<PersistentDescriptorSet>>,
) -> Self { ) -> Self {
let viewport = Viewport { let viewport = Viewport {
origin: [0.0, 0.0], offset: [0.0, 0.0],
dimensions, extent: dimensions,
depth_range: 0.0..1.0, depth_range: 0.0..=1.0,
}; };
let pipeline_inner = pipeline.inner().clone(); let pipeline_inner = pipeline.inner().clone();
@@ -766,10 +1002,10 @@ impl WlxPass {
pipeline.graphics.queue.queue_family_index(), pipeline.graphics.queue.queue_family_index(),
CommandBufferUsage::MultipleSubmit, CommandBufferUsage::MultipleSubmit,
CommandBufferInheritanceInfo { CommandBufferInheritanceInfo {
render_pass: Some(CommandBufferInheritanceRenderPassType::BeginRendering( render_pass: Some(CommandBufferInheritanceRenderPassType::BeginRenderPass(
CommandBufferInheritanceRenderingInfo { CommandBufferInheritanceRenderPassInfo {
color_attachment_formats: vec![Some(pipeline.format)], subpass: Subpass::from(pipeline.render_pass.clone(), 0).unwrap(),
..Default::default() framebuffer: None,
}, },
)), )),
..Default::default() ..Default::default()
@@ -778,16 +1014,21 @@ impl WlxPass {
.unwrap(); .unwrap();
command_buffer command_buffer
.set_viewport(0, [viewport]) .set_viewport(0, smallvec![viewport])
.unwrap()
.bind_pipeline_graphics(pipeline_inner) .bind_pipeline_graphics(pipeline_inner)
.unwrap()
.bind_descriptor_sets( .bind_descriptor_sets(
PipelineBindPoint::Graphics, PipelineBindPoint::Graphics,
pipeline.inner().layout().clone(), pipeline.inner().layout().clone(),
0, 0,
descriptor_sets.clone(), descriptor_sets.clone(),
) )
.unwrap()
.bind_vertex_buffers(0, vertex_buffer.clone()) .bind_vertex_buffers(0, vertex_buffer.clone())
.unwrap()
.bind_index_buffer(index_buffer.clone()) .bind_index_buffer(index_buffer.clone())
.unwrap()
.draw_indexed(index_buffer.len() as u32, 1, 0, 0, 0) .draw_indexed(index_buffer.len() as u32, 1, 0, 0, 0)
.or_else(|err| { .or_else(|err| {
if let Some(source) = err.source() { if let Some(source) = err.source() {
@@ -802,7 +1043,7 @@ impl WlxPass {
vertex_buffer, vertex_buffer,
index_buffer, index_buffer,
descriptor_sets, descriptor_sets,
command_buffer: Arc::new(command_buffer.build().unwrap()), command_buffer: command_buffer.build().unwrap(),
} }
} }
} }

View File

@@ -3,7 +3,7 @@ use std::{rc::Rc, str::FromStr, sync::Arc};
use fontconfig::{FontConfig, OwnedPattern}; use fontconfig::{FontConfig, OwnedPattern};
use freetype::{bitmap::PixelMode, face::LoadFlag, Face, Library}; use freetype::{bitmap::PixelMode, face::LoadFlag, Face, Library};
use idmap::IdMap; use idmap::IdMap;
use vulkano::{command_buffer::CommandBufferUsage, format::Format, image::ImmutableImage}; use vulkano::{command_buffer::CommandBufferUsage, format::Format, image::Image};
use crate::graphics::WlxGraphics; use crate::graphics::WlxGraphics;
@@ -26,7 +26,7 @@ struct Font {
} }
pub struct Glyph { pub struct Glyph {
pub tex: Option<Arc<ImmutableImage>>, pub tex: Option<Arc<Image>>,
pub top: f32, pub top: f32,
pub left: f32, pub left: f32,
pub width: f32, pub width: f32,

View File

@@ -2,10 +2,9 @@ use std::sync::Arc;
use glam::{Vec2, Vec3}; use glam::{Vec2, Vec3};
use vulkano::{ use vulkano::{
command_buffer::{CommandBufferUsage, PrimaryAutoCommandBuffer}, command_buffer::CommandBufferUsage,
format::Format, format::Format,
image::{view::ImageView, AttachmentImage, ImageAccess, ImageLayout, ImageViewAbstract}, image::{sampler::Filter, view::ImageView, ImageLayout},
sampler::Filter,
}; };
use crate::{ use crate::{
@@ -189,8 +188,9 @@ pub struct CanvasData<D> {
graphics: Arc<WlxGraphics>, graphics: Arc<WlxGraphics>,
pipeline_color: Arc<WlxPipeline>, pipeline_bg_color: Arc<WlxPipeline>,
pipeline_glyph: Arc<WlxPipeline>, pipeline_fg_glyph: Arc<WlxPipeline>,
pipeline_final: Arc<WlxPipeline>,
} }
pub struct Canvas<D, S> { pub struct Canvas<D, S> {
@@ -204,14 +204,10 @@ pub struct Canvas<D, S> {
interact_stride: usize, interact_stride: usize,
interact_rows: usize, interact_rows: usize,
view_fg: Arc<ImageView<AttachmentImage>>, view_final: Arc<ImageView>,
view_bg: Arc<ImageView<AttachmentImage>>,
view_final: Arc<ImageView<AttachmentImage>>,
pass_fg: WlxPass, pass_fg: WlxPass,
pass_bg: WlxPass, pass_bg: WlxPass,
first_render: bool,
} }
impl<D, S> Canvas<D, S> { impl<D, S> Canvas<D, S> {
@@ -222,27 +218,6 @@ impl<D, S> Canvas<D, S> {
format: Format, format: Format,
data: D, data: D,
) -> Self { ) -> Self {
let pipeline_color = graphics.create_pipeline(
vert_common::load(graphics.device.clone()).unwrap(),
frag_color::load(graphics.device.clone()).unwrap(),
format,
);
let pipeline_glyph = graphics.create_pipeline(
vert_common::load(graphics.device.clone()).unwrap(),
frag_glyph::load(graphics.device.clone()).unwrap(),
format,
);
let vertex_buffer =
graphics.upload_verts(width as _, height as _, 0., 0., width as _, height as _);
let pipeline = graphics.create_pipeline(
vert_common::load(graphics.device.clone()).unwrap(),
frag_sprite::load(graphics.device.clone()).unwrap(),
format,
);
let tex_fg = graphics.render_texture(width as _, height as _, format); let tex_fg = graphics.render_texture(width as _, height as _, format);
let tex_bg = graphics.render_texture(width as _, height as _, format); let tex_bg = graphics.render_texture(width as _, height as _, format);
let tex_final = graphics.render_texture(width as _, height as _, format); let tex_final = graphics.render_texture(width as _, height as _, format);
@@ -251,15 +226,41 @@ impl<D, S> Canvas<D, S> {
let view_bg = ImageView::new_default(tex_bg.clone()).unwrap(); let view_bg = ImageView::new_default(tex_bg.clone()).unwrap();
let view_final = ImageView::new_default(tex_final.clone()).unwrap(); let view_final = ImageView::new_default(tex_final.clone()).unwrap();
let set_fg = pipeline.uniform_sampler(0, view_fg.clone(), Filter::Nearest); let pipeline_bg_color = graphics.create_pipeline(
let set_bg = pipeline.uniform_sampler(0, view_bg.clone(), Filter::Nearest); view_bg.clone(),
let pass_fg = pipeline.create_pass( vert_common::load(graphics.device.clone()).unwrap(),
frag_color::load(graphics.device.clone()).unwrap(),
format,
);
let pipeline_fg_glyph = graphics.create_pipeline(
view_fg.clone(),
vert_common::load(graphics.device.clone()).unwrap(),
frag_glyph::load(graphics.device.clone()).unwrap(),
format,
);
let vertex_buffer =
graphics.upload_verts(width as _, height as _, 0., 0., width as _, height as _);
let pipeline_final = graphics.create_pipeline_with_layouts(
view_final.clone(),
vert_common::load(graphics.device.clone()).unwrap(),
frag_sprite::load(graphics.device.clone()).unwrap(),
format,
ImageLayout::TransferSrcOptimal,
ImageLayout::TransferSrcOptimal,
);
let set_fg = pipeline_final.uniform_sampler(0, view_fg.clone(), Filter::Linear);
let set_bg = pipeline_final.uniform_sampler(0, view_bg.clone(), Filter::Linear);
let pass_fg = pipeline_final.create_pass(
[width as _, height as _], [width as _, height as _],
vertex_buffer.clone(), vertex_buffer.clone(),
graphics.quad_indices.clone(), graphics.quad_indices.clone(),
vec![set_fg], vec![set_fg],
); );
let pass_bg = pipeline.create_pass( let pass_bg = pipeline_final.create_pass(
[width as _, height as _], [width as _, height as _],
vertex_buffer.clone(), vertex_buffer.clone(),
graphics.quad_indices.clone(), graphics.quad_indices.clone(),
@@ -275,8 +276,9 @@ impl<D, S> Canvas<D, S> {
width, width,
height, height,
graphics, graphics,
pipeline_color, pipeline_bg_color,
pipeline_glyph, pipeline_fg_glyph,
pipeline_final,
}, },
controls: Vec::new(), controls: Vec::new(),
hover_controls: [None, None], hover_controls: [None, None],
@@ -284,12 +286,9 @@ impl<D, S> Canvas<D, S> {
interact_map: vec![None; stride * rows], interact_map: vec![None; stride * rows],
interact_stride: stride, interact_stride: stride,
interact_rows: rows, interact_rows: rows,
view_fg,
view_bg,
view_final, view_final,
pass_fg, pass_fg,
pass_bg, pass_bg,
first_render: true,
} }
} }
@@ -321,13 +320,13 @@ impl<D, S> Canvas<D, S> {
.canvas .canvas
.graphics .graphics
.create_command_buffer(CommandBufferUsage::OneTimeSubmit) .create_command_buffer(CommandBufferUsage::OneTimeSubmit)
.begin(self.view_bg.clone()); .begin_render_pass(&self.canvas.pipeline_final);
for c in self.controls.iter_mut() { for c in self.controls.iter_mut() {
if let Some(fun) = c.on_render_bg { if let Some(fun) = c.on_render_bg {
fun(c, &self.canvas, app, &mut cmd_buffer); fun(c, &self.canvas, app, &mut cmd_buffer);
} }
} }
cmd_buffer.end_render().build_and_execute_now() cmd_buffer.end_render_pass().build_and_execute_now()
} }
fn render_fg(&mut self, app: &mut AppState) { fn render_fg(&mut self, app: &mut AppState) {
@@ -335,13 +334,13 @@ impl<D, S> Canvas<D, S> {
.canvas .canvas
.graphics .graphics
.create_command_buffer(CommandBufferUsage::OneTimeSubmit) .create_command_buffer(CommandBufferUsage::OneTimeSubmit)
.begin(self.view_fg.clone()); .begin_render_pass(&self.canvas.pipeline_final);
for c in self.controls.iter_mut() { for c in self.controls.iter_mut() {
if let Some(fun) = c.on_render_fg { if let Some(fun) = c.on_render_fg {
fun(c, &self.canvas, app, &mut cmd_buffer); fun(c, &self.canvas, app, &mut cmd_buffer);
} }
} }
cmd_buffer.end_render().build_and_execute_now() cmd_buffer.end_render_pass().build_and_execute_now()
} }
} }
@@ -399,8 +398,12 @@ impl<D, S> OverlayRenderer for Canvas<D, S> {
} }
} }
let image = self.view_final.image().inner().image.clone(); if !dirty {
return;
}
/*
let image = self.view_final.image().clone();
if self.first_render { if self.first_render {
self.first_render = false; self.first_render = false;
} else { } else {
@@ -414,16 +417,15 @@ impl<D, S> OverlayRenderer for Canvas<D, S> {
.wait(None) .wait(None)
.unwrap(); .unwrap();
} }
*/
let mut cmd_buffer = self let mut cmd_buffer = self
.canvas .canvas
.graphics .graphics
.create_command_buffer(CommandBufferUsage::OneTimeSubmit) .create_command_buffer(CommandBufferUsage::OneTimeSubmit)
.begin(self.view_final.clone()); .begin_render_pass(&self.canvas.pipeline_final);
if dirty { self.render_fg(app);
self.render_fg(app);
}
// static background // static background
cmd_buffer.run_ref(&self.pass_bg); cmd_buffer.run_ref(&self.pass_bg);
@@ -444,8 +446,10 @@ impl<D, S> OverlayRenderer for Canvas<D, S> {
// mostly static text // mostly static text
cmd_buffer.run_ref(&self.pass_fg); cmd_buffer.run_ref(&self.pass_fg);
{ {
let _ = cmd_buffer.end_render().build_and_execute(); let _ = cmd_buffer.end_render_pass().build_and_execute();
} }
/*
self.canvas self.canvas
.graphics .graphics
.transition_layout( .transition_layout(
@@ -455,8 +459,9 @@ impl<D, S> OverlayRenderer for Canvas<D, S> {
) )
.wait(None) .wait(None)
.unwrap(); .unwrap();
*/
} }
fn view(&mut self) -> Option<Arc<dyn ImageViewAbstract>> { fn view(&mut self) -> Option<Arc<ImageView>> {
Some(self.view_final.clone()) Some(self.view_final.clone())
} }
} }
@@ -477,21 +482,9 @@ pub struct Control<D, S> {
pub on_release: Option<fn(&mut Self, &mut D, &mut AppState)>, pub on_release: Option<fn(&mut Self, &mut D, &mut AppState)>,
pub test_highlight: Option<fn(&Self, &mut D, &mut AppState) -> bool>, pub test_highlight: Option<fn(&Self, &mut D, &mut AppState) -> bool>,
on_render_bg: Option< on_render_bg: Option<fn(&Self, &CanvasData<D>, &mut AppState, &mut WlxCommandBuffer)>,
fn(&Self, &CanvasData<D>, &mut AppState, &mut WlxCommandBuffer<PrimaryAutoCommandBuffer>), on_render_hl: Option<fn(&Self, &CanvasData<D>, &mut AppState, &mut WlxCommandBuffer, bool)>,
>, on_render_fg: Option<fn(&Self, &CanvasData<D>, &mut AppState, &mut WlxCommandBuffer)>,
on_render_hl: Option<
fn(
&Self,
&CanvasData<D>,
&mut AppState,
&mut WlxCommandBuffer<PrimaryAutoCommandBuffer>,
bool,
),
>,
on_render_fg: Option<
fn(&Self, &CanvasData<D>, &mut AppState, &mut WlxCommandBuffer<PrimaryAutoCommandBuffer>),
>,
} }
impl<D, S> Control<D, S> { impl<D, S> Control<D, S> {
@@ -532,7 +525,7 @@ impl<D, S> Control<D, S> {
&self, &self,
canvas: &CanvasData<D>, canvas: &CanvasData<D>,
_: &mut AppState, _: &mut AppState,
cmd_buffer: &mut WlxCommandBuffer<PrimaryAutoCommandBuffer>, cmd_buffer: &mut WlxCommandBuffer,
) { ) {
let pass = { let pass = {
let vertex_buffer = canvas.graphics.upload_verts( let vertex_buffer = canvas.graphics.upload_verts(
@@ -543,11 +536,11 @@ impl<D, S> Control<D, S> {
self.rect.w, self.rect.w,
self.rect.h, self.rect.h,
); );
let set0 = canvas.pipeline_color.uniform_buffer( let set0 = canvas.pipeline_bg_color.uniform_buffer(
0, 0,
vec![self.bg_color.x, self.bg_color.y, self.bg_color.z, 1.], vec![self.bg_color.x, self.bg_color.y, self.bg_color.z, 1.],
); );
canvas.pipeline_color.create_pass( canvas.pipeline_bg_color.create_pass(
[canvas.width as _, canvas.height as _], [canvas.width as _, canvas.height as _],
vertex_buffer, vertex_buffer,
canvas.graphics.quad_indices.clone(), canvas.graphics.quad_indices.clone(),
@@ -562,7 +555,7 @@ impl<D, S> Control<D, S> {
&self, &self,
canvas: &CanvasData<D>, canvas: &CanvasData<D>,
_: &mut AppState, _: &mut AppState,
cmd_buffer: &mut WlxCommandBuffer<PrimaryAutoCommandBuffer>, cmd_buffer: &mut WlxCommandBuffer,
strong: bool, strong: bool,
) { ) {
let vertex_buffer = canvas.graphics.upload_verts( let vertex_buffer = canvas.graphics.upload_verts(
@@ -573,7 +566,7 @@ impl<D, S> Control<D, S> {
self.rect.w, self.rect.w,
self.rect.h, self.rect.h,
); );
let set0 = canvas.pipeline_color.uniform_buffer( let set0 = canvas.pipeline_bg_color.uniform_buffer(
0, 0,
vec![ vec![
self.bg_color.x, self.bg_color.x,
@@ -582,7 +575,7 @@ impl<D, S> Control<D, S> {
if strong { 0.5 } else { 0.3 }, if strong { 0.5 } else { 0.3 },
], ],
); );
let pass = canvas.pipeline_color.create_pass( let pass = canvas.pipeline_bg_color.create_pass(
[canvas.width as _, canvas.height as _], [canvas.width as _, canvas.height as _],
vertex_buffer.clone(), vertex_buffer.clone(),
canvas.graphics.quad_indices.clone(), canvas.graphics.quad_indices.clone(),
@@ -596,7 +589,7 @@ impl<D, S> Control<D, S> {
&self, &self,
canvas: &CanvasData<D>, canvas: &CanvasData<D>,
app: &mut AppState, app: &mut AppState,
cmd_buffer: &mut WlxCommandBuffer<PrimaryAutoCommandBuffer>, cmd_buffer: &mut WlxCommandBuffer,
) { ) {
let mut cur_y = self.rect.y; let mut cur_y = self.rect.y;
for line in self.text.lines() { for line in self.text.lines() {
@@ -611,16 +604,16 @@ impl<D, S> Control<D, S> {
glyph.width, glyph.width,
glyph.height, glyph.height,
); );
let set0 = canvas.pipeline_glyph.uniform_sampler( let set0 = canvas.pipeline_fg_glyph.uniform_sampler(
0, 0,
ImageView::new_default(tex).unwrap(), ImageView::new_default(tex).unwrap(),
Filter::Nearest, Filter::Nearest,
); );
let set1 = canvas.pipeline_glyph.uniform_buffer( let set1 = canvas.pipeline_fg_glyph.uniform_buffer(
1, 1,
vec![self.fg_color.x, self.fg_color.y, self.fg_color.z, 1.], vec![self.fg_color.x, self.fg_color.y, self.fg_color.z, 1.],
); );
let pass = canvas.pipeline_glyph.create_pass( let pass = canvas.pipeline_fg_glyph.create_pass(
[canvas.width as _, canvas.height as _], [canvas.width as _, canvas.height as _],
vertex_buffer, vertex_buffer,
canvas.graphics.quad_indices.clone(), canvas.graphics.quad_indices.clone(),
@@ -637,7 +630,7 @@ impl<D, S> Control<D, S> {
&self, &self,
canvas: &CanvasData<D>, canvas: &CanvasData<D>,
app: &mut AppState, app: &mut AppState,
cmd_buffer: &mut WlxCommandBuffer<PrimaryAutoCommandBuffer>, cmd_buffer: &mut WlxCommandBuffer,
) { ) {
let (w, h) = app let (w, h) = app
.fc .fc
@@ -656,16 +649,16 @@ impl<D, S> Control<D, S> {
glyph.width, glyph.width,
glyph.height, glyph.height,
); );
let set0 = canvas.pipeline_glyph.uniform_sampler( let set0 = canvas.pipeline_fg_glyph.uniform_sampler(
0, 0,
ImageView::new_default(tex).unwrap(), ImageView::new_default(tex).unwrap(),
Filter::Nearest, Filter::Nearest,
); );
let set1 = canvas.pipeline_glyph.uniform_buffer( let set1 = canvas.pipeline_fg_glyph.uniform_buffer(
1, 1,
vec![self.fg_color.x, self.fg_color.y, self.fg_color.z, 1.], vec![self.fg_color.x, self.fg_color.y, self.fg_color.z, 1.],
); );
let pass = canvas.pipeline_glyph.create_pass( let pass = canvas.pipeline_fg_glyph.create_pass(
[canvas.width as _, canvas.height as _], [canvas.width as _, canvas.height as _],
vertex_buffer, vertex_buffer,
canvas.graphics.quad_indices.clone(), canvas.graphics.quad_indices.clone(),

View File

@@ -8,10 +8,7 @@ use vulkano::{
buffer::Subbuffer, buffer::Subbuffer,
command_buffer::CommandBufferUsage, command_buffer::CommandBufferUsage,
format::Format, format::Format,
image::{ image::{sampler::Filter, view::ImageView, Image, ImageLayout},
view::ImageView, AttachmentImage, ImageAccess, ImageLayout, ImageViewAbstract, StorageImage,
},
sampler::Filter,
sync::GpuFuture, sync::GpuFuture,
Handle, VulkanObject, Handle, VulkanObject,
}; };
@@ -32,7 +29,7 @@ use crate::{
}, },
graphics::{Vert2Uv, WlxGraphics, WlxPipeline}, graphics::{Vert2Uv, WlxGraphics, WlxPipeline},
hid::{MOUSE_LEFT, MOUSE_MIDDLE, MOUSE_RIGHT}, hid::{MOUSE_LEFT, MOUSE_MIDDLE, MOUSE_RIGHT},
shaders::{frag_sprite, vert_common}, shaders::{frag_screen, vert_common},
state::{AppSession, AppState}, state::{AppSession, AppState},
}; };
@@ -110,19 +107,11 @@ struct ScreenPipeline {
graphics: Arc<WlxGraphics>, graphics: Arc<WlxGraphics>,
pipeline: Arc<WlxPipeline>, pipeline: Arc<WlxPipeline>,
vertex_buffer: Subbuffer<[Vert2Uv]>, vertex_buffer: Subbuffer<[Vert2Uv]>,
target_layout: ImageLayout,
pub view: Arc<ImageView<AttachmentImage>>,
} }
impl ScreenPipeline { impl ScreenPipeline {
fn new(graphics: Arc<WlxGraphics>, image: &StorageImage) -> Self { fn new(graphics: Arc<WlxGraphics>, image: &Image) -> Self {
let pipeline = graphics.create_pipeline( let dim = image.extent();
vert_common::load(graphics.device.clone()).unwrap(),
frag_sprite::load(graphics.device.clone()).unwrap(),
Format::R8G8B8A8_UNORM,
);
let dim = image.dimensions().width_height();
let vertex_buffer = let vertex_buffer =
graphics.upload_verts(dim[0] as _, dim[1] as _, 0.0, 0.0, dim[0] as _, dim[1] as _); graphics.upload_verts(dim[0] as _, dim[1] as _, 0.0, 0.0, dim[0] as _, dim[1] as _);
@@ -131,26 +120,31 @@ impl ScreenPipeline {
let view = ImageView::new_default(render_texture).unwrap(); let view = ImageView::new_default(render_texture).unwrap();
let pipeline = graphics.create_pipeline_with_layouts(
view,
vert_common::load(graphics.device.clone()).unwrap(),
frag_screen::load(graphics.device.clone()).unwrap(),
Format::R8G8B8A8_UNORM,
ImageLayout::ColorAttachmentOptimal,
ImageLayout::ColorAttachmentOptimal,
);
Self { Self {
graphics, graphics,
pipeline, pipeline,
vertex_buffer, vertex_buffer,
view,
target_layout: ImageLayout::Undefined,
} }
} }
fn render(&mut self, image: Arc<StorageImage>) { fn render(&mut self, image: Arc<Image>) {
if image.inner().image.handle().as_raw() if image.handle().as_raw() == self.pipeline.view.image().handle().as_raw() {
== self.view.image().inner().image.handle().as_raw()
{
return; return;
} }
let mut command_buffer = self let mut command_buffer = self
.graphics .graphics
.create_command_buffer(CommandBufferUsage::OneTimeSubmit) .create_command_buffer(CommandBufferUsage::OneTimeSubmit)
.begin(self.view.clone()); .begin_render_pass(&self.pipeline);
let set0 = self.pipeline.uniform_sampler( let set0 = self.pipeline.uniform_sampler(
0, 0,
@@ -158,7 +152,7 @@ impl ScreenPipeline {
Filter::Linear, Filter::Linear,
); );
let dim = self.view.dimensions().width_height(); let dim = self.pipeline.view.image().extent();
let dim = [dim[0] as f32, dim[1] as f32]; let dim = [dim[0] as f32, dim[1] as f32];
let pass = self.pipeline.create_pass( let pass = self.pipeline.create_pass(
@@ -169,35 +163,15 @@ impl ScreenPipeline {
); );
command_buffer.run_ref(&pass); command_buffer.run_ref(&pass);
let image = self.view.image().inner().image.clone();
if self.target_layout == ImageLayout::TransferSrcOptimal {
self.graphics
.transition_layout(
image.clone(),
ImageLayout::TransferSrcOptimal,
ImageLayout::ColorAttachmentOptimal,
)
.wait(None)
.unwrap();
}
{ {
let mut exec = command_buffer.end_render().build_and_execute(); let mut exec = command_buffer.end_render_pass().build_and_execute();
exec.flush().unwrap(); exec.flush().unwrap();
exec.cleanup_finished(); exec.cleanup_finished();
} }
}
self.graphics pub(super) fn view(&self) -> Arc<ImageView> {
.transition_layout( self.pipeline.view.clone()
image,
ImageLayout::ColorAttachmentOptimal,
ImageLayout::TransferSrcOptimal,
)
.wait(None)
.unwrap();
self.target_layout = ImageLayout::TransferSrcOptimal;
} }
} }
@@ -205,7 +179,7 @@ pub struct ScreenRenderer {
capture: Box<dyn WlxCapture>, capture: Box<dyn WlxCapture>,
receiver: Option<Receiver<WlxFrame>>, receiver: Option<Receiver<WlxFrame>>,
pipeline: Option<ScreenPipeline>, pipeline: Option<ScreenPipeline>,
last_frame: Option<Arc<dyn ImageViewAbstract>>, last_image: Option<Arc<ImageView>>,
} }
impl ScreenRenderer { impl ScreenRenderer {
@@ -218,7 +192,7 @@ impl ScreenRenderer {
capture: Box::new(capture), capture: Box::new(capture),
receiver: None, receiver: None,
pipeline: None, pipeline: None,
last_frame: None, last_image: None,
}) })
} }
@@ -236,7 +210,7 @@ impl ScreenRenderer {
capture: Box::new(capture), capture: Box::new(capture),
receiver: None, receiver: None,
pipeline: None, pipeline: None,
last_frame: None, last_image: None,
}) })
} }
} }
@@ -254,13 +228,13 @@ impl OverlayRenderer for ScreenRenderer {
for frame in receiver.try_iter() { for frame in receiver.try_iter() {
match frame { match frame {
WlxFrame::Dmabuf(frame) => { WlxFrame::Dmabuf(frame) => {
if let Ok(new) = app.graphics.dmabuf_texture(frame) { if let Some(new) = app.graphics.dmabuf_texture(frame) {
let pipeline = self let pipeline = self
.pipeline .pipeline
.get_or_insert_with(|| ScreenPipeline::new(app.graphics.clone(), &new)); .get_or_insert_with(|| ScreenPipeline::new(app.graphics.clone(), &new));
log::info!("New frame");
pipeline.render(new); pipeline.render(new);
self.last_frame = Some(pipeline.view.clone()); self.last_image = Some(pipeline.view());
} }
} }
WlxFrame::MemFd(_frame) => { WlxFrame::MemFd(_frame) => {
@@ -280,8 +254,8 @@ impl OverlayRenderer for ScreenRenderer {
fn resume(&mut self, _app: &mut AppState) { fn resume(&mut self, _app: &mut AppState) {
self.capture.resume(); self.capture.resume();
} }
fn view(&mut self) -> Option<Arc<dyn ImageViewAbstract>> { fn view(&mut self) -> Option<Arc<ImageView>> {
self.last_frame.take() self.last_image.take()
} }
} }

View File

@@ -106,3 +106,120 @@ pub mod frag_srgb {
", ",
} }
} }
pub mod frag_screen {
vulkano_shaders::shader! {
ty: "fragment",
src: r"#version 310 es
precision highp float;
layout (location = 0) in vec2 in_uv;
layout (location = 0) out vec4 out_color;
layout (set = 0, binding = 0) uniform sampler2D in_texture;
layout (set = 0, binding = 1) uniform ColorBlock {
uniform vec4 in_color;
};
vec4 supersample(sampler2D tex, vec2 uv) {
float ddx = dFdx(uv.x);
float ddy = dFdy(uv.y);
float width = sqrt(ddx*ddx + ddy*ddy);
ivec2 size = textureSize(tex, 0);
ivec2 pixelWidth = ivec2(width * vec2(size));
ivec2 xy = ivec2(uv * vec2(size));
ivec2 start = xy - pixelWidth/2;
ivec2 end = xy + pixelWidth/2;
vec4 outColor = vec4(0.0);
int n = 0;
for (int xSample = start.x; xSample <= end.x; xSample++) {
for (int ySample = start.y; ySample <= end.y; ySample++) {
n++;
outColor += texelFetch(tex, clamp(ivec2(xSample, ySample), ivec2(0), size), 0);
}
}
if (n > 0) {
return outColor / float(n);
} else {
return vec4(0.0);
}
}
float gaussian(float x, float t) {
float PI = 3.14159265358;
return exp(-x*x/(2.0 * t*t))/(sqrt(2.0*PI)*t);
}
float besselI0(float x) {
return 1.0 + pow(x, 2.0) * (0.25 + pow(x, 2.0) * (0.015625 + pow(x, 2.0) * (0.000434028 + pow(x, 2.0) * (6.78168e-6 + pow(x, 2.0) * (6.78168e-8 + pow(x, 2.0) * (4.7095e-10 + pow(x, 2.0) * (2.40281e-12 + pow(x, 2.0) * (9.38597e-15 + pow(x, 2.0) * (2.8969e-17 + 7.24226e-20 * pow(x, 2.0))))))))));
}
float kaiser(float x, float alpha) {
if (x > 1.0) {
return 0.0;
}
return besselI0(alpha * sqrt(1.0-x*x));
}
vec4 lowpassFilter(sampler2D tex, vec2 uv, float alpha) {
float PI = 3.14159265358;
vec4 q = vec4(0.0);
vec2 dx_uv = dFdx(uv);
vec2 dy_uv = dFdy(uv);
//float width = sqrt(max(dot(dx_uv, dx_uv), dot(dy_uv, dy_uv)));
vec2 width = abs(vec2(dx_uv.x, dy_uv.y));
ivec2 size = textureSize(tex, 0);
vec2 pixelWidth = floor(width * vec2(size));
vec2 aspectRatio = normalize(pixelWidth);
ivec2 xy = ivec2(uv * vec2(size));
vec2 xyf = uv * vec2(size);
pixelWidth = clamp(pixelWidth, vec2(1.0), vec2(2.0));
ivec2 start = xy - ivec2(pixelWidth);
ivec2 end = xy + ivec2(pixelWidth);
vec4 outColor = vec4(0.0);
float qSum = 0.0;
for (int v = start.y; v <= end.y; v++) {
for (int u = start.x; u <= end.x; u++) {
float kx = (xyf.x - float(u))/pixelWidth.x;
float ky = (xyf.y - float(v))/pixelWidth.y;
//float lanczosValue = gaussian(kx, fcx);
float lanczosValue = kaiser(sqrt(kx*kx + ky*ky), alpha);
q += texelFetch(tex, ivec2(u, v), 0) * lanczosValue;
qSum += lanczosValue;
}
}
return q/qSum;
}
void main()
{
out_color = lowpassFilter(in_texture, in_uv, 4.0);
out_color.a = 1.0;
}
",
}
}

111
src/shaders/src/screen.frag Normal file
View File

@@ -0,0 +1,111 @@
#version 310 es
precision highp float;
layout (location = 0) in vec2 in_uv;
layout (location = 0) out vec4 out_color;
layout (set = 0, binding = 0) uniform sampler2D in_texture;
layout (set = 0, binding = 1) uniform ColorBlock {
uniform vec4 in_color;
};
vec4 supersample(sampler2D tex, vec2 uv) {
float ddx = dFdx(uv.x);
float ddy = dFdy(uv.y);
float width = sqrt(ddx*ddx + ddy*ddy);
ivec2 size = textureSize(tex, 0);
ivec2 pixelWidth = ivec2(width * vec2(size));
ivec2 xy = ivec2(uv * vec2(size));
ivec2 start = xy - pixelWidth/2;
ivec2 end = xy + pixelWidth/2;
vec4 outColor = vec4(0.0);
int n = 0;
for (int xSample = start.x; xSample <= end.x; xSample++) {
for (int ySample = start.y; ySample <= end.y; ySample++) {
n++;
outColor += texelFetch(tex, clamp(ivec2(xSample, ySample), ivec2(0), size), 0);
}
}
if (n > 0) {
return outColor / float(n);
} else {
return vec4(0.0);
}
}
float gaussian(float x, float t) {
float PI = 3.14159265358;
return exp(-x*x/(2.0 * t*t))/(sqrt(2.0*PI)*t);
}
float besselI0(float x) {
return 1.0 + pow(x, 2.0) * (0.25 + pow(x, 2.0) * (0.015625 + pow(x, 2.0) * (0.000434028 + pow(x, 2.0) * (6.78168e-6 + pow(x, 2.0) * (6.78168e-8 + pow(x, 2.0) * (4.7095e-10 + pow(x, 2.0) * (2.40281e-12 + pow(x, 2.0) * (9.38597e-15 + pow(x, 2.0) * (2.8969e-17 + 7.24226e-20 * pow(x, 2.0))))))))));
}
float kaiser(float x, float alpha) {
if (x > 1.0) {
return 0.0;
}
return besselI0(alpha * sqrt(1.0-x*x));
}
vec4 lowpassFilter(sampler2D tex, vec2 uv, float alpha) {
float PI = 3.14159265358;
vec4 q = vec4(0.0);
vec2 dx_uv = dFdx(uv);
vec2 dy_uv = dFdy(uv);
//float width = sqrt(max(dot(dx_uv, dx_uv), dot(dy_uv, dy_uv)));
vec2 width = abs(vec2(dx_uv.x, dy_uv.y));
ivec2 size = textureSize(tex, 0);
vec2 pixelWidth = floor(width * vec2(size));
vec2 aspectRatio = normalize(pixelWidth);
ivec2 xy = ivec2(uv * vec2(size));
vec2 xyf = uv * vec2(size);
pixelWidth = clamp(pixelWidth, vec2(1.0), vec2(2.0));
ivec2 start = xy - ivec2(pixelWidth);
ivec2 end = xy + ivec2(pixelWidth);
vec4 outColor = vec4(0.0);
float qSum = 0.0;
for (int v = start.y; v <= end.y; v++) {
for (int u = start.x; u <= end.x; u++) {
float kx = fcFactor * (xyf.x - float(u))/pixelWidth.x;
float ky = fcFactor * (xyf.y - float(v))/pixelWidth.y;
//float lanczosValue = gaussian(kx, fcx);
float lanczosValue = kaiser(sqrt(kx*kx + ky*ky), alpha);
q += texelFetch(tex, ivec2(u, v), 0) * lanczosValue;
qSum += lanczosValue;
}
}
return q/qSum;
}
void main()
{
out_color = lowpassFilter(in_texture, in_uv, 4.0);
out_color.a = 1.0;
}