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 graphics_pipeline;
|
||||
mod luts;
|
||||
mod mipmap;
|
||||
mod options;
|
||||
mod samplers;
|
||||
mod texture;
|
||||
mod util;
|
||||
|
||||
pub use framebuffer::OutputView;
|
||||
pub use filter_chain::FilterChainWGPU;
|
||||
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 librashader_common::{Size, WrapMode};
|
||||
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};
|
||||
use wgpu::TextureDescriptor;
|
||||
|
||||
pub(crate) struct LutTexture(InputImage);
|
||||
impl AsRef<InputImage> for LutTexture {
|
||||
|
@ -17,9 +19,11 @@ impl LutTexture {
|
|||
pub fn new(
|
||||
device: &wgpu::Device,
|
||||
queue: &wgpu::Queue,
|
||||
_cmd: &mut wgpu::CommandEncoder,
|
||||
cmd: &mut wgpu::CommandEncoder,
|
||||
image: Image,
|
||||
config: &TextureConfig,
|
||||
mipmapper: &mut MipmapGen,
|
||||
sampler_set: &SamplerSet,
|
||||
) -> LutTexture {
|
||||
let texture = device.create_texture(&TextureDescriptor {
|
||||
label: Some(&config.name),
|
||||
|
@ -55,19 +59,20 @@ impl LutTexture {
|
|||
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 {
|
||||
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 view = texture.create_view(&wgpu::TextureViewDescriptor::default());
|
||||
|
||||
let image = InputImage {
|
||||
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::mipmap::MipmapGen;
|
||||
use crate::samplers::SamplerSet;
|
||||
use librashader_common::{FilterMode, ImageFormat, Size, WrapMode};
|
||||
use librashader_presets::Scale2D;
|
||||
use librashader_runtime::scaling::{MipmapSize, ScaleFramebuffer, ViewportSize};
|
||||
|
@ -149,7 +151,14 @@ impl OwnedImage {
|
|||
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) {}
|
||||
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 {
|
||||
|
|
Loading…
Reference in a new issue