rt(wgpu): add structure to wgpu backend

This commit is contained in:
chyyran 2023-12-16 20:28:41 +09:00 committed by Ronny Chan
parent 8cfe1e9da2
commit 2b995539f2
19 changed files with 566 additions and 282 deletions

View file

@ -12,10 +12,8 @@
<cargoProject FILE="$PROJECT_DIR$/Cargo.toml" /> <cargoProject FILE="$PROJECT_DIR$/Cargo.toml" />
</component> </component>
<component name="ChangeListManager"> <component name="ChangeListManager">
<list default="true" id="02471831-07cd-4975-a00c-e042450023a1" name="Changes" comment="rt(wgpu): create pipeline bind group layouts"> <list default="true" id="02471831-07cd-4975-a00c-e042450023a1" name="Changes" comment="rt(wgpu): create pipeline">
<change afterPath="$PROJECT_DIR$/librashader-runtime-wgpu/src/samplers.rs" afterDir="false" />
<change beforePath="$PROJECT_DIR$/.idea/workspace.xml" beforeDir="false" afterPath="$PROJECT_DIR$/.idea/workspace.xml" afterDir="false" /> <change beforePath="$PROJECT_DIR$/.idea/workspace.xml" beforeDir="false" afterPath="$PROJECT_DIR$/.idea/workspace.xml" afterDir="false" />
<change beforePath="$PROJECT_DIR$/librashader-runtime-wgpu/src/lib.rs" beforeDir="false" afterPath="$PROJECT_DIR$/librashader-runtime-wgpu/src/lib.rs" afterDir="false" />
</list> </list>
<option name="SHOW_DIALOG" value="false" /> <option name="SHOW_DIALOG" value="false" />
<option name="HIGHLIGHT_CONFLICTS" value="true" /> <option name="HIGHLIGHT_CONFLICTS" value="true" />
@ -58,39 +56,39 @@
<option name="hideEmptyMiddlePackages" value="true" /> <option name="hideEmptyMiddlePackages" value="true" />
<option name="showLibraryContents" value="true" /> <option name="showLibraryContents" value="true" />
</component> </component>
<component name="PropertiesComponent">{ <component name="PropertiesComponent"><![CDATA[{
&quot;keyToString&quot;: { "keyToString": {
&quot;Cargo.Build `Test back::wgsl::test::test_into`.executor&quot;: &quot;Run&quot;, "Cargo.Build `Test back::wgsl::test::test_into`.executor": "Run",
&quot;Cargo.Build `Test reflect::cross::test::test_into`.executor&quot;: &quot;Run&quot;, "Cargo.Build `Test reflect::cross::test::test_into`.executor": "Run",
&quot;Cargo.Test back::wgsl::test::test_into.executor&quot;: &quot;Run&quot;, "Cargo.Test back::wgsl::test::test_into.executor": "Run",
&quot;Cargo.Test front::naga::test::naga_playground (1).executor&quot;: &quot;Run&quot;, "Cargo.Test front::naga::test::naga_playground (1).executor": "Run",
&quot;Cargo.Test front::naga::test::naga_playground.executor&quot;: &quot;Run&quot;, "Cargo.Test front::naga::test::naga_playground.executor": "Run",
&quot;Cargo.Test reflect::cross::test::test_into.executor&quot;: &quot;Run&quot;, "Cargo.Test reflect::cross::test::test_into.executor": "Run",
&quot;Cargo.Test triangle_d3d11.executor&quot;: &quot;Run&quot;, "Cargo.Test triangle_d3d11.executor": "Run",
&quot;Cargo.Test triangle_d3d12.executor&quot;: &quot;Run&quot;, "Cargo.Test triangle_d3d12.executor": "Run",
&quot;Cargo.Test triangle_gl.executor&quot;: &quot;Run&quot;, "Cargo.Test triangle_gl.executor": "Run",
&quot;Cargo.Test triangle_gl46.executor&quot;: &quot;Run&quot;, "Cargo.Test triangle_gl46.executor": "Run",
&quot;Cargo.Test triangle_vk.executor&quot;: &quot;Run&quot;, "Cargo.Test triangle_vk.executor": "Run",
&quot;Cargo.Test triangle_wgpu.executor&quot;: &quot;Run&quot;, "Cargo.Test triangle_wgpu.executor": "Run",
&quot;RunOnceActivity.OpenProjectViewOnStart&quot;: &quot;true&quot;, "RunOnceActivity.OpenProjectViewOnStart": "true",
&quot;RunOnceActivity.RadMigrateCodeStyle&quot;: &quot;true&quot;, "RunOnceActivity.RadMigrateCodeStyle": "true",
&quot;RunOnceActivity.ShowReadmeOnStart&quot;: &quot;true&quot;, "RunOnceActivity.ShowReadmeOnStart": "true",
&quot;RunOnceActivity.cidr.known.project.marker&quot;: &quot;true&quot;, "RunOnceActivity.cidr.known.project.marker": "true",
&quot;RunOnceActivity.readMode.enableVisualFormatting&quot;: &quot;true&quot;, "RunOnceActivity.readMode.enableVisualFormatting": "true",
&quot;cf.first.check.clang-format&quot;: &quot;false&quot;, "cf.first.check.clang-format": "false",
&quot;cidr.known.project.marker&quot;: &quot;true&quot;, "cidr.known.project.marker": "true",
&quot;git-widget-placeholder&quot;: &quot;feat-wgpu-runtime&quot;, "git-widget-placeholder": "feat-wgpu-runtime",
&quot;last_opened_file_path&quot;: &quot;C:/coding/librashader&quot;, "last_opened_file_path": "C:/coding/glslang-rs",
&quot;node.js.detected.package.eslint&quot;: &quot;true&quot;, "node.js.detected.package.eslint": "true",
&quot;node.js.detected.package.tslint&quot;: &quot;true&quot;, "node.js.detected.package.tslint": "true",
&quot;node.js.selected.package.eslint&quot;: &quot;(autodetect)&quot;, "node.js.selected.package.eslint": "(autodetect)",
&quot;node.js.selected.package.tslint&quot;: &quot;(autodetect)&quot;, "node.js.selected.package.tslint": "(autodetect)",
&quot;nodejs_package_manager_path&quot;: &quot;npm&quot;, "nodejs_package_manager_path": "npm",
&quot;org.rust.cargo.project.model.PROJECT_DISCOVERY&quot;: &quot;true&quot;, "org.rust.cargo.project.model.PROJECT_DISCOVERY": "true",
&quot;settings.editor.selected.configurable&quot;: &quot;language.rust&quot;, "settings.editor.selected.configurable": "language.rust",
&quot;vue.rearranger.settings.migration&quot;: &quot;true&quot; "vue.rearranger.settings.migration": "true"
} }
}</component> }]]></component>
<component name="RecentsManager"> <component name="RecentsManager">
<key name="MoveFile.RECENT_KEYS"> <key name="MoveFile.RECENT_KEYS">
<recent name="F:\coding\librashader\librashader-reflect\src\back\wgsl" /> <recent name="F:\coding\librashader\librashader-reflect\src\back\wgsl" />
@ -266,7 +264,8 @@
<workItem from="1702482450853" duration="399000" /> <workItem from="1702482450853" duration="399000" />
<workItem from="1702482871248" duration="556000" /> <workItem from="1702482871248" duration="556000" />
<workItem from="1702484102491" duration="5258000" /> <workItem from="1702484102491" duration="5258000" />
<workItem from="1702561144428" duration="385000" /> <workItem from="1702561144428" duration="1836000" />
<workItem from="1702640983281" duration="967000" />
</task> </task>
<task id="LOCAL-00001" summary="rt(wgpu): basic triangle example"> <task id="LOCAL-00001" summary="rt(wgpu): basic triangle example">
<option name="closed" value="true" /> <option name="closed" value="true" />
@ -316,7 +315,23 @@
<option name="project" value="LOCAL" /> <option name="project" value="LOCAL" />
<updated>1702514856945</updated> <updated>1702514856945</updated>
</task> </task>
<option name="localTasksCounter" value="7" /> <task id="LOCAL-00007" summary="rt(wgpu): sampler set">
<option name="closed" value="true" />
<created>1702561653875</created>
<option name="number" value="00007" />
<option name="presentableId" value="LOCAL-00007" />
<option name="project" value="LOCAL" />
<updated>1702561653875</updated>
</task>
<task id="LOCAL-00008" summary="rt(wgpu): create pipeline">
<option name="closed" value="true" />
<created>1702562564811</created>
<option name="number" value="00008" />
<option name="presentableId" value="LOCAL-00008" />
<option name="project" value="LOCAL" />
<updated>1702562564811</updated>
</task>
<option name="localTasksCounter" value="9" />
<servers /> <servers />
</component> </component>
<component name="TypeScriptGeneratedFilesManager"> <component name="TypeScriptGeneratedFilesManager">
@ -330,7 +345,9 @@
<MESSAGE value="rt(wgpu): load shaders" /> <MESSAGE value="rt(wgpu): load shaders" />
<MESSAGE value="reflect(wgsl): give push uniform a non-overlapping bind group" /> <MESSAGE value="reflect(wgsl): give push uniform a non-overlapping bind group" />
<MESSAGE value="rt(wgpu): create pipeline bind group layouts" /> <MESSAGE value="rt(wgpu): create pipeline bind group layouts" />
<option name="LAST_COMMIT_MESSAGE" value="rt(wgpu): create pipeline bind group layouts" /> <MESSAGE value="rt(wgpu): sampler set" />
<MESSAGE value="rt(wgpu): create pipeline" />
<option name="LAST_COMMIT_MESSAGE" value="rt(wgpu): create pipeline" />
</component> </component>
<component name="XDebuggerManager"> <component name="XDebuggerManager">
<breakpoint-manager> <breakpoint-manager>

1
Cargo.lock generated
View file

@ -1830,6 +1830,7 @@ dependencies = [
name = "librashader-runtime-wgpu" name = "librashader-runtime-wgpu"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"array-concat",
"bytemuck", "bytemuck",
"config", "config",
"env_logger", "env_logger",

View file

@ -175,3 +175,13 @@ impl From<WrapMode> for wgpu_types::AddressMode {
} }
} }
} }
impl From<Size<u32>> for wgpu_types::Extent3d {
fn from(value: Size<u32>) -> Self {
wgpu_types::Extent3d {
width: value.width,
height: value.height,
depth_or_array_layers: 1,
}
}
}

View file

@ -126,7 +126,7 @@ impl FilterPass {
let residual = self let residual = self
.graphics_pipeline .graphics_pipeline
.begin_rendering(&parent.device, output, cmd)?; .begin_rendering(output, cmd)?;
unsafe { unsafe {
parent.device.cmd_bind_pipeline( parent.device.cmd_bind_pipeline(
@ -178,7 +178,7 @@ impl FilterPass {
.device .device
.cmd_set_viewport(cmd, 0, &[output.output.size.into()]); .cmd_set_viewport(cmd, 0, &[output.output.size.into()]);
parent.draw_quad.draw_quad(cmd, vbo_type); parent.draw_quad.draw_quad(cmd, vbo_type);
self.graphics_pipeline.end_rendering(&parent.device, cmd); self.graphics_pipeline.end_rendering(cmd);
} }
Ok(residual) Ok(residual)
} }

View file

@ -384,14 +384,13 @@ impl VulkanGraphicsPipeline {
#[inline(always)] #[inline(always)]
pub(crate) fn begin_rendering( pub(crate) fn begin_rendering(
&self, &self,
device: &ash::Device,
output: &RenderTarget<OutputImage>, output: &RenderTarget<OutputImage>,
cmd: vk::CommandBuffer, cmd: vk::CommandBuffer,
) -> error::Result<Option<vk::Framebuffer>> { ) -> error::Result<Option<vk::Framebuffer>> {
if let Some(render_pass) = &self.render_pass { if let Some(render_pass) = &self.render_pass {
let attachments = [output.output.image_view]; let attachments = [output.output.image_view];
let framebuffer = unsafe { let framebuffer = unsafe {
device.create_framebuffer( self.device.create_framebuffer(
&vk::FramebufferCreateInfo::builder() &vk::FramebufferCreateInfo::builder()
.render_pass(render_pass.handle) .render_pass(render_pass.handle)
.attachments(&attachments) .attachments(&attachments)
@ -418,7 +417,7 @@ impl VulkanGraphicsPipeline {
extent: output.output.size.into(), extent: output.output.size.into(),
}); });
unsafe { unsafe {
device.cmd_begin_render_pass(cmd, &render_pass_info, vk::SubpassContents::INLINE); self.device.cmd_begin_render_pass(cmd, &render_pass_info, vk::SubpassContents::INLINE);
} }
Ok(Some(framebuffer)) Ok(Some(framebuffer))
} else { } else {
@ -438,18 +437,18 @@ impl VulkanGraphicsPipeline {
.color_attachments(&attachments); .color_attachments(&attachments);
unsafe { unsafe {
device.cmd_begin_rendering(cmd, &rendering_info); self.device.cmd_begin_rendering(cmd, &rendering_info);
} }
Ok(None) Ok(None)
} }
} }
pub(crate) fn end_rendering(&self, device: &ash::Device, cmd: vk::CommandBuffer) { pub(crate) fn end_rendering(&self, cmd: vk::CommandBuffer) {
unsafe { unsafe {
if self.render_pass.is_none() { if self.render_pass.is_none() {
device.cmd_end_rendering(cmd); self.device.cmd_end_rendering(cmd);
} else { } else {
device.cmd_end_render_pass(cmd) self.device.cmd_end_render_pass(cmd)
} }
} }
} }

View file

@ -21,7 +21,7 @@ parking_lot = "0.12.1"
rayon = "1.8.0" rayon = "1.8.0"
bytemuck = { version = "1.14.0", features = ["derive"] } bytemuck = { version = "1.14.0", features = ["derive"] }
array-concat = "0.5.2"
[dev-dependencies] [dev-dependencies]
config = { version = "0.13.4", features = [] } config = { version = "0.13.4", features = [] }

View file

@ -0,0 +1,52 @@
use array_concat::concat_arrays;
use librashader_runtime::quad::QuadType;
use wgpu::util::{BufferInitDescriptor, DeviceExt};
use wgpu::{Buffer, BufferDescriptor, Device, RenderPass};
#[rustfmt::skip]
const VBO_OFFSCREEN: [f32; 16] = [
// Offscreen
-1.0f32, -1.0, 0.0, 0.0,
-1.0, 1.0, 0.0, 1.0,
1.0, -1.0, 1.0, 0.0,
1.0, 1.0, 1.0, 1.0,
];
#[rustfmt::skip]
const VBO_DEFAULT_FINAL: [f32; 16] = [
// Final
0.0f32, 0.0, 0.0, 0.0,
0.0, 1.0, 0.0, 1.0,
1.0, 0.0, 1.0, 0.0,
1.0, 1.0, 1.0, 1.0,
];
static VBO_DATA: &[f32; 32] = &concat_arrays!(VBO_OFFSCREEN, VBO_DEFAULT_FINAL);
pub struct DrawQuad {
buffer: Buffer,
}
impl DrawQuad {
pub fn new(device: &Device) -> DrawQuad {
let buffer = device.create_buffer_init(&BufferInitDescriptor {
label: Some("librashader vbo"),
contents: bytemuck::cast_slice(VBO_DATA),
usage: wgpu::BufferUsages::VERTEX,
});
DrawQuad { buffer }
}
pub fn bind_vbo_for_frame<'a, 'b: 'a>(&'b self, cmd: &mut RenderPass<'a>) {
cmd.set_vertex_buffer(0, self.buffer.slice(0..));
}
pub fn draw_quad<'a, 'b: 'a>(&'b self, cmd: &mut RenderPass<'a>, vbo: QuadType) {
let offset = match vbo {
QuadType::Offscreen => 0..3,
QuadType::Final => 1..4,
};
cmd.draw(offset, 0..1)
}
}

View file

@ -6,7 +6,7 @@ use librashader_runtime::image::ImageError;
use std::convert::Infallible; use std::convert::Infallible;
use thiserror::Error; use thiserror::Error;
/// Cumulative error type for Vulkan filter chains. /// Cumulative error type for WGPU filter chains.
#[derive(Error, Debug)] #[derive(Error, Debug)]
pub enum FilterChainError { pub enum FilterChainError {
#[error("SPIRV reflection error")] #[error("SPIRV reflection error")]

View file

@ -6,7 +6,7 @@ use librashader_reflect::reflect::presets::{CompilePresetTarget, ShaderPassArtif
use librashader_reflect::reflect::semantics::ShaderSemantics; use librashader_reflect::reflect::semantics::ShaderSemantics;
use librashader_reflect::reflect::ReflectShader; use librashader_reflect::reflect::ReflectShader;
use librashader_runtime::binding::BindingUtil; use librashader_runtime::binding::BindingUtil;
use librashader_runtime::image::{Image, ImageError, UVDirection, BGRA8}; use librashader_runtime::image::{Image, ImageError, UVDirection, BGRA8, RGBA8};
use librashader_runtime::quad::QuadType; use librashader_runtime::quad::QuadType;
use librashader_runtime::uniforms::UniformStorage; use librashader_runtime::uniforms::UniformStorage;
use parking_lot::RwLock; use parking_lot::RwLock;
@ -16,22 +16,25 @@ use std::convert::Infallible;
use std::path::Path; use std::path::Path;
use std::sync::Arc; use std::sync::Arc;
use librashader_cache::CachedCompilation; use librashader_common::{ImageFormat, Size};
use librashader_reflect::back::wgsl::WgslCompileOptions;
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 rayon::prelude::*; use rayon::prelude::*;
use wgpu::{CommandBuffer, CommandEncoder, Device, Queue, TextureFormat}; use wgpu::{CommandBuffer, CommandEncoder, Device, Queue, TextureFormat};
use librashader_common::ImageFormat; use crate::draw_quad::DrawQuad;
use librashader_reflect::back::wgsl::WgslCompileOptions;
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; use crate::graphics_pipeline::WgpuGraphicsPipeline;
use crate::luts::LutTexture;
use crate::samplers::SamplerSet;
use crate::texture::{InputImage, OwnedImage};
type ShaderPassMeta = type ShaderPassMeta =
ShaderPassArtifact<impl CompileReflectShader<WGSL, GlslangCompilation> + Send>; ShaderPassArtifact<impl CompileReflectShader<WGSL, GlslangCompilation> + Send>;
fn compile_passes( fn compile_passes(
shaders: Vec<ShaderPassConfig>, shaders: Vec<ShaderPassConfig>,
textures: &[TextureConfig], textures: &[TextureConfig],
@ -45,29 +48,35 @@ fn compile_passes(
pub struct FilterChainWGPU { pub struct FilterChainWGPU {
pub(crate) common: FilterCommon, pub(crate) common: FilterCommon,
passes: Box<[FilterPass]>, passes: Box<[FilterPass]>,
// vulkan: VulkanObjects, output_framebuffers: Box<[OwnedImage]>,
// output_framebuffers: Box<[OwnedImage]>, feedback_framebuffers: Box<[OwnedImage]>,
// feedback_framebuffers: Box<[OwnedImage]>, history_framebuffers: VecDeque<OwnedImage>,
// history_framebuffers: VecDeque<OwnedImage>, disable_mipmaps: bool,
// disable_mipmaps: bool,
// residuals: Box<[FrameResiduals]>, // residuals: Box<[FrameResiduals]>,
} }
pub struct FilterMutable { pub struct FilterMutable {
// pub(crate) passes_enabled: usize, pub passes_enabled: usize,
// pub(crate) parameters: FxHashMap<String, f32>, pub(crate) parameters: FxHashMap<String, f32>,
} }
pub(crate) struct FilterCommon { pub(crate) struct FilterCommon {
// pub(crate) luts: FxHashMap<usize, LutTexture>, // pub(crate) luts: FxHashMap<usize, LutTexture>,
// pub samplers: SamplerSet, // pub samplers: SamplerSet,
// pub(crate) draw_quad: DrawQuad, // pub(crate) draw_quad: DrawQuad,
// pub output_textures: Box<[Option<InputImage>]>, pub output_textures: Box<[Option<InputImage>]>,
// pub feedback_textures: Box<[Option<InputImage>]>, pub feedback_textures: Box<[Option<InputImage>]>,
// pub history_textures: Box<[Option<InputImage>]>, pub history_textures: Box<[Option<InputImage>]>,
// pub config: FilterMutable, // pub config: FilterMutable,
// pub device: Arc<ash::Device>, // pub device: Arc<ash::Device>,
// pub(crate) internal_frame_count: usize, // pub(crate) internal_frame_count: usize,
luts: FxHashMap<usize, LutTexture>,
samplers: SamplerSet,
config: FilterMutable,
internal_frame_count: i32,
draw_quad: DrawQuad,
device: Arc<Device>,
} }
impl FilterChainWGPU { impl FilterChainWGPU {
@ -79,92 +88,94 @@ impl FilterChainWGPU {
/// 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 fn load_from_preset_deferred( pub fn load_from_preset_deferred(
device: &Device, device: Arc<Device>,
// cmd: &mut CommandEncoder, queue: &mut wgpu::Queue,
cmd: &mut wgpu::CommandEncoder,
preset: ShaderPreset, preset: ShaderPreset,
) -> error::Result<FilterChainWGPU> {
) -> error::Result<FilterChainWGPU>
{
let (passes, semantics) = compile_passes(preset.shaders, &preset.textures)?; let (passes, semantics) = compile_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);
// if frames_in_flight == 0 {
// frames_in_flight = 3;
// }
//
// // initialize passes // // initialize passes
let filters = Self::init_passes( let filters = Self::init_passes(Arc::clone(&device), passes, &semantics)?;
&device,
passes,
&semantics,
)?;
// //
// let luts = FilterChainVulkan::load_luts(&device, cmd, &preset.textures)?; let luts = FilterChainWGPU::load_luts(&device, queue, cmd, &preset.textures)?;
// let samplers = SamplerSet::new(&device.device)?; let samplers = SamplerSet::new(&device);
// //
// let framebuffer_gen = let framebuffer_gen =
// || OwnedImage::new(&device, Size::new(1, 1), ImageFormat::R8G8B8A8Unorm, 1); || Ok::<_, error::FilterChainError>(OwnedImage::new(Arc::clone(&device), Size::new(1, 1), 1, ImageFormat::R8G8B8A8Unorm));
// let input_gen = || None; let input_gen = || None;
// let framebuffer_init = FramebufferInit::new( let framebuffer_init = FramebufferInit::new(
// filters.iter().map(|f| &f.reflection.meta), filters.iter().map(|f| &f.reflection.meta),
// &framebuffer_gen, &framebuffer_gen,
// &input_gen, &input_gen,
// ); );
// //
// // initialize output framebuffers // // initialize output framebuffers
// let (output_framebuffers, output_textures) = framebuffer_init.init_output_framebuffers()?; let (output_framebuffers, output_textures) = framebuffer_init.init_output_framebuffers()?;
// //
// // initialize feedback framebuffers // initialize feedback framebuffers
// let (feedback_framebuffers, feedback_textures) = let (feedback_framebuffers, feedback_textures) =
// framebuffer_init.init_output_framebuffers()?; framebuffer_init.init_output_framebuffers()?;
// //
// // initialize history // initialize history
// let (history_framebuffers, history_textures) = framebuffer_init.init_history()?; let (history_framebuffers, history_textures) = framebuffer_init.init_history()?;
// //
// let mut intermediates = Vec::new(); // let mut intermediates = Vec::new();
// intermediates.resize_with(frames_in_flight as usize, || { // intermediates.resize_with(frames_in_flight as usize, || {
// FrameResiduals::new(&device.device) // FrameResiduals::new(&device.device)
// }); // });
// Ok(FilterChainVulkan { let draw_quad = DrawQuad::new(&device);
// common: FilterCommon {
// luts,
// samplers,
// config: FilterMutable {
// passes_enabled: preset.shader_count as usize,
// parameters: preset
// .parameters
// .into_iter()
// .map(|param| (param.name, param.value))
// .collect(),
// },
// draw_quad: DrawQuad::new(&device.device, &device.alloc)?,
// device: device.device.clone(),
// output_textures,
// feedback_textures,
// history_textures,
// internal_frame_count: 0,
// },
// passes: filters,
// vulkan: device,
// output_framebuffers,
// feedback_framebuffers,
// history_framebuffers,
// residuals: intermediates.into_boxed_slice(),
// disable_mipmaps: options.map_or(false, |o| o.force_no_mipmaps),
// })
Ok(FilterChainWGPU { Ok(FilterChainWGPU {
common: FilterCommon {}, common: FilterCommon {
luts,
samplers,
config: FilterMutable {
passes_enabled: preset.shader_count as usize,
parameters: preset
.parameters
.into_iter()
.map(|param| (param.name, param.value))
.collect(),
},
draw_quad,
device,
output_textures,
feedback_textures,
history_textures,
internal_frame_count: 0,
},
passes: filters, passes: filters,
output_framebuffers,
feedback_framebuffers,
history_framebuffers,
disable_mipmaps: false // todo: force no mipmaps,
}) })
} }
fn load_luts(
device: &wgpu::Device,
queue: &mut wgpu::Queue,
cmd: &mut wgpu::CommandEncoder,
textures: &[TextureConfig],
) -> error::Result<FxHashMap<usize, LutTexture>> {
let mut luts = FxHashMap::default();
let images = textures
.par_iter()
.map(|texture| Image::load(&texture.path, UVDirection::TopLeft))
.collect::<Result<Vec<Image>, ImageError>>()?;
for (index, (texture, image)) in textures.iter().zip(images).enumerate() {
let texture = LutTexture::new(device, queue, cmd, image, texture);
luts.insert(index, texture);
}
Ok(luts)
}
fn init_passes( fn init_passes(
device: &Device, device: Arc<Device>,
passes: Vec<ShaderPassMeta>, passes: Vec<ShaderPassMeta>,
semantics: &ShaderSemantics, semantics: &ShaderSemantics,
) -> error::Result<Box<[FilterPass]>> { ) -> error::Result<Box<[FilterPass]>> {
@ -192,29 +203,20 @@ impl FilterChainWGPU {
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: Option<TextureFormat> = if let Some(format) = config.get_format_override() { let render_pass_format: Option<TextureFormat> =
format.into() if let Some(format) = config.get_format_override() {
} else { format.into()
source.format.into() } else {
}; source.format.into()
};
let graphics_pipeline = WgpuGraphicsPipeline::new( let graphics_pipeline = WgpuGraphicsPipeline::new(
device, Arc::clone(&device),
&wgsl, &wgsl,
&reflection, &reflection,
render_pass_format.unwrap_or(TextureFormat::R8Unorm) render_pass_format.unwrap_or(TextureFormat::R8Unorm),
); );
// let graphics_pipeline = VulkanGraphicsPipeline::new(
// &vulkan.device,
// &spirv_words,
// &reflection,
// frames_in_flight,
// render_pass_format,
// disable_cache,
// )?;
Ok(FilterPass { Ok(FilterPass {
// device: vulkan.device.clone(), // device: vulkan.device.clone(),
reflection, reflection,
@ -233,6 +235,7 @@ impl FilterChainWGPU {
let filters: error::Result<Vec<FilterPass>> = filters.into_iter().collect(); let filters: error::Result<Vec<FilterPass>> = filters.into_iter().collect();
let filters = filters?; let filters = filters?;
Ok(filters.into_boxed_slice()) Ok(filters.into_boxed_slice())
} }
} }

View file

@ -1,13 +1,13 @@
use std::sync::Arc; use crate::graphics_pipeline::WgpuGraphicsPipeline;
use rustc_hash::FxHashMap;
use librashader_preprocess::ShaderSource; use librashader_preprocess::ShaderSource;
use librashader_presets::ShaderPassConfig; use librashader_presets::ShaderPassConfig;
use librashader_reflect::back::ShaderCompilerOutput;
use librashader_reflect::back::wgsl::NagaWgslContext; use librashader_reflect::back::wgsl::NagaWgslContext;
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; use rustc_hash::FxHashMap;
use std::sync::Arc;
pub struct FilterPass { pub struct FilterPass {
pub reflection: ShaderReflection, pub reflection: ShaderReflection,

View file

@ -0,0 +1,7 @@
use wgpu::TextureView;
use librashader_common::Size;
pub(crate) struct OutputImage {
pub size: Size<u32>,
pub view: TextureView
}

View file

@ -1,28 +1,43 @@
use std::borrow::Cow; use crate::{error, util};
use std::num::NonZeroU32;
use std::sync::Arc;
use wgpu::{BindGroup, BindGroupDescriptor, BindGroupLayout, BindGroupLayoutDescriptor, BindGroupLayoutEntry, BindingType, BufferBindingType, BufferSize, Device, PipelineLayout, PushConstantRange, SamplerBindingType, ShaderModule, ShaderSource, ShaderStages, TextureFormat, TextureSampleType, TextureViewDimension, VertexAttribute, VertexBufferLayout};
use librashader_reflect::back::ShaderCompilerOutput;
use librashader_reflect::back::wgsl::NagaWgslContext; use librashader_reflect::back::wgsl::NagaWgslContext;
use librashader_reflect::reflect::semantics::BufferReflection; use librashader_reflect::back::ShaderCompilerOutput;
use librashader_reflect::reflect::ShaderReflection; use librashader_reflect::reflect::ShaderReflection;
use crate::util; use std::borrow::Cow;
use std::sync::Arc;
use wgpu::{BindGroup, BindGroupDescriptor, BindGroupLayout, BindGroupLayoutDescriptor, BindGroupLayoutEntry, BindingType, BufferBindingType, BufferSize, CommandEncoder, Device, Operations, PipelineLayout, PushConstantRange, RenderPass, RenderPassColorAttachment, RenderPassDescriptor, RenderPipelineDescriptor, SamplerBindingType, ShaderModule, ShaderSource, ShaderStages, TextureFormat, TextureSampleType, TextureViewDimension, VertexAttribute, VertexBufferLayout};
use librashader_runtime::render_target::RenderTarget;
use crate::framebuffer::OutputImage;
pub struct WgpuGraphicsPipeline { pub struct WgpuGraphicsPipeline {
vertex: ShaderModule, layout: PipelineLayoutObjects,
fragment: ShaderModule render_pipeline: wgpu::RenderPipeline,
} }
pub struct PipelineLayoutObjects { pub struct PipelineLayoutObjects {
pub layout: PipelineLayout, layout: PipelineLayout,
pub bind_group_layouts: Vec<BindGroupLayout> bind_group_layouts: Vec<BindGroupLayout>,
fragment_entry_name: String,
vertex_entry_name: String,
vertex: ShaderModule,
fragment: ShaderModule,
device: Arc<wgpu::Device>
} }
impl PipelineLayoutObjects { impl PipelineLayoutObjects {
pub fn new( pub fn new(
reflection: &ShaderReflection, reflection: &ShaderReflection,
device: &Device shader_assembly: &ShaderCompilerOutput<String, NagaWgslContext>,
device: Arc<wgpu::Device>,
) -> Self { ) -> Self {
let vertex = device.create_shader_module(wgpu::ShaderModuleDescriptor {
label: Some("vertex"),
source: ShaderSource::Wgsl(Cow::from(&shader_assembly.vertex)),
});
let fragment = device.create_shader_module(wgpu::ShaderModuleDescriptor {
label: Some("fragment"),
source: ShaderSource::Wgsl(Cow::from(&shader_assembly.fragment)),
});
let mut bind_group_layouts = Vec::new(); let mut bind_group_layouts = Vec::new();
@ -31,7 +46,9 @@ impl PipelineLayoutObjects {
let mut push_constant_range = Vec::new(); let mut push_constant_range = Vec::new();
if let Some(push_meta) = reflection.push_constant.as_ref() && !push_meta.stage_mask.is_empty() { if let Some(push_meta) = reflection.push_constant.as_ref()
&& !push_meta.stage_mask.is_empty()
{
let push_mask = util::binding_stage_to_wgpu_stage(push_meta.stage_mask); let push_mask = util::binding_stage_to_wgpu_stage(push_meta.stage_mask);
if let Some(binding) = push_meta.binding { if let Some(binding) = push_meta.binding {
@ -53,7 +70,9 @@ impl PipelineLayoutObjects {
} }
} }
if let Some(ubo_meta) = reflection.ubo.as_ref() && !ubo_meta.stage_mask.is_empty() { if let Some(ubo_meta) = reflection.ubo.as_ref()
&& !ubo_meta.stage_mask.is_empty()
{
let ubo_mask = util::binding_stage_to_wgpu_stage(ubo_meta.stage_mask); let ubo_mask = util::binding_stage_to_wgpu_stage(ubo_meta.stage_mask);
main_bindings.push(BindGroupLayoutEntry { main_bindings.push(BindGroupLayoutEntry {
binding: ubo_meta.binding, binding: ubo_meta.binding,
@ -99,80 +118,56 @@ impl PipelineLayoutObjects {
bind_group_layouts.push(main_bind_group); bind_group_layouts.push(main_bind_group);
bind_group_layouts.push(sampler_bind_group); bind_group_layouts.push(sampler_bind_group);
let bind_group_layout_refs = bind_group_layouts.iter().collect::<Vec<_>>();
let layout = device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor { let layout = device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor {
label: Some("shader pipeline layout"), label: Some("shader pipeline layout"),
bind_group_layouts: &bind_group_layouts.as_ref(), bind_group_layouts: &bind_group_layout_refs,
push_constant_ranges: &push_constant_range.as_ref(), push_constant_ranges: &push_constant_range.as_ref(),
}); });
Self { Self {
layout, layout,
bind_group_layouts bind_group_layouts,
fragment_entry_name: shader_assembly.context.fragment.entry_points[0]
.name
.clone(),
vertex_entry_name: shader_assembly.context.vertex.entry_points[0].name.clone(),
vertex,
fragment,
device,
} }
} }
}
pub fn create_pipeline(&self, framebuffer_format: TextureFormat) -> wgpu::RenderPipeline {
self.device.create_render_pipeline(&wgpu::RenderPipelineDescriptor {
impl WgpuGraphicsPipeline {
pub fn new(
device: &Device,
shader_assembly: &ShaderCompilerOutput<String, NagaWgslContext>,
reflection: &ShaderReflection,
render_pass_format: TextureFormat,
) -> Self {
let vertex = device.create_shader_module(wgpu::ShaderModuleDescriptor {
label: Some("vertex"),
source: ShaderSource::Wgsl(Cow::from(&shader_assembly.vertex))
});
let fragment = device.create_shader_module(wgpu::ShaderModuleDescriptor {
label: Some("fragment"),
source: ShaderSource::Wgsl(Cow::from(&shader_assembly.fragment))
});
let layout = PipelineLayoutObjects::new(reflection, device);
let vao_layout = VertexBufferLayout {
array_stride: 4 * std::mem::size_of::<f32>() as wgpu::BufferAddress,
step_mode: wgpu::VertexStepMode::Vertex,
attributes: &[
wgpu::VertexAttribute {
format: wgpu::VertexFormat::Float32x2,
offset: 0,
shader_location: 0,
},
wgpu::VertexAttribute {
format: wgpu::VertexFormat::Float32x2,
offset: (2 * std::mem::size_of::<f32>()) as wgpu::BufferAddress,
shader_location: 1,
},
],
};
let render_pipeline = device.create_render_pipeline(&wgpu::RenderPipelineDescriptor {
label: Some("Render Pipeline"), label: Some("Render Pipeline"),
layout: Some(&layout.layout), layout: Some(&self.layout),
vertex: wgpu::VertexState { vertex: wgpu::VertexState {
module: &vertex, module: &self.vertex,
entry_point: &shader_assembly entry_point: &self.vertex_entry_name,
.context buffers: &[VertexBufferLayout {
.vertex array_stride: 4 * std::mem::size_of::<f32>() as wgpu::BufferAddress,
.entry_points[0] step_mode: wgpu::VertexStepMode::Vertex,
.name, attributes: &[
buffers: &[ wgpu::VertexAttribute {
vao_layout format: wgpu::VertexFormat::Float32x2,
], offset: 0,
shader_location: 0,
},
wgpu::VertexAttribute {
format: wgpu::VertexFormat::Float32x2,
offset: (2 * std::mem::size_of::<f32>()) as wgpu::BufferAddress,
shader_location: 1,
},
],
}],
}, },
fragment: Some(wgpu::FragmentState { fragment: Some(wgpu::FragmentState {
module: &fragment, module: &self.fragment,
entry_point: &shader_assembly entry_point: &self.fragment_entry_name,
.context
.fragment
.entry_points[0]
.name,
targets: &[Some(wgpu::ColorTargetState { targets: &[Some(wgpu::ColorTargetState {
format: render_pass_format, format: framebuffer_format,
blend: Some(wgpu::BlendState::REPLACE), blend: Some(wgpu::BlendState::REPLACE),
write_mask: wgpu::ColorWrites::ALL, write_mask: wgpu::ColorWrites::ALL,
})], })],
@ -193,11 +188,64 @@ impl WgpuGraphicsPipeline {
alpha_to_coverage_enabled: false, alpha_to_coverage_enabled: false,
}, },
multiview: None, multiview: None,
}); })
}
Self { }
vertex,
fragment, impl WgpuGraphicsPipeline {
} pub fn new(
device: Arc<wgpu::Device>,
shader_assembly: &ShaderCompilerOutput<String, NagaWgslContext>,
reflection: &ShaderReflection,
render_pass_format: TextureFormat,
) -> Self {
let layout = PipelineLayoutObjects::new(reflection, shader_assembly, device);
let render_pipeline = layout.create_pipeline(render_pass_format);
Self {
layout,
render_pipeline,
}
}
pub fn recompile(&mut self, format: TextureFormat) {
let render_pipeline = self.layout.create_pipeline(format);
self.render_pipeline = render_pipeline;
}
pub(crate) fn begin_rendering<'pass>(
&'pass self,
output: &RenderTarget<'pass, OutputImage>,
cmd: &'pass mut CommandEncoder
) -> RenderPass<'pass> {
let mut render_pass = cmd.begin_render_pass(&RenderPassDescriptor {
label: Some("librashader"),
color_attachments: &[Some(RenderPassColorAttachment {
view: &output.output.view,
resolve_target: None,
ops: Operations {
load: wgpu::LoadOp::Clear(wgpu::Color {
r: 0.0,
g: 0.0,
b: 0.0,
a: 0.0,
}),
store: wgpu::StoreOp::Store,
},
})],
depth_stencil_attachment: None,
timestamp_writes: None,
occlusion_query_set: None,
});
render_pass.set_viewport(
output.x,
output.y,
output.output.size.width as f32,
output.output.size.height as f32,
1.0,
1.0
);
render_pass
} }
} }

View file

@ -7,14 +7,16 @@
#![feature(let_chains)] #![feature(let_chains)]
#![feature(strict_provenance)] #![feature(strict_provenance)]
mod draw_quad;
mod filter_chain;
mod error; mod error;
mod texture; mod filter_chain;
mod filter_pass; mod filter_pass;
mod graphics_pipeline; mod graphics_pipeline;
mod util;
mod samplers; mod samplers;
mod texture;
mod util;
mod framebuffer;
mod luts;
pub use filter_chain::FilterChainWGPU; pub use filter_chain::FilterChainWGPU;
pub use filter_pass::FilterPass; pub use filter_pass::FilterPass;

View file

@ -0,0 +1,60 @@
use wgpu::{ImageDataLayout, Label, TextureDescriptor};
use wgpu::util::DeviceExt;
use librashader_presets::TextureConfig;
use librashader_runtime::image::{BGRA8, Image};
use librashader_runtime::scaling::MipmapSize;
pub(crate) struct LutTexture {
texture: wgpu::Texture,
}
impl LutTexture {
pub fn new(
device: &wgpu::Device,
queue: &mut wgpu::Queue,
_cmd: &mut wgpu::CommandEncoder,
image: Image,
config: &TextureConfig
) -> LutTexture {
let texture = device.create_texture(&TextureDescriptor {
label: Some(&config.name),
size: image.size.into(),
mip_level_count: if config.mipmap {
image.size.calculate_miplevels()
} else {
1
},
sample_count: 1,
dimension: wgpu::TextureDimension::D2,
format: wgpu::TextureFormat::Rgba8Unorm,
usage: wgpu::TextureUsages::TEXTURE_BINDING
| wgpu::TextureUsages::COPY_DST
// need render attachment for mipmaps...
| wgpu::TextureUsages::RENDER_ATTACHMENT,
view_formats: &[wgpu::TextureFormat::Rgba8Unorm],
});
queue.write_texture(
wgpu::ImageCopyTexture {
texture: &texture,
mip_level: 0,
origin: wgpu::Origin3d::ZERO,
aspect: wgpu::TextureAspect::All,
},
&image.bytes,
wgpu::ImageDataLayout {
offset: 0,
bytes_per_row: Some(4 * image.size.width),
rows_per_image: None,
},
image.size.into()
);
// todo: mipmaps
Self {
texture
}
}
}

View file

@ -1,5 +1,5 @@
use librashader_common::{FilterMode, WrapMode};
use crate::error; use crate::error;
use librashader_common::{FilterMode, WrapMode};
use rustc_hash::FxHashMap; use rustc_hash::FxHashMap;
use std::sync::Arc; use std::sync::Arc;
use wgpu::{Sampler, SamplerBorderColor, SamplerDescriptor}; use wgpu::{Sampler, SamplerBorderColor, SamplerDescriptor};
@ -22,7 +22,7 @@ impl SamplerSet {
} }
} }
pub fn new(device: &wgpu::Device) -> error::Result<SamplerSet> { pub fn new(device: &wgpu::Device) -> SamplerSet {
let mut samplers = FxHashMap::default(); let mut samplers = FxHashMap::default();
let wrap_modes = &[ let wrap_modes = &[
WrapMode::ClampToBorder, WrapMode::ClampToBorder,
@ -37,18 +37,18 @@ impl SamplerSet {
(*wrap_mode, *filter_mode, *mipmap_filter), (*wrap_mode, *filter_mode, *mipmap_filter),
device.create_sampler(&SamplerDescriptor { device.create_sampler(&SamplerDescriptor {
label: None, label: None,
address_mode_u: wrap_mode.into(), address_mode_u: (*wrap_mode).into(),
address_mode_v: wrap_mode.into(), address_mode_v: (*wrap_mode).into(),
address_mode_w: wrap_mode.into(), address_mode_w: (*wrap_mode).into(),
mag_filter: filter_mode.into(), mag_filter: (*filter_mode).into(),
min_filter: filter_mode.into(), min_filter: (*filter_mode).into(),
mipmap_filter: mipmap_filter.into(), mipmap_filter: (*mipmap_filter).into(),
lod_min_clamp: 0.0, lod_min_clamp: 0.0,
lod_max_clamp: 1000.0, lod_max_clamp: 1000.0,
compare: None, compare: None,
anisotropy_clamp: 1, anisotropy_clamp: 1,
border_color: Some(SamplerBorderColor::TransparentBlack), border_color: Some(SamplerBorderColor::TransparentBlack),
}) }),
); );
} }
} }
@ -56,6 +56,6 @@ impl SamplerSet {
// assert all samplers were created. // assert all samplers were created.
assert_eq!(samplers.len(), wrap_modes.len() * 2 * 2); assert_eq!(samplers.len(), wrap_modes.len() * 2 * 2);
Ok(SamplerSet { samplers }) SamplerSet { samplers }
} }
} }

View file

@ -0,0 +1,95 @@
use std::sync::Arc;
use wgpu::TextureFormat;
use librashader_common::{FilterMode, ImageFormat, Size, WrapMode};
use librashader_presets::Scale2D;
use librashader_runtime::scaling::{MipmapSize, ViewportSize};
pub struct OwnedImage {
device: Arc<wgpu::Device>,
pub image: wgpu::Texture,
pub view: wgpu::TextureView,
pub max_miplevels: u32,
pub levels: u32,
pub size: Size<u32>,
pub format: wgpu::TextureFormat,
}
pub struct InputImage {
/// A handle to the `VkImage`.
pub image: wgpu::Texture,
pub image_view: wgpu::TextureView,
pub wrap_mode: WrapMode,
pub filter_mode: FilterMode,
pub mip_filter: FilterMode,
}
impl OwnedImage {
pub fn new(device: Arc<wgpu::Device>,
size: Size<u32>,
max_miplevels: u32,
format: ImageFormat,
) -> Self {
let format: Option<wgpu::TextureFormat> = format.into();
let format = format.unwrap_or(wgpu::TextureFormat::Rgba8Unorm);
let texture = device.create_texture(&wgpu::TextureDescriptor {
label: None,
size: size.into(),
mip_level_count: std::cmp::min(max_miplevels, size.calculate_miplevels()),
sample_count: 1,
dimension: wgpu::TextureDimension::D2,
format,
usage: wgpu::TextureUsages::TEXTURE_BINDING
| wgpu::TextureUsages::RENDER_ATTACHMENT
| wgpu::TextureUsages::COPY_DST
| wgpu::TextureUsages::COPY_SRC,
view_formats: &[format.into()],
});
let view = texture.create_view(&wgpu::TextureViewDescriptor {
label: None,
format: Some(format),
dimension: Some(wgpu::TextureViewDimension::D2),
aspect: wgpu::TextureAspect::All,
base_mip_level: 0,
mip_level_count: None,
base_array_layer: 0,
array_layer_count: None,
});
Self {
device,
image: texture,
view,
max_miplevels,
levels: std::cmp::min(max_miplevels, size.calculate_miplevels()),
size,
format,
}
}
pub fn scale(
&mut self,
scaling: Scale2D,
format: ImageFormat,
viewport_size: &Size<u32>,
source_size: &Size<u32>,
mipmap: bool,
) -> Size<u32> {
let size = source_size.scale_viewport(scaling, *viewport_size);
let format: Option<wgpu::TextureFormat> = format.into();
let format = format.unwrap_or(wgpu::TextureFormat::Rgba8Unorm);
if self.size != size
|| (mipmap && self.max_miplevels == 1)
|| (!mipmap && self.max_miplevels != 1)
|| format != self.format
{
let mut new = OwnedImage::new(Arc::clone(&self.device), size, self.max_miplevels, format.into());
std::mem::swap(self, &mut new);
}
size
}
}

View file

@ -1,5 +1,5 @@
use wgpu::ShaderStages;
use librashader_reflect::reflect::semantics::BindingStage; use librashader_reflect::reflect::semantics::BindingStage;
use wgpu::ShaderStages;
pub fn binding_stage_to_wgpu_stage(stage_mask: BindingStage) -> ShaderStages { pub fn binding_stage_to_wgpu_stage(stage_mask: BindingStage) -> ShaderStages {
let mut mask = ShaderStages::empty(); let mut mask = ShaderStages::empty();

View file

@ -4,11 +4,11 @@ use winit::{
window::{Window, WindowBuilder}, window::{Window, WindowBuilder},
}; };
use librashader_presets::ShaderPreset;
use librashader_runtime_wgpu::FilterChainWGPU;
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::*;
@ -35,30 +35,29 @@ impl Vertex {
shader_location: 1, shader_location: 1,
format: wgpu::VertexFormat::Float32x3, format: wgpu::VertexFormat::Float32x3,
}, },
] ],
} }
} }
} }
const VERTICES: &[Vertex] = &[ const VERTICES: &[Vertex] = &[
Vertex { // top Vertex {
// top
position: [0.0, 0.5, 0.0], position: [0.0, 0.5, 0.0],
color: [1.0, 0.0, 0.0], color: [1.0, 0.0, 0.0],
}, },
Vertex { // bottom left Vertex {
// bottom left
position: [-0.5, -0.5, 0.0], position: [-0.5, -0.5, 0.0],
color: [0.0, 1.0, 0.0], color: [0.0, 1.0, 0.0],
}, },
Vertex { // bottom right Vertex {
// bottom right
position: [0.5, -0.5, 0.0], position: [0.5, -0.5, 0.0],
color: [0.0, 0.0, 1.0], color: [0.0, 0.0, 1.0],
}, },
]; ];
struct State { struct State {
surface: wgpu::Surface, surface: wgpu::Surface,
device: wgpu::Device, device: wgpu::Device,
@ -71,7 +70,7 @@ struct State {
vertex_buffer: wgpu::Buffer, vertex_buffer: wgpu::Buffer,
num_vertices: u32, num_vertices: u32,
chain: FilterChainWGPU chain: FilterChainWGPU,
} }
impl State { impl State {
async fn new(window: &Window) -> Self { async fn new(window: &Window) -> Self {
@ -113,7 +112,8 @@ impl State {
view_formats: vec![], view_formats: vec![],
}; };
let preset = ShaderPreset::try_parse("../test/shaders_slang/crt/crt-royale.slangp").unwrap(); let preset =
ShaderPreset::try_parse("../test/shaders_slang/crt/crt-royale.slangp").unwrap();
let chain = FilterChainWGPU::load_from_preset_deferred(&device, preset).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 {
@ -132,9 +132,7 @@ impl State {
vertex: wgpu::VertexState { vertex: wgpu::VertexState {
module: &shader, module: &shader,
entry_point: "vs_main", entry_point: "vs_main",
buffers: &[ buffers: &[Vertex::desc()],
Vertex::desc(),
],
}, },
fragment: Some(wgpu::FragmentState { fragment: Some(wgpu::FragmentState {
module: &shader, module: &shader,
@ -163,14 +161,11 @@ impl State {
multiview: None, multiview: None,
}); });
let vertex_buffer = device.create_buffer_init(&wgpu::util::BufferInitDescriptor {
let vertex_buffer = device.create_buffer_init( label: Some("Vertex Buffer"),
&wgpu::util::BufferInitDescriptor { contents: bytemuck::cast_slice(VERTICES),
label: Some("Vertex Buffer"), usage: wgpu::BufferUsages::VERTEX,
contents: bytemuck::cast_slice(VERTICES), });
usage: wgpu::BufferUsages::VERTEX,
},
);
let clear_color = wgpu::Color { let clear_color = wgpu::Color {
r: 0.1, r: 0.1,
@ -189,7 +184,7 @@ impl State {
render_pipeline, render_pipeline,
vertex_buffer, vertex_buffer,
num_vertices, num_vertices,
chain chain,
} }
} }
fn resize(&mut self, new_size: winit::dpi::PhysicalSize<u32>) { fn resize(&mut self, new_size: winit::dpi::PhysicalSize<u32>) {
@ -223,7 +218,7 @@ impl State {
resolve_target: None, resolve_target: None,
ops: wgpu::Operations { ops: wgpu::Operations {
load: wgpu::LoadOp::Clear(self.clear_color), load: wgpu::LoadOp::Clear(self.clear_color),
store: wgpu::StoreOp::Store, store: wgpu::StoreOp::Store,
}, },
})], })],
depth_stencil_attachment: None, depth_stencil_attachment: None,
@ -251,8 +246,6 @@ pub fn run() {
.build(); .build();
let window = WindowBuilder::new().build(&event_loop).unwrap(); let window = WindowBuilder::new().build(&event_loop).unwrap();
pollster::block_on(async { pollster::block_on(async {
let mut state = State::new(&window).await; let mut state = State::new(&window).await;
event_loop.run(move |event, _, control_flow| { event_loop.run(move |event, _, control_flow| {
@ -267,11 +260,11 @@ pub fn run() {
WindowEvent::CloseRequested WindowEvent::CloseRequested
| WindowEvent::KeyboardInput { | WindowEvent::KeyboardInput {
input: input:
KeyboardInput { KeyboardInput {
state: ElementState::Pressed, state: ElementState::Pressed,
virtual_keycode: Some(VirtualKeyCode::Escape), virtual_keycode: Some(VirtualKeyCode::Escape),
.. ..
}, },
.. ..
} => *control_flow = ControlFlow::Exit, } => *control_flow = ControlFlow::Exit,
WindowEvent::Resized(physical_size) => { WindowEvent::Resized(physical_size) => {
@ -302,6 +295,4 @@ pub fn run() {
} }
}); });
}); });
} }

View file

@ -1,7 +1,6 @@
mod hello_triangle; mod hello_triangle;
#[test] #[test]
fn triangle_wgpu() fn triangle_wgpu() {
{
hello_triangle::run() hello_triangle::run()
} }