diff --git a/frontend/desktop/src/ui/window.rs b/frontend/desktop/src/ui/window.rs index be40584..1378ade 100644 --- a/frontend/desktop/src/ui/window.rs +++ b/frontend/desktop/src/ui/window.rs @@ -187,6 +187,7 @@ impl GfxDevice { required_features: features, required_limits: wgpu::Limits { max_texture_dimension_2d: 4096, + max_bind_groups: 5, ..wgpu::Limits::downlevel_webgl2_defaults() }, }, diff --git a/render/soft-3d/src/lib.rs b/render/soft-3d/src/lib.rs index 199d506..16c5028 100644 --- a/render/soft-3d/src/lib.rs +++ b/render/soft-3d/src/lib.rs @@ -832,9 +832,8 @@ impl Renderer { }}; } - let fog_color = rgb5_to_rgb6(rendering_data.fog_color.cast()); if rendering_data.control.fog_only_alpha() { - let fog_alpha = fog_color[3]; + let fog_alpha = rendering_data.fog_color[3] as u16; for x in 0..256 { let attrs = self.attr_buffer.0[x]; if !attrs.fog_enabled() { @@ -846,6 +845,7 @@ impl Renderer { ((fog_alpha * density + alpha * (0x80 - density)) >> 7) as u8; } } else { + let fog_color = rgb5_to_rgb6(rendering_data.fog_color.cast()); for x in 0..256 { let attrs = self.attr_buffer.0[x]; if !attrs.fog_enabled() { diff --git a/render/wgpu-2d/src/common/gfx.rs b/render/wgpu-2d/src/common/gfx.rs index 6048db6..1a5d38a 100644 --- a/render/wgpu-2d/src/common/gfx.rs +++ b/render/wgpu-2d/src/common/gfx.rs @@ -10,7 +10,7 @@ use std::{ Arc, }, thread, - time::Duration, + // time::Duration, }; pub enum Renderer3dRx { @@ -787,18 +787,19 @@ impl GfxThreadData { drop(render_pass); - if let Renderer3dGfxThreadData::Accel { - last_submitted_frame, - .. - } = &self.renderer_3d_data - { - while last_submitted_frame.0.load(Ordering::Relaxed) < frame.frame_index { - if self.shared_data.stopped.load(Ordering::Relaxed) { - return; - } - thread::park_timeout(Duration::from_millis(1)); - } - } + // TODO: Proper synchronization + // if let Renderer3dGfxThreadData::Accel { + // last_submitted_frame, + // .. + // } = &self.renderer_3d_data + // { + // while last_submitted_frame.0.load(Ordering::Relaxed) < frame.frame_index { + // if self.shared_data.stopped.load(Ordering::Relaxed) { + // return; + // } + // thread::park_timeout(Duration::from_millis(1)); + // } + // } self.queue.submit([command_encoder.finish()]); } else { diff --git a/render/wgpu-3d/src/data.rs b/render/wgpu-3d/src/data.rs index 481d78c..ccb4e4d 100644 --- a/render/wgpu-3d/src/data.rs +++ b/render/wgpu-3d/src/data.rs @@ -41,6 +41,14 @@ impl GxData { } } +#[derive(Clone, PartialEq, Eq)] +pub struct FogData { + pub depth_shift: u8, + pub offset: u16, + pub densities: [u8; 0x20], + pub color: Color, +} + pub struct RenderingData { pub control: RenderingControl, @@ -50,12 +58,10 @@ pub struct RenderingData { pub clear_image_offset: [u8; 2], pub clear_depth: u32, - pub fog_offset: u16, - pub fog_densities: [u8; 0x20], + pub fog_data: FogData, pub rear_plane_fog_enabled: bool, pub clear_color: Color, - pub fog_color: Color, pub edge_colors: [Color; 8], pub toon_colors: [Color; 0x20], @@ -85,9 +91,12 @@ impl RenderingData { self.toon_colors = state.toon_colors; self.edge_colors = state.edge_colors; - self.fog_color = state.fog_color; - self.fog_densities = state.fog_densities; - self.fog_offset = state.fog_offset; + self.fog_data = FogData { + depth_shift: state.control.fog_depth_shift(), + color: state.fog_color, + densities: state.fog_densities, + offset: state.fog_offset, + }; self.rear_plane_fog_enabled = state.rear_plane_fog_enabled; } diff --git a/render/wgpu-3d/src/lib.rs b/render/wgpu-3d/src/lib.rs index c95af9d..c13fe43 100644 --- a/render/wgpu-3d/src/lib.rs +++ b/render/wgpu-3d/src/lib.rs @@ -10,7 +10,7 @@ #![warn(clippy::all)] mod data; -pub use data::{FrameData, GxData, RenderingData}; +pub use data::{FogData, FrameData, GxData, RenderingData}; mod render; #[cfg(feature = "threaded")] pub mod threaded; @@ -27,7 +27,7 @@ use dust_core::{ utils::mem_prelude::*, }; use std::sync::Arc; -use utils::{color_to_wgpu_f64, decode_rgb5, round_up_to_alignment}; +use utils::{color_to_wgpu_f64, decode_rgb5, expand_depth, round_up_to_alignment}; use wgpu::util::DeviceExt; proc_bitfield::bitfield! { @@ -36,18 +36,17 @@ proc_bitfield::bitfield! { pub texture_mapping_enabled: bool @ 0, pub highlight_shading_enabled: bool @ 1, pub alpha_blending_enabled: bool @ 3, + // TODO // pub antialiasing_enabled: bool @ 4, - - // TODO: These may require other special handling // pub edge_marking_enabled: bool @ 5, - // pub fog_only_alpha: bool @ 6, - // pub fog_enabled: bool @ 7, + pub attrs_enabled: bool @ 6, + pub fog_enabled: bool @ 7, } } impl From for ControlFlags { fn from(other: RenderingControl) -> Self { - ControlFlags(other.0 as u8 & 0xB) + ControlFlags(other.0 as u8 & 0x8B).with_attrs_enabled(other.fog_enabled()) } } @@ -98,6 +97,8 @@ proc_bitfield::bitfield! { pub mode: u8 @ 3..=4, pub is_shadow: bool @ 5, pub w_buffering: bool @ 6, + pub attrs_enabled: bool @ 7, + pub fog_enabled: bool @ 8, } } @@ -109,22 +110,26 @@ enum BatchKind { Opaque { pipeline: PipelineKey, texture: Option<(TextureKey, SamplerKey)>, + fog_enabled: bool, }, Translucent { pipeline: PipelineKey, texture: Option<(TextureKey, SamplerKey)>, id: u8, alpha_and_ref: (u8, u8), + fog_enabled: bool, }, TranslucentNoDepthUpdate { pipeline: PipelineKey, texture: Option<(TextureKey, SamplerKey)>, id: u8, alpha_and_ref: (u8, u8), + fog_enabled: bool, }, Wireframe { pipeline: PipelineKey, texture: Option<(TextureKey, SamplerKey)>, + fog_enabled: bool, }, } @@ -139,6 +144,7 @@ impl BatchKind { } else { let texture_mapping_enabled = control.texture_mapping_enabled() && poly.tex_params.format() != 0; + let global_fog_enabled = control.fog_enabled(); let pipeline = PipelineKey(0) .with_texture_mapping_enabled(texture_mapping_enabled) .with_alpha_blending_enabled( @@ -155,7 +161,9 @@ impl BatchKind { } }) .with_is_shadow(is_shadow) - .with_w_buffering(w_buffering); + .with_w_buffering(w_buffering) + .with_attrs_enabled(control.attrs_enabled()) + .with_fog_enabled(global_fog_enabled); let texture = texture_mapping_enabled.then(|| { ( TextureKey::new(poly.tex_params, poly.tex_palette_base), @@ -172,6 +180,7 @@ impl BatchKind { texture, id, alpha_and_ref: (alpha, alpha_ref), + fog_enabled: global_fog_enabled && poly.attrs.fog_enabled(), } } else { BatchKind::TranslucentNoDepthUpdate { @@ -179,12 +188,21 @@ impl BatchKind { texture, id, alpha_and_ref: (alpha, alpha_ref), + fog_enabled: global_fog_enabled && poly.attrs.fog_enabled(), } } } else if alpha == 0 { - BatchKind::Wireframe { pipeline, texture } + BatchKind::Wireframe { + pipeline, + texture, + fog_enabled: global_fog_enabled && poly.attrs.fog_enabled(), + } } else { - BatchKind::Opaque { pipeline, texture } + BatchKind::Opaque { + pipeline, + texture, + fog_enabled: global_fog_enabled && poly.attrs.fog_enabled(), + } } } } @@ -202,26 +220,34 @@ enum PreparedBatchKind { depth_test_equal: bool, }, Opaque { - pipeline: Option, + pipeline_changed: bool, + pipeline: PipelineKey, + fog_enabled: Option>, texture: Option>, + toon_bg_index: Option>, }, Translucent { - pipeline_changed: bool, pipeline: PipelineKey, - texture: Option>, id: Option, alpha_and_ref: Option<(u8, u8)>, + fog_enabled: Option>, + texture: Option>, + toon_bg_index: Option>, }, TranslucentNoDepthUpdate { - pipeline_changed: bool, pipeline: PipelineKey, - texture: Option>, id: Option, alpha_and_ref: Option<(u8, u8)>, + fog_enabled: Option>, + texture: Option>, + toon_bg_index: Option>, }, Wireframe { - pipeline: Option, + pipeline_changed: bool, + pipeline: PipelineKey, + fog_enabled: Option>, texture: Option>, + toon_bg_index: Option>, }, } @@ -586,17 +612,54 @@ fn create_sampler(device: &wgpu::Device, sampler_key: SamplerKey) -> wgpu::Sampl } struct OutputAttachments { - color: wgpu::Texture, - color_view: wgpu::TextureView, + color: [(wgpu::Texture, wgpu::TextureView, wgpu::BindGroup); 2], depth_view: wgpu::TextureView, + attrs_view: wgpu::TextureView, + depth_attrs_bg: wgpu::BindGroup, } impl OutputAttachments { - fn new(device: &wgpu::Device, resolution_scale_shift: u8) -> Self { + fn new( + device: &wgpu::Device, + resolution_scale_shift: u8, + color_bg_layout: &wgpu::BindGroupLayout, + depth_attrs_bg_layout: &wgpu::BindGroupLayout, + ) -> Self { let resolution_scale = 1 << resolution_scale_shift; - let color = device.create_texture(&wgpu::TextureDescriptor { - label: Some("3D renderer color"), + let color = [0, 1].map(|_| { + let color = device.create_texture(&wgpu::TextureDescriptor { + label: Some("3D renderer color"), + size: wgpu::Extent3d { + width: 256 * resolution_scale, + height: 192 * resolution_scale, + depth_or_array_layers: 1, + }, + mip_level_count: 1, + sample_count: 1, + dimension: wgpu::TextureDimension::D2, + format: wgpu::TextureFormat::Rgba8Unorm, + usage: wgpu::TextureUsages::RENDER_ATTACHMENT + | wgpu::TextureUsages::TEXTURE_BINDING, + view_formats: &[], + }); + let color_view = color.create_view(&wgpu::TextureViewDescriptor { + label: Some("3D renderer color view"), + ..wgpu::TextureViewDescriptor::default() + }); + let color_bg = device.create_bind_group(&wgpu::BindGroupDescriptor { + label: Some("3D renderer color bind group"), + layout: color_bg_layout, + entries: &[wgpu::BindGroupEntry { + binding: 0, + resource: wgpu::BindingResource::TextureView(&color_view), + }], + }); + (color, color_view, color_bg) + }); + + let depth = device.create_texture(&wgpu::TextureDescriptor { + label: Some("3D renderer depth"), size: wgpu::Extent3d { width: 256 * resolution_scale, height: 192 * resolution_scale, @@ -605,17 +668,17 @@ impl OutputAttachments { mip_level_count: 1, sample_count: 1, dimension: wgpu::TextureDimension::D2, - format: wgpu::TextureFormat::Rgba8Unorm, + format: wgpu::TextureFormat::Depth24PlusStencil8, usage: wgpu::TextureUsages::RENDER_ATTACHMENT | wgpu::TextureUsages::TEXTURE_BINDING, view_formats: &[], }); - let color_view = color.create_view(&wgpu::TextureViewDescriptor { - label: Some("3D renderer color view"), + let depth_view = depth.create_view(&wgpu::TextureViewDescriptor { + label: Some("3D renderer depth view"), ..wgpu::TextureViewDescriptor::default() }); - let depth = device.create_texture(&wgpu::TextureDescriptor { - label: Some("3D renderer depth"), + let attrs = device.create_texture(&wgpu::TextureDescriptor { + label: Some("3D renderer attributes"), size: wgpu::Extent3d { width: 256 * resolution_scale, height: 192 * resolution_scale, @@ -624,29 +687,63 @@ impl OutputAttachments { mip_level_count: 1, sample_count: 1, dimension: wgpu::TextureDimension::D2, - format: wgpu::TextureFormat::Depth24PlusStencil8, - usage: wgpu::TextureUsages::RENDER_ATTACHMENT, + format: wgpu::TextureFormat::Rgba8Unorm, + usage: wgpu::TextureUsages::RENDER_ATTACHMENT | wgpu::TextureUsages::TEXTURE_BINDING, view_formats: &[], }); - let depth_view = depth.create_view(&wgpu::TextureViewDescriptor { - label: Some("3D renderer depth view"), + let attrs_view = attrs.create_view(&wgpu::TextureViewDescriptor { + label: Some("3D renderer attributes view"), ..wgpu::TextureViewDescriptor::default() }); + let depth_attrs_bg = device.create_bind_group(&wgpu::BindGroupDescriptor { + label: Some("3D renderer depth/attrs bind group"), + layout: depth_attrs_bg_layout, + entries: &[ + wgpu::BindGroupEntry { + binding: 0, + resource: wgpu::BindingResource::TextureView(&depth.create_view( + &wgpu::TextureViewDescriptor { + label: Some("3D renderer depth only view"), + aspect: wgpu::TextureAspect::DepthOnly, + ..wgpu::TextureViewDescriptor::default() + }, + )), + }, + wgpu::BindGroupEntry { + binding: 1, + resource: wgpu::BindingResource::TextureView(&attrs_view), + }, + ], + }); + OutputAttachments { color, - color_view, depth_view, + attrs_view, + depth_attrs_bg, } } } +struct BgLayouts { + color: wgpu::BindGroupLayout, + depth_attrs: wgpu::BindGroupLayout, + id: wgpu::BindGroupLayout, + alpha_and_ref: wgpu::BindGroupLayout, + fog_enabled: wgpu::BindGroupLayout, + texture: wgpu::BindGroupLayout, + toon: wgpu::BindGroupLayout, + fog_data: wgpu::BindGroupLayout, +} + pub struct Renderer { device: Arc, queue: Arc, resolution_scale_shift: u8, // hi_res_coords_mask: u16x2, + color_output_index: u8, output_attachments: OutputAttachments, vtx_buffer: wgpu::Buffer, @@ -654,30 +751,36 @@ pub struct Renderer { idx_buffer: wgpu::Buffer, idx_buffer_contents: Vec, - toon_colors: [Color; 0x20], - toon_buffer: wgpu::Buffer, - toon_bg_layout: wgpu::BindGroupLayout, - toon_bg: wgpu::BindGroup, + bg_layouts: BgLayouts, - // rear_plane_texture: wgpu::Texture, - // render_rear_plane_bitmap_pipeline: Pipeline, - pipelines: HashMap, - trans_pipelines: HashMap, - trans_no_depth_update_pipelines: HashMap, - textures: HashMap, - samplers: [Option; 0x10], - texture_bg_layout: wgpu::BindGroupLayout, - texture_bgs: HashMap<(TextureKey, SamplerKey), wgpu::BindGroup>, - - id_bg_layout: wgpu::BindGroupLayout, id_bg: wgpu::BindGroup, id_bg_elem_size: usize, - alpha_and_ref_bg_layout: wgpu::BindGroupLayout, alpha_and_ref_bg: wgpu::BindGroup, alpha_and_ref_bg_elem_size: usize, + fog_enabled_bg: wgpu::BindGroup, + fog_enabled_bg_elem_size: usize, + + textures: HashMap, + // rear_plane_texture: wgpu::Texture, + samplers: [Option; 0x10], + texture_bgs: HashMap<(TextureKey, SamplerKey), wgpu::BindGroup>, texture_decode_buffer: Vec, + + toon_colors: [Color; 0x20], + toon_buffer: wgpu::Buffer, + toon_bg: wgpu::BindGroup, + + fog_data: FogData, + fog_data_buffer: wgpu::Buffer, + fog_data_bg: wgpu::BindGroup, + + opaque_pipelines: HashMap, + trans_pipelines: HashMap, + trans_no_depth_update_pipelines: HashMap, + // rear_plane_bitmap_pipeline: Pipeline, + fog_pipelines: [wgpu::RenderPipeline; 2], batches: Vec, } @@ -692,8 +795,6 @@ impl Renderer { // let hi_res_coords_mask = u16x2::splat(!(0x10 >> resolution_scale_shift.min(4)) - 1); - let output_attachments = OutputAttachments::new(&device, resolution_scale_shift); - let vert_buffer = device.create_buffer(&wgpu::BufferDescriptor { label: Some("3D renderer vertices"), size: mem::size_of::() as u64 * 6144, @@ -708,61 +809,48 @@ impl Renderer { mapped_at_creation: false, }); - let toon_buffer = device.create_buffer(&wgpu::BufferDescriptor { - label: Some("3D renderer toon table"), - size: 0x200, - usage: wgpu::BufferUsages::COPY_DST | wgpu::BufferUsages::UNIFORM, - mapped_at_creation: false, - }); - let toon_bg_layout = device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor { - label: Some("3D renderer toon table bind group layout"), + let color_bg_layout = device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor { + label: Some("3D renderer color bind group layout"), entries: &[wgpu::BindGroupLayoutEntry { binding: 0, visibility: wgpu::ShaderStages::FRAGMENT, - ty: wgpu::BindingType::Buffer { - ty: wgpu::BufferBindingType::Uniform, - has_dynamic_offset: false, - min_binding_size: wgpu::BufferSize::new(0x200), + ty: wgpu::BindingType::Texture { + sample_type: wgpu::TextureSampleType::Float { filterable: false }, + view_dimension: wgpu::TextureViewDimension::D2, + multisampled: false, }, count: None, }], }); - let toon_bg = device.create_bind_group(&wgpu::BindGroupDescriptor { - label: Some("3D renderer toon table bind group"), - layout: &toon_bg_layout, - entries: &[wgpu::BindGroupEntry { - binding: 0, - resource: wgpu::BindingResource::Buffer(wgpu::BufferBinding { - buffer: &toon_buffer, - offset: 0, - size: wgpu::BufferSize::new(0x200), - }), - }], - }); - let texture_bg_layout = device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor { - label: Some("3D renderer texture bind group layout"), - entries: &[ - wgpu::BindGroupLayoutEntry { - binding: 0, - visibility: wgpu::ShaderStages::FRAGMENT, - ty: wgpu::BindingType::Texture { - sample_type: wgpu::TextureSampleType::Float { filterable: true }, - view_dimension: wgpu::TextureViewDimension::D2, - multisampled: false, + let depth_attrs_bg_layout = + device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor { + label: Some("3D renderer depth/attrs bind group layout"), + entries: &[ + wgpu::BindGroupLayoutEntry { + binding: 0, + visibility: wgpu::ShaderStages::FRAGMENT, + ty: wgpu::BindingType::Texture { + sample_type: wgpu::TextureSampleType::Depth, + view_dimension: wgpu::TextureViewDimension::D2, + multisampled: false, + }, + count: None, }, - count: None, - }, - wgpu::BindGroupLayoutEntry { - binding: 1, - visibility: wgpu::ShaderStages::FRAGMENT, - ty: wgpu::BindingType::Sampler(wgpu::SamplerBindingType::Filtering), - count: None, - }, - ], - }); + wgpu::BindGroupLayoutEntry { + binding: 1, + visibility: wgpu::ShaderStages::FRAGMENT, + ty: wgpu::BindingType::Texture { + sample_type: wgpu::TextureSampleType::Float { filterable: false }, + view_dimension: wgpu::TextureViewDimension::D2, + multisampled: false, + }, + count: None, + }, + ], + }); - macro_rules! uniform_bind_group { + macro_rules! constant_buffer_bg { ($label: literal, $shader_stages: expr, $binding_size: expr, $contents: expr) => {{ let layout = device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor { label: Some(concat!("3D renderer ", $label, " bind group layout")), @@ -803,7 +891,7 @@ impl Renderer { let id_bg_elem_size = round_up_to_alignment(4, min_uniform_buffer_offset_alignment as usize); - let (id_bg_layout, id_bg) = uniform_bind_group!("ID", wgpu::ShaderStages::FRAGMENT, 4, { + let (id_bg_layout, id_bg) = constant_buffer_bg!("ID", wgpu::ShaderStages::FRAGMENT, 4, { let mut buffer_contents = vec![0; id_bg_elem_size * 0x40]; let mut addr = 0; for i in 0..0x40 { @@ -815,7 +903,7 @@ impl Renderer { let alpha_and_ref_bg_elem_size = round_up_to_alignment(8, min_uniform_buffer_offset_alignment as usize); - let (alpha_and_ref_bg_layout, alpha_and_ref_bg) = uniform_bind_group!( + let (alpha_and_ref_bg_layout, alpha_and_ref_bg) = constant_buffer_bg!( "alpha", wgpu::ShaderStages::VERTEX | wgpu::ShaderStages::FRAGMENT, 8, @@ -836,12 +924,136 @@ impl Renderer { } ); + let fog_enabled_bg_elem_size = + round_up_to_alignment(4, min_uniform_buffer_offset_alignment as usize); + let (fog_enabled_bg_layout, fog_enabled_bg) = + constant_buffer_bg!("fog enabled", wgpu::ShaderStages::FRAGMENT, 4, { + let mut buffer_contents = vec![0; fog_enabled_bg_elem_size * 2]; + let mut addr = 0; + for attrs in [0_u8, 1] { + buffer_contents[addr..addr + 4].copy_from_slice(&(attrs as u32).to_ne_bytes()); + addr += fog_enabled_bg_elem_size; + } + buffer_contents + }); + + let texture_bg_layout = device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor { + label: Some("3D renderer texture bind group layout"), + entries: &[ + wgpu::BindGroupLayoutEntry { + binding: 0, + visibility: wgpu::ShaderStages::FRAGMENT, + ty: wgpu::BindingType::Texture { + sample_type: wgpu::TextureSampleType::Float { filterable: true }, + view_dimension: wgpu::TextureViewDimension::D2, + multisampled: false, + }, + count: None, + }, + wgpu::BindGroupLayoutEntry { + binding: 1, + visibility: wgpu::ShaderStages::FRAGMENT, + ty: wgpu::BindingType::Sampler(wgpu::SamplerBindingType::Filtering), + count: None, + }, + ], + }); + + let toon_buffer = device.create_buffer(&wgpu::BufferDescriptor { + label: Some("3D renderer toon table"), + size: 0x200, + usage: wgpu::BufferUsages::COPY_DST | wgpu::BufferUsages::UNIFORM, + mapped_at_creation: false, + }); + let toon_bg_layout = device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor { + label: Some("3D renderer toon table bind group layout"), + entries: &[wgpu::BindGroupLayoutEntry { + binding: 0, + visibility: wgpu::ShaderStages::FRAGMENT, + ty: wgpu::BindingType::Buffer { + ty: wgpu::BufferBindingType::Uniform, + has_dynamic_offset: false, + min_binding_size: wgpu::BufferSize::new(0x200), + }, + count: None, + }], + }); + let toon_bg = device.create_bind_group(&wgpu::BindGroupDescriptor { + label: Some("3D renderer toon table bind group"), + layout: &toon_bg_layout, + entries: &[wgpu::BindGroupEntry { + binding: 0, + resource: wgpu::BindingResource::Buffer(wgpu::BufferBinding { + buffer: &toon_buffer, + offset: 0, + size: wgpu::BufferSize::new(0x200), + }), + }], + }); + + let fog_data_buffer = device.create_buffer(&wgpu::BufferDescriptor { + label: Some("3D renderer fog data"), + size: 0x90 << 2, + usage: wgpu::BufferUsages::COPY_DST | wgpu::BufferUsages::UNIFORM, + mapped_at_creation: false, + }); + let fog_data_bg_layout = + device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor { + label: Some("3D renderer fog data bind group layout"), + entries: &[wgpu::BindGroupLayoutEntry { + binding: 0, + visibility: wgpu::ShaderStages::FRAGMENT, + ty: wgpu::BindingType::Buffer { + ty: wgpu::BufferBindingType::Uniform, + has_dynamic_offset: false, + min_binding_size: wgpu::BufferSize::new(0x90 << 2), + }, + count: None, + }], + }); + let fog_data_bg = device.create_bind_group(&wgpu::BindGroupDescriptor { + label: Some("3D renderer fog data bind group"), + layout: &fog_data_bg_layout, + entries: &[wgpu::BindGroupEntry { + binding: 0, + resource: wgpu::BindingResource::Buffer(wgpu::BufferBinding { + buffer: &fog_data_buffer, + offset: 0, + size: wgpu::BufferSize::new(0x90 << 2), + }), + }], + }); + + let output_attachments = OutputAttachments::new( + &device, + resolution_scale_shift, + &color_bg_layout, + &depth_attrs_bg_layout, + ); + + let bg_layouts = BgLayouts { + color: color_bg_layout, + depth_attrs: depth_attrs_bg_layout, + id: id_bg_layout, + alpha_and_ref: alpha_and_ref_bg_layout, + fog_enabled: fog_enabled_bg_layout, + texture: texture_bg_layout, + toon: toon_bg_layout, + fog_data: fog_data_bg_layout, + }; + + let fog_pipelines = [ + render::fog::create_pipeline(false, &device, &bg_layouts), + render::fog::create_pipeline(true, &device, &bg_layouts), + ]; + Renderer { device, queue, resolution_scale_shift, // hi_res_coords_mask, + color_output_index: 0, output_attachments, vtx_buffer: vert_buffer, @@ -849,29 +1061,40 @@ impl Renderer { idx_buffer, idx_buffer_contents: Vec::new(), - toon_colors: [Color::splat(0xFF); 0x20], - toon_buffer, - toon_bg_layout, - toon_bg, - - pipelines: HashMap::default(), - trans_pipelines: HashMap::default(), - trans_no_depth_update_pipelines: HashMap::default(), + bg_layouts, - textures: HashMap::default(), - samplers: [const { None }; 0x10], - texture_bg_layout, - texture_bgs: HashMap::default(), - - id_bg_layout, id_bg, id_bg_elem_size, alpha_and_ref_bg, - alpha_and_ref_bg_layout, alpha_and_ref_bg_elem_size, + fog_enabled_bg, + fog_enabled_bg_elem_size, + + textures: HashMap::default(), + samplers: [const { None }; 0x10], + texture_bgs: HashMap::default(), texture_decode_buffer: Vec::new(), + + toon_colors: [Color::splat(0xFF); 0x20], + toon_buffer, + toon_bg, + + fog_data: FogData { + depth_shift: 0xFF, + offset: 0, + densities: [0; 32], + color: Color::splat(0), + }, + fog_data_buffer, + fog_data_bg, + + opaque_pipelines: HashMap::default(), + trans_pipelines: HashMap::default(), + trans_no_depth_update_pipelines: HashMap::default(), + fog_pipelines, + batches: Vec::new(), } } @@ -896,12 +1119,22 @@ impl Renderer { return; } self.resolution_scale_shift = value; - self.output_attachments = OutputAttachments::new(&self.device, value); + self.output_attachments = OutputAttachments::new( + &self.device, + value, + &self.bg_layouts.color, + &self.bg_layouts.depth_attrs, + ); + } + + #[inline] + pub fn color_output_index(&self) -> u8 { + self.color_output_index } pub fn create_output_view(&self) -> wgpu::TextureView { - self.output_attachments - .color + self.output_attachments.color[self.color_output_index as usize] + .0 .create_view(&Default::default()) } @@ -914,39 +1147,70 @@ impl Renderer { self.texture_bgs .retain(|(texture, _), _| self.textures.contains_key(texture)); + let control_flags = ControlFlags::from(frame.rendering.control); + + let mut toon_used = false; + let mut fog_used = false; + let mut command_encoder = self.device .create_command_encoder(&wgpu::CommandEncoderDescriptor { label: Some("3D renderer command encoder"), }); - let mut render_pass = command_encoder.begin_render_pass(&wgpu::RenderPassDescriptor { - label: Some("3D renderer render pass"), - color_attachments: &[Some(wgpu::RenderPassColorAttachment { - view: &self.output_attachments.color_view, + let mut color_attachments = vec![Some(wgpu::RenderPassColorAttachment { + view: &self.output_attachments.color[0].1, + resolve_target: None, + ops: wgpu::Operations { + load: wgpu::LoadOp::Clear(if frame.rendering.control.rear_plane_bitmap_enabled() { + wgpu::Color::BLACK + } else { + color_to_wgpu_f64(frame.rendering.clear_color) + }), + store: wgpu::StoreOp::Store, + }, + })]; + + if control_flags.attrs_enabled() { + color_attachments.push(Some(wgpu::RenderPassColorAttachment { + view: &self.output_attachments.attrs_view, resolve_target: None, ops: wgpu::Operations { - load: wgpu::LoadOp::Clear( - if frame.rendering.control.rear_plane_bitmap_enabled() { - wgpu::Color::BLACK + load: wgpu::LoadOp::Clear(wgpu::Color { + r: 0.0, + g: 0.0, + b: 0.0, + a: if control_flags.fog_enabled() && frame.rendering.rear_plane_fog_enabled + { + fog_used = true; + 1.0 } else { - color_to_wgpu_f64(frame.rendering.clear_color) + 0.0 }, - ), + }), store: wgpu::StoreOp::Store, }, - })], + })); + } + + let mut render_pass = command_encoder.begin_render_pass(&wgpu::RenderPassDescriptor { + label: Some("3D renderer render pass"), + color_attachments: &color_attachments, depth_stencil_attachment: Some(wgpu::RenderPassDepthStencilAttachment { view: &self.output_attachments.depth_view, depth_ops: Some(wgpu::Operations { load: wgpu::LoadOp::Clear( if frame.rendering.control.rear_plane_bitmap_enabled() { - 0.0 + 1.0 } else { frame.rendering.clear_depth as f32 / (1 << 24) as f32 }, ), - store: wgpu::StoreOp::Discard, + store: if control_flags.attrs_enabled() { + wgpu::StoreOp::Store + } else { + wgpu::StoreOp::Discard + }, }), stencil_ops: Some(wgpu::Operations { load: wgpu::LoadOp::Clear(0), @@ -963,10 +1227,6 @@ impl Renderer { let polys = &frame.gx.poly_ram[..frame.gx.poly_ram_level as usize]; if !polys.is_empty() && frame.rendering.alpha_test_ref < 0x1F { - let control_flags = ControlFlags::from(frame.rendering.control); - - let mut toon_used = false; - self.vtx_buffer_contents.clear(); self.idx_buffer_contents.clear(); @@ -992,7 +1252,7 @@ impl Renderer { .get_or_insert_with(|| create_sampler(&self.device, sampler_key)); self.device.create_bind_group(&wgpu::BindGroupDescriptor { label: Some("3D renderer texture bind group"), - layout: &self.texture_bg_layout, + layout: &self.bg_layouts.texture, entries: &[ wgpu::BindGroupEntry { binding: 0, @@ -1032,9 +1292,9 @@ impl Renderer { let $ident = if true$(&& $cond)* { let res = bg_index; bg_index += 1; - res + Some(res) } else { - 0 + None }; )* $process @@ -1049,20 +1309,24 @@ impl Renderer { PreparedBatchKind::ShadowMask { depth_test_equal } } - BatchKind::Opaque { pipeline, texture } => { + BatchKind::Opaque { + pipeline, + texture, + fog_enabled, + } => { field_updates!( Opaque; pipeline, cur_pipeline, pipeline_changed; - texture, cur_texture, texture_changed + texture, cur_texture, texture_changed; + fog_enabled, cur_fog_enabled, fog_enabled_changed ); if pipeline_changed { - self.pipelines.entry(pipeline).or_insert_with(|| { + self.opaque_pipelines.entry(pipeline).or_insert_with(|| { render::opaque::create_pipeline( pipeline, &self.device, - &self.toon_bg_layout, - &self.texture_bg_layout, + &self.bg_layouts, ) }); } @@ -1076,13 +1340,18 @@ impl Renderer { bg_indices!( 0, ( - _toon_bg_index * pipeline.mode() >= 2, - texture_bg_index * texture.is_some() + fog_enabled_bg_index * pipeline.fog_enabled(), + texture_bg_index * texture.is_some(), + toon_bg_index * pipeline.mode() >= 2 ), PreparedBatchKind::Opaque { - pipeline: pipeline_changed.then_some(pipeline), + pipeline_changed, + pipeline, + fog_enabled: (pipeline_changed || fog_enabled_changed) + .then_some(fog_enabled_bg_index.map(|i| (fog_enabled, i))), texture: (texture_changed || pipeline_changed) - .then(|| texture.map(|t| (t, texture_bg_index))), + .then(|| texture.zip(texture_bg_index)), + toon_bg_index: pipeline_changed.then_some(toon_bg_index), } ) } @@ -1092,24 +1361,24 @@ impl Renderer { texture, id, alpha_and_ref, + fog_enabled, } => { field_updates!( Translucent; pipeline, cur_pipeline, pipeline_changed; texture, cur_texture, texture_changed; id, cur_id, id_changed; - alpha_and_ref, cur_alpha_and_ref, alpha_and_ref_changed + alpha_and_ref, cur_alpha_and_ref, alpha_and_ref_changed; + fog_enabled, cur_fog_enabled, fog_enabled_changed ); if pipeline_changed { self.trans_pipelines.entry(pipeline).or_insert_with(|| { render::trans::create_pipeline( pipeline, + true, &self.device, - &self.id_bg_layout, - &self.alpha_and_ref_bg_layout, - &self.toon_bg_layout, - &self.texture_bg_layout, + &self.bg_layouts, ) }); } @@ -1123,16 +1392,19 @@ impl Renderer { bg_indices!( 2, ( - _toon_bg_index * pipeline.mode() >= 2, - texture_bg_index * texture.is_some() + fog_enabled_bg_index * pipeline.fog_enabled(), + texture_bg_index * texture.is_some(), + toon_bg_index * pipeline.mode() >= 2 ), PreparedBatchKind::Translucent { - pipeline_changed, pipeline, - texture: (texture_changed || pipeline_changed) - .then(|| texture.map(|t| (t, texture_bg_index))), id: id_changed.then_some(id), - alpha_and_ref: alpha_and_ref_changed.then_some(alpha_and_ref) + alpha_and_ref: alpha_and_ref_changed.then_some(alpha_and_ref), + fog_enabled: (pipeline_changed || fog_enabled_changed) + .then_some(fog_enabled_bg_index.map(|i| (fog_enabled, i))), + texture: (texture_changed || pipeline_changed) + .then(|| texture.zip(texture_bg_index)), + toon_bg_index: pipeline_changed.then_some(toon_bg_index), } ) } @@ -1142,26 +1414,26 @@ impl Renderer { texture, id, alpha_and_ref, + fog_enabled, } => { field_updates!( TranslucentNoDepthUpdate; pipeline, cur_pipeline, pipeline_changed; texture, cur_texture, texture_changed; id, cur_id, id_changed; - alpha_and_ref, cur_alpha_and_ref, alpha_and_ref_changed + alpha_and_ref, cur_alpha_and_ref, alpha_and_ref_changed; + fog_enabled, cur_fog_enabled, fog_enabled_changed ); if pipeline_changed { self.trans_no_depth_update_pipelines .entry(pipeline) .or_insert_with(|| { - render::trans_no_depth_update::create_pipeline( + render::trans::create_pipeline( pipeline, + false, &self.device, - &self.id_bg_layout, - &self.alpha_and_ref_bg_layout, - &self.toon_bg_layout, - &self.texture_bg_layout, + &self.bg_layouts, ) }); } @@ -1175,25 +1447,33 @@ impl Renderer { bg_indices!( 2, ( - _toon_bg_index * pipeline.mode() >= 2, - texture_bg_index * texture.is_some() + fog_enabled_bg_index * pipeline.fog_enabled(), + texture_bg_index * texture.is_some(), + toon_bg_index * pipeline.mode() >= 2 ), PreparedBatchKind::TranslucentNoDepthUpdate { - pipeline_changed, pipeline, - texture: (texture_changed || pipeline_changed) - .then(|| texture.map(|t| (t, texture_bg_index))), id: id_changed.then_some(id), - alpha_and_ref: alpha_and_ref_changed.then_some(alpha_and_ref) + alpha_and_ref: alpha_and_ref_changed.then_some(alpha_and_ref), + fog_enabled: (pipeline_changed || fog_enabled_changed) + .then_some(fog_enabled_bg_index.map(|i| (fog_enabled, i))), + texture: (texture_changed || pipeline_changed) + .then(|| texture.zip(texture_bg_index)), + toon_bg_index: pipeline_changed.then_some(toon_bg_index), } ) } - BatchKind::Wireframe { pipeline, texture } => { + BatchKind::Wireframe { + pipeline, + texture, + fog_enabled, + } => { field_updates!( Wireframe; pipeline, cur_pipeline, pipeline_changed; - texture, cur_texture, texture_changed + texture, cur_texture, texture_changed; + fog_enabled, cur_fog_enabled, fog_enabled_changed ); if pipeline_changed { @@ -1209,13 +1489,18 @@ impl Renderer { bg_indices!( 0, ( - _toon_bg_index * pipeline.mode() >= 2, - texture_bg_index * texture.is_some() + fog_enabled_bg_index * pipeline.fog_enabled(), + texture_bg_index * texture.is_some(), + toon_bg_index * pipeline.mode() >= 2 ), PreparedBatchKind::Wireframe { - pipeline: pipeline_changed.then_some(pipeline), + pipeline_changed, + pipeline, + fog_enabled: (pipeline_changed || fog_enabled_changed) + .then_some(fog_enabled_bg_index.map(|i| (fog_enabled, i))), texture: (texture_changed || pipeline_changed) - .then(|| texture.map(|t| (t, texture_bg_index))), + .then(|| texture.zip(texture_bg_index)), + toon_bg_index: pipeline_changed.then_some(toon_bg_index), } ) } @@ -1253,6 +1538,7 @@ impl Renderer { } toon_used |= poly.attrs.mode() == 2; + fog_used |= poly.attrs.fog_enabled(); let verts_len = poly.attrs.verts_len(); @@ -1285,6 +1571,8 @@ impl Renderer { } finish_batch!(); + fog_used &= control_flags.fog_enabled(); + unsafe { self.queue.write_buffer( &self.vtx_buffer, @@ -1308,11 +1596,12 @@ impl Renderer { ), ), ); + if toon_used && frame.rendering.toon_colors != self.toon_colors { self.toon_colors = frame.rendering.toon_colors; let mut toon_colors = MaybeUninit::uninit_array::<0x20>(); for (dst, src) in toon_colors.iter_mut().zip(&self.toon_colors) { - *dst = MaybeUninit::new(src.cast::().to_array()); + dst.write(src.cast::().to_array()); } self.queue.write_buffer( &self.toon_buffer, @@ -1330,12 +1619,24 @@ impl Renderer { match batch.kind { PreparedBatchKind::ShadowMask { .. } => {} - PreparedBatchKind::Opaque { pipeline, texture } => { - if let Some(pipeline) = pipeline { - render_pass.set_pipeline(&self.pipelines[&pipeline]); - if pipeline.mode() >= 2 { - render_pass.set_bind_group(0, &self.toon_bg, &[]) - } + PreparedBatchKind::Opaque { + pipeline_changed, + pipeline, + fog_enabled, + texture, + toon_bg_index, + } => { + if pipeline_changed { + render_pass.set_pipeline(&self.opaque_pipelines[&pipeline]); + } + + if let Some(Some((fog_enabled, fog_enabled_bg_index))) = fog_enabled { + render_pass.set_bind_group( + fog_enabled_bg_index as u32, + &self.fog_enabled_bg, + &[(fog_enabled as usize * self.fog_enabled_bg_elem_size) + as wgpu::DynamicOffset], + ) } if let Some(Some((texture, bg_index))) = texture { @@ -1346,6 +1647,10 @@ impl Renderer { ); } + if let Some(Some(toon_bg_index)) = toon_bg_index { + render_pass.set_bind_group(toon_bg_index as u32, &self.toon_bg, &[]) + } + if batch.idxs != 0 { render_pass.draw_indexed( cur_idx_base..cur_idx_base + batch.idxs as u32, @@ -1356,16 +1661,13 @@ impl Renderer { } PreparedBatchKind::Translucent { - pipeline_changed, pipeline, - texture, id, alpha_and_ref, + fog_enabled, + texture, + toon_bg_index, } => { - if pipeline_changed && pipeline.mode() >= 2 { - render_pass.set_bind_group(2, &self.toon_bg, &[]) - } - if let Some(id) = id { render_pass.set_stencil_reference((id | 0x40) as u32); render_pass.set_bind_group( @@ -1385,6 +1687,15 @@ impl Renderer { ); } + if let Some(Some((fog_enabled, fog_enabled_bg_index))) = fog_enabled { + render_pass.set_bind_group( + fog_enabled_bg_index as u32, + &self.fog_enabled_bg, + &[(fog_enabled as usize * self.fog_enabled_bg_elem_size) + as wgpu::DynamicOffset], + ) + } + if let Some(Some((texture, bg_index))) = texture { render_pass.set_bind_group( bg_index as u32, @@ -1393,6 +1704,10 @@ impl Renderer { ); } + if let Some(Some(toon_bg_index)) = toon_bg_index { + render_pass.set_bind_group(toon_bg_index as u32, &self.toon_bg, &[]) + } + if batch.idxs != 0 { for pipeline in &self.trans_pipelines[&pipeline] { render_pass.set_pipeline(pipeline); @@ -1406,16 +1721,13 @@ impl Renderer { } PreparedBatchKind::TranslucentNoDepthUpdate { - pipeline_changed, pipeline, texture, id, alpha_and_ref, + fog_enabled, + toon_bg_index, } => { - if pipeline_changed && pipeline.mode() >= 2 { - render_pass.set_bind_group(2, &self.toon_bg, &[]) - } - if let Some(id) = id { render_pass.set_stencil_reference((id | 0x40) as u32); render_pass.set_bind_group( @@ -1435,6 +1747,15 @@ impl Renderer { ); } + if let Some(Some((fog_enabled, fog_enabled_bg_index))) = fog_enabled { + render_pass.set_bind_group( + fog_enabled_bg_index as u32, + &self.fog_enabled_bg, + &[(fog_enabled as usize * self.fog_enabled_bg_elem_size) + as wgpu::DynamicOffset], + ) + } + if let Some(Some((texture, bg_index))) = texture { render_pass.set_bind_group( bg_index as u32, @@ -1443,6 +1764,10 @@ impl Renderer { ); } + if let Some(Some(toon_bg_index)) = toon_bg_index { + render_pass.set_bind_group(toon_bg_index as u32, &self.toon_bg, &[]) + } + if batch.idxs != 0 { for pipeline in &self.trans_no_depth_update_pipelines[&pipeline] { render_pass.set_pipeline(pipeline); @@ -1464,6 +1789,61 @@ impl Renderer { drop(render_pass); + self.color_output_index = 0; + + if fog_used { + if frame.rendering.fog_data != self.fog_data { + self.fog_data.clone_from(&frame.rendering.fog_data); + let mut fog_data = + unsafe { MaybeUninit::<[MaybeUninit; 0x90]>::zeroed().assume_init() }; + + // TODO: The addresses are wrong?? + fog_data[0].write(self.fog_data.densities[0] as u32); + for (dst, src) in fog_data[1..0x21].iter_mut().zip(&self.fog_data.densities) { + dst.write(*src as u32); + } + fog_data[0x21].write(self.fog_data.densities[0x1F] as u32); + + let fog_color_array = self.fog_data.color.cast::().to_array(); + for (dst, src) in fog_data[0x24..0x28].iter_mut().zip(fog_color_array) { + dst.write(src); + } + + fog_data[0x28].write(expand_depth(self.fog_data.offset)); + fog_data[0x29].write(self.fog_data.depth_shift as u32); + + self.queue.write_buffer(&self.fog_data_buffer, 0, unsafe { + slice::from_raw_parts(fog_data.as_ptr() as *const u8, 0x90 << 2) + }); + } + + let input_color = &self.output_attachments.color[self.color_output_index as usize]; + self.color_output_index ^= 1; + let output_color = &self.output_attachments.color[self.color_output_index as usize]; + + let mut render_pass = command_encoder.begin_render_pass(&wgpu::RenderPassDescriptor { + label: Some("3D renderer fog render pass"), + color_attachments: &[Some(wgpu::RenderPassColorAttachment { + view: &output_color.1, + 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, + }); + render_pass.set_bind_group(0, &self.fog_data_bg, &[]); + render_pass.set_bind_group(1, &input_color.2, &[]); + render_pass.set_bind_group(2, &self.output_attachments.depth_attrs_bg, &[]); + render_pass.set_pipeline( + &self.fog_pipelines[frame.rendering.control.fog_only_alpha() as usize], + ); + render_pass.draw(0..4, 0..1); + } + command_encoder.finish() } } diff --git a/render/wgpu-3d/src/render.rs b/render/wgpu-3d/src/render.rs index 36c4d15..52a347a 100644 --- a/render/wgpu-3d/src/render.rs +++ b/render/wgpu-3d/src/render.rs @@ -8,154 +8,21 @@ macro_rules! ifdef { }; } +mod common; +pub use common::*; +mod w_buffer; +pub use w_buffer::*; +mod attrs; +pub use attrs::*; +mod toon; +pub use toon::*; +mod texture; +pub use texture::*; +pub mod fog; +pub use fog::FogCode; + pub mod opaque; pub mod trans; -pub mod trans_no_depth_update; - -struct CommonCode { - common_vert_inputs: &'static str, - common_vert_outputs: &'static str, - common_set_vert_outputs: &'static str, - - common_frag_inputs: &'static str, - common_frag_outputs: &'static str, -} - -impl CommonCode { - const fn new() -> Self { - CommonCode { - common_vert_inputs: " - @location(0) position: vec2, - @location(1) depth: u32, - @location(2) w: u32, - @location(4) v_color: vec4,", - - common_vert_outputs: " - @builtin(position) position: vec4, - @location(0) v_color: vec4,", - - // TODO: Use `(vec2(position) - 7.99)`? - common_set_vert_outputs: " - let depth_f32 = f32(depth) * (1.0 / 0x1000000.0); - output.position = vec4( - vec2(position) * vec2(0.125 / 256.0, -0.125 / 192.0) + \ - vec2(-1.0, 1.0), - depth_f32, - 1.0, - ) * (f32(w) * (1.0 / 0x1000.)); - output.v_color = vec4(vec3(v_color.xyz) * vec3(1.0 / 511.0), 1.0);", - - common_frag_inputs: "@location(0) v_color: vec4,", - common_frag_outputs: "@location(0) color: vec4,", - } - } -} - -const COMMON_VERT_ATTRIBS: [wgpu::VertexAttribute; 4] = [ - wgpu::VertexAttribute { - format: wgpu::VertexFormat::Uint16x2, - offset: 0, - shader_location: 0, - }, - wgpu::VertexAttribute { - format: wgpu::VertexFormat::Uint32, - offset: 4, - shader_location: 1, - }, - wgpu::VertexAttribute { - format: wgpu::VertexFormat::Uint32, - offset: 8, - shader_location: 2, - }, - wgpu::VertexAttribute { - format: wgpu::VertexFormat::Uint16x4, - offset: 16, - shader_location: 4, - }, -]; - -#[derive(Default)] -struct WBufferCode { - w_buffer_vert_outputs: &'static str, - w_buffer_set_vert_outputs: &'static str, - - w_buffer_frag_inputs: &'static str, - w_buffer_frag_outputs: &'static str, - w_buffer_set_frag_outputs: &'static str, -} - -impl WBufferCode { - const fn new() -> Self { - WBufferCode { - w_buffer_vert_outputs: "@location(2) w: f32,", - w_buffer_set_vert_outputs: "output.w = f32(depth) * (1.0 / 0x1000000.0);", - w_buffer_frag_inputs: "@location(2) w: f32,", - w_buffer_frag_outputs: "@builtin(frag_depth) frag_depth: f32,", - w_buffer_set_frag_outputs: "output.frag_depth = w;", - } - } -} - -#[derive(Default)] -struct TextureCode { - texture_uniforms: String, - - texture_vert_inputs: &'static str, - texture_vert_outputs: &'static str, - texture_set_vert_outputs: &'static str, - - texture_frag_inputs: &'static str, - texture_get_color: &'static str, -} - -impl TextureCode { - fn new(bg_index: u32) -> Self { - TextureCode { - texture_uniforms: format!( - "@group({bg_index}) @binding(0) var t_texture: texture_2d; - @group({bg_index}) @binding(1) var s_texture: sampler;", - ), - - texture_vert_inputs: "@location(3) uv: vec2,", - texture_vert_outputs: "@location(1) uv: vec2,", - texture_set_vert_outputs: "output.uv = vec2(uv) * vec2(1.0 / 16.0);", - - texture_frag_inputs: "@location(1) uv: vec2,", - texture_get_color: "let t_color = textureSample(t_texture, s_texture, uv / \ - vec2(textureDimensions(t_texture))) * vec4(255.0 / \ - 31.0);", - } - } -} - -const TEXTURE_VERT_ATTRIBS: [wgpu::VertexAttribute; 1] = [wgpu::VertexAttribute { - format: wgpu::VertexFormat::Sint16x2, - offset: 12, - shader_location: 3, -}]; - -#[derive(Default)] -struct ToonCode { - toon_uniforms: String, - - toon_get_color: &'static str, -} - -impl ToonCode { - fn new(bg_index: u32) -> ToonCode { - ToonCode { - toon_uniforms: format!( - "struct ToonUniform {{ - colors: array, 0x20>, - }}; - - @group({bg_index}) @binding(0) var toon: ToonUniform;" - ), - toon_get_color: "let toon_color = vec4(toon.colors[u32(v_color.r * 31.0)]) * \ - (1.0 / 31.0);", - } - } -} fn get_output_color(mode: u8, texture_mapping_enabled: bool) -> &'static str { if texture_mapping_enabled { diff --git a/render/wgpu-3d/src/render/attrs.rs b/render/wgpu-3d/src/render/attrs.rs new file mode 100644 index 0000000..166a1e5 --- /dev/null +++ b/render/wgpu-3d/src/render/attrs.rs @@ -0,0 +1,14 @@ +#[derive(Default)] +pub struct AttrsCode { + pub attrs_frag_outputs: &'static str, + pub attrs_init_frag_outputs: &'static str, +} + +impl AttrsCode { + pub const fn new() -> Self { + AttrsCode { + attrs_frag_outputs: "@location(1) attrs: vec4,", + attrs_init_frag_outputs: "output.attrs = vec4(0);", + } + } +} diff --git a/render/wgpu-3d/src/render/common.rs b/render/wgpu-3d/src/render/common.rs new file mode 100644 index 0000000..5dc7325 --- /dev/null +++ b/render/wgpu-3d/src/render/common.rs @@ -0,0 +1,61 @@ +pub struct CommonCode { + pub common_vert_inputs: &'static str, + pub common_vert_outputs: &'static str, + pub common_set_vert_outputs: &'static str, + + pub common_frag_inputs: &'static str, + pub common_frag_outputs: &'static str, +} + +impl CommonCode { + pub const fn new() -> Self { + CommonCode { + common_vert_inputs: " + @location(0) position: vec2, + @location(1) depth: u32, + @location(2) w: u32, + @location(4) v_color: vec4,", + + common_vert_outputs: " + @builtin(position) position: vec4, + @location(0) v_color: vec4,", + + // TODO: Use `(vec2(position) - 7.99)`? + common_set_vert_outputs: " + let depth_f32 = f32(depth) * (1.0 / 0x1000000); + output.position = vec4( + vec2(position) * vec2(0.125 / 256.0, -0.125 / 192.0) + \ + vec2(-1.0, 1.0), + depth_f32, + 1.0, + ) * (f32(w) * (1.0 / 0x10000)); + output.v_color = vec4(vec3(v_color.rgb) * vec3(1.0 / 511.0), 1.0);", + + common_frag_inputs: "@location(0) v_color: vec4,", + common_frag_outputs: "@location(0) color: vec4,", + } + } +} + +pub const COMMON_VERT_ATTRIBS: [wgpu::VertexAttribute; 4] = [ + wgpu::VertexAttribute { + format: wgpu::VertexFormat::Uint16x2, + offset: 0, + shader_location: 0, + }, + wgpu::VertexAttribute { + format: wgpu::VertexFormat::Uint32, + offset: 4, + shader_location: 1, + }, + wgpu::VertexAttribute { + format: wgpu::VertexFormat::Uint32, + offset: 8, + shader_location: 2, + }, + wgpu::VertexAttribute { + format: wgpu::VertexFormat::Uint16x4, + offset: 16, + shader_location: 4, + }, +]; diff --git a/render/wgpu-3d/src/render/fog.rs b/render/wgpu-3d/src/render/fog.rs new file mode 100644 index 0000000..ec3f8c6 --- /dev/null +++ b/render/wgpu-3d/src/render/fog.rs @@ -0,0 +1,154 @@ +use crate::BgLayouts; + +#[derive(Default)] +pub struct FogCode { + pub fog_uniforms: String, + pub fog_set_frag_outputs: &'static str, +} + +impl FogCode { + pub fn new(enabled_bg_index: u32) -> Self { + FogCode { + fog_uniforms: format!( + "struct FogEnabledUniform {{ + enabled: u32, + }}; + + @group({enabled_bg_index}) @binding(0) var fog_enabled: FogEnabledUniform;", + ), + + fog_set_frag_outputs: "output.attrs.a = f32(fog_enabled.enabled);", + } + } +} + +fn shader_module_src(only_alpha: bool) -> String { + let blend = if only_alpha { + "color.a = mix(color.a, fog_color.a, density);" + } else { + "color = mix(color, fog_color, density);" + }; + + format!( + " +struct WrappedDensity {{ + @align(16) value: u32 +}} + +struct FogDataUniform {{ + densities: array, + color: vec4, + offset: u32, + depth_shift: u32, +}}; + +@group(0) @binding(0) var fog_data: FogDataUniform; +@group(1) @binding(0) var color_texture: texture_2d; +@group(2) @binding(0) var depth_texture: texture_depth_2d; +@group(2) @binding(1) var attrs_texture: texture_2d; + +struct VertOutput {{ + @builtin(position) pos: vec4, +}} + +@vertex +fn vs_main( + @builtin(vertex_index) vertex_index: u32, +) -> VertOutput {{ + var vert_positions: array, 4> = array, 4>( + vec2(-1.0, 1.0), + vec2(1.0, 1.0), + vec2(-1.0, -1.0), + vec2(1.0, -1.0), + ); + + var output: VertOutput; + output.pos = vec4((*(&vert_positions))[vertex_index], 0.0, 1.0); + return output; +}} + +@fragment +fn fs_main( + @builtin(position) position: vec4, +) -> @location(0) vec4 {{ + var coords = vec2(position.xy); + var color = textureLoad(color_texture, coords, 0); + var depth = textureLoad(depth_texture, coords, 0); + var attrs = textureLoad(attrs_texture, coords, 0); + var fog_color = vec4(fog_data.color) * vec4(1.0 / 31.0); + if attrs.a > 0.5 {{ + var z = u32(depth * 0x1000000); + var offset: u32; + if z < fog_data.offset {{ + offset = 0u; + }} else {{ + offset = min(((z - fog_data.offset) >> 2) << fog_data.depth_shift, 32u << 17); + }}; + var index = offset >> 17; + var fract = offset & 0x1FFFFu; + var density = f32((fog_data.densities[index].value * (0x20000u - fract) + + fog_data.densities[index + 1].value * fract) >> 17) * (1.0 / 0x80.0); + {blend} + }} + return color; +}}" + ) +} + +pub(crate) fn create_pipeline( + only_alpha: bool, + device: &wgpu::Device, + bg_layouts: &BgLayouts, +) -> wgpu::RenderPipeline { + let layout = device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor { + label: Some("3D renderer fog pipeline layout"), + bind_group_layouts: &[ + &bg_layouts.fog_data, + &bg_layouts.color, + &bg_layouts.depth_attrs, + ], + push_constant_ranges: &[], + }); + + let shader_module = device.create_shader_module(wgpu::ShaderModuleDescriptor { + label: Some("3D renderer fog shader module"), + source: wgpu::ShaderSource::Wgsl(shader_module_src(only_alpha).into()), + }); + + device.create_render_pipeline(&wgpu::RenderPipelineDescriptor { + label: Some("3D renderer fog pipeline"), + layout: Some(&layout), + + vertex: wgpu::VertexState { + module: &shader_module, + entry_point: "vs_main", + buffers: &[], + }, + + primitive: wgpu::PrimitiveState { + topology: wgpu::PrimitiveTopology::TriangleStrip, + strip_index_format: None, + front_face: wgpu::FrontFace::Ccw, + cull_mode: None, + unclipped_depth: false, + polygon_mode: wgpu::PolygonMode::Fill, + conservative: false, + }, + + depth_stencil: None, + + multisample: wgpu::MultisampleState::default(), + + fragment: Some(wgpu::FragmentState { + module: &shader_module, + entry_point: "fs_main", + targets: &[Some(wgpu::ColorTargetState { + format: wgpu::TextureFormat::Rgba8Unorm, + blend: None, + write_mask: wgpu::ColorWrites::ALL, + })], + }), + + multiview: None, + }) +} diff --git a/render/wgpu-3d/src/render/opaque.rs b/render/wgpu-3d/src/render/opaque.rs index 580af9e..2e435d3 100644 --- a/render/wgpu-3d/src/render/opaque.rs +++ b/render/wgpu-3d/src/render/opaque.rs @@ -1,11 +1,16 @@ use super::{ - get_output_color, CommonCode, TextureCode, ToonCode, WBufferCode, COMMON_VERT_ATTRIBS, - PRIMITIVE_STATE, TEXTURE_VERT_ATTRIBS, + get_output_color, AttrsCode, CommonCode, FogCode, TextureCode, ToonCode, WBufferCode, + COMMON_VERT_ATTRIBS, PRIMITIVE_STATE, TEXTURE_VERT_ATTRIBS, }; -use crate::{PipelineKey, Vertex}; +use crate::{BgLayouts, PipelineKey, Vertex}; use core::mem; -fn shader_module_src(pipeline: PipelineKey, texture_bg_index: u32) -> String { +fn shader_module_src( + pipeline: PipelineKey, + fog_enabled_bg_index: u32, + texture_bg_index: u32, + toon_bg_index: u32, +) -> String { let CommonCode { common_vert_inputs, common_vert_outputs, @@ -14,11 +19,6 @@ fn shader_module_src(pipeline: PipelineKey, texture_bg_index: u32) -> String { common_frag_outputs, } = CommonCode::new(); - let ToonCode { - toon_uniforms, - toon_get_color, - } = ifdef!(pipeline.mode() >= 2, ToonCode::new(0)); - let WBufferCode { w_buffer_vert_outputs, w_buffer_set_vert_outputs, @@ -39,12 +39,28 @@ fn shader_module_src(pipeline: PipelineKey, texture_bg_index: u32) -> String { TextureCode::new(texture_bg_index) ); + let ToonCode { + toon_uniforms, + toon_get_color, + } = ifdef!(pipeline.mode() >= 2, ToonCode::new(toon_bg_index)); + + let AttrsCode { + attrs_frag_outputs, + attrs_init_frag_outputs, + } = ifdef!(pipeline.attrs_enabled(), AttrsCode::new()); + + let FogCode { + fog_uniforms, + fog_set_frag_outputs, + } = ifdef!(pipeline.fog_enabled(), FogCode::new(fog_enabled_bg_index)); + let get_output_color = get_output_color(pipeline.mode(), pipeline.texture_mapping_enabled()); format!( " {texture_uniforms} {toon_uniforms} +{fog_uniforms} struct VertOutput {{ {common_vert_outputs} @@ -68,6 +84,7 @@ fn vs_main( struct FragOutput {{ {common_frag_outputs} {w_buffer_frag_outputs} + {attrs_frag_outputs} }} @fragment @@ -77,13 +94,15 @@ fn fs_main( {texture_frag_inputs} ) -> FragOutput {{ var output: FragOutput; - {w_buffer_set_frag_outputs} {texture_get_color} {toon_get_color} {get_output_color} if output.color.a < 0.5 {{ discard; }} + {w_buffer_set_frag_outputs} + {attrs_init_frag_outputs} + {fog_set_frag_outputs} return output; }}" ) @@ -92,29 +111,42 @@ fn fs_main( pub(crate) fn create_pipeline( pipeline: PipelineKey, device: &wgpu::Device, - toon_bg_layout: &wgpu::BindGroupLayout, - texture_bg_layout: &wgpu::BindGroupLayout, + bg_layouts: &BgLayouts, ) -> wgpu::RenderPipeline { - let mut pipeline_bg_layouts = Vec::new(); + let mut bg_layouts_ = Vec::new(); - if pipeline.mode() >= 2 { - pipeline_bg_layouts.push(toon_bg_layout); + let fog_enabled_bg_index = bg_layouts_.len() as u32; + if pipeline.fog_enabled() { + bg_layouts_.push(&bg_layouts.fog_enabled); } - let texture_bg_index = pipeline_bg_layouts.len() as u32; + let texture_bg_index = bg_layouts_.len() as u32; if pipeline.texture_mapping_enabled() { - pipeline_bg_layouts.push(texture_bg_layout); + bg_layouts_.push(&bg_layouts.texture); + } + + let toon_bg_index = bg_layouts_.len() as u32; + if pipeline.mode() >= 2 { + bg_layouts_.push(&bg_layouts.toon); } let layout = device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor { label: Some("3D renderer opaque pipeline layout"), - bind_group_layouts: &pipeline_bg_layouts, + bind_group_layouts: &bg_layouts_, push_constant_ranges: &[], }); let shader_module = device.create_shader_module(wgpu::ShaderModuleDescriptor { label: Some("3D renderer opaque shader module"), - source: wgpu::ShaderSource::Wgsl(shader_module_src(pipeline, texture_bg_index).into()), + source: wgpu::ShaderSource::Wgsl( + shader_module_src( + pipeline, + fog_enabled_bg_index, + texture_bg_index, + toon_bg_index, + ) + .into(), + ), }); let mut attribs = COMMON_VERT_ATTRIBS.to_vec(); @@ -162,11 +194,26 @@ pub(crate) fn create_pipeline( fragment: Some(wgpu::FragmentState { module: &shader_module, entry_point: "fs_main", - targets: &[Some(wgpu::ColorTargetState { - format: wgpu::TextureFormat::Rgba8Unorm, - blend: None, - write_mask: wgpu::ColorWrites::ALL, - })], + targets: if pipeline.attrs_enabled() { + &[ + Some(wgpu::ColorTargetState { + format: wgpu::TextureFormat::Rgba8Unorm, + blend: None, + write_mask: wgpu::ColorWrites::ALL, + }), + Some(wgpu::ColorTargetState { + format: wgpu::TextureFormat::Rgba8Unorm, + blend: None, + write_mask: wgpu::ColorWrites::ALL, + }), + ] + } else { + &[Some(wgpu::ColorTargetState { + format: wgpu::TextureFormat::Rgba8Unorm, + blend: None, + write_mask: wgpu::ColorWrites::ALL, + })] + }, }), multiview: None, diff --git a/render/wgpu-3d/src/render/texture.rs b/render/wgpu-3d/src/render/texture.rs new file mode 100644 index 0000000..e423504 --- /dev/null +++ b/render/wgpu-3d/src/render/texture.rs @@ -0,0 +1,39 @@ + + +#[derive(Default)] +pub struct TextureCode { + pub texture_uniforms: String, + + pub texture_vert_inputs: &'static str, + pub texture_vert_outputs: &'static str, + pub texture_set_vert_outputs: &'static str, + + pub texture_frag_inputs: &'static str, + pub texture_get_color: &'static str, +} + +impl TextureCode { + pub fn new(bg_index: u32) -> Self { + TextureCode { + texture_uniforms: format!( + "@group({bg_index}) @binding(0) var t_texture: texture_2d; + @group({bg_index}) @binding(1) var s_texture: sampler;", + ), + + texture_vert_inputs: "@location(3) uv: vec2,", + texture_vert_outputs: "@location(1) uv: vec2,", + texture_set_vert_outputs: "output.uv = vec2(uv) * vec2(1.0 / 16.0);", + + texture_frag_inputs: "@location(1) uv: vec2,", + texture_get_color: "let t_color = textureSample(t_texture, s_texture, uv / \ + vec2(textureDimensions(t_texture))) * vec4(255.0 / \ + 31.0);", + } + } +} + +pub const TEXTURE_VERT_ATTRIBS: [wgpu::VertexAttribute; 1] = [wgpu::VertexAttribute { + format: wgpu::VertexFormat::Sint16x2, + offset: 12, + shader_location: 3, +}]; diff --git a/render/wgpu-3d/src/render/toon.rs b/render/wgpu-3d/src/render/toon.rs new file mode 100644 index 0000000..758d21a --- /dev/null +++ b/render/wgpu-3d/src/render/toon.rs @@ -0,0 +1,23 @@ +#[derive(Default)] +pub struct ToonCode { + pub toon_uniforms: String, + + pub toon_get_color: &'static str, +} + +impl ToonCode { + pub fn new(bg_index: u32) -> ToonCode { + ToonCode { + toon_uniforms: format!( + "struct ToonUniform {{ + colors: array, 0x20>, + }}; + + @group({bg_index}) @binding(0) var toon: ToonUniform;" + ), + + toon_get_color: "let toon_color = vec4(toon.colors[u32(v_color.r * 31.0)]) * \ + (1.0 / 31.0);", + } + } +} diff --git a/render/wgpu-3d/src/render/trans.rs b/render/wgpu-3d/src/render/trans.rs index da15ac3..fb6d76d 100644 --- a/render/wgpu-3d/src/render/trans.rs +++ b/render/wgpu-3d/src/render/trans.rs @@ -1,11 +1,16 @@ use super::{ - get_output_color, CommonCode, TextureCode, ToonCode, WBufferCode, COMMON_VERT_ATTRIBS, - PRIMITIVE_STATE, TEXTURE_VERT_ATTRIBS, TRANS_BLENDING, + get_output_color, AttrsCode, CommonCode, FogCode, TextureCode, ToonCode, WBufferCode, + COMMON_VERT_ATTRIBS, PRIMITIVE_STATE, TEXTURE_VERT_ATTRIBS, TRANS_BLENDING, }; -use crate::{PipelineKey, Vertex}; +use crate::{BgLayouts, PipelineKey, Vertex}; use core::mem; -pub(super) fn shader_module_src(pipeline: PipelineKey, texture_bg_index: u32) -> [String; 2] { +pub(super) fn shader_module_src( + pipeline: PipelineKey, + fog_enabled_bg_index: u32, + texture_bg_index: u32, + toon_bg_index: u32, +) -> [String; 2] { let CommonCode { common_vert_inputs, common_vert_outputs, @@ -14,11 +19,6 @@ pub(super) fn shader_module_src(pipeline: PipelineKey, texture_bg_index: u32) -> common_frag_outputs, } = CommonCode::new(); - let ToonCode { - toon_uniforms, - toon_get_color, - } = ifdef!(pipeline.mode() >= 2, ToonCode::new(2)); - let WBufferCode { w_buffer_vert_outputs, w_buffer_set_vert_outputs, @@ -39,11 +39,27 @@ pub(super) fn shader_module_src(pipeline: PipelineKey, texture_bg_index: u32) -> TextureCode::new(texture_bg_index) ); + let ToonCode { + toon_uniforms, + toon_get_color, + } = ifdef!(pipeline.mode() >= 2, ToonCode::new(toon_bg_index)); + + let AttrsCode { + attrs_frag_outputs, + attrs_init_frag_outputs, + } = ifdef!(pipeline.attrs_enabled(), AttrsCode::new()); + + let FogCode { + fog_uniforms, + fog_set_frag_outputs, + } = ifdef!(pipeline.fog_enabled(), FogCode::new(fog_enabled_bg_index)); + let get_output_color = get_output_color(pipeline.mode(), pipeline.texture_mapping_enabled()); [ - "if output.color.a < 1.0 { discard; }", - "if (output.color.a < alpha_and_ref.alpha_ref) || (output.color.a >= 1.0) { discard; }", + "if output.color.a < 30.5 / 31.0 { discard; }", + "if (output.color.a < alpha_and_ref.alpha_ref) || (output.color.a >= 30.5 / 31.0) { \ + discard; }", ] .map(|alpha_test| { format!( @@ -57,6 +73,7 @@ struct AlphaAndRefUniform {{ {texture_uniforms} {toon_uniforms} +{fog_uniforms} struct VertOutput {{ {common_vert_outputs} @@ -80,6 +97,7 @@ fn vs_main( struct FragOutput {{ {common_frag_outputs} {w_buffer_frag_outputs} + {attrs_frag_outputs} }} @fragment @@ -89,11 +107,13 @@ fn fs_main( {texture_frag_inputs} ) -> FragOutput {{ var output: FragOutput; - {w_buffer_set_frag_outputs} {texture_get_color} {toon_get_color} {get_output_color} {alpha_test} + {w_buffer_set_frag_outputs} + {attrs_init_frag_outputs} + {fog_set_frag_outputs} return output; }}" ) @@ -102,31 +122,40 @@ fn fs_main( pub(crate) fn create_pipeline( pipeline: PipelineKey, + update_depth: bool, device: &wgpu::Device, - id_bg_layout: &wgpu::BindGroupLayout, - alpha_and_ref_bg_layout: &wgpu::BindGroupLayout, - toon_bg_layout: &wgpu::BindGroupLayout, - texture_bg_layout: &wgpu::BindGroupLayout, + bg_layouts: &BgLayouts, ) -> [wgpu::RenderPipeline; 2] { - let mut bg_layouts = vec![id_bg_layout, alpha_and_ref_bg_layout]; + let mut bg_layouts_ = vec![&bg_layouts.id, &bg_layouts.alpha_and_ref]; - if pipeline.mode() >= 2 { - bg_layouts.push(toon_bg_layout); + let fog_enabled_bg_index = bg_layouts_.len() as u32; + if pipeline.fog_enabled() { + bg_layouts_.push(&bg_layouts.fog_enabled); } - let texture_bg_index = bg_layouts.len() as u32; + let texture_bg_index = bg_layouts_.len() as u32; if pipeline.texture_mapping_enabled() { - bg_layouts.push(texture_bg_layout); + bg_layouts_.push(&bg_layouts.texture); + } + + let toon_bg_index = bg_layouts_.len() as u32; + if pipeline.mode() >= 2 { + bg_layouts_.push(&bg_layouts.toon); } let layout = device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor { label: Some("3D renderer translucent pipeline layout"), - bind_group_layouts: &bg_layouts, + bind_group_layouts: &bg_layouts_, push_constant_ranges: &[], }); let (opaque_shader_module, trans_shader_module) = { - let [opaque_src, trans_src] = shader_module_src(pipeline, texture_bg_index); + let [opaque_src, trans_src] = shader_module_src( + pipeline, + fog_enabled_bg_index, + texture_bg_index, + toon_bg_index, + ); ( device.create_shader_module(wgpu::ShaderModuleDescriptor { label: Some("3D renderer translucent opaque pass shader module"), @@ -185,16 +214,51 @@ pub(crate) fn create_pipeline( fragment: Some(wgpu::FragmentState { module: &opaque_shader_module, entry_point: "fs_main", - targets: &[Some(wgpu::ColorTargetState { - format: wgpu::TextureFormat::Rgba8Unorm, - blend: None, - write_mask: wgpu::ColorWrites::ALL, - })], + targets: if pipeline.attrs_enabled() { + &[ + Some(wgpu::ColorTargetState { + format: wgpu::TextureFormat::Rgba8Unorm, + blend: None, + write_mask: wgpu::ColorWrites::ALL, + }), + Some(wgpu::ColorTargetState { + format: wgpu::TextureFormat::Rgba8Unorm, + blend: None, + write_mask: wgpu::ColorWrites::ALL, + }), + ] + } else { + &[Some(wgpu::ColorTargetState { + format: wgpu::TextureFormat::Rgba8Unorm, + blend: None, + write_mask: wgpu::ColorWrites::ALL, + })] + }, }), multiview: None, }; + let mut trans_fragment_targets = vec![Some(wgpu::ColorTargetState { + format: wgpu::TextureFormat::Rgba8Unorm, + blend: pipeline.alpha_blending_enabled().then_some(TRANS_BLENDING), + write_mask: wgpu::ColorWrites::ALL, + })]; + if pipeline.attrs_enabled() { + trans_fragment_targets.push(Some(wgpu::ColorTargetState { + format: wgpu::TextureFormat::Rgba8Unorm, + blend: pipeline.fog_enabled().then_some(wgpu::BlendState { + color: wgpu::BlendComponent::REPLACE, + alpha: wgpu::BlendComponent { + src_factor: wgpu::BlendFactor::One, + dst_factor: wgpu::BlendFactor::One, + operation: wgpu::BlendOperation::Min, + }, + }), + write_mask: wgpu::ColorWrites::ALL, + })); + } + [ device.create_render_pipeline(&opaque_desc), device.create_render_pipeline(&wgpu::RenderPipelineDescriptor { @@ -212,7 +276,7 @@ pub(crate) fn create_pipeline( depth_stencil: Some(wgpu::DepthStencilState { format: wgpu::TextureFormat::Depth24PlusStencil8, - depth_write_enabled: true, + depth_write_enabled: update_depth, depth_compare: if pipeline.depth_test_equal() { wgpu::CompareFunction::Equal } else { @@ -230,11 +294,7 @@ pub(crate) fn create_pipeline( fragment: Some(wgpu::FragmentState { module: &trans_shader_module, entry_point: "fs_main", - targets: &[Some(wgpu::ColorTargetState { - format: wgpu::TextureFormat::Rgba8Unorm, - blend: pipeline.alpha_blending_enabled().then_some(TRANS_BLENDING), - write_mask: wgpu::ColorWrites::ALL, - })], + targets: &trans_fragment_targets, }), ..opaque_desc diff --git a/render/wgpu-3d/src/render/trans_no_depth_update.rs b/render/wgpu-3d/src/render/trans_no_depth_update.rs deleted file mode 100644 index 4952785..0000000 --- a/render/wgpu-3d/src/render/trans_no_depth_update.rs +++ /dev/null @@ -1,150 +0,0 @@ -use super::{ - trans::shader_module_src, COMMON_VERT_ATTRIBS, PRIMITIVE_STATE, TEXTURE_VERT_ATTRIBS, - TRANS_BLENDING, -}; -use crate::{PipelineKey, Vertex}; -use core::mem; - -pub(crate) fn create_pipeline( - pipeline: PipelineKey, - device: &wgpu::Device, - id_bg_layout: &wgpu::BindGroupLayout, - alpha_and_ref_bg_layout: &wgpu::BindGroupLayout, - toon_bg_layout: &wgpu::BindGroupLayout, - texture_bg_layout: &wgpu::BindGroupLayout, -) -> [wgpu::RenderPipeline; 2] { - let mut bg_layouts = vec![id_bg_layout, alpha_and_ref_bg_layout]; - - if pipeline.mode() >= 2 { - bg_layouts.push(toon_bg_layout); - } - - let texture_bg_index = bg_layouts.len() as u32; - if pipeline.texture_mapping_enabled() { - bg_layouts.push(texture_bg_layout); - } - - let layout = device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor { - label: Some("3D renderer translucent no depth update pipeline layout"), - bind_group_layouts: &bg_layouts, - push_constant_ranges: &[], - }); - - let (opaque_shader_module, trans_shader_module) = { - let [opaque_src, trans_src] = shader_module_src(pipeline, texture_bg_index); - ( - device.create_shader_module(wgpu::ShaderModuleDescriptor { - label: Some("3D renderer translucent no depth update opaque pass shader module"), - source: wgpu::ShaderSource::Wgsl(opaque_src.into()), - }), - device.create_shader_module(wgpu::ShaderModuleDescriptor { - label: Some( - "3D renderer translucent no depth update translucent pass shader module", - ), - source: wgpu::ShaderSource::Wgsl(trans_src.into()), - }), - ) - }; - - let mut attribs = COMMON_VERT_ATTRIBS.to_vec(); - - if pipeline.texture_mapping_enabled() { - attribs.extend_from_slice(&TEXTURE_VERT_ATTRIBS); - } - - let stencil_face_state = wgpu::StencilFaceState { - compare: wgpu::CompareFunction::NotEqual, - fail_op: wgpu::StencilOperation::Keep, - depth_fail_op: wgpu::StencilOperation::Keep, - pass_op: wgpu::StencilOperation::Replace, - }; - - let opaque_desc = wgpu::RenderPipelineDescriptor { - label: Some("3D renderer translucent no depth update pipeline opaque pass"), - layout: Some(&layout), - - vertex: wgpu::VertexState { - module: &opaque_shader_module, - entry_point: "vs_main", - buffers: &[wgpu::VertexBufferLayout { - array_stride: mem::size_of::() as u64, - step_mode: wgpu::VertexStepMode::Vertex, - attributes: &attribs, - }], - }, - - primitive: PRIMITIVE_STATE, - - depth_stencil: Some(wgpu::DepthStencilState { - format: wgpu::TextureFormat::Depth24PlusStencil8, - depth_write_enabled: true, - depth_compare: if pipeline.depth_test_equal() { - wgpu::CompareFunction::Equal - } else { - wgpu::CompareFunction::Less - }, - stencil: wgpu::StencilState::default(), - bias: wgpu::DepthBiasState::default(), - }), - - multisample: wgpu::MultisampleState::default(), - - fragment: Some(wgpu::FragmentState { - module: &opaque_shader_module, - entry_point: "fs_main", - targets: &[Some(wgpu::ColorTargetState { - format: wgpu::TextureFormat::Rgba8Unorm, - blend: None, - write_mask: wgpu::ColorWrites::ALL, - })], - }), - - multiview: None, - }; - - [ - device.create_render_pipeline(&opaque_desc), - device.create_render_pipeline(&wgpu::RenderPipelineDescriptor { - label: Some("3D renderer translucent no depth update pipeline translucent pass"), - - vertex: wgpu::VertexState { - module: &trans_shader_module, - entry_point: "vs_main", - buffers: &[wgpu::VertexBufferLayout { - array_stride: mem::size_of::() as u64, - step_mode: wgpu::VertexStepMode::Vertex, - attributes: &attribs, - }], - }, - - depth_stencil: Some(wgpu::DepthStencilState { - format: wgpu::TextureFormat::Depth24PlusStencil8, - depth_write_enabled: false, - depth_compare: if pipeline.depth_test_equal() { - wgpu::CompareFunction::Equal - } else { - wgpu::CompareFunction::Less - }, - stencil: wgpu::StencilState { - front: stencil_face_state, - back: stencil_face_state, - read_mask: 0x7F, - write_mask: 0x7F, - }, - bias: wgpu::DepthBiasState::default(), - }), - - fragment: Some(wgpu::FragmentState { - module: &trans_shader_module, - entry_point: "fs_main", - targets: &[Some(wgpu::ColorTargetState { - format: wgpu::TextureFormat::Rgba8Unorm, - blend: pipeline.alpha_blending_enabled().then_some(TRANS_BLENDING), - write_mask: wgpu::ColorWrites::ALL, - })], - }), - - ..opaque_desc - }), - ] -} diff --git a/render/wgpu-3d/src/render/w_buffer.rs b/render/wgpu-3d/src/render/w_buffer.rs new file mode 100644 index 0000000..f95d841 --- /dev/null +++ b/render/wgpu-3d/src/render/w_buffer.rs @@ -0,0 +1,21 @@ +#[derive(Default)] +pub struct WBufferCode { + pub w_buffer_vert_outputs: &'static str, + pub w_buffer_set_vert_outputs: &'static str, + + pub w_buffer_frag_inputs: &'static str, + pub w_buffer_frag_outputs: &'static str, + pub w_buffer_set_frag_outputs: &'static str, +} + +impl WBufferCode { + pub const fn new() -> Self { + WBufferCode { + w_buffer_vert_outputs: "@location(2) w: f32,", + w_buffer_set_vert_outputs: "output.w = f32(depth) * (1.0 / 0x1000000);", + w_buffer_frag_inputs: "@location(2) w: f32,", + w_buffer_frag_outputs: "@builtin(frag_depth) frag_depth: f32,", + w_buffer_set_frag_outputs: "output.frag_depth = w;", + } + } +} diff --git a/render/wgpu-3d/src/threaded.rs b/render/wgpu-3d/src/threaded.rs index fccb5c3..ad7cedd 100644 --- a/render/wgpu-3d/src/threaded.rs +++ b/render/wgpu-3d/src/threaded.rs @@ -259,6 +259,7 @@ pub fn init( .name("3D rendering".to_string()) .spawn(move || { let mut raw_soft_renderer = soft::Renderer::new(); + let mut color_output_index = renderer.color_output_index(); loop { if shared_data.stopped.load(Ordering::Relaxed) { break; @@ -289,8 +290,19 @@ pub fn init( if frame.render { let resolution_scale_shift = shared_data.resolution_scale_shift.load(Ordering::Relaxed); + let mut color_output_updated = false; + + if color_output_index != renderer.color_output_index() { + color_output_updated = true; + color_output_index = renderer.color_output_index(); + } + if resolution_scale_shift != renderer.resolution_scale_shift() { + color_output_updated = true; renderer.set_resolution_scale_shift(resolution_scale_shift); + } + + if color_output_updated { color_output_view_tx .send(renderer.create_output_view()) .expect(