From c9c5cb76bd8bf1d2dcc165e5e4a72e6bb5663356 Mon Sep 17 00:00:00 2001 From: Dennis Ranke Date: Sun, 10 Jul 2022 16:37:39 +0200 Subject: [PATCH] start refactoring wgpu code to allow for different upscale filters --- uw8-window/src/gpu.rs | 401 ++++++++++++++++++++++-------------------- 1 file changed, 215 insertions(+), 186 deletions(-) diff --git a/uw8-window/src/gpu.rs b/uw8-window/src/gpu.rs index 986b371..22043de 100644 --- a/uw8-window/src/gpu.rs +++ b/uw8-window/src/gpu.rs @@ -77,54 +77,8 @@ impl Window { device, queue, } = self; - let framebuffer_texture = device.create_texture(&wgpu::TextureDescriptor { - size: wgpu::Extent3d { - width: 320, - height: 240, - depth_or_array_layers: 1, - }, - mip_level_count: 1, - sample_count: 1, - dimension: wgpu::TextureDimension::D2, - format: wgpu::TextureFormat::R8Uint, - usage: wgpu::TextureUsages::TEXTURE_BINDING | wgpu::TextureUsages::COPY_DST, - label: None, - }); - let palette_texture = device.create_texture(&wgpu::TextureDescriptor { - size: wgpu::Extent3d { - width: 256, - height: 1, - depth_or_array_layers: 1, - }, - mip_level_count: 1, - sample_count: 1, - dimension: wgpu::TextureDimension::D1, - format: wgpu::TextureFormat::Rgba8UnormSrgb, - usage: wgpu::TextureUsages::TEXTURE_BINDING | wgpu::TextureUsages::COPY_DST, - label: None, - }); - - let screen_texture = device.create_texture(&wgpu::TextureDescriptor { - size: wgpu::Extent3d { - width: 320, - height: 240, - depth_or_array_layers: 1, - }, - mip_level_count: 1, - sample_count: 1, - dimension: wgpu::TextureDimension::D2, - format: wgpu::TextureFormat::Rgba8UnormSrgb, - usage: wgpu::TextureUsages::TEXTURE_BINDING | wgpu::TextureUsages::RENDER_ATTACHMENT, - label: None, - }); - - let framebuffer_texture_view = - framebuffer_texture.create_view(&wgpu::TextureViewDescriptor::default()); - let palette_texture_view = - palette_texture.create_view(&wgpu::TextureViewDescriptor::default()); - let screen_texture_view = - screen_texture.create_view(&wgpu::TextureViewDescriptor::default()); + let palette_screen_mode = PaletteScreenMode::new(&device); let mut uniforms = Uniforms { texture_scale: texture_scale_from_resolution(window.inner_size()), @@ -136,48 +90,6 @@ impl Window { usage: wgpu::BufferUsages::UNIFORM | wgpu::BufferUsages::COPY_DST, }); - let palette_bind_group_layout = - device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor { - entries: &[ - wgpu::BindGroupLayoutEntry { - binding: 0, - visibility: wgpu::ShaderStages::FRAGMENT, - ty: wgpu::BindingType::Texture { - multisampled: false, - view_dimension: wgpu::TextureViewDimension::D2, - sample_type: wgpu::TextureSampleType::Uint, - }, - count: None, - }, - wgpu::BindGroupLayoutEntry { - binding: 1, - visibility: wgpu::ShaderStages::FRAGMENT, - ty: wgpu::BindingType::Texture { - multisampled: false, - view_dimension: wgpu::TextureViewDimension::D1, - sample_type: wgpu::TextureSampleType::Float { filterable: false }, - }, - count: None, - }, - ], - label: None, - }); - - let palette_bind_group = device.create_bind_group(&wgpu::BindGroupDescriptor { - layout: &palette_bind_group_layout, - entries: &[ - wgpu::BindGroupEntry { - binding: 0, - resource: wgpu::BindingResource::TextureView(&framebuffer_texture_view), - }, - wgpu::BindGroupEntry { - binding: 1, - resource: wgpu::BindingResource::TextureView(&palette_texture_view), - }, - ], - label: None, - }); - let crt_bind_group_layout = device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor { entries: &[ @@ -210,7 +122,7 @@ impl Window { entries: &[ wgpu::BindGroupEntry { binding: 0, - resource: wgpu::BindingResource::TextureView(&screen_texture_view), + resource: wgpu::BindingResource::TextureView(&palette_screen_mode.screen_view), }, wgpu::BindGroupEntry { binding: 1, @@ -220,41 +132,6 @@ impl Window { label: None, }); - let palette_shader = device.create_shader_module(wgpu::ShaderModuleDescriptor { - label: None, - source: wgpu::ShaderSource::Wgsl(include_str!("palette.wgsl").into()), - }); - - let palette_pipeline_layout = - device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor { - label: None, - bind_group_layouts: &[&palette_bind_group_layout], - push_constant_ranges: &[], - }); - - let palette_pipeline = device.create_render_pipeline(&wgpu::RenderPipelineDescriptor { - label: None, - layout: Some(&palette_pipeline_layout), - vertex: wgpu::VertexState { - module: &palette_shader, - entry_point: "vs_main", - buffers: &[], - }, - fragment: Some(wgpu::FragmentState { - module: &palette_shader, - entry_point: "fs_main", - targets: &[Some(wgpu::ColorTargetState { - format: wgpu::TextureFormat::Rgba8UnormSrgb, - blend: None, - write_mask: wgpu::ColorWrites::ALL, - })], - }), - primitive: Default::default(), - depth_stencil: None, - multisample: Default::default(), - multiview: None, - }); - let crt_shader = device.create_shader_module(wgpu::ShaderModuleDescriptor { label: None, source: wgpu::ShaderSource::Wgsl(include_str!("crt.wgsl").into()), @@ -360,8 +237,7 @@ impl Window { let next_frame = update( &mut GpuFramebuffer { queue: &queue, - framebuffer: &framebuffer_texture, - palette: &palette_texture, + framebuffer: &palette_screen_mode, }, gamepad, reset, @@ -376,25 +252,7 @@ impl Window { let mut encoder = device .create_command_encoder(&wgpu::CommandEncoderDescriptor { label: None }); - { - let mut render_pass = - encoder.begin_render_pass(&wgpu::RenderPassDescriptor { - label: None, - color_attachments: &[Some(wgpu::RenderPassColorAttachment { - view: &screen_texture_view, - resolve_target: None, - ops: wgpu::Operations { - load: wgpu::LoadOp::Load, - store: true, - }, - })], - depth_stencil_attachment: None, - }); - - render_pass.set_pipeline(&palette_pipeline); - render_pass.set_bind_group(0, &palette_bind_group, &[]); - render_pass.draw(0..3, 0..1); - } + palette_screen_mode.resolve_screen(&mut encoder); { let mut render_pass = @@ -431,51 +289,14 @@ impl Window { } struct GpuFramebuffer<'a> { - framebuffer: &'a wgpu::Texture, - palette: &'a wgpu::Texture, + framebuffer: &'a PaletteScreenMode, queue: &'a wgpu::Queue, } impl<'a> Framebuffer for GpuFramebuffer<'a> { fn update(&mut self, pixels: &[u8], palette: &[u8]) { - self.queue.write_texture( - wgpu::ImageCopyTexture { - texture: self.framebuffer, - mip_level: 0, - origin: wgpu::Origin3d::ZERO, - aspect: wgpu::TextureAspect::All, - }, - &bytemuck::cast_slice(pixels), - wgpu::ImageDataLayout { - offset: 0, - bytes_per_row: NonZeroU32::new(320), - rows_per_image: None, - }, - wgpu::Extent3d { - width: 320, - height: 240, - depth_or_array_layers: 1, - }, - ); - self.queue.write_texture( - wgpu::ImageCopyTexture { - texture: self.palette, - mip_level: 0, - origin: wgpu::Origin3d::ZERO, - aspect: wgpu::TextureAspect::All, - }, - &bytemuck::cast_slice(palette), - wgpu::ImageDataLayout { - offset: 0, - bytes_per_row: NonZeroU32::new(256 * 4), - rows_per_image: None, - }, - wgpu::Extent3d { - width: 256, - height: 1, - depth_or_array_layers: 1, - }, - ); + self.framebuffer.write_framebuffer(self.queue, pixels); + self.framebuffer.write_palette(self.queue, palette); } } @@ -494,3 +315,211 @@ fn texture_scale_from_resolution(res: PhysicalSize) -> [f32; 4] { struct Uniforms { texture_scale: [f32; 4], } +struct PaletteScreenMode { + framebuffer: wgpu::Texture, + palette: wgpu::Texture, + screen_view: wgpu::TextureView, + bind_group: wgpu::BindGroup, + pipeline: wgpu::RenderPipeline, +} + +impl PaletteScreenMode { + fn new(device: &wgpu::Device) -> PaletteScreenMode { + let framebuffer_texture = device.create_texture(&wgpu::TextureDescriptor { + size: wgpu::Extent3d { + width: 320, + height: 240, + depth_or_array_layers: 1, + }, + mip_level_count: 1, + sample_count: 1, + dimension: wgpu::TextureDimension::D2, + format: wgpu::TextureFormat::R8Uint, + usage: wgpu::TextureUsages::TEXTURE_BINDING | wgpu::TextureUsages::COPY_DST, + label: None, + }); + + let palette_texture = device.create_texture(&wgpu::TextureDescriptor { + size: wgpu::Extent3d { + width: 256, + height: 1, + depth_or_array_layers: 1, + }, + mip_level_count: 1, + sample_count: 1, + dimension: wgpu::TextureDimension::D1, + format: wgpu::TextureFormat::Rgba8UnormSrgb, + usage: wgpu::TextureUsages::TEXTURE_BINDING | wgpu::TextureUsages::COPY_DST, + label: None, + }); + + let screen_texture = device.create_texture(&wgpu::TextureDescriptor { + size: wgpu::Extent3d { + width: 320, + height: 240, + depth_or_array_layers: 1, + }, + mip_level_count: 1, + sample_count: 1, + dimension: wgpu::TextureDimension::D2, + format: wgpu::TextureFormat::Rgba8UnormSrgb, + usage: wgpu::TextureUsages::TEXTURE_BINDING | wgpu::TextureUsages::RENDER_ATTACHMENT, + label: None, + }); + + let framebuffer_texture_view = + framebuffer_texture.create_view(&wgpu::TextureViewDescriptor::default()); + let palette_texture_view = + palette_texture.create_view(&wgpu::TextureViewDescriptor::default()); + let screen_texture_view = + screen_texture.create_view(&wgpu::TextureViewDescriptor::default()); + + let palette_bind_group_layout = + device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor { + entries: &[ + wgpu::BindGroupLayoutEntry { + binding: 0, + visibility: wgpu::ShaderStages::FRAGMENT, + ty: wgpu::BindingType::Texture { + multisampled: false, + view_dimension: wgpu::TextureViewDimension::D2, + sample_type: wgpu::TextureSampleType::Uint, + }, + count: None, + }, + wgpu::BindGroupLayoutEntry { + binding: 1, + visibility: wgpu::ShaderStages::FRAGMENT, + ty: wgpu::BindingType::Texture { + multisampled: false, + view_dimension: wgpu::TextureViewDimension::D1, + sample_type: wgpu::TextureSampleType::Float { filterable: false }, + }, + count: None, + }, + ], + label: None, + }); + + let palette_bind_group = device.create_bind_group(&wgpu::BindGroupDescriptor { + layout: &palette_bind_group_layout, + entries: &[ + wgpu::BindGroupEntry { + binding: 0, + resource: wgpu::BindingResource::TextureView(&framebuffer_texture_view), + }, + wgpu::BindGroupEntry { + binding: 1, + resource: wgpu::BindingResource::TextureView(&palette_texture_view), + }, + ], + label: None, + }); + + let palette_shader = device.create_shader_module(wgpu::ShaderModuleDescriptor { + label: None, + source: wgpu::ShaderSource::Wgsl(include_str!("palette.wgsl").into()), + }); + + let palette_pipeline_layout = + device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor { + label: None, + bind_group_layouts: &[&palette_bind_group_layout], + push_constant_ranges: &[], + }); + + let palette_pipeline = device.create_render_pipeline(&wgpu::RenderPipelineDescriptor { + label: None, + layout: Some(&palette_pipeline_layout), + vertex: wgpu::VertexState { + module: &palette_shader, + entry_point: "vs_main", + buffers: &[], + }, + fragment: Some(wgpu::FragmentState { + module: &palette_shader, + entry_point: "fs_main", + targets: &[Some(wgpu::ColorTargetState { + format: wgpu::TextureFormat::Rgba8UnormSrgb, + blend: None, + write_mask: wgpu::ColorWrites::ALL, + })], + }), + primitive: Default::default(), + depth_stencil: None, + multisample: Default::default(), + multiview: None, + }); + + PaletteScreenMode { + framebuffer: framebuffer_texture, + palette: palette_texture, + screen_view: screen_texture_view, + bind_group: palette_bind_group, + pipeline: palette_pipeline, + } + } + + fn write_framebuffer(&self, queue: &wgpu::Queue, pixels: &[u8]) { + queue.write_texture( + wgpu::ImageCopyTexture { + texture: &self.framebuffer, + mip_level: 0, + origin: wgpu::Origin3d::ZERO, + aspect: wgpu::TextureAspect::All, + }, + &bytemuck::cast_slice(pixels), + wgpu::ImageDataLayout { + offset: 0, + bytes_per_row: NonZeroU32::new(320), + rows_per_image: None, + }, + wgpu::Extent3d { + width: 320, + height: 240, + depth_or_array_layers: 1, + }, + ); + } + + fn write_palette(&self, queue: &wgpu::Queue, palette: &[u8]) { + queue.write_texture( + wgpu::ImageCopyTexture { + texture: &self.palette, + mip_level: 0, + origin: wgpu::Origin3d::ZERO, + aspect: wgpu::TextureAspect::All, + }, + &bytemuck::cast_slice(palette), + wgpu::ImageDataLayout { + offset: 0, + bytes_per_row: NonZeroU32::new(256 * 4), + rows_per_image: None, + }, + wgpu::Extent3d { + width: 256, + height: 1, + depth_or_array_layers: 1, + }, + ); + } + + fn resolve_screen(&self, encoder: &mut wgpu::CommandEncoder) { + let mut render_pass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor { + label: None, + color_attachments: &[Some(wgpu::RenderPassColorAttachment { + view: &self.screen_view, + resolve_target: None, + ops: wgpu::Operations { + load: wgpu::LoadOp::Load, + store: true, + }, + })], + depth_stencil_attachment: None, + }); + + render_pass.set_pipeline(&self.pipeline); + render_pass.set_bind_group(0, &self.bind_group, &[]); + render_pass.draw(0..3, 0..1); + } +}