From: Josh Simmons Date: Wed, 15 May 2024 06:37:49 +0000 (+0200) Subject: shark: Use indexable structs for gpu resources X-Git-Url: https://git.nega.tv//gitweb.cgi?a=commitdiff_plain;h=2abaebf7f27dd3a1e70f7ff9fcbc9be87a7cf233;p=josh%2Fnarcissus shark: Use indexable structs for gpu resources --- diff --git a/title/shark/src/main.rs b/title/shark/src/main.rs index 01b4aff..dcabd7c 100644 --- a/title/shark/src/main.rs +++ b/title/shark/src/main.rs @@ -1,4 +1,5 @@ use std::fmt::Write; +use std::ops::Index; use std::path::Path; use std::time::{Duration, Instant}; @@ -15,8 +16,9 @@ use narcissus_gpu::{ ColorSpace, Device, DeviceExt, Extent2d, Extent3d, Frame, Image, ImageAspectFlags, ImageBarrier, ImageDesc, ImageDimension, ImageFormat, ImageLayout, ImageSubresourceRange, ImageTiling, ImageUsageFlags, IndexType, LoadOp, MemoryLocation, Offset2d, PersistentBuffer, - PresentMode, RenderingAttachment, RenderingDesc, Scissor, StoreOp, SwapchainConfigurator, - SwapchainImage, ThreadToken, TypedBind, Viewport, + PresentMode, RenderingAttachment, RenderingDesc, Sampler, SamplerAddressMode, SamplerDesc, + SamplerFilter, Scissor, StoreOp, SwapchainConfigurator, SwapchainImage, ThreadToken, TypedBind, + Viewport, }; use narcissus_image as image; use narcissus_maths::{ @@ -527,288 +529,346 @@ impl<'a> UiState<'a> { } } -struct Model<'gpu> { +enum SamplerRes { + Bilinear, +} + +pub struct Samplers { + bilinear: Sampler, +} + +impl Index for Samplers { + type Output = Sampler; + + fn index(&self, index: SamplerRes) -> &Self::Output { + match index { + SamplerRes::Bilinear => &self.bilinear, + } + } +} + +impl Samplers { + fn load(gpu: &Gpu) -> Samplers { + let bilinear = gpu.create_sampler(&SamplerDesc { + filter: SamplerFilter::Bilinear, + address_mode: SamplerAddressMode::Clamp, + compare_op: None, + mip_lod_bias: 0.0, + min_lod: 0.0, + max_lod: 0.0, + }); + Samplers { bilinear } + } +} + +struct Model<'a> { indices: u32, - vertex_buffer: PersistentBuffer<'gpu>, - index_buffer: PersistentBuffer<'gpu>, + vertex_buffer: PersistentBuffer<'a>, + index_buffer: PersistentBuffer<'a>, } enum ModelRes { Shark, } -impl ModelRes { - const MAX_MODELS: usize = 1; +struct Models<'a> { + shark: Model<'a>, } -struct Models<'gpu>([Model<'gpu>; ModelRes::MAX_MODELS]); +impl<'a> Index for Models<'a> { + type Output = Model<'a>; + + fn index(&self, index: ModelRes) -> &Self::Output { + match index { + ModelRes::Shark => &self.shark, + } + } +} + +impl<'a> Models<'a> { + pub fn load(gpu: &'a Gpu) -> Models<'a> { + fn load_model

(gpu: &Gpu, path: P) -> Model + where + P: AsRef, + { + let (vertices, indices) = load_obj(path); + let vertex_buffer = gpu.create_persistent_buffer_with_data( + MemoryLocation::Device, + BufferUsageFlags::STORAGE, + vertices.as_slice(), + ); + let index_buffer = gpu.create_persistent_buffer_with_data( + MemoryLocation::Device, + BufferUsageFlags::INDEX, + indices.as_slice(), + ); + + Model { + indices: indices.len() as u32, + vertex_buffer, + index_buffer, + } + } + + Models { + shark: load_model(gpu, "title/shark/data/blåhaj.obj"), + } + } +} enum ImageRes { TonyMcMapfaceLut, Shark, } -impl ImageRes { - const MAX_IMAGES: usize = 2; +struct Images { + tony_mc_mapface_lut: Image, + shark: Image, } -struct Images([Image; ImageRes::MAX_IMAGES]); +impl Index for Images { + type Output = Image; -type Gpu = dyn Device + 'static; + fn index(&self, index: ImageRes) -> &Self::Output { + match index { + ImageRes::TonyMcMapfaceLut => &self.tony_mc_mapface_lut, + ImageRes::Shark => &self.shark, + } + } +} -struct DrawState<'gpu> { - gpu: &'gpu Gpu, +impl Images { + fn load(gpu: &Gpu, thread_token: &ThreadToken) -> Images { + fn load_image

( + gpu: &Gpu, + frame: &Frame, + thread_token: &ThreadToken, + cmd_encoder: &mut CmdEncoder, + path: P, + ) -> Image + where + P: AsRef, + { + let image_data = + image::Image::from_buffer(std::fs::read(path.as_ref()).unwrap().as_slice()) + .unwrap(); + + let width = image_data.width() as u32; + let height = image_data.height() as u32; + + let image = gpu.create_image(&ImageDesc { + memory_location: MemoryLocation::Device, + host_mapped: false, + usage: ImageUsageFlags::SAMPLED | ImageUsageFlags::TRANSFER, + dimension: ImageDimension::Type2d, + format: ImageFormat::RGBA8_SRGB, + tiling: ImageTiling::Optimal, + width, + height, + depth: 1, + layer_count: 1, + mip_levels: 1, + }); - basic_pipeline: BasicPipeline, - ui_pipeline: UiPipeline, - display_transform_pipeline: DisplayTransformPipeline, + gpu.cmd_barrier( + cmd_encoder, + None, + &[ImageBarrier::layout_optimal( + &[Access::None], + &[Access::TransferWrite], + image, + ImageAspectFlags::COLOR, + )], + ); - width: u32, - height: u32, + let buffer = gpu.request_transient_buffer_with_data( + frame, + thread_token, + BufferUsageFlags::TRANSFER, + image_data.as_slice(), + ); - depth_image: Image, - render_target_image: Image, + gpu.cmd_copy_buffer_to_image( + cmd_encoder, + buffer.to_arg(), + image, + ImageLayout::Optimal, + &[BufferImageCopy { + image_extent: Extent3d { + width, + height, + depth: 1, + }, + ..default() + }], + ); - glyph_atlas_image: Image, + gpu.cmd_barrier( + cmd_encoder, + None, + &[ImageBarrier::layout_optimal( + &[Access::TransferWrite], + &[Access::FragmentShaderSampledImageRead], + image, + ImageAspectFlags::COLOR, + )], + ); - models: Models<'gpu>, - images: Images, + image + } - transforms: Vec, -} + fn load_dds

( + gpu: &Gpu, + frame: &Frame, + thread_token: &ThreadToken, + cmd_encoder: &mut CmdEncoder, + path: P, + ) -> Image + where + P: AsRef, + { + let image_data = std::fs::read(path.as_ref()).unwrap(); + let dds = dds::Dds::from_buffer(&image_data).unwrap(); + let header_dxt10 = dds.header_dxt10.unwrap(); + + let width = dds.header.width; + let height = dds.header.height; + let depth = dds.header.depth; + + let dimension = match header_dxt10.resource_dimension { + dds::D3D10ResourceDimension::Texture1d => ImageDimension::Type1d, + dds::D3D10ResourceDimension::Texture2d => ImageDimension::Type2d, + dds::D3D10ResourceDimension::Texture3d => ImageDimension::Type3d, + _ => panic!(), + }; -fn load_models(gpu: &Gpu) -> Models { - fn load_model

(gpu: &Gpu, path: P) -> Model - where - P: AsRef, - { - let (vertices, indices) = load_obj(path); - let vertex_buffer = gpu.create_persistent_buffer_with_data( - MemoryLocation::Device, - BufferUsageFlags::STORAGE, - vertices.as_slice(), - ); - let index_buffer = gpu.create_persistent_buffer_with_data( - MemoryLocation::Device, - BufferUsageFlags::INDEX, - indices.as_slice(), - ); + let format = match header_dxt10.dxgi_format { + dds::DxgiFormat::R9G9B9E5_SHAREDEXP => ImageFormat::E5B9G9R9_UFLOAT, + _ => panic!(), + }; - Model { - indices: indices.len() as u32, - vertex_buffer, - index_buffer, - } - } + let image = gpu.create_image(&ImageDesc { + memory_location: MemoryLocation::Device, + host_mapped: false, + usage: ImageUsageFlags::SAMPLED | ImageUsageFlags::TRANSFER, + dimension, + format, + tiling: ImageTiling::Optimal, + width, + height, + depth, + layer_count: 1, + mip_levels: 1, + }); - Models([load_model(gpu, "title/shark/data/blåhaj.obj")]) -} + gpu.cmd_barrier( + cmd_encoder, + None, + &[ImageBarrier { + prev_access: &[Access::None], + next_access: &[Access::TransferWrite], + prev_layout: ImageLayout::Optimal, + next_layout: ImageLayout::Optimal, + subresource_range: ImageSubresourceRange::default(), + image, + }], + ); -fn load_images(gpu: &Gpu, thread_token: &ThreadToken) -> Images { - fn load_image

( - gpu: &Gpu, - frame: &Frame, - thread_token: &ThreadToken, - cmd_encoder: &mut CmdEncoder, - path: P, - ) -> Image - where - P: AsRef, - { - let image_data = - image::Image::from_buffer(std::fs::read(path.as_ref()).unwrap().as_slice()).unwrap(); - - let width = image_data.width() as u32; - let height = image_data.height() as u32; - - let image = gpu.create_image(&ImageDesc { - memory_location: MemoryLocation::Device, - host_mapped: false, - usage: ImageUsageFlags::SAMPLED | ImageUsageFlags::TRANSFER, - dimension: ImageDimension::Type2d, - format: ImageFormat::RGBA8_SRGB, - tiling: ImageTiling::Optimal, - width, - height, - depth: 1, - layer_count: 1, - mip_levels: 1, - }); + let buffer = gpu.request_transient_buffer_with_data( + frame, + thread_token, + BufferUsageFlags::TRANSFER, + dds.data, + ); - gpu.cmd_barrier( - cmd_encoder, - None, - &[ImageBarrier::layout_optimal( - &[Access::None], - &[Access::TransferWrite], + gpu.cmd_copy_buffer_to_image( + cmd_encoder, + buffer.to_arg(), image, - ImageAspectFlags::COLOR, - )], - ); + ImageLayout::Optimal, + &[BufferImageCopy { + image_extent: Extent3d { + width, + height, + depth, + }, + ..default() + }], + ); - let buffer = gpu.request_transient_buffer_with_data( - frame, - thread_token, - BufferUsageFlags::TRANSFER, - image_data.as_slice(), - ); + gpu.cmd_barrier( + cmd_encoder, + None, + &[ImageBarrier { + prev_access: &[Access::TransferWrite], + next_access: &[Access::ShaderSampledImageRead], + prev_layout: ImageLayout::Optimal, + next_layout: ImageLayout::Optimal, + subresource_range: ImageSubresourceRange::default(), + image, + }], + ); - gpu.cmd_copy_buffer_to_image( - cmd_encoder, - buffer.to_arg(), - image, - ImageLayout::Optimal, - &[BufferImageCopy { - image_extent: Extent3d { - width, - height, - depth: 1, - }, - ..default() - }], - ); + image + } - gpu.cmd_barrier( - cmd_encoder, - None, - &[ImageBarrier::layout_optimal( - &[Access::TransferWrite], - &[Access::FragmentShaderSampledImageRead], - image, - ImageAspectFlags::COLOR, - )], - ); + let images; + let frame = gpu.begin_frame(); + { + let frame = &frame; - image - } + let mut cmd_encoder = gpu.request_cmd_encoder(frame, thread_token); + { + let cmd_encoder = &mut cmd_encoder; - fn load_dds

( - gpu: &Gpu, - frame: &Frame, - thread_token: &ThreadToken, - cmd_encoder: &mut CmdEncoder, - path: P, - ) -> Image - where - P: AsRef, - { - let image_data = std::fs::read(path.as_ref()).unwrap(); - let dds = dds::Dds::from_buffer(&image_data).unwrap(); - let header_dxt10 = dds.header_dxt10.unwrap(); - - let width = dds.header.width; - let height = dds.header.height; - let depth = dds.header.depth; - - let dimension = match header_dxt10.resource_dimension { - dds::D3D10ResourceDimension::Texture1d => ImageDimension::Type1d, - dds::D3D10ResourceDimension::Texture2d => ImageDimension::Type2d, - dds::D3D10ResourceDimension::Texture3d => ImageDimension::Type3d, - _ => panic!(), - }; - - let format = match header_dxt10.dxgi_format { - dds::DxgiFormat::R9G9B9E5_SHAREDEXP => ImageFormat::E5B9G9R9_UFLOAT, - _ => panic!(), - }; - - let image = gpu.create_image(&ImageDesc { - memory_location: MemoryLocation::Device, - host_mapped: false, - usage: ImageUsageFlags::SAMPLED | ImageUsageFlags::TRANSFER, - dimension, - format, - tiling: ImageTiling::Optimal, - width, - height, - depth, - layer_count: 1, - mip_levels: 1, - }); + images = Images { + tony_mc_mapface_lut: load_dds( + gpu, + frame, + thread_token, + cmd_encoder, + "title/shark/data/tony_mc_mapface.dds", + ), + shark: load_image( + gpu, + frame, + thread_token, + cmd_encoder, + "title/shark/data/blåhaj.png", + ), + }; + } - gpu.cmd_barrier( - cmd_encoder, - None, - &[ImageBarrier { - prev_access: &[Access::None], - next_access: &[Access::TransferWrite], - prev_layout: ImageLayout::Optimal, - next_layout: ImageLayout::Optimal, - subresource_range: ImageSubresourceRange::default(), - image, - }], - ); + gpu.submit(frame, cmd_encoder); + } + gpu.end_frame(frame); - let buffer = gpu.request_transient_buffer_with_data( - frame, - thread_token, - BufferUsageFlags::TRANSFER, - dds.data, - ); + images + } +} - gpu.cmd_copy_buffer_to_image( - cmd_encoder, - buffer.to_arg(), - image, - ImageLayout::Optimal, - &[BufferImageCopy { - image_extent: Extent3d { - width, - height, - depth, - }, - ..default() - }], - ); +type Gpu = dyn Device + 'static; - gpu.cmd_barrier( - cmd_encoder, - None, - &[ImageBarrier { - prev_access: &[Access::TransferWrite], - next_access: &[Access::ShaderSampledImageRead], - prev_layout: ImageLayout::Optimal, - next_layout: ImageLayout::Optimal, - subresource_range: ImageSubresourceRange::default(), - image, - }], - ); +struct DrawState<'gpu> { + gpu: &'gpu Gpu, - image - } + basic_pipeline: BasicPipeline, + ui_pipeline: UiPipeline, + display_transform_pipeline: DisplayTransformPipeline, - let images; - let frame = gpu.begin_frame(); - { - let frame = &frame; + width: u32, + height: u32, - let mut cmd_encoder = gpu.request_cmd_encoder(frame, thread_token); - { - let cmd_encoder = &mut cmd_encoder; + depth_image: Image, + render_target_image: Image, - images = Images([ - load_dds( - gpu, - frame, - thread_token, - cmd_encoder, - "title/shark/data/tony_mc_mapface.dds", - ), - load_image( - gpu, - frame, - thread_token, - cmd_encoder, - "title/shark/data/blåhaj.png", - ), - ]); - } + glyph_atlas_image: Image, - gpu.submit(frame, cmd_encoder); - } - gpu.end_frame(frame); + samplers: Samplers, + models: Models<'gpu>, + images: Images, - images + transforms: Vec, } impl<'gpu> DrawState<'gpu> { @@ -817,8 +877,9 @@ impl<'gpu> DrawState<'gpu> { let ui_pipeline = UiPipeline::new(gpu); let primitive_pipeline = DisplayTransformPipeline::new(gpu); - let models = load_models(gpu); - let images = load_images(gpu, thread_token); + let samplers = Samplers::load(gpu); + let models = Models::load(gpu); + let images = Images::load(gpu, thread_token); Self { gpu, @@ -830,6 +891,7 @@ impl<'gpu> DrawState<'gpu> { depth_image: default(), render_target_image: default(), glyph_atlas_image: default(), + samplers, models, images, transforms: vec![], @@ -1110,8 +1172,8 @@ impl<'gpu> DrawState<'gpu> { ); { - let model = &self.models.0[ModelRes::Shark as usize]; - let image = self.images.0[ImageRes::Shark as usize]; + let model = &self.models[ModelRes::Shark]; + let image = self.images[ImageRes::Shark]; let transform_buffer = gpu.request_transient_buffer_with_data( frame, @@ -1139,7 +1201,7 @@ impl<'gpu> DrawState<'gpu> { Bind { binding: 2, array_element: 0, - typed: TypedBind::Sampler(&[self.basic_pipeline.sampler]), + typed: TypedBind::Sampler(&[self.samplers[SamplerRes::Bilinear]]), }, Bind { binding: 3, @@ -1238,7 +1300,7 @@ impl<'gpu> DrawState<'gpu> { Bind { binding: 4, array_element: 0, - typed: TypedBind::Sampler(&[self.ui_pipeline.sampler]), + typed: TypedBind::Sampler(&[self.samplers[SamplerRes::Bilinear]]), }, Bind { binding: 5, @@ -1292,14 +1354,14 @@ impl<'gpu> DrawState<'gpu> { Bind { binding: 0, array_element: 0, - typed: TypedBind::Sampler(&[self.display_transform_pipeline.sampler]), + typed: TypedBind::Sampler(&[self.samplers[SamplerRes::Bilinear]]), }, Bind { binding: 1, array_element: 0, typed: TypedBind::SampledImage(&[( ImageLayout::Optimal, - self.images.0[ImageRes::TonyMcMapfaceLut as usize], + self.images[ImageRes::TonyMcMapfaceLut], )]), }, Bind { diff --git a/title/shark/src/pipelines/basic.rs b/title/shark/src/pipelines/basic.rs index 08df2a3..5cc4d3c 100644 --- a/title/shark/src/pipelines/basic.rs +++ b/title/shark/src/pipelines/basic.rs @@ -2,8 +2,7 @@ use narcissus_core::default; use narcissus_gpu::{ BindGroupLayout, BindGroupLayoutDesc, BindGroupLayoutEntryDesc, BindingType, BlendMode, CompareOp, CullingMode, FrontFace, GraphicsPipelineDesc, GraphicsPipelineLayout, ImageFormat, - Pipeline, PolygonMode, Sampler, SamplerAddressMode, SamplerDesc, SamplerFilter, ShaderDesc, - ShaderStageFlags, Topology, + Pipeline, PolygonMode, ShaderDesc, ShaderStageFlags, Topology, }; use narcissus_maths::Mat4; @@ -26,7 +25,6 @@ pub struct Vertex { pub struct BasicPipeline { pub uniforms_bind_group_layout: BindGroupLayout, pub storage_bind_group_layout: BindGroupLayout, - pub sampler: Sampler, pub pipeline: Pipeline, } @@ -70,15 +68,6 @@ impl BasicPipeline { ], }); - let sampler = gpu.create_sampler(&SamplerDesc { - filter: SamplerFilter::Point, - address_mode: SamplerAddressMode::Clamp, - compare_op: None, - mip_lod_bias: 0.0, - min_lod: 0.0, - max_lod: 1000.0, - }); - let pipeline = gpu.create_graphics_pipeline(&GraphicsPipelineDesc { vertex_shader: ShaderDesc { entry: c"main", @@ -112,7 +101,6 @@ impl BasicPipeline { Self { uniforms_bind_group_layout, storage_bind_group_layout, - sampler, pipeline, } } diff --git a/title/shark/src/pipelines/display_transform.rs b/title/shark/src/pipelines/display_transform.rs index 8891fb6..f0c1e00 100644 --- a/title/shark/src/pipelines/display_transform.rs +++ b/title/shark/src/pipelines/display_transform.rs @@ -1,7 +1,6 @@ use narcissus_gpu::{ BindGroupLayout, BindGroupLayoutDesc, BindGroupLayoutEntryDesc, BindingType, - ComputePipelineDesc, Pipeline, Sampler, SamplerAddressMode, SamplerDesc, SamplerFilter, - ShaderDesc, ShaderStageFlags, + ComputePipelineDesc, Pipeline, ShaderDesc, ShaderStageFlags, }; use crate::Gpu; @@ -16,7 +15,6 @@ pub struct DisplayTransformUniforms { pub struct DisplayTransformPipeline { pub bind_group_layout: BindGroupLayout, pub pipeline: Pipeline, - pub sampler: Sampler, } impl DisplayTransformPipeline { @@ -50,15 +48,6 @@ impl DisplayTransformPipeline { ], }); - let sampler = gpu.create_sampler(&SamplerDesc { - filter: SamplerFilter::Bilinear, - address_mode: SamplerAddressMode::Clamp, - compare_op: None, - mip_lod_bias: 0.0, - min_lod: 0.0, - max_lod: 0.0, - }); - let pipeline = gpu.create_compute_pipeline(&ComputePipelineDesc { shader: ShaderDesc { entry: c"main", @@ -70,7 +59,6 @@ impl DisplayTransformPipeline { Self { bind_group_layout, pipeline, - sampler, } } } diff --git a/title/shark/src/pipelines/ui.rs b/title/shark/src/pipelines/ui.rs index 11053ea..85260f3 100644 --- a/title/shark/src/pipelines/ui.rs +++ b/title/shark/src/pipelines/ui.rs @@ -3,8 +3,7 @@ use narcissus_font::TouchedGlyphIndex; use narcissus_gpu::{ BindGroupLayout, BindGroupLayoutDesc, BindGroupLayoutEntryDesc, BindingType, BlendMode, CompareOp, CullingMode, FrontFace, GraphicsPipelineDesc, GraphicsPipelineLayout, ImageFormat, - Pipeline, PolygonMode, Sampler, SamplerAddressMode, SamplerDesc, SamplerFilter, ShaderDesc, - ShaderStageFlags, Topology, + Pipeline, PolygonMode, ShaderDesc, ShaderStageFlags, Topology, }; use crate::Gpu; @@ -46,7 +45,6 @@ pub struct PrimitiveInstance { pub struct UiPipeline { pub bind_group_layout: BindGroupLayout, - pub sampler: Sampler, pub pipeline: Pipeline, } @@ -93,15 +91,6 @@ impl UiPipeline { ], }); - let sampler = gpu.create_sampler(&SamplerDesc { - filter: SamplerFilter::Bilinear, - address_mode: SamplerAddressMode::Clamp, - compare_op: None, - mip_lod_bias: 0.0, - min_lod: 0.0, - max_lod: 0.0, - }); - let pipeline = gpu.create_graphics_pipeline(&GraphicsPipelineDesc { vertex_shader: ShaderDesc { entry: c"main", @@ -134,7 +123,6 @@ impl UiPipeline { Self { bind_group_layout, - sampler, pipeline, } }