Fix compositor output routing and pointer hints; format imports
This commit is contained in:
1 parent
88e4f3c135
commit
46509f880a
108 files changed
+3682
-8371
No files matched your search
+36
-84
@@ -1,28 +1,22 @@
|
||||
//! One decoded image and one texture per GPU context, not double-buffered
|
||||
//! full-screen UI surfaces per monitor. Resize changes sampling only.
|
||||
use crate::presentation::NativeTextureElement;
|
||||
use std::cell::Cell;
|
||||
use std::collections::HashMap;
|
||||
use std::path::PathBuf;
|
||||
use std::rc::Rc;
|
||||
use std::sync::mpsc;
|
||||
use std::time::{Duration, Instant};
|
||||
|
||||
use serde::Deserialize;
|
||||
use smithay::{
|
||||
backend::{
|
||||
allocator::Fourcc,
|
||||
renderer::{
|
||||
ErasedContextId, ImportMem, Renderer,
|
||||
element::Id,
|
||||
gles::{GlesRenderer, GlesTexture},
|
||||
utils::CommitCounter,
|
||||
},
|
||||
},
|
||||
output::Output,
|
||||
utils::{Buffer, Physical, Rectangle, Size},
|
||||
};
|
||||
use std::{
|
||||
cell::Cell,
|
||||
collections::HashMap,
|
||||
path::PathBuf,
|
||||
rc::Rc,
|
||||
sync::mpsc,
|
||||
time::{Duration, Instant},
|
||||
};
|
||||
use smithay::backend::allocator::Fourcc;
|
||||
use smithay::backend::renderer::element::Id;
|
||||
use smithay::backend::renderer::gles::{GlesRenderer, GlesTexture};
|
||||
use smithay::backend::renderer::utils::CommitCounter;
|
||||
use smithay::backend::renderer::{ErasedContextId, ImportMem, Renderer};
|
||||
use smithay::output::Output;
|
||||
use smithay::utils::{Buffer, Physical, Rectangle, Size};
|
||||
|
||||
use crate::presentation::NativeTextureElement;
|
||||
|
||||
const UPLOAD_RETRY_DELAY: Duration = Duration::from_secs(5);
|
||||
|
||||
@@ -80,10 +74,7 @@ impl WallpaperState {
|
||||
Self::with_wakeup(config, None)
|
||||
}
|
||||
|
||||
pub fn with_wakeup(
|
||||
config: WallpaperConfig,
|
||||
wakeup: Option<smithay::reexports::calloop::LoopSignal>,
|
||||
) -> Self {
|
||||
pub fn with_wakeup(config: WallpaperConfig, wakeup: Option<smithay::reexports::calloop::LoopSignal>) -> Self {
|
||||
let retained = config.clone();
|
||||
let (sender, receiver) = mpsc::channel();
|
||||
let owned = config.path.as_ref().is_some_and(|path| path.is_file());
|
||||
@@ -92,8 +83,7 @@ impl WallpaperState {
|
||||
let wakeup = wakeup.clone();
|
||||
std::thread::spawn(move || {
|
||||
let load = || -> Result<image::RgbaImage, String> {
|
||||
let (width, height) =
|
||||
image::image_dimensions(&path).map_err(|e| e.to_string())?;
|
||||
let (width, height) = image::image_dimensions(&path).map_err(|e| e.to_string())?;
|
||||
if u64::from(width) * u64::from(height) * 4 > 256 * 1024 * 1024 {
|
||||
return Err("wallpaper exceeds the 256 MiB decode limit".into());
|
||||
}
|
||||
@@ -164,9 +154,7 @@ impl WallpaperState {
|
||||
}
|
||||
|
||||
fn upload_ready(&self, context: &ErasedContextId, now: Instant) -> bool {
|
||||
self.upload_retries
|
||||
.get(context)
|
||||
.is_none_or(|retry| now >= *retry)
|
||||
self.upload_retries.get(context).is_none_or(|retry| now >= *retry)
|
||||
}
|
||||
|
||||
pub(crate) fn take_retry_wakeup(&self) -> bool {
|
||||
@@ -250,11 +238,7 @@ impl WallpaperState {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn element(
|
||||
&mut self,
|
||||
renderer: &mut GlesRenderer,
|
||||
output: &Output,
|
||||
) -> Option<NativeTextureElement> {
|
||||
pub fn element(&mut self, renderer: &mut GlesRenderer, output: &Output) -> Option<NativeTextureElement> {
|
||||
let pixels = self.pixels.as_ref()?;
|
||||
let context = renderer.context_id().erased();
|
||||
if !self.textures.contains_key(&context) {
|
||||
@@ -265,32 +249,21 @@ impl WallpaperState {
|
||||
match renderer.import_memory(pixels.as_raw(), Fourcc::Abgr8888, size, false) {
|
||||
Ok(texture) => {
|
||||
self.upload_retries.remove(&context);
|
||||
tracing::debug!(
|
||||
bytes = pixels.as_raw().len(),
|
||||
"uploaded shared wallpaper texture"
|
||||
);
|
||||
self.textures.insert(
|
||||
context.clone(),
|
||||
WallpaperTexture {
|
||||
texture,
|
||||
id: Id::new(),
|
||||
},
|
||||
);
|
||||
tracing::debug!(bytes = pixels.as_raw().len(), "uploaded shared wallpaper texture");
|
||||
self.textures
|
||||
.insert(context.clone(), WallpaperTexture { texture, id: Id::new() });
|
||||
}
|
||||
Err(error) => {
|
||||
// Avoid retrying a large failed allocation every frame, but
|
||||
// allow recovery from temporary GPU memory pressure.
|
||||
self.upload_retries
|
||||
.insert(context, Instant::now() + UPLOAD_RETRY_DELAY);
|
||||
self.upload_retries.insert(context, Instant::now() + UPLOAD_RETRY_DELAY);
|
||||
tracing::debug!(%error, "wallpaper texture import failed");
|
||||
return None;
|
||||
}
|
||||
}
|
||||
}
|
||||
let cached = self.textures.get(&context)?;
|
||||
let output_size = output
|
||||
.current_transform()
|
||||
.transform_size(output.current_mode()?.size);
|
||||
let output_size = output.current_transform().transform_size(output.current_mode()?.size);
|
||||
let (geometry, source) = image_geometry(
|
||||
(pixels.width() as i32, pixels.height() as i32).into(),
|
||||
output_size,
|
||||
@@ -324,11 +297,7 @@ fn image_geometry(
|
||||
(
|
||||
Rectangle::from_size(output),
|
||||
Rectangle::new(
|
||||
(
|
||||
(f64::from(image.w) - width) / 2.0,
|
||||
(f64::from(image.h) - height) / 2.0,
|
||||
)
|
||||
.into(),
|
||||
((f64::from(image.w) - width) / 2.0, (f64::from(image.h) - height) / 2.0).into(),
|
||||
(width, height).into(),
|
||||
),
|
||||
)
|
||||
@@ -341,10 +310,7 @@ fn image_geometry(
|
||||
)
|
||||
.into();
|
||||
(
|
||||
Rectangle::new(
|
||||
((output.w - size.w) / 2, (output.h - size.h) / 2).into(),
|
||||
size,
|
||||
),
|
||||
Rectangle::new(((output.w - size.w) / 2, (output.h - size.h) / 2).into(), size),
|
||||
Rectangle::from_size(image.to_f64()),
|
||||
)
|
||||
}
|
||||
@@ -373,9 +339,7 @@ mod tests {
|
||||
state.arm_retry_timer(&event_loop.handle(), now).unwrap();
|
||||
assert!(state.retry_timer_pending.get());
|
||||
assert!(!state.take_retry_wakeup());
|
||||
event_loop
|
||||
.dispatch(Some(Duration::from_secs(1)), &mut ())
|
||||
.unwrap();
|
||||
event_loop.dispatch(Some(Duration::from_secs(1)), &mut ()).unwrap();
|
||||
assert!(!state.retry_timer_pending.get());
|
||||
assert!(
|
||||
state.take_retry_wakeup(),
|
||||
@@ -383,10 +347,7 @@ mod tests {
|
||||
);
|
||||
assert!(!state.take_retry_wakeup());
|
||||
let after = Instant::now();
|
||||
assert_eq!(
|
||||
state.next_retry_deadline(after),
|
||||
Some(after + UPLOAD_RETRY_DELAY)
|
||||
);
|
||||
assert_eq!(state.next_retry_deadline(after), Some(after + UPLOAD_RETRY_DELAY));
|
||||
state.forget_context(&context);
|
||||
assert_eq!(state.next_retry_deadline(after), None);
|
||||
state.retry_wakeup.set(true);
|
||||
@@ -398,7 +359,8 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn decoder_wakes_an_idle_event_loop() {
|
||||
use smithay::reexports::calloop::{EventLoop, timer::Timer};
|
||||
use smithay::reexports::calloop::EventLoop;
|
||||
use smithay::reexports::calloop::timer::Timer;
|
||||
let mut event_loop = EventLoop::<WallpaperState>::try_new().unwrap();
|
||||
event_loop
|
||||
.handle()
|
||||
@@ -407,8 +369,7 @@ mod tests {
|
||||
})
|
||||
.unwrap();
|
||||
let signal = event_loop.get_signal();
|
||||
let mut state =
|
||||
WallpaperState::with_wakeup(WallpaperConfig::default(), Some(signal.clone()));
|
||||
let mut state = WallpaperState::with_wakeup(WallpaperConfig::default(), Some(signal.clone()));
|
||||
event_loop
|
||||
.run(None, &mut state, |state| {
|
||||
if state.poll() {
|
||||
@@ -429,18 +390,14 @@ mod tests {
|
||||
mode: WallpaperMode::Fill,
|
||||
});
|
||||
let now = Instant::now();
|
||||
state
|
||||
.upload_retries
|
||||
.insert(context.clone(), now + UPLOAD_RETRY_DELAY);
|
||||
state.upload_retries.insert(context.clone(), now + UPLOAD_RETRY_DELAY);
|
||||
assert!(!state.upload_ready(&context, now));
|
||||
assert!(state.upload_ready(&other, now));
|
||||
assert!(state.upload_ready(&context, now + UPLOAD_RETRY_DELAY));
|
||||
state.forget_context(&context);
|
||||
assert!(state.upload_ready(&context, now));
|
||||
|
||||
state
|
||||
.upload_retries
|
||||
.insert(context.clone(), now + UPLOAD_RETRY_DELAY);
|
||||
state.upload_retries.insert(context.clone(), now + UPLOAD_RETRY_DELAY);
|
||||
let (sender, receiver) = mpsc::channel();
|
||||
state.receiver = Some(receiver);
|
||||
sender.send(Ok(image::RgbaImage::new(2, 2))).unwrap();
|
||||
@@ -489,16 +446,11 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn fill_crops_and_fit_letterboxes_without_reallocating_image() {
|
||||
let (geometry, source) = image_geometry(
|
||||
(3840, 2160).into(),
|
||||
(1600, 1000).into(),
|
||||
WallpaperMode::Fill,
|
||||
);
|
||||
let (geometry, source) = image_geometry((3840, 2160).into(), (1600, 1000).into(), WallpaperMode::Fill);
|
||||
assert_eq!(geometry.size, (1600, 1000).into());
|
||||
assert_eq!(source.size.h, 2160.0);
|
||||
assert!(source.loc.x > 0.0);
|
||||
let (geometry, source) =
|
||||
image_geometry((3840, 2160).into(), (1600, 1000).into(), WallpaperMode::Fit);
|
||||
let (geometry, source) = image_geometry((3840, 2160).into(), (1600, 1000).into(), WallpaperMode::Fit);
|
||||
assert_eq!(geometry.size, (1600, 900).into());
|
||||
assert_eq!(geometry.loc, (0, 50).into());
|
||||
assert_eq!(source.size, (3840.0, 2160.0).into());
|
||||
|
||||
Reference in new issue
Block a user