mirror of
https://github.com/wayvr-org/wayvr.git
synced 2026-10-28 15:02:39 +01:00
Compare commits
4
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
db777d7937 | ||
|
|
f94c0c4ace | ||
|
|
5f4c97794c | ||
|
|
d9288a877c |
No files matched your search
Generated
+1
-2
@@ -4773,8 +4773,7 @@ checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d"
|
||||
[[package]]
|
||||
name = "rxscreen"
|
||||
version = "0.1.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "afbab13f83503a8272b7150d487494992cf6c59c299dcaf5d8ffac75bad9fc96"
|
||||
source = "git+https://github.com/galister/rxscreen.git?rev=7197e1de6622b65859e6f2060b5750185e0dad2a#7197e1de6622b65859e6f2060b5750185e0dad2a"
|
||||
dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
@@ -1,16 +1,14 @@
|
||||
use std::rc::Rc;
|
||||
|
||||
use crate::tab::settings::{self, SettingType, Task, horiz_cell, mount_requires_restart};
|
||||
use crate::{
|
||||
tab::settings::{self, SettingType, Task, horiz_cell, mount_requires_restart},
|
||||
util::wgui_simple,
|
||||
};
|
||||
use wgui::{
|
||||
components::{
|
||||
button::{ButtonClickEvent, ComponentButton},
|
||||
checkbox::ComponentCheckbox,
|
||||
slider::ComponentSlider,
|
||||
},
|
||||
components::{button::ComponentButton, checkbox::ComponentCheckbox, slider::ComponentSlider},
|
||||
layout::{Layout, WidgetID},
|
||||
parser::{Fetchable, ParseDocumentParams, ParserState, TemplateParams},
|
||||
task::Tasks,
|
||||
widget::label::WidgetLabel,
|
||||
windowing::context_menu,
|
||||
};
|
||||
use wlx_common::{DesktopBackend, XrBackend, config::GeneralConfig, dash_interface::InterfaceFeats};
|
||||
@@ -297,7 +295,6 @@ where
|
||||
mp.idx += 1;
|
||||
|
||||
let mut params = TemplateParams::new();
|
||||
params.insert("id", &id);
|
||||
|
||||
match setting.get_translation() {
|
||||
Ok(translation) => params.insert("translation", translation),
|
||||
@@ -310,69 +307,63 @@ where
|
||||
|
||||
let id_cell = horiz_cell(mp.layout, parent)?;
|
||||
|
||||
mp.parser_state
|
||||
.instantiate_template(mp.doc_params, "DropdownButton", mp.layout, id_cell, params)?;
|
||||
let setting_str = setting.as_ref();
|
||||
let title = setting.get_enum_title(mp.config);
|
||||
|
||||
let feats = mp.feats;
|
||||
let cells = EnumType::VARIANTS
|
||||
.iter()
|
||||
.filter_map(|item| {
|
||||
if item.get_bool("Hidden").unwrap_or(false) {
|
||||
return None;
|
||||
}
|
||||
if item
|
||||
.get_str("Backend")
|
||||
.is_some_and(|x| XrBackend::try_from(x).unwrap() != feats.xr_backend)
|
||||
{
|
||||
return None;
|
||||
}
|
||||
if item
|
||||
.get_str("Desktop")
|
||||
.is_some_and(|x| DesktopBackend::try_from(x).unwrap() != feats.desktop_backend)
|
||||
{
|
||||
return None;
|
||||
}
|
||||
|
||||
let value = item.as_ref();
|
||||
let title = SettingType::get_enum_title_inner(*item);
|
||||
let tooltip = SettingType::get_enum_tooltip_inner(*item);
|
||||
|
||||
let text = &title.text;
|
||||
let translated = if title.translated { "1" } else { "0" };
|
||||
let action = format!("{setting_str};{id};{value};{text};{translated}");
|
||||
|
||||
Some(context_menu::Cell::Button(context_menu::Button {
|
||||
action_name: Some(action.into()),
|
||||
title,
|
||||
tooltip,
|
||||
..Default::default()
|
||||
}))
|
||||
})
|
||||
.collect();
|
||||
|
||||
let tasks = mp.tasks.clone();
|
||||
wgui_simple::mount_dropdown(wgui_simple::MountDropdownParams {
|
||||
layout: mp.layout,
|
||||
parser_state: mp.parser_state,
|
||||
doc_params: mp.doc_params,
|
||||
parent: id_cell,
|
||||
id,
|
||||
params,
|
||||
current_text: title,
|
||||
cells,
|
||||
on_open: Box::new(move |pos, cells| tasks.push(Task::OpenContextMenu(pos, cells))),
|
||||
})?;
|
||||
|
||||
if setting.requires_restart() {
|
||||
mount_requires_restart(mp.layout, id_cell)?;
|
||||
}
|
||||
|
||||
let setting_str = setting.as_ref();
|
||||
let title = setting.get_enum_title(mp.config);
|
||||
|
||||
{
|
||||
let mut label = mp
|
||||
.parser_state
|
||||
.fetch_widget_as::<WidgetLabel>(&mp.layout.state, &format!("{id}_value"))?;
|
||||
label.set_text_simple(&mut mp.layout.state.globals.get(), title);
|
||||
}
|
||||
|
||||
let btn = mp.parser_state.fetch_component_as::<ComponentButton>(&id)?;
|
||||
btn.on_click(Rc::new({
|
||||
let feats = mp.feats;
|
||||
let tasks = mp.tasks.clone();
|
||||
move |_common, e: ButtonClickEvent| {
|
||||
tasks.push(Task::OpenContextMenu(
|
||||
e.mouse_pos_absolute.into(),
|
||||
EnumType::VARIANTS
|
||||
.iter()
|
||||
.filter_map(|item| {
|
||||
if item.get_bool("Hidden").unwrap_or(false) {
|
||||
return None;
|
||||
}
|
||||
if item
|
||||
.get_str("Backend")
|
||||
.is_some_and(|x| XrBackend::try_from(x).unwrap() != feats.xr_backend)
|
||||
{
|
||||
return None;
|
||||
}
|
||||
if item
|
||||
.get_str("Desktop")
|
||||
.is_some_and(|x| DesktopBackend::try_from(x).unwrap() != feats.desktop_backend)
|
||||
{
|
||||
return None;
|
||||
}
|
||||
|
||||
let value = item.as_ref();
|
||||
let title = SettingType::get_enum_title_inner(*item);
|
||||
let tooltip = SettingType::get_enum_tooltip_inner(*item);
|
||||
|
||||
let text = &title.text;
|
||||
let translated = if title.translated { "1" } else { "0" };
|
||||
|
||||
Some(context_menu::Cell::Button(context_menu::Button {
|
||||
action_name: Some(format!("{setting_str};{id};{value};{text};{translated}").into()),
|
||||
title,
|
||||
tooltip,
|
||||
..Default::default()
|
||||
}))
|
||||
})
|
||||
.collect(),
|
||||
));
|
||||
Ok(())
|
||||
}
|
||||
}));
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
use std::rc::Rc;
|
||||
|
||||
use wgui::{
|
||||
components::button::{ButtonClickEvent, ComponentButton},
|
||||
globals::WguiGlobals,
|
||||
i18n::Translation,
|
||||
layout::WidgetID,
|
||||
@@ -9,7 +8,7 @@ use wgui::{
|
||||
parser::{Fetchable, TemplateParams},
|
||||
task::Tasks,
|
||||
widget::label::WidgetLabel,
|
||||
windowing::context_menu::{self},
|
||||
windowing::context_menu,
|
||||
};
|
||||
use wlx_common::{async_executor::AsyncExecutor, config::GeneralConfig, dash_interface::ConfigChangeKind};
|
||||
|
||||
@@ -21,6 +20,7 @@ use crate::{
|
||||
},
|
||||
util::{
|
||||
popup_manager::PopupHolder,
|
||||
wgui_simple,
|
||||
whisper::{
|
||||
WHISPER_MODELS, WhisperModel, whisper_any_models_downloaded, whisper_delete_all_models, whisper_model_from_name,
|
||||
whisper_model_path,
|
||||
@@ -319,47 +319,35 @@ fn whisper_gpu_select_dropdown(
|
||||
let parent = horiz_cell(mp.layout, parent)?;
|
||||
|
||||
let mut params = TemplateParams::new();
|
||||
params.insert("id", &id);
|
||||
params.insert("translation", "APP_SETTINGS.WHISPER_GPU_SELECT");
|
||||
|
||||
mp.parser_state
|
||||
.instantiate_template(mp.doc_params, "DropdownButton", mp.layout, parent, params)?;
|
||||
let current_text = Translation::from_raw_text_string(mp.config.whisper_gpu.to_string());
|
||||
|
||||
{
|
||||
let mut label = mp
|
||||
.parser_state
|
||||
.fetch_widget_as::<WidgetLabel>(&mp.layout.state, &format!("{id}_value"))?;
|
||||
label.set_text_simple(
|
||||
&mut mp.layout.state.globals.get(),
|
||||
Translation::from_raw_text_string(mp.config.whisper_gpu.to_string()),
|
||||
);
|
||||
}
|
||||
let cells = vulkan_devices
|
||||
.iter()
|
||||
.enumerate()
|
||||
.filter(|(_, name)| !name.contains("llvmpipe"))
|
||||
.map(|(idx, name)| {
|
||||
context_menu::Cell::Button(context_menu::Button {
|
||||
action_name: Some(format!(";whisper_gpu;{};{}", id, idx).into()),
|
||||
title: Translation::from_raw_text_string(name.to_string()),
|
||||
..Default::default()
|
||||
})
|
||||
})
|
||||
.collect();
|
||||
|
||||
let btn = mp.parser_state.fetch_component_as::<ComponentButton>(&id)?;
|
||||
btn.on_click(Rc::new({
|
||||
let parent_tasks = mp.tasks.clone();
|
||||
move |_common, e: ButtonClickEvent| {
|
||||
let mut cells = Vec::new();
|
||||
|
||||
for (idx, name) in vulkan_devices.iter().enumerate() {
|
||||
if name.contains("llvmpipe") {
|
||||
continue;
|
||||
}
|
||||
|
||||
cells.push(context_menu::Cell::Button(context_menu::Button {
|
||||
action_name: Some(format!(";whisper_gpu;{};{}", id, idx).into()),
|
||||
title: Translation::from_raw_text_string(name.to_string()),
|
||||
..Default::default()
|
||||
}));
|
||||
}
|
||||
|
||||
parent_tasks.push(ParentTask::OpenContextMenu(e.mouse_pos_absolute.into(), cells));
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}));
|
||||
|
||||
Ok(())
|
||||
let tasks = mp.tasks.clone();
|
||||
wgui_simple::mount_dropdown(wgui_simple::MountDropdownParams {
|
||||
layout: mp.layout,
|
||||
parser_state: mp.parser_state,
|
||||
doc_params: mp.doc_params,
|
||||
parent,
|
||||
id,
|
||||
params,
|
||||
current_text,
|
||||
cells,
|
||||
on_open: Box::new(move |pos, cells| tasks.push(ParentTask::OpenContextMenu(pos, cells))),
|
||||
})
|
||||
}
|
||||
|
||||
fn whisper_models_dropdown(mp: &mut MacroParams, parent: WidgetID) -> anyhow::Result<()> {
|
||||
@@ -382,57 +370,49 @@ fn whisper_models_dropdown(mp: &mut MacroParams, parent: WidgetID) -> anyhow::Re
|
||||
});
|
||||
|
||||
let mut params = TemplateParams::new();
|
||||
params.insert("id", &id);
|
||||
params.insert("translation", "APP_SETTINGS.WHISPER_MODEL");
|
||||
params.insert("tooltip", "APP_SETTINGS.WHISPER_MODEL_HELP");
|
||||
|
||||
mp.parser_state
|
||||
.instantiate_template(mp.doc_params, "DropdownButton", mp.layout, parent, params)?;
|
||||
|
||||
{
|
||||
let mut label = mp
|
||||
.parser_state
|
||||
.fetch_widget_as::<WidgetLabel>(&mp.layout.state, &format!("{id}_value"))?;
|
||||
label.set_text_simple(&mut mp.layout.state.globals.get(), current_translation);
|
||||
}
|
||||
|
||||
let btn = mp.parser_state.fetch_component_as::<ComponentButton>(&id)?;
|
||||
btn.on_click(Rc::new({
|
||||
let parent_tasks = mp.tasks.clone();
|
||||
move |_common, e: ButtonClickEvent| {
|
||||
let mut cells = WHISPER_MODELS
|
||||
.iter()
|
||||
.enumerate()
|
||||
.map(|(idx, item)| {
|
||||
context_menu::Cell::Button(context_menu::Button {
|
||||
action_name: Some(format!(";whisper_model;{id};{}", item.file_name).into()),
|
||||
title: Translation::from_raw_text(item.display_name),
|
||||
tooltip: None,
|
||||
attribs: vec![],
|
||||
sprite_src_builtin: if downloaded_models.contains(&idx) {
|
||||
Some("@/dashboard/check.svg".into())
|
||||
} else {
|
||||
None
|
||||
},
|
||||
})
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
cells.insert(
|
||||
0,
|
||||
let mut cells = WHISPER_MODELS
|
||||
.iter()
|
||||
.enumerate()
|
||||
.map(|(idx, item)| {
|
||||
if downloaded_models.contains(&idx) {
|
||||
context_menu::Cell::Button(context_menu::Button {
|
||||
action_name: Some(format!(";whisper_model;{id};").into()),
|
||||
title: Translation::from_translation_key("APP_SETTINGS.OPTION.NONE"),
|
||||
tooltip: None,
|
||||
attribs: vec![],
|
||||
action_name: Some(format!(";whisper_model;{id};{}", item.file_name).into()),
|
||||
title: Translation::from_raw_text(item.display_name),
|
||||
sprite_src_builtin: Some("@/dashboard/check.svg".into()),
|
||||
..Default::default()
|
||||
}),
|
||||
);
|
||||
})
|
||||
} else {
|
||||
context_menu::Cell::Button(context_menu::Button {
|
||||
action_name: Some(format!(";whisper_model;{id};{}", item.file_name).into()),
|
||||
title: Translation::from_raw_text(item.display_name),
|
||||
..Default::default()
|
||||
})
|
||||
}
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
parent_tasks.push(ParentTask::OpenContextMenu(e.mouse_pos_absolute.into(), cells));
|
||||
Ok(())
|
||||
}
|
||||
}));
|
||||
cells.insert(
|
||||
0,
|
||||
context_menu::Cell::Button(context_menu::Button {
|
||||
action_name: Some(format!(";whisper_model;{id};").into()),
|
||||
title: Translation::from_translation_key("APP_SETTINGS.OPTION.NONE"),
|
||||
..Default::default()
|
||||
}),
|
||||
);
|
||||
|
||||
Ok(())
|
||||
let tasks = mp.tasks.clone();
|
||||
wgui_simple::mount_dropdown(wgui_simple::MountDropdownParams {
|
||||
layout: mp.layout,
|
||||
parser_state: mp.parser_state,
|
||||
doc_params: mp.doc_params,
|
||||
parent,
|
||||
id,
|
||||
params,
|
||||
current_text: current_translation,
|
||||
cells,
|
||||
on_open: Box::new(move |pos, cells| tasks.push(ParentTask::OpenContextMenu(pos, cells))),
|
||||
})
|
||||
}
|
||||
@@ -1,12 +1,16 @@
|
||||
use glam::{Mat4, Vec2};
|
||||
use std::rc::Rc;
|
||||
use wgui::{
|
||||
animation::{Animation, AnimationDuration, AnimationEasing},
|
||||
assets::AssetPathRef,
|
||||
color::WguiColorName,
|
||||
components::{self, button::ButtonClickCallback},
|
||||
components::{
|
||||
self,
|
||||
button::{ButtonClickCallback, ButtonClickEvent, ComponentButton},
|
||||
},
|
||||
i18n::Translation,
|
||||
layout::{Layout, LayoutTask, WidgetID},
|
||||
parser::{Fetchable, ParseDocumentParams},
|
||||
parser::{Fetchable, ParseDocumentParams, ParserState, TemplateParams},
|
||||
renderer_vk::{
|
||||
text::{FontWeight, TextStyle, custom_glyph::CustomGlyphData},
|
||||
util::centered_matrix,
|
||||
@@ -17,6 +21,7 @@ use wgui::{
|
||||
label::{WidgetLabel, WidgetLabelParams},
|
||||
sprite::{WidgetSprite, WidgetSpriteParams},
|
||||
},
|
||||
windowing::context_menu,
|
||||
};
|
||||
|
||||
pub struct CreateButtonParams<'a> {
|
||||
@@ -166,3 +171,39 @@ pub fn create_loading(par: CreateLoadingParams) -> anyhow::Result<WidgetID> {
|
||||
|
||||
Ok(id_root)
|
||||
}
|
||||
|
||||
pub struct MountDropdownParams<'a> {
|
||||
pub layout: &'a mut Layout,
|
||||
pub parser_state: &'a mut ParserState,
|
||||
pub doc_params: &'a ParseDocumentParams<'a>,
|
||||
pub parent: WidgetID,
|
||||
pub id: String,
|
||||
pub params: TemplateParams,
|
||||
pub current_text: Translation,
|
||||
pub cells: Vec<context_menu::Cell>,
|
||||
pub on_open: Box<dyn Fn(context_menu::Position, Vec<context_menu::Cell>)>,
|
||||
}
|
||||
|
||||
pub fn mount_dropdown(par: MountDropdownParams) -> anyhow::Result<()> {
|
||||
let mut params = par.params;
|
||||
params.insert("id", &par.id);
|
||||
|
||||
par
|
||||
.parser_state
|
||||
.instantiate_template(par.doc_params, "DropdownButton", par.layout, par.parent, params)?;
|
||||
|
||||
{
|
||||
let mut label = par
|
||||
.parser_state
|
||||
.fetch_widget_as::<WidgetLabel>(&par.layout.state, &format!("{}_value", par.id))?;
|
||||
label.set_text_simple(&mut par.layout.state.globals.get(), par.current_text);
|
||||
}
|
||||
|
||||
let btn = par.parser_state.fetch_component_as::<ComponentButton>(&par.id)?;
|
||||
btn.on_click(Rc::new(move |_common, e: ButtonClickEvent| {
|
||||
(par.on_open)(e.mouse_pos_absolute.into(), par.cells.clone());
|
||||
Ok(())
|
||||
}));
|
||||
|
||||
Ok(())
|
||||
}
|
||||
@@ -3,17 +3,13 @@ use std::rc::Rc;
|
||||
use strum::EnumProperty;
|
||||
use wgui::{
|
||||
assets::AssetPathRef,
|
||||
components::{
|
||||
button::{ButtonClickEvent, ComponentButton},
|
||||
slider::ComponentSlider,
|
||||
},
|
||||
components::{button::ComponentButton, slider::ComponentSlider},
|
||||
globals::WguiGlobals,
|
||||
i18n::Translation,
|
||||
layout::{Layout, WidgetID},
|
||||
log::LogErr,
|
||||
parser::{Fetchable, ParseDocumentParams, ParserState, TemplateParams},
|
||||
task::Tasks,
|
||||
widget::label::WidgetLabel,
|
||||
windowing::context_menu::{self, TickResult},
|
||||
};
|
||||
use wlx_common::{
|
||||
@@ -1012,7 +1008,7 @@ fn create_dropdown<B: 'static + BindingsDropdown>(
|
||||
.iter()
|
||||
.map(|item| {
|
||||
context_menu::Cell::Button(context_menu::Button {
|
||||
action_name: Some(item.action_str(&action, side)),
|
||||
action_name: Some(item.action_str(&action, side).into()),
|
||||
title: item.translation(),
|
||||
..Default::default()
|
||||
})
|
||||
@@ -1023,7 +1019,7 @@ fn create_dropdown<B: 'static + BindingsDropdown>(
|
||||
cells.insert(
|
||||
0,
|
||||
context_menu::Cell::Button(context_menu::Button {
|
||||
action_name: Some(action_str),
|
||||
action_name: Some(action_str.into()),
|
||||
title: Translation::from_translation_key("APP_SETTINGS.OPTION.NONE"),
|
||||
..Default::default()
|
||||
}),
|
||||
@@ -1036,35 +1032,24 @@ fn create_dropdown<B: 'static + BindingsDropdown>(
|
||||
fn create_dropdown_with_cells(
|
||||
mp: &mut MacroParams,
|
||||
parent: WidgetID,
|
||||
mut params: TemplateParams,
|
||||
params: TemplateParams,
|
||||
current_text: Translation,
|
||||
cells: Vec<context_menu::Cell>,
|
||||
) -> anyhow::Result<()> {
|
||||
let id = mp.idx.to_string();
|
||||
mp.idx += 1;
|
||||
params.insert("id", &id);
|
||||
|
||||
mp.parser_state
|
||||
.instantiate_template(mp.doc_params, "DropdownButton", mp.layout, parent, params)?;
|
||||
|
||||
{
|
||||
let mut label = mp
|
||||
.parser_state
|
||||
.fetch_widget_as::<WidgetLabel>(&mp.layout.state, &format!("{id}_value"))?;
|
||||
label.set_text_simple(&mut mp.layout.state.globals.get(), current_text);
|
||||
}
|
||||
|
||||
let btn = mp.parser_state.fetch_component_as::<ComponentButton>(&id)?;
|
||||
btn.on_click(Rc::new({
|
||||
let tasks = mp.tasks.clone();
|
||||
let cells = cells.clone();
|
||||
move |_common, e: ButtonClickEvent| {
|
||||
tasks.push(Task::OpenContextMenu(e.mouse_pos_absolute.into(), cells.clone()));
|
||||
Ok(())
|
||||
}
|
||||
}));
|
||||
|
||||
Ok(())
|
||||
let tasks = mp.tasks.clone();
|
||||
wgui_simple::mount_dropdown(wgui_simple::MountDropdownParams {
|
||||
layout: mp.layout,
|
||||
parser_state: mp.parser_state,
|
||||
doc_params: mp.doc_params,
|
||||
parent,
|
||||
id,
|
||||
params,
|
||||
current_text,
|
||||
cells,
|
||||
on_open: Box::new(move |pos, cells| tasks.push(Task::OpenContextMenu(pos, cells))),
|
||||
})
|
||||
}
|
||||
|
||||
fn apply_subpath(
|
||||
|
||||
@@ -31,6 +31,9 @@ use crate::{
|
||||
|
||||
const CURSOR_SIZE: f32 = 16. / 1440.;
|
||||
|
||||
// synchronize queue shared by the WlxCapture worker threads
|
||||
static CAPTURE_QUEUE_MUTEX: Mutex<()> = Mutex::new(());
|
||||
|
||||
struct BufPass {
|
||||
pass: WGfxPass<Vert2Uv>,
|
||||
buf_vert: Arc<Buffer<Vert2Uv>>,
|
||||
@@ -664,6 +667,17 @@ fn upload_image(
|
||||
height: u32,
|
||||
format: Format,
|
||||
data: &[u8],
|
||||
) -> Option<Arc<Image>> {
|
||||
upload_image_with_row_length(me, width, height, format, data, 0)
|
||||
}
|
||||
|
||||
fn upload_image_with_row_length(
|
||||
me: &WlxCaptureIn,
|
||||
width: u32,
|
||||
height: u32,
|
||||
format: Format,
|
||||
data: &[u8],
|
||||
buffer_row_length: u32,
|
||||
) -> Option<Arc<Image>> {
|
||||
let cmd_result = if me.use_capture_queue {
|
||||
me.gfx
|
||||
@@ -679,15 +693,23 @@ fn upload_image(
|
||||
return None;
|
||||
}
|
||||
};
|
||||
let image = match cmd_xfer.upload_image(width, height, format, data) {
|
||||
Ok(x) => x,
|
||||
Err(e) => {
|
||||
log::error!("{}: Could not create vkImage: {:?}", me.name, e);
|
||||
return None;
|
||||
}
|
||||
};
|
||||
let image =
|
||||
match cmd_xfer.upload_image_with_row_length(width, height, format, data, buffer_row_length)
|
||||
{
|
||||
Ok(x) => x,
|
||||
Err(e) => {
|
||||
log::error!("{}: Could not create vkImage: {:?}", me.name, e);
|
||||
return None;
|
||||
}
|
||||
};
|
||||
|
||||
if let Err(e) = cmd_xfer.build_and_execute_now() {
|
||||
let result = if me.use_capture_queue {
|
||||
let _guard = CAPTURE_QUEUE_MUTEX.lock().unwrap(); // mutex poison only
|
||||
cmd_xfer.build_and_execute_now()
|
||||
} else {
|
||||
cmd_xfer.build_and_execute_now()
|
||||
};
|
||||
if let Err(e) = result {
|
||||
log::error!("{}: Could not execute upload: {:?}", me.name, e);
|
||||
return None;
|
||||
}
|
||||
@@ -757,8 +779,22 @@ pub(super) fn receive_callback(me: &WlxCaptureIn, frame: WlxFrame) -> Option<Wlx
|
||||
}
|
||||
};
|
||||
|
||||
let data = unsafe { std::slice::from_raw_parts(frame.ptr as *const u8, frame.size) };
|
||||
let image = upload_image(me, frame.format.width, frame.format.height, format, data)?;
|
||||
// SAFETY: the MemPtr params & allocation and must be valid and must outlive the callback
|
||||
let pixels = unsafe {
|
||||
std::slice::from_raw_parts(
|
||||
(frame.ptr as *const u8).add(frame.offset),
|
||||
frame.size - frame.offset,
|
||||
)
|
||||
};
|
||||
let buffer_row_length = (frame.stride / 4) as u32;
|
||||
let image = upload_image_with_row_length(
|
||||
me,
|
||||
frame.format.width,
|
||||
frame.format.height,
|
||||
format,
|
||||
pixels,
|
||||
buffer_row_length,
|
||||
)?;
|
||||
|
||||
Some(WlxCaptureOut {
|
||||
image: me.gfx.create_image_view(image).ok()?,
|
||||
@@ -811,6 +847,8 @@ pub(super) enum MainThreadFrame {
|
||||
Cpu {
|
||||
format: FrameFormat,
|
||||
data: Vec<u8>,
|
||||
offset: usize,
|
||||
stride: usize,
|
||||
mouse: Option<MouseMeta>,
|
||||
},
|
||||
Dmabuf {
|
||||
@@ -870,12 +908,16 @@ where
|
||||
MainThreadFrame::Cpu {
|
||||
format,
|
||||
data,
|
||||
offset,
|
||||
stride,
|
||||
mouse,
|
||||
} => {
|
||||
let frame = wlx_frame::MemPtrFrame {
|
||||
format,
|
||||
ptr: data.as_ptr() as usize,
|
||||
size: data.len(),
|
||||
offset,
|
||||
stride,
|
||||
mouse,
|
||||
};
|
||||
receive_callback(
|
||||
@@ -910,22 +952,24 @@ fn receive_callback_dummy(_: &DmaExporterProxy, frame: WlxFrame) -> Option<MainT
|
||||
Some(MainThreadFrame::Cpu {
|
||||
format: frame.format,
|
||||
data: map.as_slice().to_vec(),
|
||||
offset: frame.plane.offset as _,
|
||||
stride: (frame.format.width as usize).checked_mul(4)?,
|
||||
mouse: frame.mouse,
|
||||
})
|
||||
}
|
||||
WlxFrame::MemPtr(frame) => {
|
||||
let data = if frame.size == 0 {
|
||||
Vec::new()
|
||||
} else {
|
||||
if frame.ptr == 0 {
|
||||
log::error!("Main-thread CPU capture received a null MemPtr frame");
|
||||
return None;
|
||||
}
|
||||
unsafe { std::slice::from_raw_parts(frame.ptr as *const u8, frame.size) }.to_vec()
|
||||
// SAFETY: Allocation must be valid & must outlive the callback
|
||||
let pixels = unsafe {
|
||||
std::slice::from_raw_parts(
|
||||
(frame.ptr as *const u8).add(frame.offset),
|
||||
frame.size - frame.offset,
|
||||
)
|
||||
};
|
||||
Some(MainThreadFrame::Cpu {
|
||||
format: frame.format,
|
||||
data,
|
||||
data: pixels.to_vec(),
|
||||
offset: frame.offset,
|
||||
stride: frame.stride,
|
||||
mouse: frame.mouse,
|
||||
})
|
||||
}
|
||||
|
||||
@@ -320,8 +320,12 @@ impl OverlayWindowConfig {
|
||||
return;
|
||||
}
|
||||
|
||||
let to_hmd = (state.transform.translation - app.input_state.hmd.translation).normalize();
|
||||
let watch_normal = state.transform.transform_vector3a(Vec3A::NEG_Z).normalize();
|
||||
let to_hmd =
|
||||
(state.transform.translation - app.input_state.hmd.translation).normalize_or_zero();
|
||||
let watch_normal = state
|
||||
.transform
|
||||
.transform_vector3a(Vec3A::NEG_Z)
|
||||
.normalize_or_zero();
|
||||
let dot = to_hmd.dot(watch_normal);
|
||||
|
||||
let range = (app.session.config.watch_view_angle_max
|
||||
|
||||
+18
-3
@@ -139,6 +139,17 @@ impl CommandBufferBuilder<CmdBufGfx> {
|
||||
|
||||
impl CommandBufferBuilder<CmdBufXfer> {
|
||||
pub fn upload_image(&mut self, width: u32, height: u32, format: Format, data: &[u8]) -> anyhow::Result<Arc<Image>> {
|
||||
self.upload_image_with_row_length(width, height, format, data, 0)
|
||||
}
|
||||
|
||||
pub fn upload_image_with_row_length(
|
||||
&mut self,
|
||||
width: u32,
|
||||
height: u32,
|
||||
format: Format,
|
||||
data: &[u8],
|
||||
buffer_row_length: u32,
|
||||
) -> anyhow::Result<Arc<Image>> {
|
||||
let image = self.graphics.create_image(ImageCreateInfo::new_2d(
|
||||
width,
|
||||
height,
|
||||
@@ -149,9 +160,13 @@ impl CommandBufferBuilder<CmdBufXfer> {
|
||||
.graphics
|
||||
.empty_buffer::<u8>(BufferUsage::TRANSFER_SRC, data.len() as u64)?;
|
||||
staging.write()?.copy_from_slice(data);
|
||||
self
|
||||
.raw
|
||||
.copy_buffer_to_image(&staging.raw, &image.raw, [0, 0, 0], [width, height, 1]);
|
||||
self.raw.copy_buffer_to_image_with_row_length(
|
||||
&staging.raw,
|
||||
&image.raw,
|
||||
[0, 0, 0],
|
||||
[width, height, 1],
|
||||
buffer_row_length,
|
||||
);
|
||||
self.keepalive.push(Box::new(staging));
|
||||
self.keepalive.push(Box::new(image.clone()));
|
||||
Ok(image)
|
||||
|
||||
+12
-1
@@ -2494,11 +2494,22 @@ impl RawCommandBuffer {
|
||||
image: &Arc<RawImage>,
|
||||
offset: [u32; 3],
|
||||
extent: [u32; 3],
|
||||
) {
|
||||
self.copy_buffer_to_image_with_row_length(buffer, image, offset, extent, 0);
|
||||
}
|
||||
|
||||
pub(super) fn copy_buffer_to_image_with_row_length(
|
||||
&mut self,
|
||||
buffer: &RawBuffer,
|
||||
image: &Arc<RawImage>,
|
||||
offset: [u32; 3],
|
||||
extent: [u32; 3],
|
||||
buffer_row_length: u32,
|
||||
) {
|
||||
self.transition_image(image, ImageLayout::TransferDst);
|
||||
let regions = [vk::BufferImageCopy::default()
|
||||
.buffer_offset(0)
|
||||
.buffer_row_length(0)
|
||||
.buffer_row_length(buffer_row_length)
|
||||
.buffer_image_height(0)
|
||||
.image_subresource(vk::ImageSubresourceLayers {
|
||||
aspect_mask: vk::ImageAspectFlags::COLOR,
|
||||
|
||||
@@ -31,7 +31,9 @@ wayland-protocols = {
|
||||
|
||||
drm-fourcc = "2.2.0"
|
||||
rxscreen = {
|
||||
version = "0.1.7",
|
||||
git = "https://github.com/galister/rxscreen.git",
|
||||
rev = "7197e1de6622b65859e6f2060b5750185e0dad2a",
|
||||
# version = "0.1.7",
|
||||
features = [
|
||||
"mouse",
|
||||
"shm",
|
||||
|
||||
@@ -128,6 +128,8 @@ pub struct MemPtrFrame {
|
||||
pub format: FrameFormat,
|
||||
pub ptr: usize,
|
||||
pub size: usize,
|
||||
pub offset: usize,
|
||||
pub stride: usize,
|
||||
pub mouse: Option<MouseMeta>,
|
||||
}
|
||||
|
||||
|
||||
@@ -376,10 +376,24 @@ where
|
||||
}
|
||||
}
|
||||
DataType::MemPtr => {
|
||||
let raw = datas[0].as_raw();
|
||||
let chunk = datas[0].chunk();
|
||||
let offset = chunk.offset() as usize;
|
||||
let chunk_size = chunk.size() as usize;
|
||||
let Some(size) = offset.checked_add(chunk_size) else {
|
||||
log::error!("{name}: PipeWire chunk range overflow");
|
||||
return;
|
||||
};
|
||||
if size > raw.maxsize as usize {
|
||||
log::error!("{name}: PipeWire chunk extends beyond allocation");
|
||||
return;
|
||||
}
|
||||
let memptr = MemPtrFrame {
|
||||
format: *format,
|
||||
ptr: datas[0].as_raw().data as _,
|
||||
size: datas[0].chunk().size() as _,
|
||||
ptr: raw.data as _,
|
||||
size,
|
||||
offset,
|
||||
stride: chunk.stride() as _,
|
||||
mouse: mouse_meta,
|
||||
};
|
||||
|
||||
|
||||
@@ -109,6 +109,8 @@ where
|
||||
transform: Transform::Normal,
|
||||
},
|
||||
ptr: unsafe { image.as_ptr() as _ },
|
||||
offset: 0,
|
||||
stride: image.bytes_per_line() as _,
|
||||
size,
|
||||
mouse: d.root_mouse_position().and_then(|root_pos| {
|
||||
monitor.mouse_to_local(root_pos).map(|(x, y)| MouseMeta {
|
||||
|
||||
Reference in new issue
Block a user