wgpu: enable pipeline caching
This commit is contained in:
parent
6ce711db26
commit
35f499f5e1
1
Cargo.lock
generated
1
Cargo.lock
generated
|
@ -1876,6 +1876,7 @@ dependencies = [
|
|||
"config",
|
||||
"env_logger",
|
||||
"image",
|
||||
"librashader-cache",
|
||||
"librashader-common",
|
||||
"librashader-preprocess",
|
||||
"librashader-presets",
|
||||
|
|
|
@ -16,3 +16,13 @@ impl Cacheable for Vec<u8> {
|
|||
Some(self.to_vec())
|
||||
}
|
||||
}
|
||||
|
||||
impl Cacheable for Option<Vec<u8>> {
|
||||
fn from_bytes(bytes: &[u8]) -> Option<Self> {
|
||||
Some(Some(Vec::from(bytes)))
|
||||
}
|
||||
|
||||
fn to_bytes(&self) -> Option<Vec<u8>> {
|
||||
self.clone()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,6 +19,7 @@ librashader-presets = { path = "../librashader-presets", version = "0.2.8" }
|
|||
librashader-preprocess = { path = "../librashader-preprocess", version = "0.2.8" }
|
||||
librashader-reflect = { path = "../librashader-reflect", version = "0.2.8", features = ["wgsl"], default-features = false }
|
||||
librashader-runtime = { path = "../librashader-runtime" , version = "0.2.8" }
|
||||
librashader-cache = { path = "../librashader-cache", version = "0.2.8" }
|
||||
|
||||
wgpu = { version = "22.0", default-features = false, features = ["wgsl"] }
|
||||
image = "0.25.1"
|
||||
|
|
|
@ -25,7 +25,7 @@ use librashader_reflect::reflect::naga::{Naga, NagaLoweringOptions};
|
|||
use librashader_runtime::framebuffer::FramebufferInit;
|
||||
use librashader_runtime::render_target::RenderTarget;
|
||||
use librashader_runtime::scaling::ScaleFramebuffer;
|
||||
use wgpu::{Device, TextureFormat};
|
||||
use wgpu::{AdapterInfo, Device, TextureFormat};
|
||||
|
||||
use crate::error;
|
||||
use crate::error::FilterChainError;
|
||||
|
@ -144,8 +144,17 @@ impl FilterChainWgpu {
|
|||
) -> error::Result<FilterChainWgpu> {
|
||||
let (passes, semantics) = compile_passes(preset.shaders, &preset.textures)?;
|
||||
|
||||
// // initialize passes
|
||||
let filters = Self::init_passes(Arc::clone(&device), passes, &semantics)?;
|
||||
// cache is opt-in for wgpu, not opt-out because of feature requirements.
|
||||
let disable_cache = options.map_or(true, |o| !o.enable_cache);
|
||||
|
||||
// initialize passes
|
||||
let filters = Self::init_passes(
|
||||
Arc::clone(&device),
|
||||
passes,
|
||||
&semantics,
|
||||
options.and_then(|o| o.adapter_info.as_ref()),
|
||||
disable_cache,
|
||||
)?;
|
||||
|
||||
let samplers = SamplerSet::new(&device);
|
||||
let mut mipmapper = MipmapGen::new(Arc::clone(&device));
|
||||
|
@ -268,6 +277,8 @@ impl FilterChainWgpu {
|
|||
device: Arc<Device>,
|
||||
passes: Vec<ShaderPassMeta>,
|
||||
semantics: &ShaderSemantics,
|
||||
adapter_info: Option<&wgpu::AdapterInfo>,
|
||||
disable_cache: bool,
|
||||
) -> error::Result<Box<[FilterPass]>> {
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
let filter_creation_fn = || {
|
||||
|
@ -320,6 +331,8 @@ impl FilterChainWgpu {
|
|||
&wgsl,
|
||||
&reflection,
|
||||
render_pass_format.unwrap_or(TextureFormat::Rgba8Unorm),
|
||||
adapter_info,
|
||||
disable_cache,
|
||||
);
|
||||
|
||||
Ok(FilterPass {
|
||||
|
|
|
@ -1,11 +1,14 @@
|
|||
use crate::error::FilterChainError;
|
||||
use crate::framebuffer::WgpuOutputView;
|
||||
use crate::util;
|
||||
use librashader_cache::cache_pipeline;
|
||||
use librashader_reflect::back::wgsl::NagaWgslContext;
|
||||
use librashader_reflect::back::ShaderCompilerOutput;
|
||||
use librashader_reflect::reflect::ShaderReflection;
|
||||
use librashader_runtime::quad::VertexInput;
|
||||
use librashader_runtime::render_target::RenderTarget;
|
||||
use std::borrow::Cow;
|
||||
use std::convert::Infallible;
|
||||
use std::sync::Arc;
|
||||
use wgpu::{
|
||||
BindGroupLayout, BindGroupLayoutDescriptor, BindGroupLayoutEntry, BindingType,
|
||||
|
@ -18,6 +21,7 @@ use wgpu::{
|
|||
pub struct WgpuGraphicsPipeline {
|
||||
pub layout: PipelineLayoutObjects,
|
||||
render_pipeline: wgpu::RenderPipeline,
|
||||
cache: Option<wgpu::PipelineCache>,
|
||||
pub format: wgpu::TextureFormat,
|
||||
}
|
||||
|
||||
|
@ -144,7 +148,11 @@ impl PipelineLayoutObjects {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn create_pipeline(&self, framebuffer_format: TextureFormat) -> wgpu::RenderPipeline {
|
||||
pub fn create_pipeline(
|
||||
&self,
|
||||
framebuffer_format: TextureFormat,
|
||||
cache: Option<&wgpu::PipelineCache>,
|
||||
) -> wgpu::RenderPipeline {
|
||||
self.device
|
||||
.create_render_pipeline(&wgpu::RenderPipelineDescriptor {
|
||||
label: Some("Render Pipeline"),
|
||||
|
@ -198,8 +206,7 @@ impl PipelineLayoutObjects {
|
|||
alpha_to_coverage_enabled: false,
|
||||
},
|
||||
multiview: None,
|
||||
// todo: WGPU pipeline caching!!
|
||||
cache: None,
|
||||
cache,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@ -210,18 +217,50 @@ impl WgpuGraphicsPipeline {
|
|||
shader_assembly: &ShaderCompilerOutput<String, NagaWgslContext>,
|
||||
reflection: &ShaderReflection,
|
||||
render_pass_format: TextureFormat,
|
||||
adapter_info: Option<&wgpu::AdapterInfo>,
|
||||
bypass_cache: bool,
|
||||
) -> Self {
|
||||
let cache = if bypass_cache {
|
||||
None
|
||||
} else {
|
||||
let name = adapter_info
|
||||
.and_then(|o| wgpu::util::pipeline_cache_key(o))
|
||||
.unwrap_or_else(|| String::from("wgpu"));
|
||||
|
||||
cache_pipeline(
|
||||
&name,
|
||||
&[
|
||||
&shader_assembly.vertex.as_str(),
|
||||
&shader_assembly.fragment.as_str(),
|
||||
],
|
||||
|pipeline_data| {
|
||||
let descriptor = wgpu::PipelineCacheDescriptor {
|
||||
label: Some("librashader-wgpu"),
|
||||
data: pipeline_data.as_deref(),
|
||||
fallback: true,
|
||||
};
|
||||
|
||||
let cache = unsafe { device.create_pipeline_cache(&descriptor) };
|
||||
Ok::<_, Infallible>(cache)
|
||||
},
|
||||
|cache| Ok(cache.get_data()),
|
||||
bypass_cache,
|
||||
)
|
||||
.ok()
|
||||
};
|
||||
|
||||
let layout = PipelineLayoutObjects::new(reflection, shader_assembly, device);
|
||||
let render_pipeline = layout.create_pipeline(render_pass_format);
|
||||
let render_pipeline = layout.create_pipeline(render_pass_format, cache.as_ref());
|
||||
Self {
|
||||
layout,
|
||||
render_pipeline,
|
||||
format: render_pass_format,
|
||||
cache,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn recompile(&mut self, format: TextureFormat) {
|
||||
let render_pipeline = self.layout.create_pipeline(format);
|
||||
let render_pipeline = self.layout.create_pipeline(format, self.cache.as_ref());
|
||||
self.render_pipeline = render_pipeline;
|
||||
}
|
||||
|
||||
|
|
|
@ -36,7 +36,6 @@ impl MipmapGen {
|
|||
depth_stencil: None,
|
||||
multisample: wgpu::MultisampleState::default(),
|
||||
multiview: None,
|
||||
// todo: caching!!
|
||||
cache: None,
|
||||
});
|
||||
|
||||
|
|
|
@ -9,4 +9,11 @@ impl_default_frame_options!(FrameOptionsWgpu);
|
|||
pub struct FilterChainOptionsWgpu {
|
||||
/// Whether or not to explicitly disable mipmap generation regardless of shader preset settings.
|
||||
pub force_no_mipmaps: bool,
|
||||
/// Enable the shader object cache. Shaders will be loaded from the cache
|
||||
/// if this is enabled.
|
||||
pub enable_cache: bool,
|
||||
/// WGPU adapter info for use to determine the name of the pipeline cache index.
|
||||
/// If this is not provided, then it will fallback to a default "wgpu" index, which
|
||||
/// may clobber the cache for a different device using WGPU.
|
||||
pub adapter_info: Option<wgpu::AdapterInfo>,
|
||||
}
|
||||
|
|
|
@ -93,9 +93,13 @@ impl<'a> State<'a> {
|
|||
let (device, queue) = adapter
|
||||
.request_device(
|
||||
&wgpu::DeviceDescriptor {
|
||||
required_features: wgpu::Features::ADDRESS_MODE_CLAMP_TO_BORDER,
|
||||
required_features: wgpu::Features::ADDRESS_MODE_CLAMP_TO_BORDER
|
||||
| wgpu::Features::PIPELINE_CACHE
|
||||
| wgpu::Features::TEXTURE_ADAPTER_SPECIFIC_FORMAT_FEATURES
|
||||
| wgpu::Features::FLOAT32_FILTERABLE,
|
||||
required_limits: wgpu::Limits::default(),
|
||||
label: None,
|
||||
memory_hints: Default::default(),
|
||||
},
|
||||
None,
|
||||
)
|
||||
|
@ -118,17 +122,14 @@ impl<'a> State<'a> {
|
|||
let device = Arc::new(device);
|
||||
let queue = Arc::new(queue);
|
||||
//
|
||||
// let preset = ShaderPreset::try_parse(
|
||||
// "../test/basic.slangp",
|
||||
// )
|
||||
// .unwrap();
|
||||
// let preset = ShaderPreset::try_parse("../test/basic.slangp").unwrap();
|
||||
//
|
||||
let preset = ShaderPreset::try_parse("../test/shaders_slang/test/history.slangp").unwrap();
|
||||
// let preset = ShaderPreset::try_parse("../test/shaders_slang/test/history.slangp").unwrap();
|
||||
|
||||
// let preset = ShaderPreset::try_parse(
|
||||
// "../test/shaders_slang/bezel/Mega_Bezel/Presets/MBZ__0__SMOOTH-ADV.slangp",
|
||||
// )
|
||||
// .unwrap();
|
||||
let preset = ShaderPreset::try_parse(
|
||||
"../test/shaders_slang/bezel/Mega_Bezel/Presets/MBZ__0__SMOOTH-ADV.slangp",
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let chain = FilterChainWgpu::load_from_preset(
|
||||
preset,
|
||||
|
@ -154,11 +155,13 @@ impl<'a> State<'a> {
|
|||
vertex: wgpu::VertexState {
|
||||
module: &shader,
|
||||
entry_point: "vs_main",
|
||||
compilation_options: Default::default(),
|
||||
buffers: &[Vertex::desc()],
|
||||
},
|
||||
fragment: Some(wgpu::FragmentState {
|
||||
module: &shader,
|
||||
entry_point: "fs_main",
|
||||
compilation_options: Default::default(),
|
||||
targets: &[Some(wgpu::ColorTargetState {
|
||||
format: config.format,
|
||||
blend: Some(wgpu::BlendState::REPLACE),
|
||||
|
@ -181,6 +184,7 @@ impl<'a> State<'a> {
|
|||
alpha_to_coverage_enabled: false,
|
||||
},
|
||||
multiview: None,
|
||||
cache: None,
|
||||
});
|
||||
|
||||
let vertex_buffer = device.create_buffer_init(&wgpu::util::BufferInitDescriptor {
|
||||
|
|
Loading…
Reference in a new issue