diff --git a/librashader-cache/src/cache.rs b/librashader-cache/src/cache.rs index 23b281a..d617366 100644 --- a/librashader-cache/src/cache.rs +++ b/librashader-cache/src/cache.rs @@ -1,5 +1,5 @@ -use crate::key::CacheKey; use crate::cacheable::Cacheable; +use crate::key::CacheKey; use platform_dirs::AppDirs; use rusqlite::{params, Connection, DatabaseName}; use std::error::Error; diff --git a/librashader-cache/src/d3d.rs b/librashader-cache/src/d3d.rs index 32e0494..f1084fa 100644 --- a/librashader-cache/src/d3d.rs +++ b/librashader-cache/src/d3d.rs @@ -1,7 +1,7 @@ //! Cache implementations for D3D blob types that need to live //! here because of the orphan rule. -use crate::{Cacheable, CacheKey}; +use crate::{CacheKey, Cacheable}; impl CacheKey for windows::Win32::Graphics::Direct3D::ID3DBlob { fn hash_bytes(&self) -> &[u8] { @@ -15,7 +15,6 @@ impl CacheKey for windows::Win32::Graphics::Direct3D::Dxc::IDxcBlob { } } - impl Cacheable for windows::Win32::Graphics::Direct3D::ID3DBlob { fn from_bytes(bytes: &[u8]) -> Option { let Some(blob) = (unsafe { windows::Win32::Graphics::Direct3D::Fxc::D3DCreateBlob(bytes.len()).ok() }) else { diff --git a/librashader-runtime-d3d11/src/filter_chain.rs b/librashader-runtime-d3d11/src/filter_chain.rs index d3d82e2..080d34c 100644 --- a/librashader-runtime-d3d11/src/filter_chain.rs +++ b/librashader-runtime-d3d11/src/filter_chain.rs @@ -118,15 +118,24 @@ impl FilterChainD3D11 { ctx: &ID3D11DeviceContext, options: Option<&FilterChainOptionsD3D11>, ) -> error::Result { - let (passes, semantics) = HLSL::compile_preset_passes::< - CachedCompilation, - FilterChainError, - >(preset.shaders, &preset.textures)?; + let disable_cache = options.map_or(false, |o| o.disable_cache); + + let (passes, semantics) = if !disable_cache { + HLSL::compile_preset_passes::, FilterChainError>( + preset.shaders, + &preset.textures, + )? + } else { + HLSL::compile_preset_passes::( + preset.shaders, + &preset.textures, + )? + }; let samplers = SamplerSet::new(device)?; // initialize passes - let filters = FilterChainD3D11::init_passes(device, passes, &semantics)?; + let filters = FilterChainD3D11::init_passes(device, passes, &semantics, disable_cache)?; println!("passes loded"); let immediate_context = unsafe { device.GetImmediateContext()? }; @@ -212,6 +221,7 @@ impl FilterChainD3D11 { device: &ID3D11Device, passes: Vec, semantics: &ShaderSemantics, + disable_cache: bool, ) -> error::Result> { let device_is_singlethreaded = unsafe { (device.GetCreationFlags() & D3D11_CREATE_DEVICE_SINGLETHREADED.0) == 1 }; @@ -235,7 +245,7 @@ impl FilterChainD3D11 { blob, )) }, - true, + !disable_cache, )?; let ia_desc = DrawQuad::get_spirv_cross_vbo_desc(); @@ -248,7 +258,7 @@ impl FilterChainD3D11 { |blob| { d3d11_compile_bound_shader(device, &blob, None, ID3D11Device::CreatePixelShader) }, - true, + !disable_cache, )?; let ubo_cbuffer = if let Some(ubo) = &reflection.ubo && ubo.size != 0 { diff --git a/librashader-runtime-d3d11/src/lib.rs b/librashader-runtime-d3d11/src/lib.rs index 967129a..5830492 100644 --- a/librashader-runtime-d3d11/src/lib.rs +++ b/librashader-runtime-d3d11/src/lib.rs @@ -61,6 +61,7 @@ mod tests { filter.as_deref().unwrap_or(FILTER_PATH), Some(&FilterChainOptionsD3D11 { force_no_mipmaps: false, + disable_cache: false, }), // replace below with 'None' for the triangle Some(image), @@ -85,6 +86,7 @@ mod tests { FILTER_PATH, Some(&FilterChainOptionsD3D11 { force_no_mipmaps: false, + disable_cache: false, }), // replace below with 'None' for the triangle // None, diff --git a/librashader-runtime-d3d11/src/options.rs b/librashader-runtime-d3d11/src/options.rs index a102d4c..bfd6d14 100644 --- a/librashader-runtime-d3d11/src/options.rs +++ b/librashader-runtime-d3d11/src/options.rs @@ -18,4 +18,7 @@ pub struct FilterChainOptionsD3D11 { /// 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. + pub disable_cache: bool, } diff --git a/librashader-runtime-d3d12/src/filter_chain.rs b/librashader-runtime-d3d12/src/filter_chain.rs index f932383..89533f8 100644 --- a/librashader-runtime-d3d12/src/filter_chain.rs +++ b/librashader-runtime-d3d12/src/filter_chain.rs @@ -207,16 +207,31 @@ impl FilterChainD3D12 { let lut_count = preset.textures.len(); let shader_copy = preset.shaders.clone(); + let disable_cache = options.map_or(false, |o| o.disable_cache); - let (passes, semantics) = DXIL::compile_preset_passes::< - CachedCompilation, - FilterChainError, - >(preset.shaders, &preset.textures)?; + let (passes, semantics) = if !disable_cache { + DXIL::compile_preset_passes::, FilterChainError>( + preset.shaders, + &preset.textures, + )? + } else { + DXIL::compile_preset_passes::( + preset.shaders, + &preset.textures, + )? + }; - let (hlsl_passes, _) = HLSL::compile_preset_passes::< - CachedCompilation, - FilterChainError, - >(shader_copy, &preset.textures)?; + let (hlsl_passes, _) = if !disable_cache { + HLSL::compile_preset_passes::, FilterChainError>( + shader_copy, + &preset.textures, + )? + } else { + HLSL::compile_preset_passes::( + shader_copy, + &preset.textures, + )? + }; let samplers = SamplerSet::new(device)?; let mipmap_gen = D3D12MipmapGen::new(device, false)?; @@ -244,6 +259,7 @@ impl FilterChainD3D12 { hlsl_passes, &semantics, options.map_or(false, |o| o.force_hlsl_pipeline), + disable_cache, )?; let mut residuals = FrameResiduals::new(); @@ -367,6 +383,7 @@ impl FilterChainD3D12 { hlsl_passes: Vec, semantics: &ShaderSemantics, force_hlsl: bool, + disable_cache: bool, ) -> error::Result<( ID3D12DescriptorHeap, ID3D12DescriptorHeap, @@ -432,7 +449,8 @@ impl FilterChainD3D12 { validator, &dxil, root_signature, - render_format + render_format, + disable_cache ) { (dxil_reflection, graphics_pipeline) } else { @@ -446,6 +464,7 @@ impl FilterChainD3D12 { &hlsl, root_signature, render_format, + disable_cache )?; (hlsl_reflection, graphics_pipeline) }; @@ -458,8 +477,8 @@ impl FilterChainD3D12 { .map_or(1, |push| push.size as usize); let uniform_storage = UniformStorage::new_with_storage( - RawD3D12Buffer::new(D3D12Buffer::new(device, ubo_size)?)?, - RawD3D12Buffer::new(D3D12Buffer::new(device, push_size)?)? + RawD3D12Buffer::new(D3D12Buffer::new(device, ubo_size)?)?, + RawD3D12Buffer::new(D3D12Buffer::new(device, push_size)?)? ); diff --git a/librashader-runtime-d3d12/src/graphics_pipeline.rs b/librashader-runtime-d3d12/src/graphics_pipeline.rs index fbdc8ca..908ae26 100644 --- a/librashader-runtime-d3d12/src/graphics_pipeline.rs +++ b/librashader-runtime-d3d12/src/graphics_pipeline.rs @@ -36,6 +36,7 @@ pub struct D3D12GraphicsPipeline { pub(crate) format: DXGI_FORMAT, vertex: Vec, fragment: Vec, + cache_disabled: bool, } const D3D12_SLANG_ROOT_PARAMETERS: &[D3D12_ROOT_PARAMETER1; 4] = &[ @@ -152,6 +153,7 @@ impl D3D12GraphicsPipeline { fragment_dxil: IDxcBlob, root_signature: &D3D12RootSignature, render_format: DXGI_FORMAT, + disable_cache: bool, ) -> error::Result { let input_element = DrawQuad::get_spirv_cross_vbo_desc(); @@ -246,7 +248,7 @@ impl D3D12GraphicsPipeline { let cached_pso = pso.GetCachedBlob()?; Ok(cached_pso) }, - true, + !disable_cache, )? }; @@ -264,6 +266,7 @@ impl D3D12GraphicsPipeline { format: render_format, vertex, fragment, + cache_disabled: disable_cache, }) } } @@ -288,8 +291,14 @@ impl D3D12GraphicsPipeline { )?; (vertex, fragment) }; - let mut new_pipeline = - Self::new_from_blobs(device, vertex.into(), fragment.into(), root_sig, format)?; + let mut new_pipeline = Self::new_from_blobs( + device, + vertex.into(), + fragment.into(), + root_sig, + format, + self.cache_disabled, + )?; std::mem::swap(self, &mut new_pipeline); Ok(()) @@ -302,6 +311,7 @@ impl D3D12GraphicsPipeline { shader_assembly: &ShaderCompilerOutput, root_signature: &D3D12RootSignature, render_format: DXGI_FORMAT, + disable_cache: bool, ) -> error::Result { if shader_assembly.vertex.requires_runtime_data() { return Err(Direct3DOperationError( @@ -319,7 +329,7 @@ impl D3D12GraphicsPipeline { &[shader_assembly.vertex.deref()], |&[source]| util::dxc_validate_shader(library, validator, source), |f| Ok(f), - true, + !disable_cache, )?; let fragment_dxil = cache_object( @@ -327,7 +337,7 @@ impl D3D12GraphicsPipeline { &[shader_assembly.fragment.deref()], |&[source]| util::dxc_validate_shader(library, validator, source), |f| Ok(f), - true, + !disable_cache, )?; Self::new_from_blobs( @@ -336,6 +346,7 @@ impl D3D12GraphicsPipeline { fragment_dxil, root_signature, render_format, + disable_cache, ) } @@ -346,13 +357,14 @@ impl D3D12GraphicsPipeline { shader_assembly: &ShaderCompilerOutput, root_signature: &D3D12RootSignature, render_format: DXGI_FORMAT, + disable_cache: bool, ) -> error::Result { let vertex_dxil = cache_object( "dxil", &[shader_assembly.vertex.as_bytes()], |&[source]| util::dxc_compile_shader(library, dxc, source, u16cstr!("vs_6_0")), |f| Ok(f), - true, + !disable_cache, )?; let fragment_dxil = cache_object( @@ -360,7 +372,7 @@ impl D3D12GraphicsPipeline { &[shader_assembly.fragment.as_bytes()], |&[source]| util::dxc_compile_shader(library, dxc, source, u16cstr!("ps_6_0")), |f| Ok(f), - true, + !disable_cache, )?; Self::new_from_blobs( @@ -369,6 +381,7 @@ impl D3D12GraphicsPipeline { fragment_dxil, root_signature, render_format, + disable_cache, ) } } diff --git a/librashader-runtime-d3d12/src/options.rs b/librashader-runtime-d3d12/src/options.rs index 1a4d4c3..ebbe0ab 100644 --- a/librashader-runtime-d3d12/src/options.rs +++ b/librashader-runtime-d3d12/src/options.rs @@ -22,4 +22,8 @@ pub struct FilterChainOptionsD3D12 { /// generation for intermediate passes 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. + pub disable_cache: bool, } diff --git a/librashader-runtime-gl/src/filter_chain/filter_impl.rs b/librashader-runtime-gl/src/filter_chain/filter_impl.rs index 78a2028..6db4bfa 100644 --- a/librashader-runtime-gl/src/filter_chain/filter_impl.rs +++ b/librashader-runtime-gl/src/filter_chain/filter_impl.rs @@ -19,6 +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_reflect::reflect::presets::{CompilePresetTarget, ShaderPassArtifact}; use librashader_reflect::reflect::ReflectShader; use librashader_runtime::binding::BindingUtil; @@ -104,15 +105,24 @@ impl FilterChainImpl { preset: ShaderPreset, options: Option<&FilterChainOptionsGL>, ) -> error::Result { - let (passes, semantics) = GLSL::compile_preset_passes::< - GlslangCompilation, - FilterChainError, - >(preset.shaders, &preset.textures)?; + let disable_cache = options.map_or(false, |o| o.disable_cache); + + let (passes, semantics) = if !disable_cache { + GLSL::compile_preset_passes::, FilterChainError>( + preset.shaders, + &preset.textures, + )? + } else { + GLSL::compile_preset_passes::( + preset.shaders, + &preset.textures, + )? + }; let version = options.map_or_else(gl_get_version, |o| gl_u16_to_version(o.glsl_version)); // initialize passes - let filters = Self::init_passes(version, passes, &semantics)?; + let filters = Self::init_passes(version, passes, &semantics, disable_cache)?; let default_filter = filters.first().map(|f| f.config.filter).unwrap_or_default(); let default_wrap = filters @@ -181,6 +191,7 @@ impl FilterChainImpl { version: GlslVersion, passes: Vec, semantics: &ShaderSemantics, + disable_cache: bool, ) -> error::Result]>> { let mut filters = Vec::new(); @@ -189,7 +200,7 @@ impl FilterChainImpl { let reflection = reflect.reflect(index, semantics)?; let glsl = reflect.compile(version)?; - let (program, ubo_location) = T::CompileShader::compile_program(glsl, true)?; + let (program, ubo_location) = T::CompileShader::compile_program(glsl, !disable_cache)?; let ubo_ring = if let Some(ubo) = &reflection.ubo { let ring = UboRing::new(ubo.size); diff --git a/librashader-runtime-gl/src/lib.rs b/librashader-runtime-gl/src/lib.rs index 991fe7a..7eb59d9 100644 --- a/librashader-runtime-gl/src/lib.rs +++ b/librashader-runtime-gl/src/lib.rs @@ -40,6 +40,7 @@ mod tests { glsl_version: 0, use_dsa: false, force_no_mipmaps: false, + disable_cache: false, }), ) // FilterChain::load_from_path("../test/slang-shaders/bezel/Mega_Bezel/Presets/MBZ__0__SMOOTH-ADV.slangp", None) @@ -59,6 +60,7 @@ mod tests { glsl_version: 0, use_dsa: true, force_no_mipmaps: false, + disable_cache: false, }), ) // FilterChain::load_from_path("../test/slang-shaders/bezel/Mega_Bezel/Presets/MBZ__0__SMOOTH-ADV.slangp", None) diff --git a/librashader-runtime-gl/src/options.rs b/librashader-runtime-gl/src/options.rs index b8009c2..4bf1e67 100644 --- a/librashader-runtime-gl/src/options.rs +++ b/librashader-runtime-gl/src/options.rs @@ -18,7 +18,11 @@ 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. 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. + pub disable_cache: bool, } diff --git a/librashader-runtime-vk/src/filter_chain.rs b/librashader-runtime-vk/src/filter_chain.rs index 9a6543c..c888e43 100644 --- a/librashader-runtime-vk/src/filter_chain.rs +++ b/librashader-runtime-vk/src/filter_chain.rs @@ -307,10 +307,20 @@ impl FilterChainVulkan { V: TryInto, FilterChainError: From, { - let (passes, semantics) = SPIRV::compile_preset_passes::< - CachedCompilation, - FilterChainError, - >(preset.shaders, &preset.textures)?; + let disable_cache = options.map_or(false, |o| o.disable_cache); + + let (passes, semantics) = if !disable_cache { + SPIRV::compile_preset_passes::, FilterChainError>( + preset.shaders, + &preset.textures, + )? + } else { + SPIRV::compile_preset_passes::( + preset.shaders, + &preset.textures, + )? + }; + let device = vulkan.try_into().map_err(From::from)?; let mut frames_in_flight = options.map_or(0, |o| o.frames_in_flight); @@ -325,6 +335,7 @@ impl FilterChainVulkan { &semantics, frames_in_flight, options.map_or(false, |o| o.use_render_pass), + disable_cache, )?; let luts = FilterChainVulkan::load_luts(&device, cmd, &preset.textures)?; @@ -388,6 +399,7 @@ impl FilterChainVulkan { semantics: &ShaderSemantics, frames_in_flight: u32, use_render_pass: bool, + disable_cache: bool, ) -> error::Result> { let frames_in_flight = std::cmp::max(1, frames_in_flight); @@ -430,6 +442,7 @@ impl FilterChainVulkan { &reflection, frames_in_flight, render_pass_format, + !disable_cache, )?; Ok(FilterPass { diff --git a/librashader-runtime-vk/src/graphics_pipeline.rs b/librashader-runtime-vk/src/graphics_pipeline.rs index 953a56b..19fd93b 100644 --- a/librashader-runtime-vk/src/graphics_pipeline.rs +++ b/librashader-runtime-vk/src/graphics_pipeline.rs @@ -314,6 +314,7 @@ impl VulkanGraphicsPipeline { reflection: &ShaderReflection, replicas: u32, render_pass_format: vk::Format, + cache_objects: bool, ) -> error::Result { let pipeline_layout = PipelineLayoutObjects::new(reflection, replicas, device)?; @@ -358,7 +359,7 @@ impl VulkanGraphicsPipeline { Ok::<_, FilterChainError>((pipeline, pipeline_cache)) }, |(_pipeline, cache)| unsafe { Ok(device.get_pipeline_cache_data(*cache)?) }, - true, + cache_objects, )?; Ok(VulkanGraphicsPipeline { diff --git a/librashader-runtime-vk/src/lib.rs b/librashader-runtime-vk/src/lib.rs index 0ef3bf6..9176315 100644 --- a/librashader-runtime-vk/src/lib.rs +++ b/librashader-runtime-vk/src/lib.rs @@ -51,6 +51,7 @@ mod tests { frames_in_flight: 3, force_no_mipmaps: false, use_render_pass: true, + disable_cache: false, }), ) .unwrap(); diff --git a/librashader-runtime-vk/src/options.rs b/librashader-runtime-vk/src/options.rs index 7ef3c6f..c327173 100644 --- a/librashader-runtime-vk/src/options.rs +++ b/librashader-runtime-vk/src/options.rs @@ -22,4 +22,7 @@ pub struct FilterChainOptionsVulkan { /// Use explicit render pass objects It is recommended if possible to use dynamic rendering, /// because render-pass mode will create new framebuffers per pass. pub use_render_pass: bool, + /// Disable the shader object cache. Shaders will be + /// recompiled rather than loaded from the cache. + pub disable_cache: bool, }