screens & basic interactions

This commit is contained in:
galister
2023-12-07 02:07:13 +01:00
parent cb039de409
commit a3b60b9607
19 changed files with 518 additions and 1599 deletions

1
Cargo.lock generated
View File

@@ -4024,7 +4024,6 @@ dependencies = [
[[package]] [[package]]
name = "wlx-capture" name = "wlx-capture"
version = "0.1.0" version = "0.1.0"
source = "git+https://github.com/galister/wlx-capture.git#56eba19fac9834e2dfb77dd3a0a93b088a93dee9"
dependencies = [ dependencies = [
"ashpd", "ashpd",
"drm-fourcc", "drm-fourcc",

View File

@@ -1,3 +1,12 @@
[profile.release-with-debug]
inherits = "release"
debuginfo-level = 1
jemalloc = false
debug = true
[rust]
debuginfo-level = 1
[package] [package]
name = "wlx-overlay-s" name = "wlx-overlay-s"
version = "0.1.0" version = "0.1.0"
@@ -36,5 +45,5 @@ vulkano-shaders = "0.33.0"
vulkano-util = "0.33.0" vulkano-util = "0.33.0"
vulkano-win = "0.33.0" vulkano-win = "0.33.0"
winit = "0.28.6" winit = "0.28.6"
wlx-capture = { git = "https://github.com/galister/wlx-capture.git" } wlx-capture = { path = "../wlx-capture" }

View File

@@ -1,7 +1,6 @@
use std::{collections::VecDeque, time::Instant}; use std::{collections::VecDeque, time::Instant};
use glam::{Affine3A, Vec2, Vec3A}; use glam::{Affine3A, Vec2, Vec3A};
use log::warn;
use ovr_overlay::TrackedDeviceIndex; use ovr_overlay::TrackedDeviceIndex;
use tinyvec::array_vec; use tinyvec::array_vec;
@@ -42,6 +41,39 @@ impl<TState, THand> InputState<TState, THand> {
pub fn post_update(&mut self) { pub fn post_update(&mut self) {
for hand in &mut self.pointers { for hand in &mut self.pointers {
#[cfg(debug_assertions)]
{
if hand.now.click != hand.before.click {
log::debug!("Hand {}: click {}", hand.idx, hand.now.click);
}
if hand.now.grab != hand.before.grab {
log::debug!("Hand {}: grab {}", hand.idx, hand.now.grab);
}
if hand.now.alt_click != hand.before.alt_click {
log::debug!("Hand {}: alt_click {}", hand.idx, hand.now.alt_click);
}
if hand.now.show_hide != hand.before.show_hide {
log::debug!("Hand {}: show_hide {}", hand.idx, hand.now.show_hide);
}
if hand.now.space_drag != hand.before.space_drag {
log::debug!("Hand {}: space_drag {}", hand.idx, hand.now.space_drag);
}
if hand.now.click_modifier_right != hand.before.click_modifier_right {
log::debug!(
"Hand {}: click_modifier_right {}",
hand.idx,
hand.now.click_modifier_right
);
}
if hand.now.click_modifier_middle != hand.before.click_modifier_middle {
log::debug!(
"Hand {}: click_modifier_middle {}",
hand.idx,
hand.now.click_modifier_middle
);
}
}
if hand.now.click_modifier_right { if hand.now.click_modifier_right {
hand.interaction.mode = PointerMode::Right; hand.interaction.mode = PointerMode::Right;
continue; continue;
@@ -176,7 +208,7 @@ pub enum PointerMode {
} }
impl<THand> Pointer<THand> { impl<THand> Pointer<THand> {
pub fn interact<O>(&mut self, overlays: &mut OverlayContainer<O>, app: &mut AppState) pub fn interact<O>(&mut self, overlays: &mut OverlayContainer<O>, app: &mut AppState) -> f32
where where
O: Default, O: Default,
{ {
@@ -184,10 +216,10 @@ impl<THand> Pointer<THand> {
if let Some(grabbed) = overlays.mut_by_id(grab_data.grabbed_id) { if let Some(grabbed) = overlays.mut_by_id(grab_data.grabbed_id) {
self.handle_grabbed(grabbed, grab_data.offset); self.handle_grabbed(grabbed, grab_data.offset);
} else { } else {
warn!("Grabbed overlay {} does not exist", grab_data.grabbed_id); log::warn!("Grabbed overlay {} does not exist", grab_data.grabbed_id);
self.interaction.grabbed = None; self.interaction.grabbed = None;
} }
return; return grab_data.offset.length(); // grab interaction
} }
let Some(mut hit) = self.get_nearest_hit(overlays) else { let Some(mut hit) = self.get_nearest_hit(overlays) else {
@@ -208,7 +240,7 @@ impl<THand> Pointer<THand> {
clicked.backend.on_pointer(app, &hit, false); clicked.backend.on_pointer(app, &hit, false);
} }
} }
return; return 0.0; // no hit
}; };
if let Some(hovered_id) = self.interaction.hovered_id { if let Some(hovered_id) = self.interaction.hovered_id {
@@ -222,14 +254,14 @@ impl<THand> Pointer<THand> {
} }
} }
let Some(hovered) = overlays.mut_by_id(hit.overlay) else { let Some(hovered) = overlays.mut_by_id(hit.overlay) else {
warn!("Hit overlay {} does not exist", hit.overlay); log::warn!("Hit overlay {} does not exist", hit.overlay);
return; return 0.0; // no hit
}; };
self.interaction.hovered_id = Some(hit.overlay); self.interaction.hovered_id = Some(hit.overlay);
if let Some(primary_pointer) = hovered.primary_pointer { if let Some(primary_pointer) = hovered.primary_pointer {
if hit.pointer < primary_pointer { if hit.pointer <= primary_pointer {
hovered.primary_pointer = Some(hit.pointer); hovered.primary_pointer = Some(hit.pointer);
hit.primary = true; hit.primary = true;
} }
@@ -237,6 +269,14 @@ impl<THand> Pointer<THand> {
hovered.primary_pointer = Some(hit.pointer); hovered.primary_pointer = Some(hit.pointer);
hit.primary = true; hit.primary = true;
} }
log::debug!("Hit: {} {:?}", hovered.state.name, hit);
if self.now.grab && !self.before.grab {
self.start_grab(hovered);
return hit.dist;
}
hovered.backend.on_hover(app, &hit); hovered.backend.on_hover(app, &hit);
if self.now.scroll.abs() > 0.1 { if self.now.scroll.abs() > 0.1 {
@@ -255,6 +295,7 @@ impl<THand> Pointer<THand> {
hovered.backend.on_pointer(app, &hit, false); hovered.backend.on_pointer(app, &hit, false);
} }
} }
hit.dist
} }
fn get_nearest_hit<O>(&mut self, overlays: &mut OverlayContainer<O>) -> Option<PointerHit> fn get_nearest_hit<O>(&mut self, overlays: &mut OverlayContainer<O>) -> Option<PointerHit>
@@ -276,15 +317,17 @@ impl<THand> Pointer<THand> {
hits.sort_by(|a, b| a.dist.partial_cmp(&b.dist).unwrap()); hits.sort_by(|a, b| a.dist.partial_cmp(&b.dist).unwrap());
for hit in hits.iter() { for hit in hits.iter() {
let uv = overlays let overlay = overlays.get_by_id(hit.overlay).unwrap(); // this is safe
.get_by_id(hit.overlay)
.unwrap() // this is safe let uv = overlay
.state .state
.transform .transform
.inverse() .inverse()
.transform_point3a(hit.hit_pos) .transform_point3a(hit.hit_pos)
.truncate(); .truncate();
let uv = overlay.state.interaction_transform.transform_point2(uv);
if uv.x < 0.0 || uv.x > 1.0 || uv.y < 0.0 || uv.y > 1.0 { if uv.x < 0.0 || uv.x > 1.0 || uv.y < 0.0 || uv.y > 1.0 {
continue; continue;
} }
@@ -315,7 +358,9 @@ impl<THand> Pointer<THand> {
offset, offset,
grabbed_id: overlay.state.id, grabbed_id: overlay.state.id,
}); });
log::info!("Hand {}: grabbed {}", self.idx, overlay.state.name);
} }
fn handle_grabbed<O>(&mut self, overlay: &mut OverlayData<O>, offset: Vec3A) fn handle_grabbed<O>(&mut self, overlay: &mut OverlayData<O>, offset: Vec3A)
where where
O: Default, O: Default,
@@ -324,7 +369,7 @@ impl<THand> Pointer<THand> {
overlay.state.transform.translation = self.pose.transform_point3a(offset); overlay.state.transform.translation = self.pose.transform_point3a(offset);
if self.now.click && !self.before.click { if self.now.click && !self.before.click {
warn!("todo: click-while-grabbed"); log::warn!("todo: click-while-grabbed");
} }
match self.interaction.mode { match self.interaction.mode {
@@ -339,11 +384,14 @@ impl<THand> Pointer<THand> {
.mul_scalar(1.0 + 0.01 * self.now.scroll); .mul_scalar(1.0 + 0.01 * self.now.scroll);
} }
} }
overlay.state.dirty = true;
} else { } else {
overlay.state.spawn_point = overlay.state.transform.translation; overlay.state.spawn_point = overlay.state.transform.translation;
self.interaction.grabbed = None; self.interaction.grabbed = None;
log::info!("Hand {}: dropped {}", self.idx, overlay.state.name);
} }
} }
fn ray_test(&self, overlay: usize, plane: &Affine3A) -> Option<RayHit> { fn ray_test(&self, overlay: usize, plane: &Affine3A) -> Option<RayHit> {
let plane_normal = plane.transform_vector3a(Vec3A::NEG_Z); let plane_normal = plane.transform_vector3a(Vec3A::NEG_Z);
let ray_dir = self.pose.transform_vector3a(Vec3A::NEG_Z); let ray_dir = self.pose.transform_vector3a(Vec3A::NEG_Z);

View File

@@ -59,6 +59,7 @@ pub(super) struct OpenVrInputState {
} }
pub(super) struct OpenVrHandState { pub(super) struct OpenVrHandState {
pub(super) line_id: usize,
has_pose: bool, has_pose: bool,
input_hnd: InputValueHandle, input_hnd: InputValueHandle,
pose_hnd: ActionHandle, pose_hnd: ActionHandle,
@@ -103,6 +104,7 @@ impl InputState<OpenVrInputState, OpenVrHandState> {
pose: Affine3A::IDENTITY, pose: Affine3A::IDENTITY,
interaction: InteractionState::default(), interaction: InteractionState::default(),
data: OpenVrHandState { data: OpenVrHandState {
line_id: 0,
has_pose: false, has_pose: false,
input_hnd: input_hnd[i], input_hnd: input_hnd[i],
pose_hnd: pose_hnd[i], pose_hnd: pose_hnd[i],

130
src/backend/openvr/lines.rs Normal file
View File

@@ -0,0 +1,130 @@
use std::f32::consts::PI;
use std::sync::atomic::{AtomicUsize, Ordering};
use std::sync::Arc;
use glam::{Affine3A, Vec3, Vec3A, Vec4};
use idmap::IdMap;
use ovr_overlay::overlay::OverlayManager;
use vulkano::command_buffer::CommandBufferUsage;
use vulkano::format::Format;
use vulkano::image::view::ImageView;
use vulkano::image::{ImageAccess, ImageLayout, ImageViewAbstract, ImmutableImage};
use crate::backend::overlay::{OverlayData, OverlayRenderer, OverlayState, SplitOverlayBackend};
use crate::graphics::WlxGraphics;
use crate::state::AppState;
use super::overlay::OpenVrOverlayData;
static AUTO_INCREMENT: AtomicUsize = AtomicUsize::new(1);
pub(super) struct LinePool {
lines: IdMap<usize, OverlayData<OpenVrOverlayData>>,
view: Arc<ImageView<ImmutableImage>>,
}
impl LinePool {
pub fn new(graphics: Arc<WlxGraphics>) -> Self {
let mut command_buffer = graphics.create_command_buffer(CommandBufferUsage::OneTimeSubmit);
let buf = vec![255; 16];
let texture = command_buffer.texture2d(2, 2, Format::R8G8B8A8_UNORM, buf);
command_buffer.build_and_execute_now();
graphics
.transition_layout(
texture.inner().image.clone(),
ImageLayout::ShaderReadOnlyOptimal,
ImageLayout::TransferSrcOptimal,
)
.wait(None)
.unwrap();
let view = ImageView::new_default(texture).unwrap();
LinePool {
lines: IdMap::new(),
view,
}
}
pub fn allocate(&mut self, overlay: &mut OverlayManager, app: &mut AppState) -> usize {
let id = AUTO_INCREMENT.fetch_add(1, Ordering::Relaxed);
let mut data = OverlayData::<OpenVrOverlayData> {
state: OverlayState {
name: Arc::from(format!("wlx-line{}", id)),
show_hide: true,
width: 0.002,
size: (0, 0),
..Default::default()
},
backend: Box::new(SplitOverlayBackend {
renderer: Box::new(StaticRenderer {
view: self.view.clone(),
}),
..Default::default()
}),
..Default::default()
};
data.data.sort_order = 69;
data.initialize(overlay, app);
data.upload_texture(overlay, &app.graphics);
self.lines.insert(id, data);
id
}
pub fn draw_from(&mut self, id: usize, mut from: Affine3A, len: f32, color: Vec4) {
let rotation = Affine3A::from_axis_angle(Vec3::X, -PI * 0.5);
from.translation = from.translation + from.transform_vector3a(Vec3A::NEG_Z) * (len * 0.5);
let transform = from * rotation * Affine3A::from_scale(Vec3::new(1., len / 0.002, 1.));
self.draw_transform(id, transform, color);
}
fn draw_transform(&mut self, id: usize, transform: Affine3A, color: Vec4) {
if let Some(data) = self.lines.get_mut(id) {
data.state.want_visible = true;
data.state.transform = transform;
data.data.color = color;
} else {
log::warn!("Line {} does not exist", id);
}
}
pub fn hide(&mut self, id: usize) {
if let Some(data) = self.lines.get_mut(id) {
data.state.want_visible = false;
} else {
log::warn!("Line {} does not exist", id);
}
}
pub fn update(&mut self, overlay: &mut OverlayManager, app: &mut AppState) {
for data in self.lines.values_mut() {
data.after_input(overlay, app);
if data.state.want_visible {
data.upload_transform(overlay);
data.upload_color(overlay);
}
}
}
}
struct StaticRenderer {
view: Arc<ImageView<ImmutableImage>>,
}
impl OverlayRenderer for StaticRenderer {
fn init(&mut self, _app: &mut AppState) {}
fn pause(&mut self, _app: &mut AppState) {}
fn resume(&mut self, _app: &mut AppState) {}
fn render(&mut self, _app: &mut AppState) {}
fn view(&mut self) -> Option<Arc<dyn ImageViewAbstract>> {
Some(self.view.clone())
}
}

View File

@@ -1,10 +1,9 @@
use glam::Vec4;
use std::{ use std::{
collections::VecDeque, collections::VecDeque,
path::Path,
time::{Duration, Instant}, time::{Duration, Instant},
}; };
use log::{error, info};
use ovr_overlay::{ use ovr_overlay::{
sys::{ETrackedDeviceProperty, EVRApplicationType, EVREventType}, sys::{ETrackedDeviceProperty, EVRApplicationType, EVREventType},
TrackedDeviceIndex, TrackedDeviceIndex,
@@ -15,7 +14,7 @@ use vulkano::{
Handle, VulkanObject, Handle, VulkanObject,
}; };
use crate::state::AppState; use crate::{backend::openvr::lines::LinePool, state::AppState};
use self::{input::action_manifest_path, overlay::OpenVrOverlayData}; use self::{input::action_manifest_path, overlay::OpenVrOverlayData};
@@ -25,12 +24,13 @@ use super::{
}; };
pub mod input; pub mod input;
pub mod lines;
pub mod overlay; pub mod overlay;
pub fn openvr_run() { pub fn openvr_run() {
let app_type = EVRApplicationType::VRApplication_Overlay; let app_type = EVRApplicationType::VRApplication_Overlay;
let Ok(context) = ovr_overlay::Context::init(app_type) else { let Ok(context) = ovr_overlay::Context::init(app_type) else {
error!("Failed to initialize OpenVR"); log::error!("Failed to initialize OpenVR");
return; return;
}; };
@@ -56,12 +56,12 @@ pub fn openvr_run() {
let mut overlays = OverlayContainer::<OpenVrOverlayData>::new(&mut state); let mut overlays = OverlayContainer::<OpenVrOverlayData>::new(&mut state);
if let Err(e) = input_mngr.set_action_manifest(action_manifest_path()) { if let Err(e) = input_mngr.set_action_manifest(action_manifest_path()) {
error!("Failed to set action manifest: {}", e.description()); log::error!("Failed to set action manifest: {}", e.description());
return; return;
}; };
let Ok(mut input) = InputState::new(&mut input_mngr) else { let Ok(mut input) = InputState::new(&mut input_mngr) else {
error!("Failed to initialize input"); log::error!("Failed to initialize input");
return; return;
}; };
@@ -69,21 +69,25 @@ pub fn openvr_run() {
TrackedDeviceIndex::HMD, TrackedDeviceIndex::HMD,
ETrackedDeviceProperty::Prop_DisplayFrequency_Float, ETrackedDeviceProperty::Prop_DisplayFrequency_Float,
) else { ) else {
error!("Failed to get display refresh rate"); log::error!("Failed to get display refresh rate");
return; return;
}; };
info!("HMD running @ {} Hz", refresh_rate); log::info!("HMD running @ {} Hz", refresh_rate);
let frame_time = (1000.0 / refresh_rate).floor() * 0.001; let frame_time = (1000.0 / refresh_rate).floor() * 0.001;
let mut next_device_update = Instant::now(); let mut next_device_update = Instant::now();
let mut due_tasks = VecDeque::with_capacity(4); let mut due_tasks = VecDeque::with_capacity(4);
let mut lines = LinePool::new(state.graphics.clone());
input.pointers[0].data.line_id = lines.allocate(&mut overlay_mngr, &mut state);
input.pointers[1].data.line_id = lines.allocate(&mut overlay_mngr, &mut state);
loop { loop {
while let Some(event) = system_mngr.poll_next_event() { while let Some(event) = system_mngr.poll_next_event() {
match event.event_type { match event.event_type {
EVREventType::VREvent_Quit => { EVREventType::VREvent_Quit => {
info!("Received quit event, shutting down."); log::info!("Received quit event, shutting down.");
return; return;
} }
EVREventType::VREvent_TrackedDeviceActivated EVREventType::VREvent_TrackedDeviceActivated
@@ -93,6 +97,7 @@ pub fn openvr_run() {
} }
_ => {} _ => {}
} }
}
if next_device_update <= Instant::now() { if next_device_update <= Instant::now() {
input.update_devices(&mut system_mngr); input.update_devices(&mut system_mngr);
@@ -115,10 +120,17 @@ pub fn openvr_run() {
input.update(&mut input_mngr, &mut system_mngr); input.update(&mut input_mngr, &mut system_mngr);
input.post_update(); input.post_update();
input input.pointers.iter_mut().for_each(|p| {
.pointers let dist = p.interact(&mut overlays, &mut state);
.iter_mut() if dist > 0.001 {
.for_each(|p| p.interact(&mut overlays, &mut state)); lines.draw_from(p.data.line_id, p.pose, dist, Vec4::ONE);
} else {
lines.draw_from(p.data.line_id, p.pose, 20.0, Vec4::ONE);
// lines.hide(p.data.line_id);
}
});
lines.update(&mut overlay_mngr, &mut state);
overlays overlays
.iter_mut() .iter_mut()
@@ -143,14 +155,15 @@ pub fn openvr_run() {
// playspace moved end frame // playspace moved end frame
state.input.on_new_frame();
let mut seconds_since_vsync = 0f32; let mut seconds_since_vsync = 0f32;
std::thread::sleep(Duration::from_secs_f32( std::thread::sleep(Duration::from_secs_f32(
if system_mngr.get_time_since_last_vsync(&mut seconds_since_vsync, &mut 0u64) { if system_mngr.get_time_since_last_vsync(&mut seconds_since_vsync, &mut 0u64) {
(frame_time - seconds_since_vsync).max(0.0) frame_time - (seconds_since_vsync % frame_time)
} else { } else {
0.011 frame_time
}, },
)); ));
} }
} }
}

View File

@@ -6,7 +6,11 @@ use ovr_overlay::{
}; };
use vulkano::{image::ImageAccess, Handle, VulkanObject}; use vulkano::{image::ImageAccess, Handle, VulkanObject};
use crate::{backend::overlay::OverlayData, graphics::WlxGraphics, state::AppState}; use crate::{
backend::overlay::{OverlayData, RelativeTo},
graphics::WlxGraphics,
state::AppState,
};
#[derive(Default)] #[derive(Default)]
pub(super) struct OpenVrOverlayData { pub(super) struct OpenVrOverlayData {
@@ -16,10 +20,11 @@ pub(super) struct OpenVrOverlayData {
pub(super) color: Vec4, pub(super) color: Vec4,
pub(super) curvature: f32, pub(super) curvature: f32,
pub(super) sort_order: u32, pub(super) sort_order: u32,
pub(super) relative_to: RelativeTo,
} }
impl OverlayData<OpenVrOverlayData> { impl OverlayData<OpenVrOverlayData> {
pub fn initialize( pub(super) fn initialize(
&mut self, &mut self,
overlay: &mut OverlayManager, overlay: &mut OverlayManager,
app: &mut AppState, app: &mut AppState,
@@ -33,6 +38,11 @@ impl OverlayData<OpenVrOverlayData> {
}; };
log::debug!("{}: initialize", self.state.name); log::debug!("{}: initialize", self.state.name);
//watch
if self.state.id == 0 {
self.data.sort_order = 68;
}
self.data.handle = Some(handle); self.data.handle = Some(handle);
self.data.color = Vec4::ONE; self.data.color = Vec4::ONE;
@@ -41,11 +51,12 @@ impl OverlayData<OpenVrOverlayData> {
self.upload_width(overlay); self.upload_width(overlay);
self.upload_color(overlay); self.upload_color(overlay);
self.upload_curvature(overlay); self.upload_curvature(overlay);
self.upload_sort_order(overlay);
handle handle
} }
pub fn after_input(&mut self, overlay: &mut OverlayManager, app: &mut AppState) { pub(super) fn after_input(&mut self, overlay: &mut OverlayManager, app: &mut AppState) {
if self.state.want_visible && !self.data.visible { if self.state.want_visible && !self.data.visible {
self.show(overlay, app); self.show(overlay, app);
} else if !self.state.want_visible && self.data.visible { } else if !self.state.want_visible && self.data.visible {
@@ -53,9 +64,12 @@ impl OverlayData<OpenVrOverlayData> {
} }
} }
pub fn after_render(&mut self, overlay: &mut OverlayManager, graphics: &WlxGraphics) { pub(super) fn after_render(&mut self, overlay: &mut OverlayManager, graphics: &WlxGraphics) {
if self.data.visible { if self.data.visible {
if self.state.dirty {
self.upload_transform(overlay); self.upload_transform(overlay);
self.state.dirty = false;
}
self.upload_texture(overlay, graphics); self.upload_texture(overlay, graphics);
} }
} }
@@ -83,7 +97,7 @@ impl OverlayData<OpenVrOverlayData> {
self.data.visible = false; self.data.visible = false;
} }
fn upload_color(&self, overlay: &mut OverlayManager) { pub(super) fn upload_color(&self, overlay: &mut OverlayManager) {
let Some(handle) = self.data.handle else { let Some(handle) = self.data.handle else {
log::debug!("{}: No overlay handle", self.state.name); log::debug!("{}: No overlay handle", self.state.name);
return; return;
@@ -104,7 +118,7 @@ impl OverlayData<OpenVrOverlayData> {
} }
} }
fn upload_width(&self, overlay: &mut OverlayManager) { pub(super) fn upload_width(&self, overlay: &mut OverlayManager) {
let Some(handle) = self.data.handle else { let Some(handle) = self.data.handle else {
log::debug!("{}: No overlay handle", self.state.name); log::debug!("{}: No overlay handle", self.state.name);
return; return;
@@ -134,7 +148,7 @@ impl OverlayData<OpenVrOverlayData> {
} }
} }
fn upload_transform(&self, overlay: &mut OverlayManager) { pub(super) fn upload_transform(&self, overlay: &mut OverlayManager) {
let Some(handle) = self.data.handle else { let Some(handle) = self.data.handle else {
log::debug!("{}: No overlay handle", self.state.name); log::debug!("{}: No overlay handle", self.state.name);
return; return;
@@ -170,7 +184,7 @@ impl OverlayData<OpenVrOverlayData> {
} }
} }
fn upload_texture(&mut self, overlay: &mut OverlayManager, graphics: &WlxGraphics) { pub(super) fn upload_texture(&mut self, overlay: &mut OverlayManager, graphics: &WlxGraphics) {
let Some(handle) = self.data.handle else { let Some(handle) = self.data.handle else {
log::debug!("{}: No overlay handle", self.state.name); log::debug!("{}: No overlay handle", self.state.name);
return; return;
@@ -210,8 +224,13 @@ impl OverlayData<OpenVrOverlayData> {
m_nQueueFamilyIndex: graphics.queue.queue_family_index(), m_nQueueFamilyIndex: graphics.queue.queue_family_index(),
}; };
log::info!("Usages: {:?}", image.usage()); log::debug!(
log::info!("nImage: {}, nFormat: {:?}, nWidth: {}, nHeight: {}, nSampleCount: {}, nQueueFamilyIndex: {}", texture.m_nImage, format, texture.m_nWidth, texture.m_nHeight, texture.m_nSampleCount, texture.m_nQueueFamilyIndex); "UploadTex: {:?}, {}x{}, {:?}",
format,
texture.m_nWidth,
texture.m_nHeight,
image.usage()
);
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);
} }

View File

@@ -3,7 +3,7 @@ use std::sync::{
Arc, Arc,
}; };
use glam::{Affine3A, Quat, Vec3A}; use glam::{Affine2, Affine3A, Quat, Vec3A};
use vulkano::image::ImageViewAbstract; use vulkano::image::ImageViewAbstract;
use crate::state::AppState; use crate::state::AppState;
@@ -22,12 +22,13 @@ pub struct OverlayState {
pub want_visible: bool, pub want_visible: bool,
pub show_hide: bool, pub show_hide: bool,
pub grabbable: bool, pub grabbable: bool,
pub dirty: bool,
pub transform: Affine3A, pub transform: Affine3A,
pub spawn_point: Vec3A, pub spawn_point: Vec3A,
pub spawn_rotation: Quat, pub spawn_rotation: Quat,
pub relative_to: RelativeTo, pub relative_to: RelativeTo,
pub primary_pointer: Option<usize>, pub primary_pointer: Option<usize>,
pub interaction_transform: Affine3A, pub interaction_transform: Affine2,
} }
impl Default for OverlayState { impl Default for OverlayState {
@@ -40,12 +41,13 @@ impl Default for OverlayState {
want_visible: false, want_visible: false,
show_hide: false, show_hide: false,
grabbable: false, grabbable: false,
dirty: false,
relative_to: RelativeTo::None, relative_to: RelativeTo::None,
spawn_point: Vec3A::NEG_Z, spawn_point: Vec3A::NEG_Z,
spawn_rotation: Quat::IDENTITY, spawn_rotation: Quat::IDENTITY,
transform: Affine3A::IDENTITY, transform: Affine3A::IDENTITY,
primary_pointer: None, primary_pointer: None,
interaction_transform: Affine3A::IDENTITY, interaction_transform: Affine2::IDENTITY,
} }
} }
} }
@@ -111,12 +113,14 @@ impl OverlayRenderer for FallbackRenderer {
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<dyn ImageViewAbstract>> {
unimplemented!() None
} }
} }
// Boilerplate and dummies // Boilerplate and dummies
#[derive(Clone, Copy, Debug, Default)]
pub enum RelativeTo { pub enum RelativeTo {
#[default]
None, None,
Head, Head,
Hand(usize), Hand(usize),

View File

@@ -1,7 +1,6 @@
use std::{error::Error, io::Cursor, slice::Iter, sync::Arc}; use std::{error::Error, io::Cursor, slice::Iter, sync::Arc};
use ash::vk::SubmitInfo; use ash::vk::SubmitInfo;
use log::{debug, error, info};
use smallvec::smallvec; use smallvec::smallvec;
use vulkano::{ use vulkano::{
buffer::{ buffer::{
@@ -28,9 +27,9 @@ use vulkano::{
}, },
format::Format, format::Format,
image::{ image::{
sys::Image, AttachmentImage, ImageAccess, ImageCreateFlags, ImageDimensions, ImageError, sys::Image, AttachmentImage, ImageCreateFlags, ImageDimensions, ImageError, ImageLayout,
ImageLayout, ImageUsage, ImageViewAbstract, ImmutableImage, MipmapsCount, StorageImage, ImageUsage, ImageViewAbstract, ImmutableImage, MipmapsCount, StorageImage, SubresourceData,
SubresourceData, SwapchainImage, SwapchainImage,
}, },
instance::{Instance, InstanceCreateInfo, InstanceExtensions}, instance::{Instance, InstanceCreateInfo, InstanceExtensions},
memory::allocator::{AllocationCreateInfo, MemoryUsage, StandardMemoryAllocator}, memory::allocator::{AllocationCreateInfo, MemoryUsage, StandardMemoryAllocator},
@@ -49,8 +48,8 @@ use vulkano::{
shader::ShaderModule, shader::ShaderModule,
swapchain::{CompositeAlpha, Surface, Swapchain, SwapchainCreateInfo}, swapchain::{CompositeAlpha, Surface, Swapchain, SwapchainCreateInfo},
sync::{ sync::{
fence::Fence, future::NowFuture, AccessFlags, DependencyInfo, ImageMemoryBarrier, fence::Fence, future::NowFuture, AccessFlags, DependencyInfo, GpuFuture,
PipelineStages, ImageMemoryBarrier, PipelineStages,
}, },
Version, VulkanLibrary, VulkanObject, Version, VulkanLibrary, VulkanObject,
}; };
@@ -103,8 +102,8 @@ impl WlxGraphics {
let library_extensions = vulkano_win::required_extensions(&library); 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);
debug!("Instance exts for app: {:?}", &required_extensions); log::debug!("Instance exts for app: {:?}", &required_extensions);
debug!("Instance exts for runtime: {:?}", &vk_instance_extensions); log::debug!("Instance exts for runtime: {:?}", &vk_instance_extensions);
let instance = Instance::new( let instance = Instance::new(
library, library,
@@ -126,7 +125,7 @@ impl WlxGraphics {
..DeviceExtensions::empty() ..DeviceExtensions::empty()
}; };
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 event_loop = EventLoop::new();
@@ -142,7 +141,7 @@ impl WlxGraphics {
}) })
.filter_map(|p| { .filter_map(|p| {
let runtime_extensions = vk_device_extensions_fn(&p); let runtime_extensions = vk_device_extensions_fn(&p);
debug!( log::debug!(
"Device exts for {}: {:?}", "Device exts for {}: {:?}",
p.properties().device_name, p.properties().device_name,
&runtime_extensions &runtime_extensions
@@ -174,7 +173,7 @@ impl WlxGraphics {
}) })
.expect("no suitable physical device found"); .expect("no suitable physical device found");
info!( log::info!(
"Using vkPhysicalDevice: {}", "Using vkPhysicalDevice: {}",
physical_device.properties().device_name, physical_device.properties().device_name,
); );
@@ -271,6 +270,7 @@ impl WlxGraphics {
(Arc::new(me), event_loop) (Arc::new(me), event_loop)
} }
#[allow(dead_code)]
pub fn create_swapchain( pub fn create_swapchain(
&self, &self,
format: Option<Format>, format: Option<Format>,
@@ -541,32 +541,7 @@ pub struct WlxCommandBuffer<T> {
} }
impl<T> WlxCommandBuffer<T> { impl<T> WlxCommandBuffer<T> {
pub fn inner(&self) -> &AutoCommandBufferBuilder<T, Arc<StandardCommandBufferAllocator>> { pub fn begin(mut self, render_target: Arc<dyn ImageViewAbstract>) -> Self {
&self.command_buffer
}
pub fn inner_mut(
&mut self,
) -> &mut AutoCommandBufferBuilder<T, Arc<StandardCommandBufferAllocator>> {
&mut self.command_buffer
}
pub fn to_inner(self) -> AutoCommandBufferBuilder<T, Arc<StandardCommandBufferAllocator>> {
self.command_buffer
}
pub fn begin(
mut self,
render_target: Arc<dyn ImageViewAbstract>,
want_layout: Option<ImageLayout>,
) -> Self {
if let Some(want_layout) = want_layout {
let mut barrier =
ImageMemoryBarrier::image(render_target.image().inner().image.clone());
barrier.old_layout = ImageLayout::ColorAttachmentOptimal;
barrier.new_layout = want_layout;
}
self.command_buffer self.command_buffer
.begin_rendering(RenderingInfo { .begin_rendering(RenderingInfo {
contents: SubpassContents::SecondaryCommandBuffers, contents: SubpassContents::SecondaryCommandBuffers,
@@ -590,13 +565,6 @@ impl<T> WlxCommandBuffer<T> {
self self
} }
pub fn run(mut self, pass: &WlxPass) -> Self {
let _ = self
.command_buffer
.execute_commands(pass.command_buffer.clone());
self
}
pub fn texture2d( pub fn texture2d(
&mut self, &mut self,
width: u32, width: u32,
@@ -614,13 +582,14 @@ impl<T> WlxCommandBuffer<T> {
&self.graphics.memory_allocator, &self.graphics.memory_allocator,
data, data,
dimensions, dimensions,
MipmapsCount::One, MipmapsCount::Log2, // required for TRANSFER_SRC
format, format,
&mut self.command_buffer, &mut self.command_buffer,
) )
.unwrap() .unwrap()
} }
#[allow(dead_code)]
pub fn texture2d_png(&mut self, bytes: Vec<u8>) -> Arc<ImmutableImage> { pub fn texture2d_png(&mut self, bytes: Vec<u8>) -> Arc<ImmutableImage> {
let cursor = Cursor::new(bytes); let cursor = Cursor::new(bytes);
let decoder = png::Decoder::new(cursor); let decoder = png::Decoder::new(cursor);
@@ -636,32 +605,24 @@ impl<T> WlxCommandBuffer<T> {
} }
impl WlxCommandBuffer<PrimaryAutoCommandBuffer> { impl WlxCommandBuffer<PrimaryAutoCommandBuffer> {
pub fn end_render_and_continue(&mut self) { pub fn end_render(mut self) -> Self {
self.command_buffer.end_rendering().unwrap(); self.command_buffer.end_rendering().unwrap();
self
} }
pub fn end_render(self) -> PrimaryAutoCommandBuffer { pub fn build(self) -> PrimaryAutoCommandBuffer {
let mut buf = self.command_buffer;
buf.end_rendering().unwrap();
buf.build().unwrap()
}
pub fn end(self) -> PrimaryAutoCommandBuffer {
self.command_buffer.build().unwrap() self.command_buffer.build().unwrap()
} }
pub fn end_render_and_execute(self) -> CommandBufferExecFuture<NowFuture> { pub fn build_and_execute(self) -> CommandBufferExecFuture<NowFuture> {
let mut buf = self.command_buffer; let queue = self.graphics.queue.clone();
buf.end_rendering().unwrap(); self.build().execute(queue).unwrap()
let buf = buf.build().unwrap();
buf.execute(self.graphics.queue.clone()).unwrap()
} }
pub fn end_and_execute(self) -> CommandBufferExecFuture<NowFuture> { pub fn build_and_execute_now(self) {
let buf = self.command_buffer; let mut exec = self.build_and_execute();
let buf = buf.build().unwrap(); exec.flush().unwrap();
buf.execute(self.graphics.queue.clone()).unwrap() exec.cleanup_finished();
} }
} }
@@ -705,10 +666,6 @@ impl WlxPipeline {
self.pipeline.clone() self.pipeline.clone()
} }
pub fn graphics(&self) -> Arc<WlxGraphics> {
self.graphics.clone()
}
pub fn uniform_sampler( pub fn uniform_sampler(
&self, &self,
set: usize, set: usize,
@@ -780,6 +737,7 @@ impl WlxPipeline {
} }
} }
#[allow(dead_code)]
pub struct WlxPass { pub struct WlxPass {
pipeline: Arc<WlxPipeline>, pipeline: Arc<WlxPipeline>,
vertex_buffer: Subbuffer<[Vert2Uv]>, vertex_buffer: Subbuffer<[Vert2Uv]>,
@@ -833,7 +791,7 @@ impl WlxPass {
.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() {
error!("Failed to draw: {}", source); log::error!("Failed to draw: {}", source);
} }
Err(err) Err(err)
}) })

File diff suppressed because it is too large Load Diff

View File

@@ -3,7 +3,6 @@ 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 log::debug;
use vulkano::{command_buffer::CommandBufferUsage, format::Format, image::ImmutableImage}; use vulkano::{command_buffer::CommandBufferUsage, format::Format, image::ImmutableImage};
use crate::graphics::WlxGraphics; use crate::graphics::WlxGraphics;
@@ -116,7 +115,7 @@ impl FontCache {
let pattern = pattern.font_match(&mut self.fc); let pattern = pattern.font_match(&mut self.fc);
if let Some(path) = pattern.filename() { if let Some(path) = pattern.filename() {
debug!( log::debug!(
"Loading font: {} {}pt", "Loading font: {} {}pt",
pattern.name().unwrap_or(path), pattern.name().unwrap_or(path),
size size
@@ -203,7 +202,7 @@ impl FontCache {
let mut cmd_buffer = graphics.create_command_buffer(CommandBufferUsage::OneTimeSubmit); let mut cmd_buffer = graphics.create_command_buffer(CommandBufferUsage::OneTimeSubmit);
let texture = cmd_buffer.texture2d(bmp.width() as _, bmp.rows() as _, format, buf); let texture = cmd_buffer.texture2d(bmp.width() as _, bmp.rows() as _, format, buf);
let _ = cmd_buffer.end_and_execute(); cmd_buffer.build_and_execute_now();
let g = Glyph { let g = Glyph {
tex: Some(texture), tex: Some(texture),

View File

@@ -93,6 +93,7 @@ impl<D, S> CanvasBuilder<D, S> {
} }
// Creates a label with fg_color, font_size inherited from the canvas // Creates a label with fg_color, font_size inherited from the canvas
#[allow(dead_code)]
pub fn label_centered( pub fn label_centered(
&mut self, &mut self,
x: f32, x: f32,
@@ -320,13 +321,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(), None); .begin(self.view_bg.clone());
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);
} }
} }
let _ = cmd_buffer.end_render_and_execute(); cmd_buffer.end_render().build_and_execute_now()
} }
fn render_fg(&mut self, app: &mut AppState) { fn render_fg(&mut self, app: &mut AppState) {
@@ -334,17 +335,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(), None); .begin(self.view_fg.clone());
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);
} }
} }
let _ = cmd_buffer.end_render_and_execute(); cmd_buffer.end_render().build_and_execute_now()
}
pub fn render_view(&self) -> Arc<ImageView<AttachmentImage>> {
self.view_final.clone()
} }
} }
@@ -385,7 +382,6 @@ impl<D, S> InteractionHandler for Canvas<D, S> {
impl<D, S> OverlayRenderer for Canvas<D, S> { impl<D, S> OverlayRenderer for Canvas<D, S> {
fn init(&mut self, app: &mut AppState) { fn init(&mut self, app: &mut AppState) {
self.render_bg(app); self.render_bg(app);
self.render_fg(app); self.render_fg(app);
} }
fn pause(&mut self, _app: &mut AppState) {} fn pause(&mut self, _app: &mut AppState) {}
@@ -423,10 +419,7 @@ impl<D, S> OverlayRenderer for Canvas<D, S> {
.canvas .canvas
.graphics .graphics
.create_command_buffer(CommandBufferUsage::OneTimeSubmit) .create_command_buffer(CommandBufferUsage::OneTimeSubmit)
.begin( .begin(self.view_final.clone());
self.view_final.clone(),
Some(ImageLayout::TransferSrcOptimal),
);
if dirty { if dirty {
self.render_fg(app); self.render_fg(app);
@@ -451,7 +444,7 @@ 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_and_execute(); let _ = cmd_buffer.end_render().build_and_execute();
} }
self.canvas self.canvas
.graphics .graphics
@@ -478,7 +471,6 @@ pub struct Control<D, S> {
text: Arc<str>, text: Arc<str>,
size: isize, size: isize,
dirty: bool, dirty: bool,
pass_hl: Option<(WlxPass, WlxPass)>,
pub on_update: Option<fn(&mut Self, &mut D, &mut AppState)>, pub on_update: Option<fn(&mut Self, &mut D, &mut AppState)>,
pub on_press: Option<fn(&mut Self, &mut D, &mut AppState)>, pub on_press: Option<fn(&mut Self, &mut D, &mut AppState)>,
@@ -524,7 +516,6 @@ impl<D, S> Control<D, S> {
test_highlight: None, test_highlight: None,
on_press: None, on_press: None,
on_release: None, on_release: None,
pass_hl: None,
} }
} }
@@ -537,11 +528,6 @@ impl<D, S> Control<D, S> {
self.dirty = true; self.dirty = true;
} }
#[inline(always)]
pub fn get_text(&self) -> &str {
&self.text
}
fn render_rect( fn render_rect(
&self, &self,
canvas: &CanvasData<D>, canvas: &CanvasData<D>,

View File

@@ -6,7 +6,6 @@ use input_linux::{
UInputHandle, UInputHandle,
}; };
use libc::{input_event, timeval}; use libc::{input_event, timeval};
use log::{error, info};
use once_cell::sync::Lazy; use once_cell::sync::Lazy;
use std::fs::File; use std::fs::File;
use std::mem::transmute; use std::mem::transmute;
@@ -14,11 +13,11 @@ use strum::{EnumIter, EnumString, IntoEnumIterator};
pub fn initialize_input() -> Box<dyn InputProvider> { pub fn initialize_input() -> Box<dyn InputProvider> {
if let Some(uinput) = UInputProvider::try_new() { if let Some(uinput) = UInputProvider::try_new() {
info!("Initialized uinput."); log::info!("Initialized uinput.");
return Box::new(uinput); return Box::new(uinput);
} }
error!("Could not create uinput provider. Keyboard/Mouse input will not work!"); log::error!("Could not create uinput provider. Keyboard/Mouse input will not work!");
error!("Check if you're in `input` group: `id -nG`"); log::error!("Check if you're in `input` group: `id -nG`");
Box::new(DummyProvider {}) Box::new(DummyProvider {})
} }
@@ -64,7 +63,7 @@ impl UInputProvider {
version: 5, version: 5,
}; };
let name = b"WlxOverlay Keyboard-Mouse Hybrid Thing\0"; let name = b"WlxOverlay-S Keyboard-Mouse Hybrid Thing\0";
let abs_info = vec![ let abs_info = vec![
AbsoluteInfoSetup { AbsoluteInfoSetup {
@@ -145,6 +144,8 @@ impl InputProvider for UInputProvider {
} }
self.mouse_moved = true; self.mouse_moved = true;
log::info!("Mouse move: {:?}", pos);
let pos = pos * (MOUSE_EXTENT / self.desktop_extent); let pos = pos * (MOUSE_EXTENT / self.desktop_extent);
let time = get_time(); let time = get_time();
@@ -154,7 +155,7 @@ impl InputProvider for UInputProvider {
new_event(time, EV_SYN, 0, 0), new_event(time, EV_SYN, 0, 0),
]; ];
if let Err(res) = self.handle.write(&events) { if let Err(res) = self.handle.write(&events) {
error!("{}", res.to_string()); log::error!("{}", res.to_string());
} }
} }
fn send_button(&self, button: u16, down: bool) { fn send_button(&self, button: u16, down: bool) {
@@ -164,7 +165,7 @@ impl InputProvider for UInputProvider {
new_event(time, EV_SYN, 0, 0), new_event(time, EV_SYN, 0, 0),
]; ];
if let Err(res) = self.handle.write(&events) { if let Err(res) = self.handle.write(&events) {
error!("{}", res.to_string()); log::error!("send_button: {}", res.to_string());
} }
} }
fn wheel(&self, delta: i32) { fn wheel(&self, delta: i32) {
@@ -174,7 +175,7 @@ impl InputProvider for UInputProvider {
new_event(time, EV_SYN, 0, 0), new_event(time, EV_SYN, 0, 0),
]; ];
if let Err(res) = self.handle.write(&events) { if let Err(res) = self.handle.write(&events) {
error!("{}", res.to_string()); log::error!("wheel: {}", res.to_string());
} }
} }
fn set_modifiers(&mut self, modifiers: u8) { fn set_modifiers(&mut self, modifiers: u8) {
@@ -195,11 +196,11 @@ impl InputProvider for UInputProvider {
new_event(time, EV_SYN, 0, 0), new_event(time, EV_SYN, 0, 0),
]; ];
if let Err(res) = self.handle.write(&events) { if let Err(res) = self.handle.write(&events) {
error!("{}", res.to_string()); log::error!("send_key: {}", res.to_string());
} }
} }
fn set_desktop_extent(&mut self, extent: Vec2) { fn set_desktop_extent(&mut self, extent: Vec2) {
info!("Desktop extent: {:?}", extent); log::info!("Desktop extent: {:?}", extent);
self.desktop_extent = extent; self.desktop_extent = extent;
} }
fn on_new_frame(&mut self) { fn on_new_frame(&mut self) {

View File

@@ -9,11 +9,10 @@ mod state;
use crate::backend::openvr::openvr_run; use crate::backend::openvr::openvr_run;
use env_logger::Env; use env_logger::Env;
use log::info;
fn main() { fn main() {
env_logger::Builder::from_env(Env::default().default_filter_or("info")).init(); env_logger::Builder::from_env(Env::default().default_filter_or("info")).init();
info!( log::info!(
"Welcome to {} version {}!", "Welcome to {} version {}!",
env!("CARGO_PKG_NAME"), env!("CARGO_PKG_NAME"),
env!("CARGO_PKG_VERSION") env!("CARGO_PKG_VERSION")

View File

@@ -1,159 +0,0 @@
#[allow(dead_code)]
#[allow(unused_imports)]
mod graphics;
//mod gui;
//mod interactions;
//mod overlay;
//mod state;
use core::slice;
use ash::vk;
use env_logger::Env;
use glam::f32::Vec4;
use log::{info, warn};
use wlx_capture::{wlr::WlrDmabufCapture, wayland::WlxClient, WlxCapture, frame::WlxFrame};
use crate::{graphics::{VkGraphics, VkDescriptor}};
fn main() {
env_logger::Builder::from_env(Env::default().default_filter_or("info")).init();
info!("Welcome to {} version {}!", env!("CARGO_PKG_NAME"), env!("CARGO_PKG_VERSION"));
// let mut app = AppState {
// fc: gui::font::FontCache::new(),
// session: state::AppSession::load(),
// };
let wl = WlxClient::new().unwrap();
let output_id = wl.outputs[0].id;
let mut capture = WlrDmabufCapture::new(wl, output_id).unwrap();
let rx = capture.init();
let gfx = VkGraphics::new();
let vert = gfx.create_shader(include_bytes!("shaders/vert-common.spv"), None);
let frag_sprite = gfx.create_shader(
include_bytes!("shaders/frag-sprite.spv"),
Some(vec![vk::DescriptorType::COMBINED_IMAGE_SAMPLER])
);
let frag_srgb = gfx.create_shader(
include_bytes!("shaders/frag-srgb.spv"),
Some(vec![vk::DescriptorType::COMBINED_IMAGE_SAMPLER])
);
let frag_glyph = gfx.create_shader(
include_bytes!("shaders/frag-glyph.spv"),
Some(vec![vk::DescriptorType::COMBINED_IMAGE_SAMPLER, vk::DescriptorType::UNIFORM_BUFFER])
);
let frag_color = gfx.create_shader(
include_bytes!("shaders/frag-color.spv"),
Some(vec![vk::DescriptorType::UNIFORM_BUFFER])
);
let pipeline = gfx.create_pipeline(vert, frag_color, gfx.swapchain_format);
let color_buf = gfx.create_buffer(vk::BufferUsageFlags::UNIFORM_BUFFER, &[Vec4::new(1.0, 0.0, 1.0, 1.0); 16]);
gfx.render_loop(|| {
let frame = gfx.create_frame();
unsafe { gfx.device.reset_command_pool(frame.command_pool, vk::CommandPoolResetFlags::RELEASE_RESOURCES) }.unwrap();
let (present_index, _) = unsafe {
gfx.swapchain_loader.acquire_next_image(
gfx.swapchain,
std::u64::MAX,
frame.present_semaphore,
vk::Fence::null()
).unwrap()
};
let command_buffer_begin_info = vk::CommandBufferBeginInfo::builder()
.flags(vk::CommandBufferUsageFlags::ONE_TIME_SUBMIT)
.build();
unsafe { gfx.device.begin_command_buffer(frame.command_buffer, &command_buffer_begin_info) }.unwrap();
let image = gfx.present_images[present_index as usize];
let image_memory_barrier = vk::ImageMemoryBarrier2::builder()
.src_stage_mask(vk::PipelineStageFlags2::TOP_OF_PIPE)
.dst_stage_mask(vk::PipelineStageFlags2::COLOR_ATTACHMENT_OUTPUT)
.dst_access_mask(vk::AccessFlags2::COLOR_ATTACHMENT_WRITE)
.old_layout(vk::ImageLayout::UNDEFINED)
.new_layout(vk::ImageLayout::COLOR_ATTACHMENT_OPTIMAL)
.image(image)
.subresource_range(vk::ImageSubresourceRange::builder().aspect_mask(vk::ImageAspectFlags::COLOR).level_count(1).layer_count(1).build())
.build();
unsafe { gfx.device.cmd_pipeline_barrier2(frame.command_buffer, &vk::DependencyInfo::builder().image_memory_barriers(slice::from_ref(&image_memory_barrier)).build()) };
let color_attachment = vk::RenderingAttachmentInfo::builder()
.image_view(gfx.present_image_views[present_index as usize])
.image_layout(vk::ImageLayout::COLOR_ATTACHMENT_OPTIMAL)
.load_op(vk::AttachmentLoadOp::CLEAR)
.store_op(vk::AttachmentStoreOp::STORE)
.clear_value(vk::ClearValue {
color: vk::ClearColorValue {
float32: [0.0, 0.0, 0.0, 1.0]
}
});
let rendering_info = vk::RenderingInfo::builder()
.render_area(vk::Rect2D::builder().extent(vk::Extent2D::builder().width(1600).height(900).build()).build())
.layer_count(1)
.color_attachments(slice::from_ref(&color_attachment))
.build();
unsafe { gfx.device.cmd_begin_rendering(frame.command_buffer, &rendering_info) };
let descriptor = VkDescriptor::Buffer(color_buf.clone());
pipeline.bind_descriptors(slice::from_ref(&descriptor));
pipeline.render(&frame, vk::Rect2D {
offset: vk::Offset2D { x: 0, y: 0 },
extent: vk::Extent2D { width: 1600, height: 900 }
});
unsafe { gfx.device.cmd_end_rendering(frame.command_buffer) };
let image_memory_barrier = vk::ImageMemoryBarrier2::builder()
.src_stage_mask(vk::PipelineStageFlags2::COLOR_ATTACHMENT_OUTPUT)
.src_access_mask(vk::AccessFlags2::COLOR_ATTACHMENT_WRITE)
.dst_stage_mask(vk::PipelineStageFlags2::BOTTOM_OF_PIPE)
.old_layout(vk::ImageLayout::COLOR_ATTACHMENT_OPTIMAL)
.new_layout(vk::ImageLayout::PRESENT_SRC_KHR)
.image(image)
.subresource_range(vk::ImageSubresourceRange::builder().aspect_mask(vk::ImageAspectFlags::COLOR).level_count(1).layer_count(1).build())
.build();
unsafe {
gfx.device.cmd_pipeline_barrier2(frame.command_buffer, &vk::DependencyInfo::builder().image_memory_barriers(slice::from_ref(&image_memory_barrier)).build());
};
unsafe { gfx.device.end_command_buffer(frame.command_buffer) }.unwrap();
let wait_semaphores = [frame.present_semaphore];
let wait_dst_stage_mask = [vk::PipelineStageFlags::COLOR_ATTACHMENT_OUTPUT];
let submit_info = vk::SubmitInfo::builder()
.wait_semaphores(&wait_semaphores)
.wait_dst_stage_mask(&wait_dst_stage_mask)
.command_buffers(slice::from_ref(&frame.command_buffer))
.signal_semaphores(slice::from_ref(&frame.render_semaphore));
unsafe { gfx.device.queue_submit(gfx.present_queue, slice::from_ref(&submit_info), frame.fence) }.unwrap();
let present_info = vk::PresentInfoKHR::builder()
.wait_semaphores(slice::from_ref(&frame.present_semaphore))
.swapchains(slice::from_ref(&gfx.swapchain))
.image_indices(slice::from_ref(&present_index))
.build();
unsafe { gfx.swapchain_loader.queue_present(gfx.present_queue, &present_info).unwrap() };
});
unsafe { gfx.device.device_wait_idle().unwrap() };
}

View File

@@ -16,7 +16,6 @@ use crate::{
state::AppState, state::AppState,
}; };
use glam::{vec2, vec3a}; use glam::{vec2, vec3a};
use log::error;
use once_cell::sync::Lazy; use once_cell::sync::Lazy;
use regex::Regex; use regex::Regex;
use rodio::{Decoder, OutputStream, Source}; use rodio::{Decoder, OutputStream, Source};
@@ -88,7 +87,7 @@ where
args: exec_args.iter().skip(1).cloned().collect(), args: exec_args.iter().skip(1).cloned().collect(),
}); });
} else { } else {
error!("Unknown key: {}", key); log::error!("Unknown key: {}", key);
} }
if let Some(state) = maybe_state { if let Some(state) = maybe_state {
@@ -109,7 +108,7 @@ where
OverlayData { OverlayData {
state: OverlayState { state: OverlayState {
name: Arc::from("Kbd"), name: Arc::from("kbd"),
show_hide: true, show_hide: true,
width: LAYOUT.row_size * 0.05, width: LAYOUT.row_size * 0.05,
size: (size.x as _, size.y as _), size: (size.x as _, size.y as _),
@@ -217,7 +216,7 @@ impl KeyboardData {
let _ = handle.play_raw(source.convert_samples()); let _ = handle.play_raw(source.convert_samples());
self.audio_stream = Some(stream); self.audio_stream = Some(stream);
} else { } else {
error!("Failed to play key click"); log::error!("Failed to play key click");
} }
} }
} }
@@ -339,7 +338,7 @@ fn key_events_for_macro(macro_verbs: &Vec<String>) -> Vec<(VirtualKey, bool)> {
} else if state.as_str() == "DOWN" { } else if state.as_str() == "DOWN" {
key_events.push((virtual_key, true)); key_events.push((virtual_key, true));
} else { } else {
error!( log::error!(
"Unknown key state in macro: {}, looking for UP or DOWN.", "Unknown key state in macro: {}, looking for UP or DOWN.",
state.as_str() state.as_str()
); );
@@ -350,7 +349,7 @@ fn key_events_for_macro(macro_verbs: &Vec<String>) -> Vec<(VirtualKey, bool)> {
key_events.push((virtual_key, false)); key_events.push((virtual_key, false));
} }
} else { } else {
error!("Unknown virtual key: {}", &caps[1]); log::error!("Unknown virtual key: {}", &caps[1]);
return vec![]; return vec![];
} }
} }

View File

@@ -1,4 +1,3 @@
use log::{info, warn};
use std::{ use std::{
f32::consts::PI, f32::consts::PI,
path::Path, path::Path,
@@ -6,9 +5,14 @@ use std::{
time::{Duration, Instant}, time::{Duration, Instant},
}; };
use vulkano::{ use vulkano::{
buffer::Subbuffer,
command_buffer::CommandBufferUsage, command_buffer::CommandBufferUsage,
format::Format, format::Format,
image::{view::ImageView, ImageAccess, ImageLayout, ImageViewAbstract, ImmutableImage}, image::{
view::ImageView, AttachmentImage, ImageAccess, ImageLayout, ImageViewAbstract, StorageImage,
},
sampler::Filter,
sync::GpuFuture,
Handle, VulkanObject, Handle, VulkanObject,
}; };
use wlx_capture::{ use wlx_capture::{
@@ -26,7 +30,9 @@ use crate::{
input::{InteractionHandler, PointerHit, PointerMode}, input::{InteractionHandler, PointerHit, PointerMode},
overlay::{OverlayData, OverlayRenderer, OverlayState, SplitOverlayBackend}, overlay::{OverlayData, OverlayRenderer, OverlayState, SplitOverlayBackend},
}, },
graphics::{Vert2Uv, WlxGraphics, WlxPipeline},
input::{MOUSE_LEFT, MOUSE_MIDDLE, MOUSE_RIGHT}, input::{MOUSE_LEFT, MOUSE_MIDDLE, MOUSE_RIGHT},
shaders::{frag_sprite, vert_common},
state::{AppSession, AppState}, state::{AppSession, AppState},
}; };
@@ -66,6 +72,7 @@ impl ScreenInteractionHandler {
impl InteractionHandler for ScreenInteractionHandler { impl InteractionHandler for ScreenInteractionHandler {
fn on_hover(&mut self, app: &mut AppState, hit: &PointerHit) { fn on_hover(&mut self, app: &mut AppState, hit: &PointerHit) {
log::info!("Hover: {:?}", hit.uv);
if self.next_move < Instant::now() { if self.next_move < Instant::now() {
let pos = self.mouse_transform.transform_point2(hit.uv); let pos = self.mouse_transform.transform_point2(hit.uv);
app.input.mouse_move(pos); app.input.mouse_move(pos);
@@ -82,7 +89,8 @@ impl InteractionHandler for ScreenInteractionHandler {
}; };
if pressed { if pressed {
self.next_move = Instant::now() + Duration::from_millis(300); self.next_move =
Instant::now() + Duration::from_millis(app.session.click_freeze_time_ms);
} }
app.input.send_button(btn, pressed); app.input.send_button(btn, pressed);
@@ -97,11 +105,106 @@ impl InteractionHandler for ScreenInteractionHandler {
fn on_left(&mut self, _app: &mut AppState, _hand: usize) {} fn on_left(&mut self, _app: &mut AppState, _hand: usize) {}
} }
struct ScreenPipeline {
graphics: Arc<WlxGraphics>,
pipeline: Arc<WlxPipeline>,
vertex_buffer: Subbuffer<[Vert2Uv]>,
target_layout: ImageLayout,
pub view: Arc<ImageView<AttachmentImage>>,
}
impl ScreenPipeline {
fn new(graphics: Arc<WlxGraphics>, image: &StorageImage) -> Self {
let pipeline = graphics.create_pipeline(
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 =
graphics.upload_verts(dim[0] as _, dim[1] as _, 0.0, 0.0, dim[0] as _, dim[1] as _);
let render_texture = graphics.render_texture(dim[0], dim[1], Format::R8G8B8A8_UNORM);
let view = ImageView::new_default(render_texture).unwrap();
Self {
graphics,
pipeline,
vertex_buffer,
view,
target_layout: ImageLayout::Undefined,
}
}
fn render(&mut self, image: Arc<StorageImage>) {
if image.inner().image.handle().as_raw()
== self.view.image().inner().image.handle().as_raw()
{
return;
}
let mut command_buffer = self
.graphics
.create_command_buffer(CommandBufferUsage::OneTimeSubmit)
.begin(self.view.clone());
let set0 = self.pipeline.uniform_sampler(
0,
ImageView::new_default(image).unwrap(),
Filter::Linear,
);
let dim = self.view.dimensions().width_height();
let dim = [dim[0] as f32, dim[1] as f32];
let pass = self.pipeline.create_pass(
dim,
self.vertex_buffer.clone(),
self.graphics.quad_indices.clone(),
vec![set0],
);
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();
exec.flush().unwrap();
exec.cleanup_finished();
}
self.graphics
.transition_layout(
image,
ImageLayout::ColorAttachmentOptimal,
ImageLayout::TransferSrcOptimal,
)
.wait(None)
.unwrap();
self.target_layout = ImageLayout::TransferSrcOptimal;
}
}
pub struct ScreenRenderer { pub struct ScreenRenderer {
capture: Box<dyn WlxCapture>, capture: Box<dyn WlxCapture>,
resolution: (i32, i32),
receiver: Option<Receiver<WlxFrame>>, receiver: Option<Receiver<WlxFrame>>,
view: Option<Arc<dyn ImageViewAbstract>>, pipeline: Option<ScreenPipeline>,
last_frame: Option<Arc<dyn ImageViewAbstract>>,
} }
impl ScreenRenderer { impl ScreenRenderer {
@@ -114,9 +217,9 @@ impl ScreenRenderer {
}; };
Some(ScreenRenderer { Some(ScreenRenderer {
capture: Box::new(capture), capture: Box::new(capture),
resolution: output.size,
receiver: None, receiver: None,
view: None, pipeline: None,
last_frame: None,
}) })
} }
@@ -132,15 +235,11 @@ impl ScreenRenderer {
Some(ScreenRenderer { Some(ScreenRenderer {
capture: Box::new(capture), capture: Box::new(capture),
resolution: output.size,
receiver: None, receiver: None,
view: None, pipeline: None,
last_frame: None,
}) })
} }
pub fn new_xshm() -> ScreenRenderer {
todo!()
}
} }
impl OverlayRenderer for ScreenRenderer { impl OverlayRenderer for ScreenRenderer {
@@ -157,28 +256,18 @@ impl OverlayRenderer for ScreenRenderer {
match frame { match frame {
WlxFrame::Dmabuf(frame) => { WlxFrame::Dmabuf(frame) => {
if let Ok(new) = app.graphics.dmabuf_texture(frame) { if let Ok(new) = app.graphics.dmabuf_texture(frame) {
if let Some(current) = self.view.as_ref() { let pipeline = self
if current.image().inner().image.handle().as_raw() .pipeline
== new.inner().image.handle().as_raw() .get_or_insert_with(|| ScreenPipeline::new(app.graphics.clone(), &new));
{
return; pipeline.render(new);
self.last_frame = Some(pipeline.view.clone());
} }
} }
app.graphics WlxFrame::MemFd(_frame) => {
.transition_layout(
new.inner().image.clone(),
ImageLayout::Undefined,
ImageLayout::TransferSrcOptimal,
)
.wait(None)
.unwrap();
self.view = Some(ImageView::new_default(new).unwrap());
}
}
WlxFrame::MemFd(frame) => {
todo!() todo!()
} }
WlxFrame::MemPtr(frame) => { WlxFrame::MemPtr(_frame) => {
todo!() todo!()
} }
_ => {} _ => {}
@@ -193,7 +282,7 @@ impl OverlayRenderer for ScreenRenderer {
self.capture.resume(); self.capture.resume();
} }
fn view(&mut self) -> Option<Arc<dyn ImageViewAbstract>> { fn view(&mut self) -> Option<Arc<dyn ImageViewAbstract>> {
self.view.as_ref().and_then(|v| Some(v.clone())) self.last_frame.take()
} }
} }
@@ -202,21 +291,25 @@ where
O: Default, O: Default,
{ {
let output = &wl.outputs[idx]; let output = &wl.outputs[idx];
info!( log::info!(
"{}: Res {}x{} Size {:?} Pos {:?}", "{}: Res {}x{} Size {:?} Pos {:?}",
output.name, output.size.0, output.size.1, output.logical_size, output.logical_pos, output.name,
output.size.0,
output.size.1,
output.logical_size,
output.logical_pos,
); );
let size = (output.size.0, output.size.1); let size = (output.size.0, output.size.1);
let mut capture: Option<ScreenRenderer> = None; let mut capture: Option<ScreenRenderer> = None;
if session.capture_method == "auto" && wl.maybe_wlr_dmabuf_mgr.is_some() { if session.capture_method == "auto" && wl.maybe_wlr_dmabuf_mgr.is_some() {
info!("{}: Using Wlr DMA-Buf", &output.name); log::info!("{}: Using Wlr DMA-Buf", &output.name);
capture = ScreenRenderer::new_wlr(output); capture = ScreenRenderer::new_wlr(output);
} }
if capture.is_none() { if capture.is_none() {
info!("{}: Using Pipewire capture", &output.name); log::info!("{}: Using Pipewire capture", &output.name);
let file_name = format!("{}.token", &output.name); let file_name = format!("{}.token", &output.name);
let full_path = Path::new(&session.config_path).join(file_name); let full_path = Path::new(&session.config_path).join(file_name);
let token = std::fs::read_to_string(full_path).ok(); let token = std::fs::read_to_string(full_path).ok();
@@ -246,6 +339,20 @@ where
_ => 0., _ => 0.,
}; };
let interaction_transform = if output.size.0 >= output.size.1 {
Affine2::from_translation(Vec2 { x: 0.5, y: 0.5 })
* Affine2::from_scale(Vec2 {
x: 1.,
y: output.size.0 as f32 / output.size.1 as f32,
})
} else {
Affine2::from_translation(Vec2 { x: 0.5, y: 0.5 })
* Affine2::from_scale(Vec2 {
x: output.size.1 as f32 / output.size.0 as f32,
y: 1.,
})
};
Some(OverlayData { Some(OverlayData {
state: OverlayState { state: OverlayState {
name: output.name.clone(), name: output.name.clone(),
@@ -254,13 +361,14 @@ where
show_hide: true, show_hide: true,
grabbable: true, grabbable: true,
spawn_rotation: Quat::from_axis_angle(axis, angle), spawn_rotation: Quat::from_axis_angle(axis, angle),
interaction_transform,
..Default::default() ..Default::default()
}, },
backend, backend,
..Default::default() ..Default::default()
}) })
} else { } else {
warn!("{}: Will not be used", &output.name); log::warn!("{}: Will not be used", &output.name);
None None
} }
} }

View File

@@ -76,7 +76,7 @@ where
let button_width = 360. / num_buttons as f32; let button_width = 360. / num_buttons as f32;
let mut button_x = 40.; let mut button_x = 40.;
let keyboard = canvas.button(button_x + 2., 162., button_width - 4., 36., "Kbd".into()); let keyboard = canvas.button(button_x + 2., 162., button_width - 4., 36., "kbd".into());
keyboard.state = Some(WatchButtonState { keyboard.state = Some(WatchButtonState {
pressed_at: Instant::now(), pressed_at: Instant::now(),
scr_idx: 0, scr_idx: 0,
@@ -95,14 +95,14 @@ where
< 2000 < 2000
{ {
app.tasks.enqueue(TaskType::Overlay( app.tasks.enqueue(TaskType::Overlay(
OverlaySelector::Name("Kbd".into()), OverlaySelector::Name("kbd".into()),
Box::new(|_app, o| { Box::new(|_app, o| {
o.want_visible = !o.want_visible; o.want_visible = !o.want_visible;
}), }),
)); ));
} else { } else {
app.tasks.enqueue(TaskType::Overlay( app.tasks.enqueue(TaskType::Overlay(
OverlaySelector::Name("Kbd".into()), OverlaySelector::Name("kbd".into()),
Box::new(|app, o| { Box::new(|app, o| {
o.reset(app); o.reset(app);
}), }),

View File

@@ -1,7 +1,6 @@
use std::{env::VarError, path::Path, sync::Arc}; use std::{env::VarError, path::Path, sync::Arc};
use glam::{Quat, Vec3}; use glam::{Quat, Vec3};
use log::warn;
use vulkano::{ use vulkano::{
device::{physical::PhysicalDevice, DeviceExtensions}, device::{physical::PhysicalDevice, DeviceExtensions},
format::Format, format::Format,
@@ -55,6 +54,7 @@ pub struct AppSession {
pub screen_flip_h: bool, pub screen_flip_h: bool,
pub screen_flip_v: bool, pub screen_flip_v: bool,
pub screen_invert_color: bool, pub screen_invert_color: bool,
pub screen_max_res: [u32; 2],
pub watch_hand: usize, pub watch_hand: usize,
pub watch_pos: Vec3, pub watch_pos: Vec3,
@@ -77,7 +77,7 @@ impl AppSession {
let config_path = std::env::var("XDG_CONFIG_HOME") let config_path = std::env::var("XDG_CONFIG_HOME")
.or_else(|_| std::env::var("HOME").map(|home| format!("{}/.config", home))) .or_else(|_| std::env::var("HOME").map(|home| format!("{}/.config", home)))
.or_else(|_| { .or_else(|_| {
warn!("Err: $XDG_CONFIG_HOME and $HOME are not set, using /tmp/wlxoverlay"); log::warn!("Err: $XDG_CONFIG_HOME and $HOME are not set, using /tmp/wlxoverlay");
Ok::<String, VarError>("/tmp".to_string()) Ok::<String, VarError>("/tmp".to_string())
}) })
.map(|config| Path::new(&config).join("wlxoverlay")) .map(|config| Path::new(&config).join("wlxoverlay"))
@@ -95,6 +95,7 @@ impl AppSession {
screen_flip_h: false, screen_flip_h: false,
screen_flip_v: false, screen_flip_v: false,
screen_invert_color: false, screen_invert_color: false,
screen_max_res: [2560, 1440],
capture_method: "auto".to_string(), capture_method: "auto".to_string(),
primary_hand: 1, primary_hand: 1,
watch_hand: 1, watch_hand: 1,