rt(wgpu): add structure to wgpu backend
This commit is contained in:
parent
8cfe1e9da2
commit
2b995539f2
|
@ -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[{
|
||||||
"keyToString": {
|
"keyToString": {
|
||||||
"Cargo.Build `Test back::wgsl::test::test_into`.executor": "Run",
|
"Cargo.Build `Test back::wgsl::test::test_into`.executor": "Run",
|
||||||
"Cargo.Build `Test reflect::cross::test::test_into`.executor": "Run",
|
"Cargo.Build `Test reflect::cross::test::test_into`.executor": "Run",
|
||||||
"Cargo.Test back::wgsl::test::test_into.executor": "Run",
|
"Cargo.Test back::wgsl::test::test_into.executor": "Run",
|
||||||
"Cargo.Test front::naga::test::naga_playground (1).executor": "Run",
|
"Cargo.Test front::naga::test::naga_playground (1).executor": "Run",
|
||||||
"Cargo.Test front::naga::test::naga_playground.executor": "Run",
|
"Cargo.Test front::naga::test::naga_playground.executor": "Run",
|
||||||
"Cargo.Test reflect::cross::test::test_into.executor": "Run",
|
"Cargo.Test reflect::cross::test::test_into.executor": "Run",
|
||||||
"Cargo.Test triangle_d3d11.executor": "Run",
|
"Cargo.Test triangle_d3d11.executor": "Run",
|
||||||
"Cargo.Test triangle_d3d12.executor": "Run",
|
"Cargo.Test triangle_d3d12.executor": "Run",
|
||||||
"Cargo.Test triangle_gl.executor": "Run",
|
"Cargo.Test triangle_gl.executor": "Run",
|
||||||
"Cargo.Test triangle_gl46.executor": "Run",
|
"Cargo.Test triangle_gl46.executor": "Run",
|
||||||
"Cargo.Test triangle_vk.executor": "Run",
|
"Cargo.Test triangle_vk.executor": "Run",
|
||||||
"Cargo.Test triangle_wgpu.executor": "Run",
|
"Cargo.Test triangle_wgpu.executor": "Run",
|
||||||
"RunOnceActivity.OpenProjectViewOnStart": "true",
|
"RunOnceActivity.OpenProjectViewOnStart": "true",
|
||||||
"RunOnceActivity.RadMigrateCodeStyle": "true",
|
"RunOnceActivity.RadMigrateCodeStyle": "true",
|
||||||
"RunOnceActivity.ShowReadmeOnStart": "true",
|
"RunOnceActivity.ShowReadmeOnStart": "true",
|
||||||
"RunOnceActivity.cidr.known.project.marker": "true",
|
"RunOnceActivity.cidr.known.project.marker": "true",
|
||||||
"RunOnceActivity.readMode.enableVisualFormatting": "true",
|
"RunOnceActivity.readMode.enableVisualFormatting": "true",
|
||||||
"cf.first.check.clang-format": "false",
|
"cf.first.check.clang-format": "false",
|
||||||
"cidr.known.project.marker": "true",
|
"cidr.known.project.marker": "true",
|
||||||
"git-widget-placeholder": "feat-wgpu-runtime",
|
"git-widget-placeholder": "feat-wgpu-runtime",
|
||||||
"last_opened_file_path": "C:/coding/librashader",
|
"last_opened_file_path": "C:/coding/glslang-rs",
|
||||||
"node.js.detected.package.eslint": "true",
|
"node.js.detected.package.eslint": "true",
|
||||||
"node.js.detected.package.tslint": "true",
|
"node.js.detected.package.tslint": "true",
|
||||||
"node.js.selected.package.eslint": "(autodetect)",
|
"node.js.selected.package.eslint": "(autodetect)",
|
||||||
"node.js.selected.package.tslint": "(autodetect)",
|
"node.js.selected.package.tslint": "(autodetect)",
|
||||||
"nodejs_package_manager_path": "npm",
|
"nodejs_package_manager_path": "npm",
|
||||||
"org.rust.cargo.project.model.PROJECT_DISCOVERY": "true",
|
"org.rust.cargo.project.model.PROJECT_DISCOVERY": "true",
|
||||||
"settings.editor.selected.configurable": "language.rust",
|
"settings.editor.selected.configurable": "language.rust",
|
||||||
"vue.rearranger.settings.migration": "true"
|
"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
1
Cargo.lock
generated
|
@ -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",
|
||||||
|
|
|
@ -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,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -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)
|
||||||
}
|
}
|
||||||
|
|
|
@ -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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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 = [] }
|
||||||
|
|
52
librashader-runtime-wgpu/src/draw_quad.rs
Normal file
52
librashader-runtime-wgpu/src/draw_quad.rs
Normal 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)
|
||||||
|
}
|
||||||
|
}
|
|
@ -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")]
|
||||||
|
|
|
@ -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> =
|
||||||
|
if let Some(format) = config.get_format_override() {
|
||||||
format.into()
|
format.into()
|
||||||
} else {
|
} else {
|
||||||
source.format.into()
|
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())
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
|
@ -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,
|
||||||
|
|
7
librashader-runtime-wgpu/src/framebuffer.rs
Normal file
7
librashader-runtime-wgpu/src/framebuffer.rs
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
use wgpu::TextureView;
|
||||||
|
use librashader_common::Size;
|
||||||
|
|
||||||
|
pub(crate) struct OutputImage {
|
||||||
|
pub size: Size<u32>,
|
||||||
|
pub view: TextureView
|
||||||
|
}
|
|
@ -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,41 +118,35 @@ 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 {
|
label: Some("Render Pipeline"),
|
||||||
pub fn new(
|
layout: Some(&self.layout),
|
||||||
device: &Device,
|
vertex: wgpu::VertexState {
|
||||||
shader_assembly: &ShaderCompilerOutput<String, NagaWgslContext>,
|
module: &self.vertex,
|
||||||
reflection: &ShaderReflection,
|
entry_point: &self.vertex_entry_name,
|
||||||
render_pass_format: TextureFormat,
|
buffers: &[VertexBufferLayout {
|
||||||
) -> 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,
|
array_stride: 4 * std::mem::size_of::<f32>() as wgpu::BufferAddress,
|
||||||
step_mode: wgpu::VertexStepMode::Vertex,
|
step_mode: wgpu::VertexStepMode::Vertex,
|
||||||
attributes: &[
|
attributes: &[
|
||||||
|
@ -148,31 +161,13 @@ impl WgpuGraphicsPipeline {
|
||||||
shader_location: 1,
|
shader_location: 1,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
};
|
}],
|
||||||
|
|
||||||
let render_pipeline = device.create_render_pipeline(&wgpu::RenderPipelineDescriptor {
|
|
||||||
label: Some("Render Pipeline"),
|
|
||||||
layout: Some(&layout.layout),
|
|
||||||
vertex: wgpu::VertexState {
|
|
||||||
module: &vertex,
|
|
||||||
entry_point: &shader_assembly
|
|
||||||
.context
|
|
||||||
.vertex
|
|
||||||
.entry_points[0]
|
|
||||||
.name,
|
|
||||||
buffers: &[
|
|
||||||
vao_layout
|
|
||||||
],
|
|
||||||
},
|
},
|
||||||
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
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -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;
|
60
librashader-runtime-wgpu/src/luts.rs
Normal file
60
librashader-runtime-wgpu/src/luts.rs
Normal 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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -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 }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
|
}
|
||||||
|
}
|
|
@ -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();
|
||||||
|
|
|
@ -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(
|
|
||||||
&wgpu::util::BufferInitDescriptor {
|
|
||||||
label: Some("Vertex Buffer"),
|
label: Some("Vertex Buffer"),
|
||||||
contents: bytemuck::cast_slice(VERTICES),
|
contents: bytemuck::cast_slice(VERTICES),
|
||||||
usage: wgpu::BufferUsages::VERTEX,
|
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>) {
|
||||||
|
@ -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| {
|
||||||
|
@ -302,6 +295,4 @@ pub fn run() {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
|
@ -1,7 +1,6 @@
|
||||||
mod hello_triangle;
|
mod hello_triangle;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn triangle_wgpu()
|
fn triangle_wgpu() {
|
||||||
{
|
|
||||||
hello_triangle::run()
|
hello_triangle::run()
|
||||||
}
|
}
|
Loading…
Reference in a new issue