rt(wgsl): mipmaps
This commit is contained in:
parent
11ab4b7c9a
commit
962a81c2e3
52
librashader-runtime-wgpu/shader/blit.wgsl
Normal file
52
librashader-runtime-wgpu/shader/blit.wgsl
Normal file
|
@ -0,0 +1,52 @@
|
||||||
|
struct VertexOutput {
|
||||||
|
@builtin(position) position: vec4<f32>,
|
||||||
|
@location(0) tex_coords: vec2<f32>,
|
||||||
|
};
|
||||||
|
|
||||||
|
// meant to be called with 3 vertex indices: 0, 1, 2
|
||||||
|
// draws one large triangle over the clip space like this:
|
||||||
|
// (the asterisks represent the clip space bounds)
|
||||||
|
//-1,1 1,1
|
||||||
|
// ---------------------------------
|
||||||
|
// | * .
|
||||||
|
// | * .
|
||||||
|
// | * .
|
||||||
|
// | * .
|
||||||
|
// | * .
|
||||||
|
// | * .
|
||||||
|
// |***************
|
||||||
|
// | . 1,-1
|
||||||
|
// | .
|
||||||
|
// | .
|
||||||
|
// | .
|
||||||
|
// | .
|
||||||
|
// |.
|
||||||
|
@vertex
|
||||||
|
fn vs_main(@builtin(vertex_index) vertex_index: u32) -> VertexOutput {
|
||||||
|
var result: VertexOutput;
|
||||||
|
let x = i32(vertex_index) / 2;
|
||||||
|
let y = i32(vertex_index) & 1;
|
||||||
|
let tc = vec2<f32>(
|
||||||
|
f32(x) * 2.0,
|
||||||
|
f32(y) * 2.0
|
||||||
|
);
|
||||||
|
result.position = vec4<f32>(
|
||||||
|
tc.x * 2.0 - 1.0,
|
||||||
|
1.0 - tc.y * 2.0,
|
||||||
|
0.0, 1.0
|
||||||
|
);
|
||||||
|
result.tex_coords = tc;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
@group(0)
|
||||||
|
@binding(0)
|
||||||
|
var r_color: texture_2d<f32>;
|
||||||
|
@group(0)
|
||||||
|
@binding(1)
|
||||||
|
var r_sampler: sampler;
|
||||||
|
|
||||||
|
@fragment
|
||||||
|
fn fs_main(vertex: VertexOutput) -> @location(0) vec4<f32> {
|
||||||
|
return textureSample(r_color, r_sampler, vertex.tex_coords);
|
||||||
|
}
|
|
@ -15,11 +15,12 @@ mod filter_pass;
|
||||||
mod framebuffer;
|
mod framebuffer;
|
||||||
mod graphics_pipeline;
|
mod graphics_pipeline;
|
||||||
mod luts;
|
mod luts;
|
||||||
|
mod mipmap;
|
||||||
mod options;
|
mod options;
|
||||||
mod samplers;
|
mod samplers;
|
||||||
mod texture;
|
mod texture;
|
||||||
mod util;
|
mod util;
|
||||||
|
|
||||||
pub use framebuffer::OutputView;
|
|
||||||
pub use filter_chain::FilterChainWGPU;
|
pub use filter_chain::FilterChainWGPU;
|
||||||
pub use filter_pass::FilterPass;
|
pub use filter_pass::FilterPass;
|
||||||
|
pub use framebuffer::OutputView;
|
||||||
|
|
|
@ -1,10 +1,12 @@
|
||||||
|
use crate::mipmap::MipmapGen;
|
||||||
|
use crate::samplers::SamplerSet;
|
||||||
use crate::texture::{Handle, InputImage};
|
use crate::texture::{Handle, InputImage};
|
||||||
|
use librashader_common::{Size, WrapMode};
|
||||||
use librashader_presets::TextureConfig;
|
use librashader_presets::TextureConfig;
|
||||||
use librashader_runtime::image::{Image, BGRA8};
|
use librashader_runtime::image::{Image, BGRA8};
|
||||||
use librashader_runtime::scaling::MipmapSize;
|
use librashader_runtime::scaling::MipmapSize;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use wgpu::util::DeviceExt;
|
use wgpu::TextureDescriptor;
|
||||||
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 {
|
||||||
|
@ -17,9 +19,11 @@ impl LutTexture {
|
||||||
pub fn new(
|
pub fn new(
|
||||||
device: &wgpu::Device,
|
device: &wgpu::Device,
|
||||||
queue: &wgpu::Queue,
|
queue: &wgpu::Queue,
|
||||||
_cmd: &mut wgpu::CommandEncoder,
|
cmd: &mut wgpu::CommandEncoder,
|
||||||
image: Image,
|
image: Image,
|
||||||
config: &TextureConfig,
|
config: &TextureConfig,
|
||||||
|
mipmapper: &mut MipmapGen,
|
||||||
|
sampler_set: &SamplerSet,
|
||||||
) -> LutTexture {
|
) -> LutTexture {
|
||||||
let texture = device.create_texture(&TextureDescriptor {
|
let texture = device.create_texture(&TextureDescriptor {
|
||||||
label: Some(&config.name),
|
label: Some(&config.name),
|
||||||
|
@ -55,19 +59,20 @@ impl LutTexture {
|
||||||
image.size.into(),
|
image.size.into(),
|
||||||
);
|
);
|
||||||
|
|
||||||
// todo: mipmaps
|
if config.mipmap {
|
||||||
|
mipmapper.generate_mipmaps(
|
||||||
|
cmd,
|
||||||
|
&texture,
|
||||||
|
&*sampler_set.get(
|
||||||
|
WrapMode::ClampToEdge,
|
||||||
|
config.filter_mode,
|
||||||
|
config.filter_mode,
|
||||||
|
),
|
||||||
|
Size::<u32>::from(texture.size()).calculate_miplevels(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
// todo: fix this
|
let view = texture.create_view(&wgpu::TextureViewDescriptor::default());
|
||||||
let view = texture.create_view(&wgpu::TextureViewDescriptor {
|
|
||||||
label: Some("lut view"),
|
|
||||||
format: None,
|
|
||||||
dimension: None,
|
|
||||||
aspect: Default::default(),
|
|
||||||
base_mip_level: 0,
|
|
||||||
mip_level_count: None,
|
|
||||||
base_array_layer: 0,
|
|
||||||
array_layer_count: None,
|
|
||||||
});
|
|
||||||
|
|
||||||
let image = InputImage {
|
let image = InputImage {
|
||||||
image: Arc::new(texture),
|
image: Arc::new(texture),
|
||||||
|
|
119
librashader-runtime-wgpu/src/mipmap.rs
Normal file
119
librashader-runtime-wgpu/src/mipmap.rs
Normal file
|
@ -0,0 +1,119 @@
|
||||||
|
use rustc_hash::FxHashMap;
|
||||||
|
use std::borrow::Cow;
|
||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
|
pub struct MipmapGen {
|
||||||
|
device: Arc<wgpu::Device>,
|
||||||
|
shader: wgpu::ShaderModule,
|
||||||
|
pipeline_cache: FxHashMap<wgpu::TextureFormat, wgpu::RenderPipeline>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl MipmapGen {
|
||||||
|
fn create_pipeline(
|
||||||
|
device: &wgpu::Device,
|
||||||
|
shader: &wgpu::ShaderModule,
|
||||||
|
format: wgpu::TextureFormat,
|
||||||
|
) -> wgpu::RenderPipeline {
|
||||||
|
let pipeline = device.create_render_pipeline(&wgpu::RenderPipelineDescriptor {
|
||||||
|
label: Some("blit"),
|
||||||
|
layout: None,
|
||||||
|
vertex: wgpu::VertexState {
|
||||||
|
module: &shader,
|
||||||
|
entry_point: "vs_main",
|
||||||
|
buffers: &[],
|
||||||
|
},
|
||||||
|
fragment: Some(wgpu::FragmentState {
|
||||||
|
module: &shader,
|
||||||
|
entry_point: "fs_main",
|
||||||
|
targets: &[Some(format.into())],
|
||||||
|
}),
|
||||||
|
primitive: wgpu::PrimitiveState {
|
||||||
|
topology: wgpu::PrimitiveTopology::TriangleList,
|
||||||
|
..Default::default()
|
||||||
|
},
|
||||||
|
depth_stencil: None,
|
||||||
|
multisample: wgpu::MultisampleState::default(),
|
||||||
|
multiview: None,
|
||||||
|
});
|
||||||
|
|
||||||
|
pipeline
|
||||||
|
}
|
||||||
|
pub fn new(device: Arc<wgpu::Device>) -> Self {
|
||||||
|
let shader = device.create_shader_module(wgpu::ShaderModuleDescriptor {
|
||||||
|
label: None,
|
||||||
|
source: wgpu::ShaderSource::Wgsl(Cow::Borrowed(include_str!("../shader/blit.wgsl"))),
|
||||||
|
});
|
||||||
|
|
||||||
|
Self {
|
||||||
|
device,
|
||||||
|
shader,
|
||||||
|
pipeline_cache: Default::default(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn generate_mipmaps(
|
||||||
|
&mut self,
|
||||||
|
cmd: &mut wgpu::CommandEncoder,
|
||||||
|
texture: &wgpu::Texture,
|
||||||
|
sampler: &wgpu::Sampler,
|
||||||
|
miplevels: u32,
|
||||||
|
) {
|
||||||
|
let format = texture.format();
|
||||||
|
let pipeline = &*self
|
||||||
|
.pipeline_cache
|
||||||
|
.entry(format)
|
||||||
|
.or_insert_with(|| Self::create_pipeline(&self.device, &self.shader, format));
|
||||||
|
|
||||||
|
let views = (0..miplevels)
|
||||||
|
.map(|mip| {
|
||||||
|
texture.create_view(&wgpu::TextureViewDescriptor {
|
||||||
|
label: Some("mip"),
|
||||||
|
format: None,
|
||||||
|
dimension: None,
|
||||||
|
aspect: wgpu::TextureAspect::All,
|
||||||
|
base_mip_level: mip,
|
||||||
|
mip_level_count: Some(1),
|
||||||
|
base_array_layer: 0,
|
||||||
|
array_layer_count: None,
|
||||||
|
})
|
||||||
|
})
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
|
for target_mip in 1..miplevels as usize {
|
||||||
|
let bind_group_layout = pipeline.get_bind_group_layout(0);
|
||||||
|
let bind_group = self.device.create_bind_group(&wgpu::BindGroupDescriptor {
|
||||||
|
layout: &bind_group_layout,
|
||||||
|
entries: &[
|
||||||
|
wgpu::BindGroupEntry {
|
||||||
|
binding: 0,
|
||||||
|
resource: wgpu::BindingResource::TextureView(&views[target_mip - 1]),
|
||||||
|
},
|
||||||
|
wgpu::BindGroupEntry {
|
||||||
|
binding: 1,
|
||||||
|
resource: wgpu::BindingResource::Sampler(&sampler),
|
||||||
|
},
|
||||||
|
],
|
||||||
|
label: None,
|
||||||
|
});
|
||||||
|
|
||||||
|
let mut pass = cmd.begin_render_pass(&wgpu::RenderPassDescriptor {
|
||||||
|
label: None,
|
||||||
|
color_attachments: &[Some(wgpu::RenderPassColorAttachment {
|
||||||
|
view: &views[target_mip],
|
||||||
|
resolve_target: None,
|
||||||
|
ops: wgpu::Operations {
|
||||||
|
load: wgpu::LoadOp::Clear(wgpu::Color::BLACK),
|
||||||
|
store: wgpu::StoreOp::Store,
|
||||||
|
},
|
||||||
|
})],
|
||||||
|
depth_stencil_attachment: None,
|
||||||
|
timestamp_writes: None,
|
||||||
|
occlusion_query_set: None,
|
||||||
|
});
|
||||||
|
|
||||||
|
pass.set_pipeline(&pipeline);
|
||||||
|
pass.set_bind_group(0, &bind_group, &[]);
|
||||||
|
pass.draw(0..3, 0..1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,4 +1,6 @@
|
||||||
use crate::error::FilterChainError;
|
use crate::error::FilterChainError;
|
||||||
|
use crate::mipmap::MipmapGen;
|
||||||
|
use crate::samplers::SamplerSet;
|
||||||
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};
|
||||||
|
@ -149,7 +151,14 @@ impl OwnedImage {
|
||||||
pub fn clear(&self, cmd: &mut wgpu::CommandEncoder) {
|
pub fn clear(&self, cmd: &mut wgpu::CommandEncoder) {
|
||||||
cmd.clear_texture(&self.image, &wgpu::ImageSubresourceRange::default());
|
cmd.clear_texture(&self.image, &wgpu::ImageSubresourceRange::default());
|
||||||
}
|
}
|
||||||
pub fn generate_mipmaps(&self, cmd: &mut wgpu::CommandEncoder) {}
|
pub fn generate_mipmaps(
|
||||||
|
&self,
|
||||||
|
cmd: &mut wgpu::CommandEncoder,
|
||||||
|
mipmapper: &mut MipmapGen,
|
||||||
|
sampler: &wgpu::Sampler,
|
||||||
|
) {
|
||||||
|
mipmapper.generate_mipmaps(cmd, &self.image, sampler, self.max_miplevels);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ScaleFramebuffer for OwnedImage {
|
impl ScaleFramebuffer for OwnedImage {
|
||||||
|
|
Loading…
Reference in a new issue