rt(wgpu): fix enough stuff to get it to draw a frame
This commit is contained in:
parent
e39834547c
commit
31891e414f
12 changed files with 405 additions and 288 deletions
|
@ -1,26 +1,27 @@
|
||||||
use std::ops::{Deref, DerefMut};
|
use std::ops::{Deref, DerefMut};
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
use parking_lot::RwLock;
|
||||||
|
|
||||||
pub struct WgpuMappedBuffer {
|
pub struct WgpuStagedBuffer {
|
||||||
buffer: wgpu::Buffer,
|
buffer: wgpu::Buffer,
|
||||||
shadow: Box<[u8]>,
|
shadow: Box<[u8]>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl WgpuMappedBuffer {
|
impl WgpuStagedBuffer {
|
||||||
pub fn new(
|
pub fn new(
|
||||||
device: &Arc<wgpu::Device>,
|
device: &Arc<wgpu::Device>,
|
||||||
usage: wgpu::BufferUsages,
|
usage: wgpu::BufferUsages,
|
||||||
size: wgpu::BufferAddress,
|
size: wgpu::BufferAddress,
|
||||||
label: wgpu::Label<'static>
|
label: wgpu::Label<'static>,
|
||||||
) -> WgpuMappedBuffer {
|
) -> WgpuStagedBuffer {
|
||||||
let buffer = device.create_buffer(&wgpu::BufferDescriptor {
|
let buffer = device.create_buffer(&wgpu::BufferDescriptor {
|
||||||
label,
|
label,
|
||||||
size,
|
size,
|
||||||
usage,
|
usage: usage | wgpu::BufferUsages::COPY_DST,
|
||||||
mapped_at_creation: true,
|
mapped_at_creation: false,
|
||||||
});
|
});
|
||||||
|
|
||||||
WgpuMappedBuffer {
|
WgpuStagedBuffer {
|
||||||
buffer,
|
buffer,
|
||||||
shadow: vec![0u8; size as usize].into_boxed_slice(),
|
shadow: vec![0u8; size as usize].into_boxed_slice(),
|
||||||
}
|
}
|
||||||
|
@ -31,13 +32,12 @@ impl WgpuMappedBuffer {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Write the contents of the backing buffer to the device buffer.
|
/// Write the contents of the backing buffer to the device buffer.
|
||||||
pub fn flush(&self) {
|
pub fn flush(&self, queue: &wgpu::Queue) {
|
||||||
self.buffer.slice(..)
|
queue.write_buffer(&self.buffer, 0, &self.shadow);
|
||||||
.get_mapped_range_mut().copy_from_slice(&self.shadow)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Deref for WgpuMappedBuffer {
|
impl Deref for WgpuStagedBuffer {
|
||||||
type Target = [u8];
|
type Target = [u8];
|
||||||
|
|
||||||
fn deref(&self) -> &Self::Target {
|
fn deref(&self) -> &Self::Target {
|
||||||
|
@ -45,7 +45,7 @@ impl Deref for WgpuMappedBuffer {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl DerefMut for WgpuMappedBuffer {
|
impl DerefMut for WgpuStagedBuffer {
|
||||||
fn deref_mut(&mut self) -> &mut Self::Target {
|
fn deref_mut(&mut self) -> &mut Self::Target {
|
||||||
self.shadow.deref_mut()
|
self.shadow.deref_mut()
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,7 +28,7 @@ pub struct DrawQuad {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl DrawQuad {
|
impl DrawQuad {
|
||||||
pub fn new(device: &Device, queue: &mut Queue) -> DrawQuad {
|
pub fn new(device: &Device) -> DrawQuad {
|
||||||
let buffer = device.create_buffer_init(&BufferInitDescriptor {
|
let buffer = device.create_buffer_init(&BufferInitDescriptor {
|
||||||
label: Some("librashader vbo"),
|
label: Some("librashader vbo"),
|
||||||
contents: bytemuck::cast_slice(&VBO_DATA),
|
contents: bytemuck::cast_slice(&VBO_DATA),
|
||||||
|
@ -38,14 +38,12 @@ impl DrawQuad {
|
||||||
DrawQuad { buffer }
|
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) {
|
pub fn draw_quad<'a, 'b: 'a>(&'b self, cmd: &mut RenderPass<'a>, vbo: QuadType) {
|
||||||
|
cmd.set_vertex_buffer(0, self.buffer.slice(0..));
|
||||||
|
|
||||||
let offset = match vbo {
|
let offset = match vbo {
|
||||||
QuadType::Offscreen => 0..3,
|
QuadType::Offscreen => 0..4,
|
||||||
QuadType::Final => 1..4,
|
QuadType::Final => 4..8,
|
||||||
};
|
};
|
||||||
|
|
||||||
cmd.draw(offset, 0..1)
|
cmd.draw(offset, 0..1)
|
||||||
|
|
|
@ -16,20 +16,22 @@ use std::convert::Infallible;
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
|
use crate::buffer::WgpuStagedBuffer;
|
||||||
|
use crate::draw_quad::DrawQuad;
|
||||||
use librashader_common::{ImageFormat, Size, Viewport};
|
use librashader_common::{ImageFormat, Size, Viewport};
|
||||||
use librashader_reflect::back::wgsl::WgslCompileOptions;
|
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::{BindGroupEntry, CommandBuffer, CommandEncoder, Device, Queue, TextureAspect, TextureFormat};
|
use wgpu::{
|
||||||
use crate::buffer::WgpuMappedBuffer;
|
BindGroupEntry, CommandBuffer, CommandEncoder, Device, Queue, TextureAspect, TextureFormat,
|
||||||
use crate::draw_quad::DrawQuad;
|
};
|
||||||
|
|
||||||
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::framebuffer::OutputImage;
|
use crate::framebuffer::OutputView;
|
||||||
use crate::graphics_pipeline::WgpuGraphicsPipeline;
|
use crate::graphics_pipeline::WgpuGraphicsPipeline;
|
||||||
use crate::luts::LutTexture;
|
use crate::luts::LutTexture;
|
||||||
use crate::options::FrameOptionsWGPU;
|
use crate::options::FrameOptionsWGPU;
|
||||||
|
@ -73,6 +75,7 @@ pub(crate) struct FilterCommon {
|
||||||
pub internal_frame_count: i32,
|
pub internal_frame_count: i32,
|
||||||
pub(crate) draw_quad: DrawQuad,
|
pub(crate) draw_quad: DrawQuad,
|
||||||
device: Arc<Device>,
|
device: Arc<Device>,
|
||||||
|
pub(crate) queue: Arc<wgpu::Queue>
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FilterChainWGPU {
|
impl FilterChainWGPU {
|
||||||
|
@ -85,7 +88,7 @@ impl FilterChainWGPU {
|
||||||
/// 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: Arc<Device>,
|
device: Arc<Device>,
|
||||||
queue: &mut wgpu::Queue,
|
queue: Arc<wgpu::Queue>,
|
||||||
cmd: &mut wgpu::CommandEncoder,
|
cmd: &mut wgpu::CommandEncoder,
|
||||||
preset: ShaderPreset,
|
preset: ShaderPreset,
|
||||||
) -> error::Result<FilterChainWGPU> {
|
) -> error::Result<FilterChainWGPU> {
|
||||||
|
@ -94,11 +97,17 @@ impl FilterChainWGPU {
|
||||||
// // initialize passes
|
// // initialize passes
|
||||||
let filters = Self::init_passes(Arc::clone(&device), passes, &semantics)?;
|
let filters = Self::init_passes(Arc::clone(&device), passes, &semantics)?;
|
||||||
//
|
//
|
||||||
let luts = FilterChainWGPU::load_luts(&device, queue, cmd, &preset.textures)?;
|
let luts = FilterChainWGPU::load_luts(&device, &queue, cmd, &preset.textures)?;
|
||||||
let samplers = SamplerSet::new(&device);
|
let samplers = SamplerSet::new(&device);
|
||||||
//
|
//
|
||||||
let framebuffer_gen =
|
let framebuffer_gen = || {
|
||||||
|| Ok::<_, error::FilterChainError>(OwnedImage::new(Arc::clone(&device), Size::new(1, 1), 1, ImageFormat::R8G8B8A8Unorm));
|
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),
|
||||||
|
@ -122,7 +131,7 @@ impl FilterChainWGPU {
|
||||||
// FrameResiduals::new(&device.device)
|
// FrameResiduals::new(&device.device)
|
||||||
// });
|
// });
|
||||||
|
|
||||||
let draw_quad = DrawQuad::new(&device, queue);
|
let draw_quad = DrawQuad::new(&device);
|
||||||
|
|
||||||
Ok(FilterChainWGPU {
|
Ok(FilterChainWGPU {
|
||||||
common: FilterCommon {
|
common: FilterCommon {
|
||||||
|
@ -138,23 +147,23 @@ impl FilterChainWGPU {
|
||||||
},
|
},
|
||||||
draw_quad,
|
draw_quad,
|
||||||
device,
|
device,
|
||||||
|
queue,
|
||||||
output_textures,
|
output_textures,
|
||||||
feedback_textures,
|
feedback_textures,
|
||||||
history_textures,
|
history_textures,
|
||||||
internal_frame_count: 0,
|
internal_frame_count: 0,
|
||||||
|
|
||||||
},
|
},
|
||||||
passes: filters,
|
passes: filters,
|
||||||
output_framebuffers,
|
output_framebuffers,
|
||||||
feedback_framebuffers,
|
feedback_framebuffers,
|
||||||
history_framebuffers,
|
history_framebuffers,
|
||||||
disable_mipmaps: false // todo: force no mipmaps,
|
disable_mipmaps: false, // todo: force no mipmaps,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn load_luts(
|
fn load_luts(
|
||||||
device: &wgpu::Device,
|
device: &wgpu::Device,
|
||||||
queue: &mut wgpu::Queue,
|
queue: &wgpu::Queue,
|
||||||
cmd: &mut wgpu::CommandEncoder,
|
cmd: &mut wgpu::CommandEncoder,
|
||||||
textures: &[TextureConfig],
|
textures: &[TextureConfig],
|
||||||
) -> error::Result<FxHashMap<usize, LutTexture>> {
|
) -> error::Result<FxHashMap<usize, LutTexture>> {
|
||||||
|
@ -170,6 +179,29 @@ impl FilterChainWGPU {
|
||||||
Ok(luts)
|
Ok(luts)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn push_history(&mut self, input: &wgpu::Texture, cmd: &mut wgpu::CommandEncoder) {
|
||||||
|
if let Some(mut back) = self.history_framebuffers.pop_back() {
|
||||||
|
if back.image.size() != input.size() || input.format() != back.image.format() {
|
||||||
|
// old back will get dropped.. do we need to defer?
|
||||||
|
let _old_back = std::mem::replace(
|
||||||
|
&mut back,
|
||||||
|
OwnedImage::new(
|
||||||
|
Arc::clone(&self.common.device),
|
||||||
|
input.size().into(),
|
||||||
|
1,
|
||||||
|
input.format().into(),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe {
|
||||||
|
back.copy_from(cmd, input);
|
||||||
|
}
|
||||||
|
|
||||||
|
self.history_framebuffers.push_front(back)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn init_passes(
|
fn init_passes(
|
||||||
device: Arc<Device>,
|
device: Arc<Device>,
|
||||||
passes: Vec<ShaderPassMeta>,
|
passes: Vec<ShaderPassMeta>,
|
||||||
|
@ -193,10 +225,19 @@ impl FilterChainWGPU {
|
||||||
.as_ref()
|
.as_ref()
|
||||||
.map_or(0, |push| push.size as wgpu::BufferAddress);
|
.map_or(0, |push| push.size as wgpu::BufferAddress);
|
||||||
|
|
||||||
|
|
||||||
let uniform_storage = UniformStorage::new_with_storage(
|
let uniform_storage = UniformStorage::new_with_storage(
|
||||||
WgpuMappedBuffer::new(&device, wgpu::BufferUsages::UNIFORM, ubo_size as wgpu::BufferAddress, Some("ubo")),
|
WgpuStagedBuffer::new(
|
||||||
WgpuMappedBuffer::new(&device, wgpu::BufferUsages::UNIFORM, push_size as wgpu::BufferAddress, Some("push"))
|
&device,
|
||||||
|
wgpu::BufferUsages::UNIFORM,
|
||||||
|
ubo_size as wgpu::BufferAddress,
|
||||||
|
Some("ubo"),
|
||||||
|
),
|
||||||
|
WgpuStagedBuffer::new(
|
||||||
|
&device,
|
||||||
|
wgpu::BufferUsages::UNIFORM,
|
||||||
|
push_size as wgpu::BufferAddress,
|
||||||
|
Some("push"),
|
||||||
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
let uniform_bindings = reflection.meta.create_binding_map(|param| param.offset());
|
let uniform_bindings = reflection.meta.create_binding_map(|param| param.offset());
|
||||||
|
@ -212,11 +253,9 @@ impl FilterChainWGPU {
|
||||||
Arc::clone(&device),
|
Arc::clone(&device),
|
||||||
&wgsl,
|
&wgsl,
|
||||||
&reflection,
|
&reflection,
|
||||||
render_pass_format.unwrap_or(TextureFormat::R8Unorm),
|
render_pass_format.unwrap_or(TextureFormat::Rgba8Unorm),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Ok(FilterPass {
|
Ok(FilterPass {
|
||||||
device: Arc::clone(&device),
|
device: Arc::clone(&device),
|
||||||
reflection,
|
reflection,
|
||||||
|
@ -235,13 +274,13 @@ impl FilterChainWGPU {
|
||||||
Ok(filters.into_boxed_slice())
|
Ok(filters.into_boxed_slice())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn frame<'a>(&mut self,
|
pub fn frame<'a>(
|
||||||
|
&mut self,
|
||||||
input: Arc<wgpu::Texture>,
|
input: Arc<wgpu::Texture>,
|
||||||
viewport: &Viewport<OutputImage<'a>>,
|
viewport: &Viewport<OutputView<'a>>,
|
||||||
cmd: &mut wgpu::CommandEncoder,
|
cmd: &mut wgpu::CommandEncoder,
|
||||||
frame_count: usize,
|
frame_count: usize,
|
||||||
options: Option<&FrameOptionsWGPU>,
|
options: Option<&FrameOptionsWGPU>,
|
||||||
|
|
||||||
) -> error::Result<()> {
|
) -> error::Result<()> {
|
||||||
let max = std::cmp::min(self.passes.len(), self.common.config.passes_enabled);
|
let max = std::cmp::min(self.passes.len(), self.common.config.passes_enabled);
|
||||||
let passes = &mut self.passes[0..max];
|
let passes = &mut self.passes[0..max];
|
||||||
|
@ -249,7 +288,7 @@ impl FilterChainWGPU {
|
||||||
if let Some(options) = &options {
|
if let Some(options) = &options {
|
||||||
if options.clear_history {
|
if options.clear_history {
|
||||||
for history in &mut self.history_framebuffers {
|
for history in &mut self.history_framebuffers {
|
||||||
// history.clear(cmd);
|
history.clear(cmd);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -258,21 +297,11 @@ impl FilterChainWGPU {
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
|
||||||
let original_image_view = input.create_view(&wgpu::TextureViewDescriptor {
|
let original_image_view = input.create_view(&wgpu::TextureViewDescriptor::default());
|
||||||
label: Some("original_image_view"),
|
|
||||||
format: Some(input.format()),
|
|
||||||
dimension: Some(wgpu::TextureViewDimension::D2),
|
|
||||||
aspect: TextureAspect::All,
|
|
||||||
base_mip_level: 1,
|
|
||||||
mip_level_count: None,
|
|
||||||
base_array_layer: 1,
|
|
||||||
array_layer_count: None,
|
|
||||||
});
|
|
||||||
|
|
||||||
let filter = passes[0].config.filter;
|
let filter = passes[0].config.filter;
|
||||||
let wrap_mode = passes[0].config.wrap_mode;
|
let wrap_mode = passes[0].config.wrap_mode;
|
||||||
|
|
||||||
|
|
||||||
// update history
|
// update history
|
||||||
for (texture, image) in self
|
for (texture, image) in self
|
||||||
.common
|
.common
|
||||||
|
@ -325,14 +354,13 @@ impl FilterChainWGPU {
|
||||||
|
|
||||||
let frame_direction = options.map_or(1, |f| f.frame_direction);
|
let frame_direction = options.map_or(1, |f| f.frame_direction);
|
||||||
|
|
||||||
|
|
||||||
for (index, pass) in pass.iter_mut().enumerate() {
|
for (index, pass) in pass.iter_mut().enumerate() {
|
||||||
let target = &self.output_framebuffers[index];
|
let target = &self.output_framebuffers[index];
|
||||||
source.filter_mode = pass.config.filter;
|
source.filter_mode = pass.config.filter;
|
||||||
source.wrap_mode = pass.config.wrap_mode;
|
source.wrap_mode = pass.config.wrap_mode;
|
||||||
source.mip_filter = pass.config.filter;
|
source.mip_filter = pass.config.filter;
|
||||||
|
|
||||||
let output_image = OutputImage::new(target);
|
let output_image = OutputView::new(target);
|
||||||
let out = RenderTarget::identity(&output_image);
|
let out = RenderTarget::identity(&output_image);
|
||||||
|
|
||||||
pass.draw(
|
pass.draw(
|
||||||
|
@ -345,11 +373,11 @@ impl FilterChainWGPU {
|
||||||
&original,
|
&original,
|
||||||
&source,
|
&source,
|
||||||
&out,
|
&out,
|
||||||
QuadType::Offscreen
|
QuadType::Offscreen,
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
if target.max_miplevels > 1 && !self.disable_mipmaps {
|
if target.max_miplevels > 1 && !self.disable_mipmaps {
|
||||||
// todo: mipmaps
|
target.generate_mipmaps(cmd);
|
||||||
}
|
}
|
||||||
|
|
||||||
source = self.common.output_textures[index].clone().unwrap();
|
source = self.common.output_textures[index].clone().unwrap();
|
||||||
|
@ -378,13 +406,12 @@ impl FilterChainWGPU {
|
||||||
&original,
|
&original,
|
||||||
&source,
|
&source,
|
||||||
&out,
|
&out,
|
||||||
QuadType::Final
|
QuadType::Final,
|
||||||
)?;
|
)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
// self.push_history(input, cmd)?;
|
self.push_history(&input, cmd);
|
||||||
self.common.internal_frame_count = self.common.internal_frame_count.wrapping_add(1);
|
self.common.internal_frame_count = self.common.internal_frame_count.wrapping_add(1);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,37 +1,42 @@
|
||||||
|
use crate::buffer::WgpuStagedBuffer;
|
||||||
|
use crate::error;
|
||||||
|
use crate::filter_chain::FilterCommon;
|
||||||
|
use crate::framebuffer::OutputView;
|
||||||
use crate::graphics_pipeline::WgpuGraphicsPipeline;
|
use crate::graphics_pipeline::WgpuGraphicsPipeline;
|
||||||
|
use crate::samplers::SamplerSet;
|
||||||
|
use crate::texture::{InputImage, OwnedImage};
|
||||||
|
use librashader_common::{ImageFormat, Size, Viewport};
|
||||||
use librashader_preprocess::ShaderSource;
|
use librashader_preprocess::ShaderSource;
|
||||||
use librashader_presets::ShaderPassConfig;
|
use librashader_presets::ShaderPassConfig;
|
||||||
use librashader_reflect::back::wgsl::NagaWgslContext;
|
use librashader_reflect::back::wgsl::NagaWgslContext;
|
||||||
use librashader_reflect::back::ShaderCompilerOutput;
|
use librashader_reflect::back::ShaderCompilerOutput;
|
||||||
use librashader_reflect::reflect::semantics::{BindingStage, MemberOffset, TextureBinding, UniformBinding};
|
use librashader_reflect::reflect::semantics::{
|
||||||
|
BindingStage, MemberOffset, TextureBinding, UniformBinding,
|
||||||
|
};
|
||||||
use librashader_reflect::reflect::ShaderReflection;
|
use librashader_reflect::reflect::ShaderReflection;
|
||||||
use librashader_runtime::uniforms::{NoUniformBinder, UniformStorage, UniformStorageAccess};
|
|
||||||
use rustc_hash::FxHashMap;
|
|
||||||
use std::sync::Arc;
|
|
||||||
use wgpu::{BindGroupDescriptor, BindGroupEntry, BindingResource, Buffer, BufferBinding, BufferUsages, RenderPass, ShaderStages, TextureView};
|
|
||||||
use wgpu::util::{BufferInitDescriptor, DeviceExt};
|
|
||||||
use librashader_common::{ImageFormat, Size, Viewport};
|
|
||||||
use librashader_runtime::binding::{BindSemantics, TextureInput};
|
use librashader_runtime::binding::{BindSemantics, TextureInput};
|
||||||
use librashader_runtime::filter_pass::FilterPassMeta;
|
use librashader_runtime::filter_pass::FilterPassMeta;
|
||||||
use librashader_runtime::quad::QuadType;
|
use librashader_runtime::quad::QuadType;
|
||||||
use librashader_runtime::render_target::RenderTarget;
|
use librashader_runtime::render_target::RenderTarget;
|
||||||
use crate::buffer::WgpuMappedBuffer;
|
use librashader_runtime::uniforms::{NoUniformBinder, UniformStorage, UniformStorageAccess};
|
||||||
use crate::error;
|
use rustc_hash::FxHashMap;
|
||||||
use crate::filter_chain::FilterCommon;
|
use std::sync::Arc;
|
||||||
use crate::framebuffer::OutputImage;
|
use wgpu::util::{BufferInitDescriptor, DeviceExt};
|
||||||
use crate::samplers::SamplerSet;
|
use wgpu::{
|
||||||
use crate::texture::{InputImage, OwnedImage};
|
BindGroupDescriptor, BindGroupEntry, BindingResource, Buffer, BufferBinding, BufferUsages,
|
||||||
|
RenderPass, ShaderStages, TextureView,
|
||||||
|
};
|
||||||
|
|
||||||
pub struct FilterPass {
|
pub struct FilterPass {
|
||||||
pub device: Arc<wgpu::Device>,
|
pub device: Arc<wgpu::Device>,
|
||||||
pub reflection: ShaderReflection,
|
pub reflection: ShaderReflection,
|
||||||
pub(crate) compiled: ShaderCompilerOutput<String, NagaWgslContext>,
|
pub(crate) compiled: ShaderCompilerOutput<String, NagaWgslContext>,
|
||||||
pub(crate) uniform_storage: UniformStorage<NoUniformBinder, Option<()>, WgpuMappedBuffer, WgpuMappedBuffer>,
|
pub(crate) uniform_storage:
|
||||||
|
UniformStorage<NoUniformBinder, Option<()>, WgpuStagedBuffer, WgpuStagedBuffer>,
|
||||||
pub uniform_bindings: FxHashMap<UniformBinding, MemberOffset>,
|
pub uniform_bindings: FxHashMap<UniformBinding, MemberOffset>,
|
||||||
pub source: ShaderSource,
|
pub source: ShaderSource,
|
||||||
pub config: ShaderPassConfig,
|
pub config: ShaderPassConfig,
|
||||||
pub graphics_pipeline: WgpuGraphicsPipeline,
|
pub graphics_pipeline: WgpuGraphicsPipeline,
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TextureInput for InputImage {
|
impl TextureInput for InputImage {
|
||||||
|
@ -42,10 +47,10 @@ impl TextureInput for InputImage {
|
||||||
|
|
||||||
pub struct WgpuArcBinding<T> {
|
pub struct WgpuArcBinding<T> {
|
||||||
binding: u32,
|
binding: u32,
|
||||||
resource: Arc<T>
|
resource: Arc<T>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl BindSemantics<NoUniformBinder, Option<()>, WgpuMappedBuffer, WgpuMappedBuffer> for FilterPass {
|
impl BindSemantics<NoUniformBinder, Option<()>, WgpuStagedBuffer, WgpuStagedBuffer> for FilterPass {
|
||||||
type InputTexture = InputImage;
|
type InputTexture = InputImage;
|
||||||
type SamplerSet = SamplerSet;
|
type SamplerSet = SamplerSet;
|
||||||
type DescriptorSet<'a> = (
|
type DescriptorSet<'a> = (
|
||||||
|
@ -66,15 +71,21 @@ impl BindSemantics<NoUniformBinder, Option<()>, WgpuMappedBuffer, WgpuMappedBuff
|
||||||
let sampler = samplers.get(texture.wrap_mode, texture.filter_mode, texture.mip_filter);
|
let sampler = samplers.get(texture.wrap_mode, texture.filter_mode, texture.mip_filter);
|
||||||
|
|
||||||
let (texture_binding, sampler_binding) = descriptors;
|
let (texture_binding, sampler_binding) = descriptors;
|
||||||
texture_binding.insert(binding.binding, WgpuArcBinding {
|
texture_binding.insert(
|
||||||
|
binding.binding,
|
||||||
|
WgpuArcBinding {
|
||||||
binding: binding.binding,
|
binding: binding.binding,
|
||||||
resource: Arc::clone(&texture.view)
|
resource: Arc::clone(&texture.view),
|
||||||
});
|
},
|
||||||
|
);
|
||||||
|
|
||||||
sampler_binding.insert(binding.binding, WgpuArcBinding {
|
sampler_binding.insert(
|
||||||
|
binding.binding,
|
||||||
|
WgpuArcBinding {
|
||||||
binding: binding.binding,
|
binding: binding.binding,
|
||||||
resource: sampler,
|
resource: sampler,
|
||||||
});
|
},
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -86,13 +97,12 @@ impl FilterPass {
|
||||||
parent: &FilterCommon,
|
parent: &FilterCommon,
|
||||||
frame_count: u32,
|
frame_count: u32,
|
||||||
frame_direction: i32,
|
frame_direction: i32,
|
||||||
viewport: &Viewport<OutputImage>,
|
viewport: &Viewport<OutputView>,
|
||||||
original: &InputImage,
|
original: &InputImage,
|
||||||
source: &InputImage,
|
source: &InputImage,
|
||||||
output: &RenderTarget<OutputImage>,
|
output: &RenderTarget<OutputView>,
|
||||||
vbo_type: QuadType,
|
vbo_type: QuadType,
|
||||||
) -> error::Result<()> {
|
) -> error::Result<()> {
|
||||||
|
|
||||||
let mut main_heap = FxHashMap::default();
|
let mut main_heap = FxHashMap::default();
|
||||||
let mut sampler_heap = FxHashMap::default();
|
let mut sampler_heap = FxHashMap::default();
|
||||||
|
|
||||||
|
@ -110,21 +120,20 @@ impl FilterPass {
|
||||||
&mut sampler_heap,
|
&mut sampler_heap,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
||||||
let mut main_heap_array = Vec::with_capacity(main_heap.len() + 1);
|
let mut main_heap_array = Vec::with_capacity(main_heap.len() + 1);
|
||||||
let mut sampler_heap_array = Vec::with_capacity(sampler_heap.len() + 1);
|
let mut sampler_heap_array = Vec::with_capacity(sampler_heap.len() + 1);
|
||||||
|
|
||||||
for binding in main_heap.values() {
|
for binding in main_heap.values() {
|
||||||
main_heap_array.push(BindGroupEntry {
|
main_heap_array.push(BindGroupEntry {
|
||||||
binding: binding.binding,
|
binding: binding.binding,
|
||||||
resource: BindingResource::TextureView(&binding.resource)
|
resource: BindingResource::TextureView(&binding.resource),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
for binding in sampler_heap.values() {
|
for binding in sampler_heap.values() {
|
||||||
sampler_heap_array.push(BindGroupEntry {
|
sampler_heap_array.push(BindGroupEntry {
|
||||||
binding: binding.binding,
|
binding: binding.binding,
|
||||||
resource: BindingResource::Sampler(&binding.resource)
|
resource: BindingResource::Sampler(&binding.resource),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -157,31 +166,24 @@ impl FilterPass {
|
||||||
let main_bind_group = self.device.create_bind_group(&BindGroupDescriptor {
|
let main_bind_group = self.device.create_bind_group(&BindGroupDescriptor {
|
||||||
label: Some("main bind group"),
|
label: Some("main bind group"),
|
||||||
layout: &self.graphics_pipeline.layout.main_bind_group_layout,
|
layout: &self.graphics_pipeline.layout.main_bind_group_layout,
|
||||||
entries: &main_heap_array
|
entries: &main_heap_array,
|
||||||
});
|
});
|
||||||
|
|
||||||
let sampler_bind_group = self.device.create_bind_group(&BindGroupDescriptor {
|
let sampler_bind_group = self.device.create_bind_group(&BindGroupDescriptor {
|
||||||
label: Some("sampler bind group"),
|
label: Some("sampler bind group"),
|
||||||
layout: &self.graphics_pipeline.layout.sampler_bind_group_layout,
|
layout: &self.graphics_pipeline.layout.sampler_bind_group_layout,
|
||||||
entries: &sampler_heap_array
|
entries: &sampler_heap_array,
|
||||||
});
|
});
|
||||||
|
|
||||||
let mut render_pass = self.graphics_pipeline
|
let mut render_pass = self.graphics_pipeline.begin_rendering(output, cmd);
|
||||||
.begin_rendering(output, cmd);
|
|
||||||
|
|
||||||
render_pass.set_bind_group(
|
render_pass.set_bind_group(0, &main_bind_group, &[]);
|
||||||
0,
|
|
||||||
&main_bind_group,
|
|
||||||
&[]
|
|
||||||
);
|
|
||||||
|
|
||||||
render_pass.set_bind_group(
|
render_pass.set_bind_group(1, &sampler_bind_group, &[]);
|
||||||
1,
|
|
||||||
&sampler_bind_group,
|
|
||||||
&[]
|
|
||||||
);
|
|
||||||
|
|
||||||
if let Some(push) = &self.reflection.push_constant && !has_pcb_buffer {
|
if let Some(push) = &self.reflection.push_constant
|
||||||
|
&& !has_pcb_buffer
|
||||||
|
{
|
||||||
let mut stage_mask = ShaderStages::empty();
|
let mut stage_mask = ShaderStages::empty();
|
||||||
if push.stage_mask.contains(BindingStage::FRAGMENT) {
|
if push.stage_mask.contains(BindingStage::FRAGMENT) {
|
||||||
stage_mask |= ShaderStages::FRAGMENT;
|
stage_mask |= ShaderStages::FRAGMENT;
|
||||||
|
@ -189,11 +191,7 @@ impl FilterPass {
|
||||||
if push.stage_mask.contains(BindingStage::VERTEX) {
|
if push.stage_mask.contains(BindingStage::VERTEX) {
|
||||||
stage_mask |= ShaderStages::VERTEX;
|
stage_mask |= ShaderStages::VERTEX;
|
||||||
}
|
}
|
||||||
render_pass.set_push_constants(
|
render_pass.set_push_constants(stage_mask, 0, self.uniform_storage.push_slice())
|
||||||
stage_mask,
|
|
||||||
0,
|
|
||||||
self.uniform_storage.push_slice()
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
parent.draw_quad.draw_quad(&mut render_pass, vbo_type);
|
parent.draw_quad.draw_quad(&mut render_pass, vbo_type);
|
||||||
|
@ -213,7 +211,7 @@ impl FilterPass {
|
||||||
original: &InputImage,
|
original: &InputImage,
|
||||||
source: &InputImage,
|
source: &InputImage,
|
||||||
main_heap: &'a mut FxHashMap<u32, WgpuArcBinding<wgpu::TextureView>>,
|
main_heap: &'a mut FxHashMap<u32, WgpuArcBinding<wgpu::TextureView>>,
|
||||||
sampler_heap: &'a mut FxHashMap<u32, WgpuArcBinding<wgpu::Sampler>>
|
sampler_heap: &'a mut FxHashMap<u32, WgpuArcBinding<wgpu::Sampler>>,
|
||||||
) {
|
) {
|
||||||
Self::bind_semantics(
|
Self::bind_semantics(
|
||||||
&self.device,
|
&self.device,
|
||||||
|
@ -240,8 +238,8 @@ impl FilterPass {
|
||||||
);
|
);
|
||||||
|
|
||||||
// flush to buffers
|
// flush to buffers
|
||||||
self.uniform_storage.inner_ubo().flush();
|
self.uniform_storage.inner_ubo().flush(&parent.queue);
|
||||||
self.uniform_storage.inner_push().flush();
|
self.uniform_storage.inner_push().flush(&parent.queue);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,18 +1,20 @@
|
||||||
use librashader_common::Size;
|
|
||||||
use crate::texture::OwnedImage;
|
use crate::texture::OwnedImage;
|
||||||
|
use librashader_common::Size;
|
||||||
|
|
||||||
pub struct OutputImage<'a> {
|
pub struct OutputView<'a> {
|
||||||
pub size: Size<u32>,
|
pub size: Size<u32>,
|
||||||
pub view: &'a wgpu::TextureView,
|
pub view: &'a wgpu::TextureView,
|
||||||
pub format: wgpu::TextureFormat,
|
pub format: wgpu::TextureFormat,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> OutputImage<'a> {
|
impl<'a> OutputView<'a> {
|
||||||
pub fn new(image: &'a OwnedImage) -> Self {
|
pub fn new(image: &'a OwnedImage) -> Self {
|
||||||
Self {
|
Self {
|
||||||
size: image.size,
|
size: image.size,
|
||||||
view: &image.view,
|
view: &image.view,
|
||||||
format: image.image.format()
|
format: image.image.format(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,17 +1,24 @@
|
||||||
|
use crate::framebuffer::OutputView;
|
||||||
use crate::{error, util};
|
use crate::{error, util};
|
||||||
use librashader_reflect::back::wgsl::NagaWgslContext;
|
use librashader_reflect::back::wgsl::NagaWgslContext;
|
||||||
use librashader_reflect::back::ShaderCompilerOutput;
|
use librashader_reflect::back::ShaderCompilerOutput;
|
||||||
use librashader_reflect::reflect::ShaderReflection;
|
use librashader_reflect::reflect::ShaderReflection;
|
||||||
|
use librashader_runtime::render_target::RenderTarget;
|
||||||
use std::borrow::Cow;
|
use std::borrow::Cow;
|
||||||
use std::sync::Arc;
|
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 wgpu::{
|
||||||
use librashader_runtime::render_target::RenderTarget;
|
BindGroup, BindGroupDescriptor, BindGroupLayout, BindGroupLayoutDescriptor,
|
||||||
use crate::framebuffer::OutputImage;
|
BindGroupLayoutEntry, BindingType, BufferBindingType, BufferSize, CommandEncoder, Device,
|
||||||
|
Operations, PipelineLayout, PushConstantRange, RenderPass, RenderPassColorAttachment,
|
||||||
|
RenderPassDescriptor, RenderPipelineDescriptor, SamplerBindingType, ShaderModule, ShaderSource,
|
||||||
|
ShaderStages, TextureFormat, TextureSampleType, TextureViewDimension, VertexAttribute,
|
||||||
|
VertexBufferLayout,
|
||||||
|
};
|
||||||
|
|
||||||
pub struct WgpuGraphicsPipeline {
|
pub struct WgpuGraphicsPipeline {
|
||||||
pub layout: PipelineLayoutObjects,
|
pub layout: PipelineLayoutObjects,
|
||||||
render_pipeline: wgpu::RenderPipeline,
|
render_pipeline: wgpu::RenderPipeline,
|
||||||
pub format: wgpu::TextureFormat
|
pub format: wgpu::TextureFormat,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct PipelineLayoutObjects {
|
pub struct PipelineLayoutObjects {
|
||||||
|
@ -22,7 +29,7 @@ pub struct PipelineLayoutObjects {
|
||||||
vertex_entry_name: String,
|
vertex_entry_name: String,
|
||||||
vertex: ShaderModule,
|
vertex: ShaderModule,
|
||||||
fragment: ShaderModule,
|
fragment: ShaderModule,
|
||||||
device: Arc<wgpu::Device>
|
device: Arc<wgpu::Device>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PipelineLayoutObjects {
|
impl PipelineLayoutObjects {
|
||||||
|
@ -138,7 +145,8 @@ impl PipelineLayoutObjects {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn create_pipeline(&self, framebuffer_format: TextureFormat) -> wgpu::RenderPipeline {
|
pub fn create_pipeline(&self, framebuffer_format: TextureFormat) -> wgpu::RenderPipeline {
|
||||||
self.device.create_render_pipeline(&wgpu::RenderPipelineDescriptor {
|
self.device
|
||||||
|
.create_render_pipeline(&wgpu::RenderPipelineDescriptor {
|
||||||
label: Some("Render Pipeline"),
|
label: Some("Render Pipeline"),
|
||||||
layout: Some(&self.layout),
|
layout: Some(&self.layout),
|
||||||
vertex: wgpu::VertexState {
|
vertex: wgpu::VertexState {
|
||||||
|
@ -202,7 +210,7 @@ impl WgpuGraphicsPipeline {
|
||||||
Self {
|
Self {
|
||||||
layout,
|
layout,
|
||||||
render_pipeline,
|
render_pipeline,
|
||||||
format: render_pass_format
|
format: render_pass_format,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -213,8 +221,8 @@ impl WgpuGraphicsPipeline {
|
||||||
|
|
||||||
pub(crate) fn begin_rendering<'pass>(
|
pub(crate) fn begin_rendering<'pass>(
|
||||||
&'pass self,
|
&'pass self,
|
||||||
output: &RenderTarget<'pass, OutputImage>,
|
output: &RenderTarget<'pass, OutputView>,
|
||||||
cmd: &'pass mut CommandEncoder
|
cmd: &'pass mut CommandEncoder,
|
||||||
) -> RenderPass<'pass> {
|
) -> RenderPass<'pass> {
|
||||||
let mut render_pass = cmd.begin_render_pass(&RenderPassDescriptor {
|
let mut render_pass = cmd.begin_render_pass(&RenderPassDescriptor {
|
||||||
label: Some("librashader"),
|
label: Some("librashader"),
|
||||||
|
@ -240,7 +248,7 @@ impl WgpuGraphicsPipeline {
|
||||||
output.x as u32,
|
output.x as u32,
|
||||||
output.y as u32,
|
output.y as u32,
|
||||||
output.output.size.width,
|
output.output.size.width,
|
||||||
output.output.size.height
|
output.output.size.height,
|
||||||
);
|
);
|
||||||
|
|
||||||
render_pass.set_viewport(
|
render_pass.set_viewport(
|
||||||
|
@ -249,10 +257,10 @@ impl WgpuGraphicsPipeline {
|
||||||
output.output.size.width as f32,
|
output.output.size.width as f32,
|
||||||
output.output.size.height as f32,
|
output.output.size.height as f32,
|
||||||
1.0,
|
1.0,
|
||||||
1.0
|
1.0,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
render_pass.set_pipeline(&self.render_pipeline);
|
||||||
render_pass
|
render_pass
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,18 +7,19 @@
|
||||||
#![feature(let_chains)]
|
#![feature(let_chains)]
|
||||||
#![feature(strict_provenance)]
|
#![feature(strict_provenance)]
|
||||||
|
|
||||||
|
mod buffer;
|
||||||
mod draw_quad;
|
mod draw_quad;
|
||||||
mod error;
|
mod error;
|
||||||
mod filter_chain;
|
mod filter_chain;
|
||||||
mod filter_pass;
|
mod filter_pass;
|
||||||
|
mod framebuffer;
|
||||||
mod graphics_pipeline;
|
mod graphics_pipeline;
|
||||||
|
mod luts;
|
||||||
|
mod options;
|
||||||
mod samplers;
|
mod samplers;
|
||||||
mod texture;
|
mod texture;
|
||||||
mod util;
|
mod util;
|
||||||
mod framebuffer;
|
|
||||||
mod luts;
|
|
||||||
mod options;
|
|
||||||
mod buffer;
|
|
||||||
|
|
||||||
|
pub use framebuffer::OutputView;
|
||||||
pub use filter_chain::FilterChainWGPU;
|
pub use filter_chain::FilterChainWGPU;
|
||||||
pub use filter_pass::FilterPass;
|
pub use filter_pass::FilterPass;
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
use std::sync::Arc;
|
|
||||||
use wgpu::{ImageDataLayout, Label, TextureDescriptor};
|
|
||||||
use wgpu::util::DeviceExt;
|
|
||||||
use librashader_presets::TextureConfig;
|
|
||||||
use librashader_runtime::image::{BGRA8, Image};
|
|
||||||
use librashader_runtime::scaling::MipmapSize;
|
|
||||||
use crate::texture::{Handle, InputImage};
|
use crate::texture::{Handle, InputImage};
|
||||||
|
use librashader_presets::TextureConfig;
|
||||||
|
use librashader_runtime::image::{Image, BGRA8};
|
||||||
|
use librashader_runtime::scaling::MipmapSize;
|
||||||
|
use std::sync::Arc;
|
||||||
|
use wgpu::util::DeviceExt;
|
||||||
|
use wgpu::{ImageDataLayout, Label, TextureDescriptor};
|
||||||
|
|
||||||
pub(crate) struct LutTexture(InputImage);
|
pub(crate) struct LutTexture(InputImage);
|
||||||
impl AsRef<InputImage> for LutTexture {
|
impl AsRef<InputImage> for LutTexture {
|
||||||
|
@ -16,10 +16,10 @@ impl AsRef<InputImage> for LutTexture {
|
||||||
impl LutTexture {
|
impl LutTexture {
|
||||||
pub fn new(
|
pub fn new(
|
||||||
device: &wgpu::Device,
|
device: &wgpu::Device,
|
||||||
queue: &mut wgpu::Queue,
|
queue: &wgpu::Queue,
|
||||||
_cmd: &mut wgpu::CommandEncoder,
|
_cmd: &mut wgpu::CommandEncoder,
|
||||||
image: Image,
|
image: Image,
|
||||||
config: &TextureConfig
|
config: &TextureConfig,
|
||||||
) -> LutTexture {
|
) -> LutTexture {
|
||||||
let texture = device.create_texture(&TextureDescriptor {
|
let texture = device.create_texture(&TextureDescriptor {
|
||||||
label: Some(&config.name),
|
label: Some(&config.name),
|
||||||
|
@ -39,7 +39,6 @@ impl LutTexture {
|
||||||
view_formats: &[wgpu::TextureFormat::Rgba8Unorm],
|
view_formats: &[wgpu::TextureFormat::Rgba8Unorm],
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
queue.write_texture(
|
queue.write_texture(
|
||||||
wgpu::ImageCopyTexture {
|
wgpu::ImageCopyTexture {
|
||||||
texture: &texture,
|
texture: &texture,
|
||||||
|
@ -53,7 +52,7 @@ impl LutTexture {
|
||||||
bytes_per_row: Some(4 * image.size.width),
|
bytes_per_row: Some(4 * image.size.width),
|
||||||
rows_per_image: None,
|
rows_per_image: None,
|
||||||
},
|
},
|
||||||
image.size.into()
|
image.size.into(),
|
||||||
);
|
);
|
||||||
|
|
||||||
// todo: mipmaps
|
// todo: mipmaps
|
||||||
|
|
|
@ -16,9 +16,12 @@ impl SamplerSet {
|
||||||
// SAFETY: the sampler set is complete for the matrix
|
// SAFETY: the sampler set is complete for the matrix
|
||||||
// wrap x filter x mipmap
|
// wrap x filter x mipmap
|
||||||
unsafe {
|
unsafe {
|
||||||
Arc::clone(&self.samplers
|
Arc::clone(
|
||||||
|
&self
|
||||||
|
.samplers
|
||||||
.get(&(wrap, filter, mipmap))
|
.get(&(wrap, filter, mipmap))
|
||||||
.unwrap_unchecked())
|
.unwrap_unchecked(),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -48,8 +51,8 @@ impl SamplerSet {
|
||||||
compare: None,
|
compare: None,
|
||||||
anisotropy_clamp: 1,
|
anisotropy_clamp: 1,
|
||||||
border_color: Some(SamplerBorderColor::TransparentBlack),
|
border_color: Some(SamplerBorderColor::TransparentBlack),
|
||||||
}),
|
})),
|
||||||
));
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
use std::ops::Deref;
|
use crate::error::FilterChainError;
|
||||||
use std::sync::Arc;
|
|
||||||
use wgpu::{TextureFormat, TextureView};
|
|
||||||
use librashader_common::{FilterMode, ImageFormat, Size, WrapMode};
|
use librashader_common::{FilterMode, ImageFormat, Size, WrapMode};
|
||||||
use librashader_presets::Scale2D;
|
use librashader_presets::Scale2D;
|
||||||
use librashader_runtime::scaling::{MipmapSize, ScaleFramebuffer, ViewportSize};
|
use librashader_runtime::scaling::{MipmapSize, ScaleFramebuffer, ViewportSize};
|
||||||
use crate::error::FilterChainError;
|
use std::ops::Deref;
|
||||||
|
use std::sync::Arc;
|
||||||
|
use wgpu::{ImageCopyTexture, TextureFormat, TextureView};
|
||||||
|
|
||||||
pub struct OwnedImage {
|
pub struct OwnedImage {
|
||||||
device: Arc<wgpu::Device>,
|
device: Arc<wgpu::Device>,
|
||||||
|
@ -17,14 +17,14 @@ pub struct OwnedImage {
|
||||||
|
|
||||||
pub enum Handle<'a, T> {
|
pub enum Handle<'a, T> {
|
||||||
Borrowed(&'a T),
|
Borrowed(&'a T),
|
||||||
Owned(Arc<T>)
|
Owned(Arc<T>),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> Clone for Handle<'_, T> {
|
impl<T> Clone for Handle<'_, T> {
|
||||||
fn clone(&self) -> Self {
|
fn clone(&self) -> Self {
|
||||||
match self {
|
match self {
|
||||||
Handle::Borrowed(r) => Handle::Borrowed(r),
|
Handle::Borrowed(r) => Handle::Borrowed(r),
|
||||||
Handle::Owned(r) => Handle::Owned(Arc::clone(r))
|
Handle::Owned(r) => Handle::Owned(Arc::clone(r)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -34,7 +34,7 @@ impl<T> Deref for Handle<'_, T> {
|
||||||
fn deref(&self) -> &Self::Target {
|
fn deref(&self) -> &Self::Target {
|
||||||
match self {
|
match self {
|
||||||
Handle::Borrowed(r) => &r,
|
Handle::Borrowed(r) => &r,
|
||||||
Handle::Owned(r) => &r
|
Handle::Owned(r) => &r,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -56,12 +56,12 @@ impl AsRef<InputImage> for InputImage {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl OwnedImage {
|
impl OwnedImage {
|
||||||
pub fn new(device: Arc<wgpu::Device>,
|
pub fn new(
|
||||||
|
device: Arc<wgpu::Device>,
|
||||||
size: Size<u32>,
|
size: Size<u32>,
|
||||||
max_miplevels: u32,
|
max_miplevels: u32,
|
||||||
format: ImageFormat,
|
format: ImageFormat,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
|
|
||||||
let format: Option<wgpu::TextureFormat> = format.into();
|
let format: Option<wgpu::TextureFormat> = format.into();
|
||||||
let format = format.unwrap_or(wgpu::TextureFormat::Rgba8Unorm);
|
let format = format.unwrap_or(wgpu::TextureFormat::Rgba8Unorm);
|
||||||
|
|
||||||
|
@ -117,7 +117,12 @@ impl OwnedImage {
|
||||||
|| (!mipmap && self.max_miplevels != 1)
|
|| (!mipmap && self.max_miplevels != 1)
|
||||||
|| format != self.image.format()
|
|| format != self.image.format()
|
||||||
{
|
{
|
||||||
let mut new = OwnedImage::new(Arc::clone(&self.device), size, self.max_miplevels, format.into());
|
let mut new = OwnedImage::new(
|
||||||
|
Arc::clone(&self.device),
|
||||||
|
size,
|
||||||
|
self.max_miplevels,
|
||||||
|
format.into(),
|
||||||
|
);
|
||||||
std::mem::swap(self, &mut new);
|
std::mem::swap(self, &mut new);
|
||||||
}
|
}
|
||||||
size
|
size
|
||||||
|
@ -132,25 +137,34 @@ impl OwnedImage {
|
||||||
mip_filter: filter,
|
mip_filter: filter,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn copy_from(&self, cmd: &mut wgpu::CommandEncoder, source: &wgpu::Texture) {
|
||||||
|
cmd.copy_texture_to_texture(
|
||||||
|
source.as_image_copy(),
|
||||||
|
self.image.as_image_copy(),
|
||||||
|
source.size(),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn clear(&self, cmd: &mut wgpu::CommandEncoder) {
|
||||||
|
cmd.clear_texture(&self.image, &wgpu::ImageSubresourceRange::default());
|
||||||
|
}
|
||||||
|
pub fn generate_mipmaps(&self, cmd: &mut wgpu::CommandEncoder) {}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ScaleFramebuffer for OwnedImage {
|
impl ScaleFramebuffer for OwnedImage {
|
||||||
type Error = FilterChainError;
|
type Error = FilterChainError;
|
||||||
type Context = ();
|
type Context = ();
|
||||||
|
|
||||||
fn scale(&mut self,
|
fn scale(
|
||||||
|
&mut self,
|
||||||
scaling: Scale2D,
|
scaling: Scale2D,
|
||||||
format: ImageFormat,
|
format: ImageFormat,
|
||||||
viewport_size: &Size<u32>,
|
viewport_size: &Size<u32>,
|
||||||
source_size: &Size<u32>,
|
source_size: &Size<u32>,
|
||||||
should_mipmap: bool,
|
should_mipmap: bool,
|
||||||
_context: &Self::Context) -> Result<Size<u32>, Self::Error> {
|
_context: &Self::Context,
|
||||||
Ok(self.scale(
|
) -> Result<Size<u32>, Self::Error> {
|
||||||
scaling,
|
Ok(self.scale(scaling, format, viewport_size, source_size, should_mipmap))
|
||||||
format,
|
|
||||||
viewport_size,
|
|
||||||
source_size,
|
|
||||||
should_mipmap,
|
|
||||||
))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,5 +1,5 @@
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use wgpu::{ Maintain, };
|
use wgpu::Maintain;
|
||||||
use winit::{
|
use winit::{
|
||||||
event::*,
|
event::*,
|
||||||
event_loop::{ControlFlow, EventLoop},
|
event_loop::{ControlFlow, EventLoop},
|
||||||
|
@ -12,6 +12,7 @@ use wgpu::util::DeviceExt;
|
||||||
use winit::event_loop::EventLoopBuilder;
|
use winit::event_loop::EventLoopBuilder;
|
||||||
use winit::keyboard::{Key, KeyCode, PhysicalKey};
|
use winit::keyboard::{Key, KeyCode, PhysicalKey};
|
||||||
use winit::platform::windows::EventLoopBuilderExtWindows;
|
use winit::platform::windows::EventLoopBuilderExtWindows;
|
||||||
|
use librashader_common::Viewport;
|
||||||
|
|
||||||
#[cfg(target_arch = "wasm32")]
|
#[cfg(target_arch = "wasm32")]
|
||||||
use wasm_bindgen::prelude::*;
|
use wasm_bindgen::prelude::*;
|
||||||
|
@ -64,7 +65,7 @@ const VERTICES: &[Vertex] = &[
|
||||||
struct State<'a> {
|
struct State<'a> {
|
||||||
surface: wgpu::Surface<'a>,
|
surface: wgpu::Surface<'a>,
|
||||||
device: Arc<wgpu::Device>,
|
device: Arc<wgpu::Device>,
|
||||||
queue: wgpu::Queue,
|
queue: Arc<wgpu::Queue>,
|
||||||
config: wgpu::SurfaceConfiguration,
|
config: wgpu::SurfaceConfiguration,
|
||||||
size: winit::dpi::PhysicalSize<u32>,
|
size: winit::dpi::PhysicalSize<u32>,
|
||||||
clear_color: wgpu::Color,
|
clear_color: wgpu::Color,
|
||||||
|
@ -74,6 +75,7 @@ struct State<'a> {
|
||||||
vertex_buffer: wgpu::Buffer,
|
vertex_buffer: wgpu::Buffer,
|
||||||
num_vertices: u32,
|
num_vertices: u32,
|
||||||
chain: FilterChainWGPU,
|
chain: FilterChainWGPU,
|
||||||
|
frame_count: usize
|
||||||
}
|
}
|
||||||
impl<'a> State<'a> {
|
impl<'a> State<'a> {
|
||||||
async fn new(window: &'a Window) -> Self {
|
async fn new(window: &'a Window) -> Self {
|
||||||
|
@ -91,7 +93,7 @@ impl<'a> State<'a> {
|
||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
let (device, mut queue) = adapter
|
let (device, queue) = adapter
|
||||||
.request_device(
|
.request_device(
|
||||||
&wgpu::DeviceDescriptor {
|
&wgpu::DeviceDescriptor {
|
||||||
required_features: wgpu::Features::ADDRESS_MODE_CLAMP_TO_BORDER,
|
required_features: wgpu::Features::ADDRESS_MODE_CLAMP_TO_BORDER,
|
||||||
|
@ -106,7 +108,7 @@ impl<'a> State<'a> {
|
||||||
let swapchain_format = swapchain_capabilities.formats[0];
|
let swapchain_format = swapchain_capabilities.formats[0];
|
||||||
|
|
||||||
let mut config = wgpu::SurfaceConfiguration {
|
let mut config = wgpu::SurfaceConfiguration {
|
||||||
usage: wgpu::TextureUsages::RENDER_ATTACHMENT,
|
usage: wgpu::TextureUsages::RENDER_ATTACHMENT | wgpu::TextureUsages::COPY_DST,
|
||||||
format: swapchain_format,
|
format: swapchain_format,
|
||||||
width: size.width,
|
width: size.width,
|
||||||
height: size.height,
|
height: size.height,
|
||||||
|
@ -117,16 +119,22 @@ impl<'a> State<'a> {
|
||||||
};
|
};
|
||||||
|
|
||||||
let device = Arc::new(device);
|
let device = Arc::new(device);
|
||||||
|
let queue = Arc::new(queue);
|
||||||
|
|
||||||
let mut cmd = device.create_command_encoder(&wgpu::CommandEncoderDescriptor {
|
let mut cmd = device.create_command_encoder(&wgpu::CommandEncoderDescriptor {
|
||||||
label: Some("start encoder"),
|
label: Some("start encoder"),
|
||||||
});
|
});
|
||||||
|
|
||||||
let preset =
|
let preset =
|
||||||
ShaderPreset::try_parse("../test/shaders_slang/crt/crt-royale.slangp").unwrap();
|
ShaderPreset::try_parse("../test/basic.slangp").unwrap();
|
||||||
|
|
||||||
|
let chain = FilterChainWGPU::load_from_preset_deferred(
|
||||||
let chain = FilterChainWGPU::load_from_preset_deferred(Arc::clone(&device), &mut queue, &mut cmd, preset).unwrap();
|
Arc::clone(&device),
|
||||||
|
Arc::clone(&queue),
|
||||||
|
&mut cmd,
|
||||||
|
preset,
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
let cmd = cmd.finish();
|
let cmd = cmd.finish();
|
||||||
|
|
||||||
|
@ -202,6 +210,7 @@ impl<'a> State<'a> {
|
||||||
vertex_buffer,
|
vertex_buffer,
|
||||||
num_vertices,
|
num_vertices,
|
||||||
chain,
|
chain,
|
||||||
|
frame_count: 0,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fn resize(&mut self, new_size: winit::dpi::PhysicalSize<u32>) {
|
fn resize(&mut self, new_size: winit::dpi::PhysicalSize<u32>) {
|
||||||
|
@ -218,9 +227,46 @@ impl<'a> State<'a> {
|
||||||
fn update(&mut self) {}
|
fn update(&mut self) {}
|
||||||
fn render(&mut self) -> Result<(), wgpu::SurfaceError> {
|
fn render(&mut self) -> Result<(), wgpu::SurfaceError> {
|
||||||
let output = self.surface.get_current_texture()?;
|
let output = self.surface.get_current_texture()?;
|
||||||
let view = output
|
|
||||||
.texture
|
let render_output = Arc::new(self.device.create_texture(
|
||||||
|
&wgpu::TextureDescriptor {
|
||||||
|
label: Some("rendertexture"),
|
||||||
|
size: output.texture.size(),
|
||||||
|
mip_level_count: output.texture.mip_level_count(),
|
||||||
|
sample_count: output.texture.sample_count(),
|
||||||
|
dimension: output.texture.dimension(),
|
||||||
|
format: output.texture.format(),
|
||||||
|
usage: wgpu::TextureUsages::TEXTURE_BINDING
|
||||||
|
| wgpu::TextureUsages::RENDER_ATTACHMENT
|
||||||
|
| wgpu::TextureUsages::COPY_DST
|
||||||
|
| wgpu::TextureUsages::COPY_SRC,
|
||||||
|
view_formats: &[output.texture.format()],
|
||||||
|
}
|
||||||
|
));
|
||||||
|
|
||||||
|
let filter_output = Arc::new(self.device.create_texture(
|
||||||
|
&wgpu::TextureDescriptor {
|
||||||
|
label: Some("filteroutput"),
|
||||||
|
size: output.texture.size(),
|
||||||
|
mip_level_count: output.texture.mip_level_count(),
|
||||||
|
sample_count: output.texture.sample_count(),
|
||||||
|
dimension: output.texture.dimension(),
|
||||||
|
format: output.texture.format(),
|
||||||
|
usage: wgpu::TextureUsages::TEXTURE_BINDING
|
||||||
|
| wgpu::TextureUsages::RENDER_ATTACHMENT
|
||||||
|
| wgpu::TextureUsages::COPY_DST
|
||||||
|
| wgpu::TextureUsages::COPY_SRC,
|
||||||
|
view_formats: &[output.texture.format()],
|
||||||
|
}
|
||||||
|
));
|
||||||
|
|
||||||
|
|
||||||
|
let view = render_output
|
||||||
.create_view(&wgpu::TextureViewDescriptor::default());
|
.create_view(&wgpu::TextureViewDescriptor::default());
|
||||||
|
|
||||||
|
let filter_view = filter_output
|
||||||
|
.create_view(&wgpu::TextureViewDescriptor::default());
|
||||||
|
|
||||||
let mut encoder = self
|
let mut encoder = self
|
||||||
.device
|
.device
|
||||||
.create_command_encoder(&wgpu::CommandEncoderDescriptor {
|
.create_command_encoder(&wgpu::CommandEncoderDescriptor {
|
||||||
|
@ -228,7 +274,8 @@ impl<'a> State<'a> {
|
||||||
});
|
});
|
||||||
|
|
||||||
{
|
{
|
||||||
let mut render_pass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
|
let mut render_pass =
|
||||||
|
encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
|
||||||
label: Some("Render Pass"),
|
label: Some("Render Pass"),
|
||||||
color_attachments: &[Some(wgpu::RenderPassColorAttachment {
|
color_attachments: &[Some(wgpu::RenderPassColorAttachment {
|
||||||
view: &view,
|
view: &view,
|
||||||
|
@ -247,9 +294,32 @@ impl<'a> State<'a> {
|
||||||
render_pass.draw(0..self.num_vertices, 0..1);
|
render_pass.draw(0..self.num_vertices, 0..1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
self.chain
|
||||||
|
.frame(Arc::clone(&render_output),
|
||||||
|
&Viewport {
|
||||||
|
x: 0.0,
|
||||||
|
y: 0.0,
|
||||||
|
mvp: None,
|
||||||
|
output: librashader_runtime_wgpu::OutputView {
|
||||||
|
size: filter_output.size().into(),
|
||||||
|
view: &filter_view,
|
||||||
|
format: filter_output.format(),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
&mut encoder,
|
||||||
|
self.frame_count, None
|
||||||
|
).expect("failed to draw frame");
|
||||||
|
|
||||||
|
encoder.copy_texture_to_texture(
|
||||||
|
filter_output.as_image_copy(),
|
||||||
|
output.texture.as_image_copy(),
|
||||||
|
output.texture.size()
|
||||||
|
);
|
||||||
|
|
||||||
self.queue.submit(std::iter::once(encoder.finish()));
|
self.queue.submit(std::iter::once(encoder.finish()));
|
||||||
output.present();
|
output.present();
|
||||||
|
|
||||||
|
self.frame_count += 1;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -266,12 +336,12 @@ pub fn run() {
|
||||||
|
|
||||||
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(|event, target| {
|
event_loop
|
||||||
|
.run(|event, target| {
|
||||||
match event {
|
match event {
|
||||||
Event::WindowEvent {
|
Event::WindowEvent {
|
||||||
window_id: _,
|
window_id: _,
|
||||||
event
|
event,
|
||||||
} => match event {
|
} => match event {
|
||||||
WindowEvent::Resized(new_size) => {
|
WindowEvent::Resized(new_size) => {
|
||||||
state.resize(new_size);
|
state.resize(new_size);
|
||||||
|
@ -291,14 +361,11 @@ pub fn run() {
|
||||||
}
|
}
|
||||||
WindowEvent::CloseRequested => target.exit(),
|
WindowEvent::CloseRequested => target.exit(),
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
},
|
||||||
Event::AboutToWait => {
|
Event::AboutToWait => window.request_redraw(),
|
||||||
window.request_redraw()
|
|
||||||
}
|
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
|
})
|
||||||
|
.unwrap();
|
||||||
}).unwrap();
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue