cache: clean up cache api

This commit is contained in:
chyyran 2023-02-15 17:40:24 -05:00 committed by Ronny Chan
parent 83422de1f7
commit 2ca6aecfe4
17 changed files with 85 additions and 115 deletions

View file

@ -3,6 +3,6 @@
<component name="VcsDirectoryMappings">
<mapping directory="$PROJECT_DIR$/.." vcs="Git" />
<mapping directory="$PROJECT_DIR$" vcs="Git" />
<mapping directory="$PROJECT_DIR$/test/slang-shaders" vcs="Git" />
<mapping directory="$PROJECT_DIR$/test/shaders_slang" vcs="Git" />
</component>
</project>

32
Cargo.lock generated
View file

@ -1162,15 +1162,6 @@ dependencies = [
"windows",
]
[[package]]
name = "librashader-common"
version = "0.1.0-rc.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7ff30c28bf8007f8061a3e429378a5d3682e61d15fe81825c9e5076a3091e349"
dependencies = [
"num-traits",
]
[[package]]
name = "librashader-common"
version = "0.1.0-rc.3"
@ -1181,6 +1172,15 @@ dependencies = [
"windows",
]
[[package]]
name = "librashader-common"
version = "0.1.0-rc.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0e22634fcfd3d0307db6d31366bb6bdd4422ec18a889a18ebe5572e47f366989"
dependencies = [
"num-traits",
]
[[package]]
name = "librashader-preprocess"
version = "0.1.0-rc.3"
@ -1188,7 +1188,7 @@ dependencies = [
"encoding_rs",
"glob",
"librashader-common 0.1.0-rc.3",
"librashader-presets 0.1.0-rc.2",
"librashader-presets 0.1.0-rc.3 (registry+https://github.com/rust-lang/crates.io-index)",
"nom",
"rayon",
"rustc-hash",
@ -1197,11 +1197,10 @@ dependencies = [
[[package]]
name = "librashader-presets"
version = "0.1.0-rc.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "de7bfd6903b4c52db1d220cb67d9e618ba87922300893586b2cf360b7591bde6"
version = "0.1.0-rc.3"
dependencies = [
"librashader-common 0.1.0-rc.2",
"glob",
"librashader-common 0.1.0-rc.3",
"nom",
"nom_locate",
"num-traits",
@ -1211,9 +1210,10 @@ dependencies = [
[[package]]
name = "librashader-presets"
version = "0.1.0-rc.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5ba84e8b4fdb76114d56f0ad2118e2cfbdde0666dd95e657afa4803c6f19bfee"
dependencies = [
"glob",
"librashader-common 0.1.0-rc.3",
"librashader-common 0.1.0-rc.3 (registry+https://github.com/rust-lang/crates.io-index)",
"nom",
"nom_locate",
"num-traits",

View file

@ -12,8 +12,8 @@ description = "RetroArch shaders for all."
[dependencies]
serde = { version = "1.0" }
librashader-reflect = { path = "../librashader-reflect", version = "0.1.0-rc.2", features = ["serialize", "dxil"] }
librashader-preprocess = { path = "../librashader-preprocess", version = "0.1.0-rc.2" }
librashader-reflect = { path = "../librashader-reflect", version = "0.1.0-rc.3", features = ["serialize", "dxil"] }
librashader-preprocess = { path = "../librashader-preprocess", version = "0.1.0-rc.3" }
platform-dirs = "0.3.0"
blake3 = { version = "1.3.3", features = ["rayon"] }
thiserror = "1.0.38"

View file

@ -5,7 +5,7 @@ use rusqlite::{params, Connection, DatabaseName};
use std::error::Error;
use std::path::PathBuf;
pub fn get_cache_dir() -> Result<PathBuf, Box<dyn Error>> {
pub(crate) fn get_cache_dir() -> Result<PathBuf, Box<dyn Error>> {
let cache_dir =
if let Some(cache_dir) = AppDirs::new(Some("librashader"), false).map(|a| a.cache_dir) {
cache_dir
@ -20,7 +20,7 @@ pub fn get_cache_dir() -> Result<PathBuf, Box<dyn Error>> {
Ok(cache_dir)
}
pub fn get_cache() -> Result<Connection, Box<dyn Error>> {
pub(crate) fn get_cache() -> Result<Connection, Box<dyn Error>> {
let cache_dir = get_cache_dir()?;
let mut conn = Connection::open(&cache_dir.join("librashader.db"))?;
@ -62,55 +62,29 @@ pub(crate) fn set_blob(conn: &Connection, index: &str, key: &[u8], value: &[u8])
}
}
pub fn get_cached_blob<T, H, const KEY_SIZE: usize>(
index: &str,
key: &[H; KEY_SIZE],
transform: impl FnOnce(Vec<u8>) -> T,
) -> Option<T>
where
H: CacheKey,
{
let cache = get_cache();
let Ok(cache) = cache else {
return None
};
let key = {
let mut hasher = blake3::Hasher::new();
for subkeys in key {
hasher.update(subkeys.hash_bytes());
}
let hash = hasher.finalize();
hash
};
let Ok(blob) = get_blob(&cache, index, key.as_bytes()) else {
return None;
};
Some(transform(blob))
}
pub fn cache_object<E, T, R, H, const KEY_SIZE: usize>(
/// Cache a shader object (usually bytecode) created by the keyed objects.
///
/// - `factory` is the function that compiles the values passed as keys to a shader object.
/// - `load` tries to load a compiled shader object to a driver-specialized result.
pub fn cache_shader_object<E, T, R, H, const KEY_SIZE: usize>(
index: &str,
keys: &[H; KEY_SIZE],
factory: impl FnOnce(&[H; KEY_SIZE]) -> Result<T, E>,
attempt: impl Fn(T) -> Result<R, E>,
do_cache: bool,
load: impl Fn(T) -> Result<R, E>,
bypass_cache: bool,
) -> Result<R, E>
where
H: CacheKey,
T: Cacheable,
{
if !do_cache {
return Ok(attempt(factory(keys)?)?);
if bypass_cache {
return Ok(load(factory(keys)?)?);
}
let cache = get_cache();
let Ok(cache) = cache else {
return Ok(attempt(factory(keys)?)?);
return Ok(load(factory(keys)?)?);
};
let hashkey = {
@ -124,7 +98,7 @@ where
'attempt: {
if let Ok(blob) = get_blob(&cache, index, hashkey.as_bytes()) {
let cached = T::from_bytes(&blob).map(&attempt);
let cached = T::from_bytes(&blob).map(&load);
match cached {
None => break 'attempt,
@ -139,27 +113,34 @@ where
if let Some(slice) = T::to_bytes(&blob) {
set_blob(&cache, index, hashkey.as_bytes(), &slice);
}
Ok(attempt(blob)?)
Ok(load(blob)?)
}
/// Cache a pipeline state object.
///
/// Keys are not used to create the object and are only used to uniquely identify the pipeline state.
///
/// - `restore_pipeline` tries to restore the pipeline with either a cached binary pipeline state
/// cache, or create a new pipeline if no cached value is available.
/// - `fetch_pipeline_state` fetches the new pipeline state cache after the pipeline was created.
pub fn cache_pipeline<E, T, R, const KEY_SIZE: usize>(
index: &str,
keys: &[&dyn CacheKey; KEY_SIZE],
attempt: impl Fn(Option<Vec<u8>>) -> Result<R, E>,
factory: impl FnOnce(&R) -> Result<T, E>,
do_cache: bool,
restore_pipeline: impl Fn(Option<Vec<u8>>) -> Result<R, E>,
fetch_pipeline_state: impl FnOnce(&R) -> Result<T, E>,
bypass_cache: bool,
) -> Result<R, E>
where
T: Cacheable,
{
if !do_cache {
return Ok(attempt(None)?);
if bypass_cache {
return Ok(restore_pipeline(None)?);
}
let cache = get_cache();
let Ok(cache) = cache else {
return Ok(attempt(None)?);
return Ok(restore_pipeline(None)?);
};
let hashkey = {
@ -173,7 +154,7 @@ where
let pipeline = 'attempt: {
if let Ok(blob) = get_blob(&cache, index, hashkey.as_bytes()) {
let cached = attempt(Some(blob));
let cached = restore_pipeline(Some(blob));
match cached {
Ok(res) => {
break 'attempt res;
@ -182,11 +163,11 @@ where
}
}
attempt(None)?
restore_pipeline(None)?
};
// update the pso every time just in case.
if let Ok(state) = factory(&pipeline) {
if let Ok(state) = fetch_pipeline_state(&pipeline) {
if let Some(slice) = T::to_bytes(&state) {
set_blob(&cache, index, hashkey.as_bytes(), &slice);
}

View file

@ -1,3 +1,4 @@
/// Trait for objects that are cacheable.
pub trait Cacheable {
fn from_bytes(bytes: &[u8]) -> Option<Self>
where

View file

@ -1,3 +1,4 @@
//! Cache helpers for `ShaderCompilation` objects to cache compiled SPIRV.
use crate::cache::{get_blob, get_cache, set_blob};
use librashader_preprocess::ShaderSource;
use librashader_reflect::back::targets::{DXIL, GLSL, HLSL, SPIRV};

View file

@ -1,10 +0,0 @@
use std::error::Error;
use thiserror::Error;
#[derive(Debug, Error)]
pub enum CacheError {
#[error("serde error")]
SerdeError,
#[error("unknown error")]
UnknownError(#[from] Box<dyn Error>),
}

View file

@ -2,20 +2,18 @@
//!
//! This crate is exempt from semantic versioning guarantees and is an implementation
//! detail of librashader runtimes.
#![feature(try_blocks)]
#![feature(once_cell)]
pub mod cache;
pub mod compilation;
pub mod error;
mod cache;
mod compilation;
mod key;
mod cacheable;
#[cfg(test)]
mod tests {}
pub use cacheable::Cacheable;
pub use key::CacheKey;
pub use compilation::CachedCompilation;
pub use cache::cache_pipeline;
pub use cache::cache_shader_object;
#[cfg(all(target_os = "windows", feature = "d3d"))]
mod d3d;

View file

@ -23,6 +23,6 @@ default = [ "line_directives" ]
line_directives = []
[dev-dependencies]
librashader-presets = "0.1.0-beta.16"
librashader-presets = "0.1.0-rc.3"
glob = "0.3.1"
rayon = "1.6.1"

View file

@ -22,8 +22,8 @@ use crate::options::{FilterChainOptionsD3D11, FrameOptionsD3D11};
use crate::samplers::SamplerSet;
use crate::util::d3d11_compile_bound_shader;
use crate::{error, util, D3D11OutputView};
use librashader_cache::cache::cache_object;
use librashader_cache::compilation::CachedCompilation;
use librashader_cache::cache_shader_object;
use librashader_cache::CachedCompilation;
use librashader_reflect::reflect::presets::{CompilePresetTarget, ShaderPassArtifact};
use librashader_runtime::binding::{BindingUtil, TextureInput};
use librashader_runtime::framebuffer::FramebufferInit;
@ -230,7 +230,7 @@ impl FilterChainD3D11 {
let reflection = reflect.reflect(index, semantics)?;
let hlsl = reflect.compile(None)?;
let (vs, vertex_dxbc) = cache_object(
let (vs, vertex_dxbc) = cache_shader_object(
"dxbc",
&[hlsl.vertex.as_bytes()],
|&[bytes]| util::d3d_compile_shader(bytes, b"main\0", b"vs_5_0\0"),
@ -245,20 +245,20 @@ impl FilterChainD3D11 {
blob,
))
},
!disable_cache,
disable_cache,
)?;
let ia_desc = DrawQuad::get_spirv_cross_vbo_desc();
let vao = util::d3d11_create_input_layout(device, &ia_desc, &vertex_dxbc)?;
let ps = cache_object(
let ps = cache_shader_object(
"dxbc",
&[hlsl.fragment.as_bytes()],
|&[bytes]| util::d3d_compile_shader(bytes, b"main\0", b"ps_5_0\0"),
|blob| {
d3d11_compile_bound_shader(device, &blob, None, ID3D11Device::CreatePixelShader)
},
!disable_cache,
disable_cache,
)?;
let ubo_cbuffer = if let Some(ubo) = &reflection.ubo && ubo.size != 0 {

View file

@ -46,7 +46,7 @@ use windows::Win32::Graphics::Dxgi::Common::DXGI_FORMAT_UNKNOWN;
use windows::Win32::System::Threading::{CreateEventA, WaitForSingleObject};
use windows::Win32::System::WindowsProgramming::INFINITE;
use librashader_cache::compilation::CachedCompilation;
use librashader_cache::CachedCompilation;
use librashader_runtime::framebuffer::FramebufferInit;
use librashader_runtime::render_target::RenderTarget;
use librashader_runtime::scaling::ScaleFramebuffer;

View file

@ -2,7 +2,7 @@ use crate::error::assume_d3d12_init;
use crate::error::FilterChainError::Direct3DOperationError;
use crate::quad_render::DrawQuad;
use crate::{error, util};
use librashader_cache::cache::{cache_object, cache_pipeline};
use librashader_cache::{cache_shader_object, cache_pipeline};
use librashader_reflect::back::cross::CrossHlslContext;
use librashader_reflect::back::dxil::DxilObject;
use librashader_reflect::back::ShaderCompilerOutput;
@ -248,7 +248,7 @@ impl D3D12GraphicsPipeline {
let cached_pso = pso.GetCachedBlob()?;
Ok(cached_pso)
},
!disable_cache,
disable_cache,
)?
};
@ -324,20 +324,20 @@ impl D3D12GraphicsPipeline {
));
}
let vertex_dxil = cache_object(
let vertex_dxil = cache_shader_object(
"dxil",
&[shader_assembly.vertex.deref()],
|&[source]| util::dxc_validate_shader(library, validator, source),
|f| Ok(f),
!disable_cache,
disable_cache,
)?;
let fragment_dxil = cache_object(
let fragment_dxil = cache_shader_object(
"dxil",
&[shader_assembly.fragment.deref()],
|&[source]| util::dxc_validate_shader(library, validator, source),
|f| Ok(f),
!disable_cache,
disable_cache,
)?;
Self::new_from_blobs(
@ -359,20 +359,20 @@ impl D3D12GraphicsPipeline {
render_format: DXGI_FORMAT,
disable_cache: bool,
) -> error::Result<D3D12GraphicsPipeline> {
let vertex_dxil = cache_object(
let vertex_dxil = cache_shader_object(
"dxil",
&[shader_assembly.vertex.as_bytes()],
|&[source]| util::dxc_compile_shader(library, dxc, source, u16cstr!("vs_6_0")),
|f| Ok(f),
!disable_cache,
disable_cache,
)?;
let fragment_dxil = cache_object(
let fragment_dxil = cache_shader_object(
"dxil",
&[shader_assembly.fragment.as_bytes()],
|&[source]| util::dxc_compile_shader(library, dxc, source, u16cstr!("ps_6_0")),
|f| Ok(f),
!disable_cache,
disable_cache,
)?;
Self::new_from_blobs(

View file

@ -19,7 +19,7 @@ use librashader_reflect::back::{CompileReflectShader, CompileShader};
use librashader_reflect::front::GlslangCompilation;
use librashader_reflect::reflect::semantics::{ShaderSemantics, UniformMeta};
use librashader_cache::compilation::CachedCompilation;
use librashader_cache::CachedCompilation;
use librashader_reflect::reflect::presets::{CompilePresetTarget, ShaderPassArtifact};
use librashader_reflect::reflect::ReflectShader;
use librashader_runtime::binding::BindingUtil;

View file

@ -47,7 +47,7 @@ impl CompileProgram for Gl4CompileProgram {
) -> crate::error::Result<(GLuint, UniformLocation<GLuint>)> {
let vertex_resources = glsl.context.artifact.vertex.get_shader_resources()?;
let program = librashader_cache::cache::cache_object(
let program = librashader_cache::cache_shader_object(
"opengl4",
&[glsl.vertex.as_str(), glsl.fragment.as_str()],
|&[vertex, fragment]| unsafe {
@ -120,7 +120,7 @@ impl CompileProgram for Gl4CompileProgram {
}
return Ok(program);
},
cache,
!cache,
)?;
let ubo_location = unsafe {

View file

@ -18,11 +18,10 @@ pub struct FilterChainOptionsGL {
/// The GLSL version. Should be at least `330`.
pub glsl_version: u16,
/// Whether or not to use the Direct State Access APIs. Only available on OpenGL 4.5+.
/// This is required to use shader caching.
/// If this is off, compiled program caching will not be available.
pub use_dsa: bool,
/// Whether or not to explicitly disable mipmap generation regardless of shader preset settings.
pub force_no_mipmaps: bool,
/// Disable the shader object cache. Shaders will be
/// recompiled rather than loaded from the cache.
/// Disable the shader object cache. Shaders will be recompiled rather than loaded from the cache.
pub disable_cache: bool,
}

View file

@ -32,7 +32,7 @@ use std::convert::Infallible;
use std::path::Path;
use std::sync::Arc;
use librashader_cache::compilation::CachedCompilation;
use librashader_cache::CachedCompilation;
use librashader_runtime::framebuffer::FramebufferInit;
use librashader_runtime::render_target::RenderTarget;
use librashader_runtime::scaling::ScaleFramebuffer;
@ -442,7 +442,7 @@ impl FilterChainVulkan {
&reflection,
frames_in_flight,
render_pass_format,
!disable_cache,
disable_cache,
)?;
Ok(FilterPass {

View file

@ -4,7 +4,7 @@ use ash::vk;
use crate::error::FilterChainError;
use crate::framebuffer::OutputImage;
use crate::render_pass::VulkanRenderPass;
use librashader_cache::cache::cache_pipeline;
use librashader_cache::cache_pipeline;
use librashader_reflect::back::ShaderCompilerOutput;
use librashader_reflect::reflect::semantics::{TextureBinding, UboReflection};
use librashader_reflect::reflect::ShaderReflection;
@ -314,7 +314,7 @@ impl VulkanGraphicsPipeline {
reflection: &ShaderReflection,
replicas: u32,
render_pass_format: vk::Format,
cache_objects: bool,
bypass_cache: bool,
) -> error::Result<VulkanGraphicsPipeline> {
let pipeline_layout = PipelineLayoutObjects::new(reflection, replicas, device)?;
@ -359,7 +359,7 @@ impl VulkanGraphicsPipeline {
Ok::<_, FilterChainError>((pipeline, pipeline_cache))
},
|(_pipeline, cache)| unsafe { Ok(device.get_pipeline_cache_data(*cache)?) },
cache_objects,
bypass_cache,
)?;
Ok(VulkanGraphicsPipeline {