/* This Source Code Form is subject to the terms of the Mozilla Public *License,v.2.0.IfacopyoftheMPLwasnotdistributedwiththis
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
use std::cell::RefCell; use std::ffi::OsString; use std::fs::{create_dir_all, read_dir, read_to_string, File}; use std::io::{Error, ErrorKind}; use std::io::{Read, Write}; use std::path::{Path, PathBuf}; use std::rc::Rc; use std::sync::Arc;
use nsstring::nsAString; use rayon::ThreadPool; use webrender::{ProgramBinary, ProgramCache, ProgramCacheObserver, ProgramSourceDigest};
if buf.len() <= 8 + 4 { return Err(Error::new(ErrorKind::InvalidData, "File size is too small"));
} let magic = &buf[0..4]; let hash = &buf[4..8 + 4]; let data = &buf[8 + 4..];
// Check if magic + version are correct. let mv: u32 = bincode::deserialize(&magic).unwrap(); if mv != MAGIC_AND_VERSION { return Err(Error::new(
ErrorKind::InvalidData, "File data is invalid (magic+version)",
));
}
// Check if hash is correct let hash: u64 = bincode::deserialize(&hash).unwrap(); let hash_data = fxhash::hash64(&data); if hash != hash_data { return Err(Error::new(ErrorKind::InvalidData, "File data is invalid (hash)"));
}
// Deserialize ProgramBinary let binary = match bincode::deserialize(&data) {
Ok(binary) => binary,
Err(_) => { return Err(Error::new(
ErrorKind::InvalidData, "Failed to deserialize ProgramBinary",
))
},
};
Ok(Arc::new(binary))
}
#[cfg(target_os = "windows")] fn get_cache_path_from_prof_path(prof_path: &nsAString) -> Option<PathBuf> { if prof_path.is_empty() { // Empty means that we do not use disk cache. return None;
}
use std::os::windows::prelude::*;
let prof_path = OsString::from_wide(prof_path.as_ref()); letmut cache_path = PathBuf::from(&prof_path);
cache_path.push("shader-cache");
Some(cache_path)
}
#[cfg(not(target_os = "windows"))] fn get_cache_path_from_prof_path(prof_path: &nsAString) -> Option<PathBuf> { if prof_path.is_empty() { // Empty means that we do not use disk cache. return None;
}
let utf8 = String::from_utf16(prof_path.as_ref()).unwrap(); let prof_path = OsString::from(utf8); letmut cache_path = PathBuf::from(&prof_path);
cache_path.push("shader-cache");
/// Helper to convert a closure returning a `Result` to one that returns void. /// This allows the enclosed code to use the question-mark operator in a /// context where the calling function doesn't expect a `Result`. #[allow(unused_must_use)] fn result_to_void<F: FnOnce() -> Result<(), ()>>(f: F) {
f();
}
/// Saves the specified binaries to the on-disk shader cache. fn save_shaders_to_disk(&mutself, entries: Vec<Arc<ProgramBinary>>) {
info!("Saving binaries to on-disk shader cache");
// Write the entries to disk on a worker thread. for entry in entries { let file_name = entry.source_digest().to_string(); let file_path = self.cache_path.join(&file_name);
/// Writes the whitelist containing the set of startup shaders to disk. fn set_startup_shaders(&mutself, entries: Vec<Arc<ProgramBinary>>) { let whitelist = entries
.iter()
.map(|e| e.source_digest().to_string())
.collect::<Vec<String>>()
.join(WHITELIST_SEPARATOR);
match deserialize_program_binary(&path) {
Ok(program) => {
program_cache.load_program_binary(program);
},
Err(err) => {
error!("shader-cache: Failed to deserialize program binary: {}", err);
},
};
} else {
info!("shader-cache: Program binary not found in disk cache");
}
}
pubfn try_load_startup_shaders_from_disk(&mutself, program_cache: &Rc<ProgramCache>) { use std::time::Instant; let start = Instant::now();
// Load and parse the whitelist if it exists letmut whitelist_path = self.cache_path.clone();
whitelist_path.push(WHITELIST_FILENAME); let whitelist = match read_to_string(&whitelist_path) {
Ok(whitelist) => whitelist
.split(WHITELIST_SEPARATOR)
.map(|s| s.to_string())
.collect::<Vec<String>>(),
Err(err) => {
info!("shader-cache: Could not read startup whitelist: {}", err);
Vec::new()
},
};
info!("Loaded startup shader whitelist in {:?}", start.elapsed());
// Load whitelisted program binaries if they exist for entry in &whitelist { self.try_load_shader_from_disk(&entry, program_cache);
let elapsed = start.elapsed();
info!("Loaded shader in {:?}", elapsed); let elapsed_ms = (elapsed.as_secs() * 1_000) + elapsed.subsec_millis() as u64;
if elapsed_ms > MAX_LOAD_TIME_MS { // Loading the startup shaders is taking too long, so bail out now. // Additionally clear the list of remaining shaders cached on disk, // so that we do not attempt to load any on demand during rendering.
error!("shader-cache: Timed out before finishing loads"); self.cached_shader_filenames.clear(); break;
}
}
}
}
pubfn try_load_startup_shaders_from_disk(&self) { iflet Some(ref disk_cache) = self.disk_cache {
disk_cache
.borrow_mut()
.try_load_startup_shaders_from_disk(&self.program_cache);
} else {
error!("shader-cache: Shader disk cache is not supported");
}
}
}
pubfn remove_disk_cache(prof_path: &nsAString) -> Result<(), Error> { use std::time::Instant;
iflet Some(cache_path) = get_cache_path_from_prof_path(prof_path) { if cache_path.exists() { let start = Instant::now();
remove_dir_all::remove_dir_all(&cache_path)?;
info!("removed all disk cache shaders in {:?}", start.elapsed());
}
}
Ok(())
}
Messung V0.5 in Prozent
¤ Dauer der Verarbeitung: 0.15 Sekunden
(vorverarbeitet am 2026-06-19)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.