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",
|
"config",
|
||||||
"env_logger",
|
"env_logger",
|
||||||
"image",
|
"image",
|
||||||
|
"librashader-cache",
|
||||||
"librashader-common",
|
"librashader-common",
|
||||||
"librashader-preprocess",
|
"librashader-preprocess",
|
||||||
"librashader-presets",
|
"librashader-presets",
|
||||||
|
|
|
@ -16,3 +16,13 @@ impl Cacheable for Vec<u8> {
|
||||||
Some(self.to_vec())
|
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-preprocess = { path = "../librashader-preprocess", version = "0.2.8" }
|
||||||
librashader-reflect = { path = "../librashader-reflect", version = "0.2.8", features = ["wgsl"], default-features = false }
|
librashader-reflect = { path = "../librashader-reflect", version = "0.2.8", features = ["wgsl"], default-features = false }
|
||||||
librashader-runtime = { path = "../librashader-runtime" , version = "0.2.8" }
|
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"] }
|
wgpu = { version = "22.0", default-features = false, features = ["wgsl"] }
|
||||||
image = "0.25.1"
|
image = "0.25.1"
|
||||||
|
|
|
@ -25,7 +25,7 @@ use librashader_reflect::reflect::naga::{Naga, NagaLoweringOptions};
|
||||||
use librashader_runtime::framebuffer::FramebufferInit;
|
use librashader_runtime::framebuffer::FramebufferInit;
|
||||||
use librashader_runtime::render_target::RenderTarget;
|
use librashader_runtime::render_target::RenderTarget;
|
||||||
use librashader_runtime::scaling::ScaleFramebuffer;
|
use librashader_runtime::scaling::ScaleFramebuffer;
|
||||||
use wgpu::{Device, TextureFormat};
|
use wgpu::{AdapterInfo, Device, TextureFormat};
|
||||||
|
|
||||||
use crate::error;
|
use crate::error;
|
||||||
use crate::error::FilterChainError;
|
use crate::error::FilterChainError;
|
||||||
|
@ -144,8 +144,17 @@ impl FilterChainWgpu {
|
||||||
) -> error::Result<FilterChainWgpu> {
|
) -> error::Result<FilterChainWgpu> {
|
||||||
let (passes, semantics) = compile_passes(preset.shaders, &preset.textures)?;
|
let (passes, semantics) = compile_passes(preset.shaders, &preset.textures)?;
|
||||||
|
|
||||||
// // initialize passes
|
// cache is opt-in for wgpu, not opt-out because of feature requirements.
|
||||||
let filters = Self::init_passes(Arc::clone(&device), passes, &semantics)?;
|
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 samplers = SamplerSet::new(&device);
|
||||||
let mut mipmapper = MipmapGen::new(Arc::clone(&device));
|
let mut mipmapper = MipmapGen::new(Arc::clone(&device));
|
||||||
|
@ -268,6 +277,8 @@ impl FilterChainWgpu {
|
||||||
device: Arc<Device>,
|
device: Arc<Device>,
|
||||||
passes: Vec<ShaderPassMeta>,
|
passes: Vec<ShaderPassMeta>,
|
||||||
semantics: &ShaderSemantics,
|
semantics: &ShaderSemantics,
|
||||||
|
adapter_info: Option<&wgpu::AdapterInfo>,
|
||||||
|
disable_cache: bool,
|
||||||
) -> error::Result<Box<[FilterPass]>> {
|
) -> error::Result<Box<[FilterPass]>> {
|
||||||
#[cfg(not(target_arch = "wasm32"))]
|
#[cfg(not(target_arch = "wasm32"))]
|
||||||
let filter_creation_fn = || {
|
let filter_creation_fn = || {
|
||||||
|
@ -320,6 +331,8 @@ impl FilterChainWgpu {
|
||||||
&wgsl,
|
&wgsl,
|
||||||
&reflection,
|
&reflection,
|
||||||
render_pass_format.unwrap_or(TextureFormat::Rgba8Unorm),
|
render_pass_format.unwrap_or(TextureFormat::Rgba8Unorm),
|
||||||
|
adapter_info,
|
||||||
|
disable_cache,
|
||||||
);
|
);
|
||||||
|
|
||||||
Ok(FilterPass {
|
Ok(FilterPass {
|
||||||
|
|
|
@ -1,11 +1,14 @@
|
||||||
|
use crate::error::FilterChainError;
|
||||||
use crate::framebuffer::WgpuOutputView;
|
use crate::framebuffer::WgpuOutputView;
|
||||||
use crate::util;
|
use crate::util;
|
||||||
|
use librashader_cache::cache_pipeline;
|
||||||
use librashader_reflect::back::wgsl::NagaWgslContext;
|
use librashader_reflect::back::wgsl::NagaWgslContext;
|
||||||
use librashader_reflect::back::ShaderCompilerOutput;
|
use librashader_reflect::back::ShaderCompilerOutput;
|
||||||
use librashader_reflect::reflect::ShaderReflection;
|
use librashader_reflect::reflect::ShaderReflection;
|
||||||
use librashader_runtime::quad::VertexInput;
|
use librashader_runtime::quad::VertexInput;
|
||||||
use librashader_runtime::render_target::RenderTarget;
|
use librashader_runtime::render_target::RenderTarget;
|
||||||
use std::borrow::Cow;
|
use std::borrow::Cow;
|
||||||
|
use std::convert::Infallible;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use wgpu::{
|
use wgpu::{
|
||||||
BindGroupLayout, BindGroupLayoutDescriptor, BindGroupLayoutEntry, BindingType,
|
BindGroupLayout, BindGroupLayoutDescriptor, BindGroupLayoutEntry, BindingType,
|
||||||
|
@ -18,6 +21,7 @@ use wgpu::{
|
||||||
pub struct WgpuGraphicsPipeline {
|
pub struct WgpuGraphicsPipeline {
|
||||||
pub layout: PipelineLayoutObjects,
|
pub layout: PipelineLayoutObjects,
|
||||||
render_pipeline: wgpu::RenderPipeline,
|
render_pipeline: wgpu::RenderPipeline,
|
||||||
|
cache: Option<wgpu::PipelineCache>,
|
||||||
pub format: wgpu::TextureFormat,
|
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
|
self.device
|
||||||
.create_render_pipeline(&wgpu::RenderPipelineDescriptor {
|
.create_render_pipeline(&wgpu::RenderPipelineDescriptor {
|
||||||
label: Some("Render Pipeline"),
|
label: Some("Render Pipeline"),
|
||||||
|
@ -198,8 +206,7 @@ impl PipelineLayoutObjects {
|
||||||
alpha_to_coverage_enabled: false,
|
alpha_to_coverage_enabled: false,
|
||||||
},
|
},
|
||||||
multiview: None,
|
multiview: None,
|
||||||
// todo: WGPU pipeline caching!!
|
cache,
|
||||||
cache: None,
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -210,18 +217,50 @@ impl WgpuGraphicsPipeline {
|
||||||
shader_assembly: &ShaderCompilerOutput<String, NagaWgslContext>,
|
shader_assembly: &ShaderCompilerOutput<String, NagaWgslContext>,
|
||||||
reflection: &ShaderReflection,
|
reflection: &ShaderReflection,
|
||||||
render_pass_format: TextureFormat,
|
render_pass_format: TextureFormat,
|
||||||
|
adapter_info: Option<&wgpu::AdapterInfo>,
|
||||||
|
bypass_cache: bool,
|
||||||
) -> Self {
|
) -> 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 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 {
|
Self {
|
||||||
layout,
|
layout,
|
||||||
render_pipeline,
|
render_pipeline,
|
||||||
format: render_pass_format,
|
format: render_pass_format,
|
||||||
|
cache,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn recompile(&mut self, format: TextureFormat) {
|
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;
|
self.render_pipeline = render_pipeline;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -36,7 +36,6 @@ impl MipmapGen {
|
||||||
depth_stencil: None,
|
depth_stencil: None,
|
||||||
multisample: wgpu::MultisampleState::default(),
|
multisample: wgpu::MultisampleState::default(),
|
||||||
multiview: None,
|
multiview: None,
|
||||||
// todo: caching!!
|
|
||||||
cache: None,
|
cache: None,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -9,4 +9,11 @@ impl_default_frame_options!(FrameOptionsWgpu);
|
||||||
pub struct FilterChainOptionsWgpu {
|
pub struct FilterChainOptionsWgpu {
|
||||||
/// Whether or not to explicitly disable mipmap generation regardless of shader preset settings.
|
/// Whether or not to explicitly disable mipmap generation regardless of shader preset settings.
|
||||||
pub force_no_mipmaps: bool,
|
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
|
let (device, queue) = adapter
|
||||||
.request_device(
|
.request_device(
|
||||||
&wgpu::DeviceDescriptor {
|
&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(),
|
required_limits: wgpu::Limits::default(),
|
||||||
label: None,
|
label: None,
|
||||||
|
memory_hints: Default::default(),
|
||||||
},
|
},
|
||||||
None,
|
None,
|
||||||
)
|
)
|
||||||
|
@ -118,17 +122,14 @@ impl<'a> State<'a> {
|
||||||
let device = Arc::new(device);
|
let device = Arc::new(device);
|
||||||
let queue = Arc::new(queue);
|
let queue = Arc::new(queue);
|
||||||
//
|
//
|
||||||
// let preset = ShaderPreset::try_parse(
|
// let preset = ShaderPreset::try_parse("../test/basic.slangp").unwrap();
|
||||||
// "../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(
|
let preset = ShaderPreset::try_parse(
|
||||||
// "../test/shaders_slang/bezel/Mega_Bezel/Presets/MBZ__0__SMOOTH-ADV.slangp",
|
"../test/shaders_slang/bezel/Mega_Bezel/Presets/MBZ__0__SMOOTH-ADV.slangp",
|
||||||
// )
|
)
|
||||||
// .unwrap();
|
.unwrap();
|
||||||
|
|
||||||
let chain = FilterChainWgpu::load_from_preset(
|
let chain = FilterChainWgpu::load_from_preset(
|
||||||
preset,
|
preset,
|
||||||
|
@ -154,11 +155,13 @@ impl<'a> State<'a> {
|
||||||
vertex: wgpu::VertexState {
|
vertex: wgpu::VertexState {
|
||||||
module: &shader,
|
module: &shader,
|
||||||
entry_point: "vs_main",
|
entry_point: "vs_main",
|
||||||
|
compilation_options: Default::default(),
|
||||||
buffers: &[Vertex::desc()],
|
buffers: &[Vertex::desc()],
|
||||||
},
|
},
|
||||||
fragment: Some(wgpu::FragmentState {
|
fragment: Some(wgpu::FragmentState {
|
||||||
module: &shader,
|
module: &shader,
|
||||||
entry_point: "fs_main",
|
entry_point: "fs_main",
|
||||||
|
compilation_options: Default::default(),
|
||||||
targets: &[Some(wgpu::ColorTargetState {
|
targets: &[Some(wgpu::ColorTargetState {
|
||||||
format: config.format,
|
format: config.format,
|
||||||
blend: Some(wgpu::BlendState::REPLACE),
|
blend: Some(wgpu::BlendState::REPLACE),
|
||||||
|
@ -181,6 +184,7 @@ impl<'a> State<'a> {
|
||||||
alpha_to_coverage_enabled: false,
|
alpha_to_coverage_enabled: false,
|
||||||
},
|
},
|
||||||
multiview: None,
|
multiview: None,
|
||||||
|
cache: None,
|
||||||
});
|
});
|
||||||
|
|
||||||
let vertex_buffer = device.create_buffer_init(&wgpu::util::BufferInitDescriptor {
|
let vertex_buffer = device.create_buffer_init(&wgpu::util::BufferInitDescriptor {
|
||||||
|
|
Loading…
Reference in a new issue