diff --git a/src/context.rs b/src/context.rs index ffaad6e..0cdbe41 100644 --- a/src/context.rs +++ b/src/context.rs @@ -4,8 +4,6 @@ use wgpu::util::DeviceExt; use winit::dpi::PhysicalSize; use winit::window::Window; -// Code here is mostly derived from https://sotrh.github.io/learn-wgpu/beginner/tutorial1-window/ - #[repr(C)] #[derive(Copy, Clone, Debug, bytemuck::Pod, bytemuck::Zeroable)] struct Vertex { @@ -13,6 +11,13 @@ struct Vertex { tex_coords: [f32; 2], } +#[repr(C)] +#[derive(Copy, Clone, Debug, bytemuck::Pod, bytemuck::Zeroable)] +struct Globals { + pub input_resolution: [f32; 2], + pub output_resolution: [f32; 2], +} + impl Vertex { fn desc() -> wgpu::VertexBufferLayout<'static> { use std::mem; @@ -46,6 +51,7 @@ pub struct Context { render_pipeline: wgpu::RenderPipeline, vertex_buffer: wgpu::Buffer, index_buffer: wgpu::Buffer, + global_buffer: wgpu::Buffer, texture: wgpu::Texture, bind_group: wgpu::BindGroup, window: Arc @@ -131,6 +137,14 @@ impl Context { mipmap_filter: wgpu::FilterMode::Nearest, ..Default::default() }); + let global_buffer = device.create_buffer_init(&wgpu::util::BufferInitDescriptor { + label: Some("Globals"), + contents: bytemuck::cast_slice(&[Globals{ + input_resolution: [SCREEN_W as f32, SCREEN_H as f32], + output_resolution: [size.width as f32, size.height as f32], + }]), + usage: wgpu::BufferUsages::UNIFORM | wgpu::BufferUsages::COPY_DST + }); let texture_bind_group_layout = device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor { @@ -151,6 +165,16 @@ impl Context { ty: wgpu::BindingType::Sampler(wgpu::SamplerBindingType::Filtering), count: None, }, + wgpu::BindGroupLayoutEntry { + binding: 2, + visibility: wgpu::ShaderStages::FRAGMENT, + ty: wgpu::BindingType::Buffer { + ty: wgpu::BufferBindingType::Uniform, + has_dynamic_offset: false, + min_binding_size: None, + }, + count: None, + } ], label: Some("Texture Bind Group Layout"), }); @@ -166,6 +190,14 @@ impl Context { binding: 1, resource: wgpu::BindingResource::Sampler(&sampler), }, + wgpu::BindGroupEntry { + binding: 2, + resource: wgpu::BindingResource::Buffer(wgpu::BufferBinding { + buffer: &global_buffer, + offset: 0, + size: None, + }) + } ], label: Some("Bind Group"), }); @@ -243,6 +275,7 @@ impl Context { render_pipeline, vertex_buffer, index_buffer, + global_buffer, texture, bind_group } @@ -266,6 +299,15 @@ impl Context { 0, bytemuck::cast_slice(&vertices)); + self.queue.write_buffer( + &self.global_buffer, + 0, + bytemuck::cast_slice(&[Globals{ + input_resolution: [SCREEN_W as f32, SCREEN_H as f32], + output_resolution: [new_size.width as f32, new_size.height as f32], + }]) + ); + self.window.request_redraw(); } @@ -372,7 +414,6 @@ impl Context { render_pass.draw_indexed(0..INDICES.len() as u32, 0, 0..1); } - // submit will accept anything that implements IntoIter self.queue.submit(std::iter::once(encoder.finish())); output.present(); diff --git a/src/shaders/shader.wgsl b/src/shaders/shader.wgsl index ebd6167..5bbd365 100644 --- a/src/shaders/shader.wgsl +++ b/src/shaders/shader.wgsl @@ -8,6 +8,11 @@ struct VertexOutput { @location(0) tex_coords: vec2, } +struct Globals { + @location(0) input_resolution: vec2, + @location(1) output_resolution: vec2 +} + @vertex fn vs_main( model: VertexInput, @@ -22,29 +27,30 @@ fn vs_main( var t_diffuse: texture_2d; @group(0) @binding(1) var s_diffuse: sampler; +@group(0) @binding(2) +var globals: Globals; + +const SCANLINE_DEPTH: f32 = 0.25; +const BLOOM: f32 = 0.4; @fragment fn fs_main(in: VertexOutput) -> @location(0) vec4 { var position = in.tex_coords; - var input_resolution = vec2(160.0, 144.0); - - var SCANLINE_DEPTH: f32 = 0.25; - var BLOOM: f32 = 0.4; - var pixel = position * input_resolution - vec2(0.5, 0.5); + var pixel = position * globals.input_resolution - vec2(0.5, 0.5); - var q11 = textureSample(t_diffuse, s_diffuse, (floor(pixel) + 0.5) / input_resolution); - var q12 = textureSample(t_diffuse, s_diffuse, (vec2(floor(pixel.x), ceil(pixel.y)) + 0.5) / input_resolution); - var q21 = textureSample(t_diffuse, s_diffuse, (vec2(ceil(pixel.x), floor(pixel.y)) + 0.5) / input_resolution); - var q22 = textureSample(t_diffuse, s_diffuse, (ceil(pixel) + 0.5) / input_resolution); + var q11 = textureSample(t_diffuse, s_diffuse, (floor(pixel) + 0.5) / globals.input_resolution); + var q12 = textureSample(t_diffuse, s_diffuse, (vec2(floor(pixel.x), ceil(pixel.y)) + 0.5) / globals.input_resolution); + var q21 = textureSample(t_diffuse, s_diffuse, (vec2(ceil(pixel.x), floor(pixel.y)) + 0.5) / globals.input_resolution); + var q22 = textureSample(t_diffuse, s_diffuse, (ceil(pixel) + 0.5) / globals.input_resolution); var s = vec2(smoothstep(0.0, 1.0, fract(pixel.x)), smoothstep(0.0, 1.0, fract(pixel.y))); var r1 = mix(q11, q21, s.x); var r2 = mix(q12, q22, s.x); - var pos = fract(position * input_resolution); - var sub_pos = fract(position * input_resolution * 6); + var pos = fract(position * globals.input_resolution); + var sub_pos = fract(position * globals.input_resolution * 6); var multiplier: f32 = 1.0; @@ -65,10 +71,10 @@ fn fs_main(in: VertexOutput) -> @location(0) vec4 { var pre_shadow = mix(textureSample(t_diffuse, s_diffuse, position) * multiplier, mix(r1, r2, s.y), BLOOM); pixel += vec2(-0.6, -0.8); - q11 = textureSample(t_diffuse, s_diffuse, (floor(pixel) + 0.5) / input_resolution); - q12 = textureSample(t_diffuse, s_diffuse, (vec2(floor(pixel.x), ceil(pixel.y)) + 0.5) / input_resolution); - q21 = textureSample(t_diffuse, s_diffuse, (vec2(ceil(pixel.x), floor(pixel.y)) + 0.5) / input_resolution); - q22 = textureSample(t_diffuse, s_diffuse, (ceil(pixel) + 0.5) / input_resolution); + q11 = textureSample(t_diffuse, s_diffuse, (floor(pixel) + 0.5) / globals.input_resolution); + q12 = textureSample(t_diffuse, s_diffuse, (vec2(floor(pixel.x), ceil(pixel.y)) + 0.5) / globals.input_resolution); + q21 = textureSample(t_diffuse, s_diffuse, (vec2(ceil(pixel.x), floor(pixel.y)) + 0.5) / globals.input_resolution); + q22 = textureSample(t_diffuse, s_diffuse, (ceil(pixel) + 0.5) / globals.input_resolution); r1 = mix(q11, q21, fract(pixel.x)); r2 = mix(q12, q22, fract(pixel.x));