rt(wgpu): load shaders

This commit is contained in:
chyyran 2023-11-30 01:49:22 -05:00 committed by Ronny Chan
parent c05d8ff06a
commit 1a16c4fadf
9 changed files with 338 additions and 39 deletions

View file

@ -18,10 +18,12 @@ d3d11 = ["windows", "dxgi"]
d3d12 = ["windows", "dxgi"] d3d12 = ["windows", "dxgi"]
dxgi = ["windows"] dxgi = ["windows"]
vulkan = ["ash"] vulkan = ["ash"]
wgpu = ["wgpu-types"]
[dependencies] [dependencies]
gl = { version = "0.14.0", optional = true } gl = { version = "0.14.0", optional = true }
ash = { version = "0.37", optional = true } ash = { version = "0.37", optional = true }
wgpu-types = { version = "0.18.0", optional = true }
num-traits = "0.2.15" num-traits = "0.2.15"

View file

@ -8,6 +8,10 @@ pub mod gl;
#[cfg(feature = "vulkan")] #[cfg(feature = "vulkan")]
pub mod vk; pub mod vk;
/// WGPU common conversions.
#[cfg(feature = "wgpu")]
pub mod wgpu;
/// DXGI common conversions. /// DXGI common conversions.
#[cfg(all(target_os = "windows", feature = "dxgi"))] #[cfg(all(target_os = "windows", feature = "dxgi"))]
pub mod dxgi; pub mod dxgi;
@ -21,6 +25,7 @@ pub mod d3d11;
pub mod d3d12; pub mod d3d12;
mod viewport; mod viewport;
pub use viewport::Viewport; pub use viewport::Viewport;
use num_traits::AsPrimitive; use num_traits::AsPrimitive;

View file

@ -0,0 +1,177 @@
use crate::{FilterMode, ImageFormat, Size, WrapMode};
impl From<ImageFormat> for Option<wgpu_types::TextureFormat> {
fn from(format: ImageFormat) -> Self {
match format {
ImageFormat::Unknown => None,
ImageFormat::R8Unorm => Some(wgpu_types::TextureFormat::R8Unorm),
ImageFormat::R8Uint => Some(wgpu_types::TextureFormat::R8Uint),
ImageFormat::R8Sint => Some(wgpu_types::TextureFormat::R8Sint),
ImageFormat::R8G8Unorm => Some(wgpu_types::TextureFormat::Rg8Unorm),
ImageFormat::R8G8Uint => Some(wgpu_types::TextureFormat::Rg8Uint),
ImageFormat::R8G8Sint => Some(wgpu_types::TextureFormat::Rg8Sint),
ImageFormat::R8G8B8A8Unorm => Some(wgpu_types::TextureFormat::Rgba8Unorm),
ImageFormat::R8G8B8A8Uint => Some(wgpu_types::TextureFormat::Rgba8Uint),
ImageFormat::R8G8B8A8Sint => Some(wgpu_types::TextureFormat::Rgba8Sint),
ImageFormat::R8G8B8A8Srgb => Some(wgpu_types::TextureFormat::Rgba8UnormSrgb),
ImageFormat::A2B10G10R10UnormPack32 => Some(wgpu_types::TextureFormat::Rgb10a2Unorm),
ImageFormat::A2B10G10R10UintPack32 => Some(wgpu_types::TextureFormat::Rgb10a2Uint),
ImageFormat::R16Uint => Some(wgpu_types::TextureFormat::R16Uint),
ImageFormat::R16Sint => Some(wgpu_types::TextureFormat::R16Sint),
ImageFormat::R16Sfloat => Some(wgpu_types::TextureFormat::R16Float),
ImageFormat::R16G16Uint => Some(wgpu_types::TextureFormat::Rg16Uint),
ImageFormat::R16G16Sint => Some(wgpu_types::TextureFormat::Rg16Sint),
ImageFormat::R16G16Sfloat => Some(wgpu_types::TextureFormat::Rg16Float),
ImageFormat::R16G16B16A16Uint => Some(wgpu_types::TextureFormat::Rgba16Uint),
ImageFormat::R16G16B16A16Sint => Some(wgpu_types::TextureFormat::Rgba16Sint),
ImageFormat::R16G16B16A16Sfloat => Some(wgpu_types::TextureFormat::Rgba16Float),
ImageFormat::R32Uint => Some(wgpu_types::TextureFormat::R32Uint),
ImageFormat::R32Sint => Some(wgpu_types::TextureFormat::R32Sint),
ImageFormat::R32Sfloat => Some(wgpu_types::TextureFormat::R32Float),
ImageFormat::R32G32Uint => Some(wgpu_types::TextureFormat::Rg32Uint),
ImageFormat::R32G32Sint => Some(wgpu_types::TextureFormat::Rg32Sint),
ImageFormat::R32G32Sfloat => Some(wgpu_types::TextureFormat::Rg32Float),
ImageFormat::R32G32B32A32Uint => Some(wgpu_types::TextureFormat::Rgba32Uint),
ImageFormat::R32G32B32A32Sint => Some(wgpu_types::TextureFormat::Rgba32Sint),
ImageFormat::R32G32B32A32Sfloat => Some(wgpu_types::TextureFormat::Rgba32Float),
}
}
}
impl From<wgpu_types::TextureFormat> for ImageFormat {
fn from(format: wgpu_types::TextureFormat) -> Self {
match format {
wgpu_types::TextureFormat::R8Unorm => ImageFormat::R8Unorm,
wgpu_types::TextureFormat::R8Uint => ImageFormat::R8Uint,
wgpu_types::TextureFormat::R8Sint => ImageFormat::R8Sint,
wgpu_types::TextureFormat::Rg8Unorm => ImageFormat::R8G8Unorm,
wgpu_types::TextureFormat::Rg8Uint => ImageFormat::R8G8Uint,
wgpu_types::TextureFormat::Rg8Sint => ImageFormat::R8G8Sint,
wgpu_types::TextureFormat::Rgba8Unorm => ImageFormat::R8G8B8A8Unorm,
wgpu_types::TextureFormat::Rgba8Uint => ImageFormat::R8G8B8A8Uint,
wgpu_types::TextureFormat::Rgba8Sint => ImageFormat::R8G8B8A8Sint,
wgpu_types::TextureFormat::Rgba8UnormSrgb => ImageFormat::R8G8B8A8Srgb,
wgpu_types::TextureFormat::Rgb10a2Unorm => ImageFormat::A2B10G10R10UnormPack32,
wgpu_types::TextureFormat::Rgb10a2Uint => ImageFormat::A2B10G10R10UintPack32,
wgpu_types::TextureFormat::R16Uint => ImageFormat::R16Uint,
wgpu_types::TextureFormat::R16Sint => ImageFormat::R16Sint,
wgpu_types::TextureFormat::R16Float => ImageFormat::R16Sfloat,
wgpu_types::TextureFormat::Rg16Uint => ImageFormat::R16G16Uint,
wgpu_types::TextureFormat::Rg16Sint => ImageFormat::R16G16Sint,
wgpu_types::TextureFormat::Rg16Float => ImageFormat::R16G16Sfloat,
wgpu_types::TextureFormat::Rgba16Uint => ImageFormat::R16G16B16A16Uint,
wgpu_types::TextureFormat::Rgba16Sint => ImageFormat::R16G16B16A16Sint,
wgpu_types::TextureFormat::Rgba16Float => ImageFormat::R16G16B16A16Sfloat,
wgpu_types::TextureFormat::R32Uint => ImageFormat::R32Uint,
wgpu_types::TextureFormat::R32Sint => ImageFormat::R32Sint,
wgpu_types::TextureFormat::R32Float => ImageFormat::R32Sfloat,
wgpu_types::TextureFormat::Rg32Uint => ImageFormat::R32G32Uint,
wgpu_types::TextureFormat::Rg32Sint => ImageFormat::R32G32Sint,
wgpu_types::TextureFormat::Rg32Float => ImageFormat::R32G32Sfloat,
wgpu_types::TextureFormat::Rgba32Uint => ImageFormat::R32G32B32A32Uint,
wgpu_types::TextureFormat::Rgba32Sint => ImageFormat::R32G32B32A32Sint,
wgpu_types::TextureFormat::Rgba32Float => ImageFormat::R32G32B32A32Sfloat,
_ => ImageFormat::Unknown
}
}
}
impl From<Option<wgpu_types::TextureFormat>> for ImageFormat {
fn from(format: Option<wgpu_types::TextureFormat>) -> Self {
let Some(format) = format else {
return ImageFormat::Unknown;
};
ImageFormat::from(format)
}
}
//
// impl From<Size<u32>> for vk::Extent3D {
// fn from(value: Size<u32>) -> Self {
// vk::Extent3D {
// width: value.width,
// height: value.height,
// depth: 1,
// }
// }
// }
//
// impl From<Size<u32>> for vk::Extent2D {
// fn from(value: Size<u32>) -> Self {
// vk::Extent2D {
// width: value.width,
// height: value.height,
// }
// }
// }
//
// impl From<vk::Extent3D> for Size<u32> {
// fn from(value: vk::Extent3D) -> Self {
// Size {
// width: value.width,
// height: value.height,
// }
// }
// }
//
// impl From<vk::Extent2D> for Size<u32> {
// fn from(value: vk::Extent2D) -> Self {
// Size {
// width: value.width,
// height: value.height,
// }
// }
// }
//
// impl From<vk::Viewport> for Size<u32> {
// fn from(value: vk::Viewport) -> Self {
// Size {
// width: value.width as u32,
// height: value.height as u32,
// }
// }
// }
//
// impl From<&vk::Viewport> for Size<u32> {
// fn from(value: &vk::Viewport) -> Self {
// Size {
// width: value.width as u32,
// height: value.height as u32,
// }
// }
// }
//
// impl From<Size<u32>> for vk::Viewport {
// fn from(value: Size<u32>) -> Self {
// vk::Viewport {
// x: 0.0,
// y: 0.0,
// width: value.width as f32,
// height: value.height as f32,
// min_depth: 0.0,
// max_depth: 1.0,
// }
// }
// }
impl From<FilterMode> for wgpu_types::FilterMode {
fn from(value: FilterMode) -> Self {
match value {
FilterMode::Linear => wgpu_types::FilterMode::Linear,
FilterMode::Nearest => wgpu_types::FilterMode::Nearest,
}
}
}
impl From<WrapMode> for wgpu_types::AddressMode {
fn from(value: WrapMode) -> Self {
match value {
WrapMode::ClampToBorder => wgpu_types::AddressMode::ClampToBorder,
WrapMode::ClampToEdge => wgpu_types::AddressMode::ClampToEdge,
WrapMode::Repeat => wgpu_types::AddressMode::Repeat,
WrapMode::MirroredRepeat => wgpu_types::AddressMode::MirrorRepeat,
}
}
}

View file

@ -0,0 +1,37 @@
[package]
name = "librashader-runtime-wgpu"
version = "0.1.0"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
librashader-common = { path = "../librashader-common", features = ["wgpu"], version = "0.1.4" }
librashader-presets = { path = "../librashader-presets", version = "0.1.4" }
librashader-preprocess = { path = "../librashader-preprocess", version = "0.1.4" }
librashader-reflect = { path = "../librashader-reflect", version = "0.1.4", features = [] }
librashader-runtime = { path = "../librashader-runtime" , version = "0.1.4" }
librashader-cache = { path = "../librashader-cache", version = "0.1.4" }
wgpu = { version = "0.18.0", features = ["spirv"] }
rustc-hash = "1.1.0"
image = "0.24.7"
thiserror = "1.0.50"
spirv_cross = { package = "librashader-spirv-cross", version = "0.23" }
parking_lot = "0.12.1"
rayon = "1.8.0"
bytemuck = { version = "1.14.0", features = ["derive"] }
[dev-dependencies]
config = { version = "0.13.4", features = [] }
env_logger = "0.10.1"
raw-window-handle = "0.5"
winit = "0.28.7"
pollster = "0.3"
log = "0.4.20"
[[test]]
name = "triangle"

View file

@ -21,10 +21,13 @@ 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 rayon::prelude::*; use rayon::prelude::*;
use wgpu::{CommandBuffer, CommandEncoder, Device, Queue, TextureFormat};
use librashader_common::ImageFormat;
use crate::error; use crate::error;
use crate::error::FilterChainError; use crate::error::FilterChainError;
use crate::filter_pass::FilterPass; use crate::filter_pass::FilterPass;
use crate::graphics_pipeline::WgpuGraphicsPipeline;
type ShaderPassMeta = type ShaderPassMeta =
ShaderPassArtifact<impl CompileReflectShader<SPIRV, GlslangCompilation> + Send>; ShaderPassArtifact<impl CompileReflectShader<SPIRV, GlslangCompilation> + Send>;
@ -47,7 +50,7 @@ fn compile_passes(
/// A Vulkan filter chain. /// A Vulkan filter chain.
pub struct FilterChainWGPU { pub struct FilterChainWGPU {
pub(crate) common: FilterCommon, pub(crate) common: FilterCommon,
// passes: Box<[FilterPass]>, passes: Box<[FilterPass]>,
// vulkan: VulkanObjects, // vulkan: VulkanObjects,
// output_framebuffers: Box<[OwnedImage]>, // output_framebuffers: Box<[OwnedImage]>,
// feedback_framebuffers: Box<[OwnedImage]>, // feedback_framebuffers: Box<[OwnedImage]>,
@ -81,7 +84,9 @@ impl FilterChainWGPU {
/// The provided command buffer must be ready for recording and contain no prior commands. /// The provided command buffer must be ready for recording and contain no prior commands.
/// The caller is responsible for ending the command buffer and immediately submitting it to a /// The caller is responsible for ending the command buffer and immediately submitting it to a
/// graphics queue. The command buffer must be completely executed before calling [`frame`](Self::frame). /// graphics queue. The command buffer must be completely executed before calling [`frame`](Self::frame).
pub unsafe fn load_from_preset_deferred( pub fn load_from_preset_deferred(
device: &Device,
// cmd: &mut CommandEncoder,
preset: ShaderPreset, preset: ShaderPreset,
) -> error::Result<FilterChainWGPU> ) -> error::Result<FilterChainWGPU>
@ -90,7 +95,6 @@ impl FilterChainWGPU {
let disable_cache = true; let disable_cache = true;
let (passes, semantics) = compile_passes(preset.shaders, &preset.textures, disable_cache)?; let (passes, semantics) = compile_passes(preset.shaders, &preset.textures, disable_cache)?;
todo!()
// let device = vulkan.try_into().map_err(From::from)?; // let device = vulkan.try_into().map_err(From::from)?;
// //
// let mut frames_in_flight = options.map_or(0, |o| o.frames_in_flight); // let mut frames_in_flight = options.map_or(0, |o| o.frames_in_flight);
@ -99,14 +103,12 @@ impl FilterChainWGPU {
// } // }
// //
// // initialize passes // // initialize passes
// let filters = Self::init_passes( let filters = Self::init_passes(
// &device, &device,
// passes, passes,
// &semantics, &semantics,
// frames_in_flight, disable_cache,
// options.map_or(false, |o| o.use_render_pass), )?;
// disable_cache,
// )?;
// //
// let luts = FilterChainVulkan::load_luts(&device, cmd, &preset.textures)?; // let luts = FilterChainVulkan::load_luts(&device, cmd, &preset.textures)?;
// let samplers = SamplerSet::new(&device.device)?; // let samplers = SamplerSet::new(&device.device)?;
@ -162,9 +164,15 @@ impl FilterChainWGPU {
// residuals: intermediates.into_boxed_slice(), // residuals: intermediates.into_boxed_slice(),
// disable_mipmaps: options.map_or(false, |o| o.force_no_mipmaps), // disable_mipmaps: options.map_or(false, |o| o.force_no_mipmaps),
// }) // })
Ok(FilterChainWGPU {
common: FilterCommon {},
passes: filters,
})
} }
fn init_passes( fn init_passes(
device: &Device,
passes: Vec<ShaderPassMeta>, passes: Vec<ShaderPassMeta>,
semantics: &ShaderSemantics, semantics: &ShaderSemantics,
disable_cache: bool, disable_cache: bool,
@ -179,31 +187,31 @@ impl FilterChainWGPU {
let spirv_words = reflect.compile(None)?; let spirv_words = reflect.compile(None)?;
let ubo_size = reflection.ubo.as_ref().map_or(0, |ubo| ubo.size as usize); let ubo_size = reflection.ubo.as_ref().map_or(0, |ubo| ubo.size as usize);
// let uniform_storage = UniformStorage::new_with_ubo_storage(
// RawVulkanBuffer::new( let uniform_storage = UniformStorage::new(
// &vulkan.device, ubo_size,
// &vulkan.alloc, reflection
// vk::BufferUsageFlags::UNIFORM_BUFFER, .push_constant
// ubo_size, .as_ref()
// )?, .map_or(0, |push| push.size as usize),
// reflection );
// .push_constant
// .as_ref()
// .map_or(0, |push| push.size as usize),
// );
//
let uniform_bindings = reflection.meta.create_binding_map(|param| param.offset()); let uniform_bindings = reflection.meta.create_binding_map(|param| param.offset());
// //
// let render_pass_format = if !use_render_pass { let render_pass_format: Option<TextureFormat> = if let Some(format) = config.get_format_override() {
// vk::Format::UNDEFINED format.into()
// } else if let Some(format) = config.get_format_override() { } else {
// format.into() source.format.into()
// } else if source.format != ImageFormat::Unknown { };
// source.format.into()
// } else {
// ImageFormat::R8G8B8A8Unorm.into() let graphics_pipeline = WgpuGraphicsPipeline::new(
// }; device,
// &spirv_words,
&reflection,
render_pass_format.unwrap_or(TextureFormat::R8Unorm)
);
// let graphics_pipeline = VulkanGraphicsPipeline::new( // let graphics_pipeline = VulkanGraphicsPipeline::new(
// &vulkan.device, // &vulkan.device,
// &spirv_words, // &spirv_words,
@ -217,11 +225,11 @@ impl FilterChainWGPU {
// device: vulkan.device.clone(), // device: vulkan.device.clone(),
reflection, reflection,
compiled: spirv_words, compiled: spirv_words,
// uniform_storage, uniform_storage,
uniform_bindings, uniform_bindings,
source, source,
config, config,
// graphics_pipeline, graphics_pipeline,
// // ubo_ring, // // ubo_ring,
// frames_in_flight, // frames_in_flight,
}) })

View file

@ -6,15 +6,16 @@ use librashader_reflect::back::ShaderCompilerOutput;
use librashader_reflect::reflect::semantics::{MemberOffset, UniformBinding}; use librashader_reflect::reflect::semantics::{MemberOffset, UniformBinding};
use librashader_reflect::reflect::ShaderReflection; use librashader_reflect::reflect::ShaderReflection;
use librashader_runtime::uniforms::{NoUniformBinder, UniformStorage}; use librashader_runtime::uniforms::{NoUniformBinder, UniformStorage};
use crate::graphics_pipeline::WgpuGraphicsPipeline;
pub struct FilterPass { pub struct FilterPass {
pub reflection: ShaderReflection, pub reflection: ShaderReflection,
pub(crate) compiled: ShaderCompilerOutput<Vec<u32>>, pub(crate) compiled: ShaderCompilerOutput<Vec<u32>>,
// pub(crate) uniform_storage: UniformStorage<NoUniformBinder, Option<()>, RawVulkanBuffer>, pub(crate) uniform_storage: UniformStorage,
pub uniform_bindings: FxHashMap<UniformBinding, MemberOffset>, pub uniform_bindings: FxHashMap<UniformBinding, MemberOffset>,
pub source: ShaderSource, pub source: ShaderSource,
pub config: ShaderPassConfig, pub config: ShaderPassConfig,
// pub graphics_pipeline: VulkanGraphicsPipeline, pub graphics_pipeline: WgpuGraphicsPipeline,
// pub ubo_ring: VkUboRing, // pub ubo_ring: VkUboRing,
// pub frames_in_flight: u32, // pub frames_in_flight: u32,
} }

View file

@ -0,0 +1,44 @@
use std::borrow::Cow;
use std::sync::Arc;
use wgpu::{Device, ShaderModule, ShaderSource, TextureFormat};
use librashader_reflect::back::ShaderCompilerOutput;
use librashader_reflect::reflect::ShaderReflection;
pub struct WgpuGraphicsPipeline {
vertex: ShaderModule,
fragment: ShaderModule
}
impl WgpuGraphicsPipeline {
pub fn new(
device: &Device,
shader_assembly: &ShaderCompilerOutput<Vec<u32>>,
reflection: &ShaderReflection,
render_pass_format: TextureFormat,
) -> Self {
let vertex = unsafe {
device.create_shader_module_spirv(&wgpu::ShaderModuleDescriptorSpirV {
label: Some("vertex"),
source: Cow::from(&shader_assembly.vertex),
})
};
let fragment = unsafe {
device.create_shader_module_spirv(&wgpu::ShaderModuleDescriptorSpirV {
label: Some("fragment"),
source: Cow::from(&shader_assembly.fragment),
})
};
// let render_pipeline_layout =
// device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor {
// label: Some("Render Pipeline Layout"),
// bind_group_layouts: &[],
// push_constant_ranges: &[],
// });
Self {
vertex,
fragment
}
}
}

View file

@ -0,0 +1,18 @@
//! librashader WGPU runtime
//!
//! This crate should not be used directly.
//! See [`librashader::runtime::wgpu`](https://docs.rs/librashader/latest/librashader/runtime/wgpu/index.html) instead.
#![deny(unsafe_op_in_unsafe_fn)]
#![feature(type_alias_impl_trait)]
#![feature(let_chains)]
#![feature(strict_provenance)]
mod filter_chain;
mod error;
mod texture;
mod filter_pass;
mod graphics_pipeline;
pub use filter_chain::FilterChainWGPU;
pub use filter_pass::FilterPass;

View file

@ -7,6 +7,8 @@ use winit::{
use wgpu::util::DeviceExt; use wgpu::util::DeviceExt;
use winit::event_loop::EventLoopBuilder; use winit::event_loop::EventLoopBuilder;
use winit::platform::windows::EventLoopBuilderExtWindows; use winit::platform::windows::EventLoopBuilderExtWindows;
use librashader_presets::ShaderPreset;
use librashader_runtime_wgpu::FilterChainWGPU;
#[cfg(target_arch = "wasm32")] #[cfg(target_arch = "wasm32")]
use wasm_bindgen::prelude::*; use wasm_bindgen::prelude::*;
@ -69,6 +71,7 @@ struct State {
vertex_buffer: wgpu::Buffer, vertex_buffer: wgpu::Buffer,
num_vertices: u32, num_vertices: u32,
chain: FilterChainWGPU
} }
impl State { impl State {
async fn new(window: &Window) -> Self { async fn new(window: &Window) -> Self {
@ -89,7 +92,7 @@ impl State {
let (device, queue) = adapter let (device, queue) = adapter
.request_device( .request_device(
&wgpu::DeviceDescriptor { &wgpu::DeviceDescriptor {
features: wgpu::Features::empty(), features: wgpu::Features::PUSH_CONSTANTS | wgpu::Features::SPIRV_SHADER_PASSTHROUGH,
limits: wgpu::Limits::default(), limits: wgpu::Limits::default(),
label: None, label: None,
}, },
@ -110,6 +113,9 @@ impl State {
view_formats: vec![], view_formats: vec![],
}; };
let preset = ShaderPreset::try_parse("../test/shaders_slang/crt/crt-royale.slangp").unwrap();
let chain = FilterChainWGPU::load_from_preset_deferred(&device, preset).unwrap();
let shader = device.create_shader_module(wgpu::ShaderModuleDescriptor { let shader = device.create_shader_module(wgpu::ShaderModuleDescriptor {
label: Some("Shader"), label: Some("Shader"),
source: wgpu::ShaderSource::Wgsl(include_str!("../shader/triangle.wgsl").into()), source: wgpu::ShaderSource::Wgsl(include_str!("../shader/triangle.wgsl").into()),
@ -183,6 +189,7 @@ impl State {
render_pipeline, render_pipeline,
vertex_buffer, vertex_buffer,
num_vertices, num_vertices,
chain
} }
} }
fn resize(&mut self, new_size: winit::dpi::PhysicalSize<u32>) { fn resize(&mut self, new_size: winit::dpi::PhysicalSize<u32>) {