Back off failed wallpaper uploads while allowing recovery
This commit is contained in:
1 parent
18cbf8f44d
commit
473ce8b332
1 file changed
+56
-1
@@ -15,7 +15,14 @@ use smithay::{
|
|||||||
output::Output,
|
output::Output,
|
||||||
utils::{Buffer, Physical, Rectangle, Size},
|
utils::{Buffer, Physical, Rectangle, Size},
|
||||||
};
|
};
|
||||||
use std::{collections::HashMap, path::PathBuf, sync::mpsc};
|
use std::{
|
||||||
|
collections::HashMap,
|
||||||
|
path::PathBuf,
|
||||||
|
sync::mpsc,
|
||||||
|
time::{Duration, Instant},
|
||||||
|
};
|
||||||
|
|
||||||
|
const UPLOAD_RETRY_DELAY: Duration = Duration::from_secs(5);
|
||||||
|
|
||||||
#[derive(Clone, Debug, Deserialize, PartialEq)]
|
#[derive(Clone, Debug, Deserialize, PartialEq)]
|
||||||
pub(crate) struct WallpaperConfig {
|
pub(crate) struct WallpaperConfig {
|
||||||
@@ -59,6 +66,7 @@ pub(crate) struct WallpaperState {
|
|||||||
receiver: Option<mpsc::Receiver<Result<image::RgbaImage, String>>>,
|
receiver: Option<mpsc::Receiver<Result<image::RgbaImage, String>>>,
|
||||||
pixels: Option<image::RgbaImage>,
|
pixels: Option<image::RgbaImage>,
|
||||||
textures: HashMap<ErasedContextId, WallpaperTexture>,
|
textures: HashMap<ErasedContextId, WallpaperTexture>,
|
||||||
|
upload_retries: HashMap<ErasedContextId, Instant>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl WallpaperState {
|
impl WallpaperState {
|
||||||
@@ -91,6 +99,7 @@ impl WallpaperState {
|
|||||||
receiver: owned.then_some(receiver),
|
receiver: owned.then_some(receiver),
|
||||||
pixels: None,
|
pixels: None,
|
||||||
textures: HashMap::new(),
|
textures: HashMap::new(),
|
||||||
|
upload_retries: HashMap::new(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -125,11 +134,19 @@ impl WallpaperState {
|
|||||||
if self.config.path.is_none() {
|
if self.config.path.is_none() {
|
||||||
self.pixels = None;
|
self.pixels = None;
|
||||||
self.textures.clear();
|
self.textures.clear();
|
||||||
|
self.upload_retries.clear();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn forget_context(&mut self, context: &ErasedContextId) {
|
pub fn forget_context(&mut self, context: &ErasedContextId) {
|
||||||
self.textures.remove(context);
|
self.textures.remove(context);
|
||||||
|
self.upload_retries.remove(context);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn upload_ready(&self, context: &ErasedContextId, now: Instant) -> bool {
|
||||||
|
self.upload_retries
|
||||||
|
.get(context)
|
||||||
|
.is_none_or(|retry| now >= *retry)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn poll(&mut self) -> bool {
|
pub fn poll(&mut self) -> bool {
|
||||||
@@ -157,6 +174,7 @@ impl WallpaperState {
|
|||||||
);
|
);
|
||||||
self.pixels = Some(pixels);
|
self.pixels = Some(pixels);
|
||||||
self.textures.clear();
|
self.textures.clear();
|
||||||
|
self.upload_retries.clear();
|
||||||
self.commit.increment();
|
self.commit.increment();
|
||||||
}
|
}
|
||||||
Err(error) => {
|
Err(error) => {
|
||||||
@@ -181,9 +199,13 @@ impl WallpaperState {
|
|||||||
let pixels = self.pixels.as_ref()?;
|
let pixels = self.pixels.as_ref()?;
|
||||||
let context = renderer.context_id().erased();
|
let context = renderer.context_id().erased();
|
||||||
if !self.textures.contains_key(&context) {
|
if !self.textures.contains_key(&context) {
|
||||||
|
if !self.upload_ready(&context, Instant::now()) {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
let size = Size::from((pixels.width() as i32, pixels.height() as i32));
|
let size = Size::from((pixels.width() as i32, pixels.height() as i32));
|
||||||
match renderer.import_memory(pixels.as_raw(), Fourcc::Abgr8888, size, false) {
|
match renderer.import_memory(pixels.as_raw(), Fourcc::Abgr8888, size, false) {
|
||||||
Ok(texture) => {
|
Ok(texture) => {
|
||||||
|
self.upload_retries.remove(&context);
|
||||||
tracing::debug!(
|
tracing::debug!(
|
||||||
bytes = pixels.as_raw().len(),
|
bytes = pixels.as_raw().len(),
|
||||||
"uploaded shared wallpaper texture"
|
"uploaded shared wallpaper texture"
|
||||||
@@ -197,6 +219,10 @@ impl WallpaperState {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
Err(error) => {
|
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);
|
||||||
tracing::debug!(%error, "wallpaper texture import failed");
|
tracing::debug!(%error, "wallpaper texture import failed");
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
@@ -269,6 +295,35 @@ fn image_geometry(
|
|||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn failed_uploads_back_off_per_context_and_reset_for_new_pixels() {
|
||||||
|
use smithay::backend::renderer::ContextId;
|
||||||
|
let context = ContextId::<GlesTexture>::new().erased();
|
||||||
|
let other = ContextId::<GlesTexture>::new().erased();
|
||||||
|
let mut state = WallpaperState::new(WallpaperConfig {
|
||||||
|
path: None,
|
||||||
|
mode: WallpaperMode::Fill,
|
||||||
|
});
|
||||||
|
let now = Instant::now();
|
||||||
|
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);
|
||||||
|
let (sender, receiver) = mpsc::channel();
|
||||||
|
state.receiver = Some(receiver);
|
||||||
|
sender.send(Ok(image::RgbaImage::new(2, 2))).unwrap();
|
||||||
|
assert!(state.poll());
|
||||||
|
assert!(state.upload_ready(&context, now));
|
||||||
|
}
|
||||||
#[test]
|
#[test]
|
||||||
fn live_reload_coalesces_decoders_and_mode_changes_invalidate_damage() {
|
fn live_reload_coalesces_decoders_and_mode_changes_invalidate_damage() {
|
||||||
let mut state = WallpaperState::new(WallpaperConfig::default());
|
let mut state = WallpaperState::new(WallpaperConfig::default());
|
||||||
|
|||||||
Reference in new issue
Block a user