mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-20 00:35:44 +00:00
Bug 1535146 - Attempt to load non-startup shaders from disk cache when required. r=bholley
On startup some program binaries are loaded from disk into an in-memory cache. When we call create_program() we check if the required program is present in this cache, and if so we call glProgramBinary(). This is done early on so that the driver can perform any necessary work in the background. There may however be binaries in the disk cache that have not yet been loaded in to memory, in order not to slow down startup. This change makes it so that we attempt to load missing binaries from disk during link_program(). The reason we do not do this in create_program() is because that would result in loading all shaders from disk during startup, which we want to avoid. Loading these shaders may therefore take slightly longer than if they'd been loaded at startup, but will still be much faster than recompiling them from scratch, and startup will remain quick. If loading the shaders on startup had previously timed out, then we do not attempt to load shaders on demand as the disk is probably too slow for that to be useful. Depends on D33954 Differential Revision: https://phabricator.services.mozilla.com/D33955 --HG-- extra : moz-landing-system : lando
This commit is contained in:
parent
c9c015cbff
commit
191dd4f438
@ -7,7 +7,7 @@ use std::path::{PathBuf};
|
||||
use std::rc::Rc;
|
||||
use std::sync::Arc;
|
||||
|
||||
use webrender::{ProgramBinary, ProgramCache, ProgramCacheObserver};
|
||||
use webrender::{ProgramBinary, ProgramCache, ProgramCacheObserver, ProgramSourceDigest};
|
||||
use bincode;
|
||||
use fxhash;
|
||||
use nsstring::nsAString;
|
||||
@ -83,6 +83,7 @@ fn get_cache_path_from_prof_path(prof_path: &nsAString) -> Option<PathBuf> {
|
||||
struct WrProgramBinaryDiskCache {
|
||||
cache_path: PathBuf,
|
||||
workers: Arc<ThreadPool>,
|
||||
cached_shader_filenames: Vec<OsString>,
|
||||
}
|
||||
|
||||
// Magic number + version. Increment the version when the binary format changes.
|
||||
@ -105,6 +106,7 @@ impl WrProgramBinaryDiskCache {
|
||||
WrProgramBinaryDiskCache {
|
||||
cache_path,
|
||||
workers: Arc::clone(workers),
|
||||
cached_shader_filenames: Vec::new(),
|
||||
}
|
||||
}
|
||||
|
||||
@ -184,6 +186,28 @@ impl WrProgramBinaryDiskCache {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn try_load_shader_from_disk(&mut self, filename: &str, program_cache: &Rc<ProgramCache>) {
|
||||
if let Some(index) = self.cached_shader_filenames.iter().position(|e| e == filename) {
|
||||
let mut path = self.cache_path.clone();
|
||||
path.push(filename);
|
||||
|
||||
self.cached_shader_filenames.swap_remove(index);
|
||||
|
||||
info!("Loading shader: {}", filename);
|
||||
|
||||
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");
|
||||
}
|
||||
}
|
||||
|
||||
pub fn try_load_startup_shaders_from_disk(&mut self, program_cache: &Rc<ProgramCache>) {
|
||||
use std::time::{Instant};
|
||||
let start = Instant::now();
|
||||
@ -202,7 +226,7 @@ impl WrProgramBinaryDiskCache {
|
||||
};
|
||||
info!("Loaded startup shader whitelist in {:?}", start.elapsed());
|
||||
|
||||
let mut cached_shader_filenames = read_dir(&self.cache_path)
|
||||
self.cached_shader_filenames = read_dir(&self.cache_path)
|
||||
.unwrap()
|
||||
.map(|e| e.unwrap().file_name())
|
||||
.filter(|e| e != WHITELIST_FILENAME)
|
||||
@ -210,25 +234,7 @@ impl WrProgramBinaryDiskCache {
|
||||
|
||||
// Load whitelisted program binaries if they exist
|
||||
for entry in &whitelist {
|
||||
if let Some(index) = cached_shader_filenames.iter().position(|e| e == entry.as_str()) {
|
||||
let mut path = self.cache_path.clone();
|
||||
path.push(entry);
|
||||
|
||||
cached_shader_filenames.swap_remove(index);
|
||||
|
||||
info!("Loading shader: {}", entry);
|
||||
|
||||
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");
|
||||
}
|
||||
self.try_load_shader_from_disk(&entry, program_cache);
|
||||
|
||||
let elapsed = start.elapsed();
|
||||
info!("Loaded shader in {:?}", elapsed);
|
||||
@ -236,7 +242,11 @@ impl WrProgramBinaryDiskCache {
|
||||
(elapsed.subsec_nanos() / 1_000_000) 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;
|
||||
}
|
||||
}
|
||||
@ -261,6 +271,11 @@ impl ProgramCacheObserver for WrProgramCacheObserver {
|
||||
self.disk_cache.borrow_mut().update(entries);
|
||||
}
|
||||
|
||||
fn try_load_shader_from_disk(&self, digest: &ProgramSourceDigest, program_cache: &Rc<ProgramCache>) {
|
||||
let filename = format!("{}", digest);
|
||||
self.disk_cache.borrow_mut().try_load_shader_from_disk(&filename, program_cache);
|
||||
}
|
||||
|
||||
fn notify_program_binary_failed(&self, _program_binary: &Arc<ProgramBinary>) {
|
||||
error!("shader-cache: Failed program_binary");
|
||||
}
|
||||
|
@ -798,6 +798,7 @@ impl ProgramBinary {
|
||||
/// The interfaces that an application can implement to handle ProgramCache update
|
||||
pub trait ProgramCacheObserver {
|
||||
fn update_disk_cache(&self, entries: Vec<Arc<ProgramBinary>>);
|
||||
fn try_load_shader_from_disk(&self, digest: &ProgramSourceDigest, program_cache: &Rc<ProgramCache>);
|
||||
fn notify_program_binary_failed(&self, program_binary: &Arc<ProgramBinary>);
|
||||
}
|
||||
|
||||
@ -1676,6 +1677,16 @@ impl Device {
|
||||
|
||||
// See if we hit the binary shader cache
|
||||
if let Some(ref cached_programs) = self.cached_programs {
|
||||
// If the shader is not in the cache, attempt to load it from disk
|
||||
if cached_programs.entries.borrow().get(&program.source_info.digest).is_none() {
|
||||
if let Some(ref handler) = cached_programs.program_cache_handler {
|
||||
handler.try_load_shader_from_disk(&program.source_info.digest, cached_programs);
|
||||
if let Some(entry) = cached_programs.entries.borrow().get(&program.source_info.digest) {
|
||||
self.gl.program_binary(program.id, entry.binary.format, &entry.binary.bytes);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(entry) = cached_programs.entries.borrow_mut().get_mut(&info.digest) {
|
||||
let mut link_status = [0];
|
||||
unsafe {
|
||||
|
@ -222,3 +222,4 @@ pub use crate::renderer::{
|
||||
pub use crate::screen_capture::{AsyncScreenshotHandle, RecordedFrameHandle};
|
||||
pub use crate::shade::{Shaders, WrShaders};
|
||||
pub use api as webrender_api;
|
||||
pub use webrender_build::shader::ProgramSourceDigest;
|
||||
|
Loading…
Reference in New Issue
Block a user