From: Joshua Simmons Date: Sat, 15 Jul 2023 19:35:26 +0000 (+0200) Subject: narcissus-gpu: Expand transient buffer support X-Git-Url: https://git.nega.tv//gitweb.cgi?a=commitdiff_plain;h=ecdea2b78ac44f4314fa37680b350571c75a1100;p=josh%2Fnarcissus narcissus-gpu: Expand transient buffer support Use transient buffers as staging area for uploads. Allow passing transient buffers to more functions. --- diff --git a/bins/narcissus/src/helpers.rs b/bins/narcissus/src/helpers.rs index 32f6649..3456b70 100644 --- a/bins/narcissus/src/helpers.rs +++ b/bins/narcissus/src/helpers.rs @@ -1,11 +1,7 @@ use std::path::Path; -use narcissus_core::{default, obj, Widen}; -use narcissus_gpu::{ - Access, Buffer, BufferDesc, BufferImageCopy, BufferUsageFlags, Device, Extent3d, Image, - ImageAspectFlags, ImageBarrier, ImageDesc, ImageDimension, ImageFormat, ImageLayout, - ImageUsageFlags, MemoryLocation, Offset3d, ThreadToken, -}; +use narcissus_core::{obj, Widen}; +use narcissus_gpu::{Buffer, BufferDesc, BufferUsageFlags, Device, MemoryLocation}; use narcissus_image as image; use narcissus_maths::{vec2, vec3, vec4, Vec2, Vec3}; @@ -93,7 +89,7 @@ pub fn load_image>(path: P) -> image::Image { texture } -pub fn create_buffer_with_data( +pub fn create_host_buffer_with_data( device: &dyn Device, usage: BufferUsageFlags, data: &[T], @@ -115,79 +111,3 @@ where ) } } - -pub fn create_image_with_data( - device: &dyn Device, - thread_token: &ThreadToken, - width: u32, - height: u32, - data: &[u8], -) -> Image { - let frame = device.begin_frame(); - - let buffer = create_buffer_with_data(device, BufferUsageFlags::TRANSFER, data); - - let image = device.create_image(&ImageDesc { - location: MemoryLocation::Device, - usage: ImageUsageFlags::SAMPLED | ImageUsageFlags::TRANSFER, - dimension: ImageDimension::Type2d, - format: ImageFormat::RGBA8_SRGB, - initial_layout: ImageLayout::Optimal, - width, - height, - depth: 1, - layer_count: 1, - mip_levels: 1, - }); - - let mut cmd_buffer = device.create_cmd_buffer(&frame, thread_token); - - device.cmd_barrier( - &mut cmd_buffer, - None, - &[ImageBarrier::layout_optimal( - &[Access::None], - &[Access::TransferWrite], - image, - ImageAspectFlags::COLOR, - )], - ); - - device.cmd_copy_buffer_to_image( - &mut cmd_buffer, - buffer, - image, - ImageLayout::Optimal, - &[BufferImageCopy { - buffer_offset: 0, - buffer_row_length: 0, - buffer_image_height: 0, - image_subresource: default(), - image_offset: Offset3d { x: 0, y: 0, z: 0 }, - image_extent: Extent3d { - width, - height, - depth: 1, - }, - }], - ); - - device.cmd_barrier( - &mut cmd_buffer, - None, - &[ImageBarrier::layout_optimal( - &[Access::TransferWrite], - &[Access::FragmentShaderSampledImageRead], - image, - ImageAspectFlags::COLOR, - )], - ); - - device.submit(&frame, cmd_buffer); - - device.destroy_buffer(&frame, buffer); - - device.end_frame(frame); - - image -} diff --git a/bins/narcissus/src/main.rs b/bins/narcissus/src/main.rs index 0e6374c..e66f7a7 100644 --- a/bins/narcissus/src/main.rs +++ b/bins/narcissus/src/main.rs @@ -4,7 +4,7 @@ use crate::{ fonts::{FontFamily, Fonts}, pipelines::{BasicPipeline, TextPipeline}, }; -use helpers::{create_buffer_with_data, create_image_with_data, load_image, load_obj}; +use helpers::{create_host_buffer_with_data, load_image, load_obj}; use mapped_buffer::MappedBuffer; use narcissus_app::{create_app, Event, Key, PressedState, WindowDesc}; use narcissus_core::{default, rand::Pcg64, slice::array_windows}; @@ -67,28 +67,33 @@ pub fn main() { let fonts = Fonts::new(); let mut glyph_cache = GlyphCache::new(&fonts, GLYPH_CACHE_SIZE, GLYPH_CACHE_SIZE, 1); - let blÃ¥haj_image = load_image("bins/narcissus/data/blÃ¥haj.png"); + let blÃ¥haj_image_data = load_image("bins/narcissus/data/blÃ¥haj.png"); let (blÃ¥haj_vertices, blÃ¥haj_indices) = load_obj("bins/narcissus/data/blÃ¥haj.obj"); - let blÃ¥haj_vertex_buffer = create_buffer_with_data( + let blÃ¥haj_vertex_buffer = create_host_buffer_with_data( device.as_ref(), BufferUsageFlags::STORAGE, blÃ¥haj_vertices.as_slice(), ); - let blÃ¥haj_index_buffer = create_buffer_with_data( + let blÃ¥haj_index_buffer = create_host_buffer_with_data( device.as_ref(), BufferUsageFlags::INDEX, blÃ¥haj_indices.as_slice(), ); - let blÃ¥haj_image = create_image_with_data( - device.as_ref(), - &thread_token, - blÃ¥haj_image.width() as u32, - blÃ¥haj_image.height() as u32, - blÃ¥haj_image.as_slice(), - ); + let blÃ¥haj_image = device.create_image(&ImageDesc { + location: MemoryLocation::Device, + usage: ImageUsageFlags::SAMPLED | ImageUsageFlags::TRANSFER, + dimension: ImageDimension::Type2d, + format: ImageFormat::RGBA8_SRGB, + initial_layout: ImageLayout::Optimal, + width: blÃ¥haj_image_data.width() as u32, + height: blÃ¥haj_image_data.height() as u32, + depth: 1, + layer_count: 1, + mip_levels: 1, + }); let mut basic_transform_buffer = MappedBuffer::new( device.as_ref(), @@ -142,17 +147,66 @@ pub fn main() { { let frame = device.begin_frame(); + + let mut blÃ¥haj_buffer = device.request_transient_buffer( + &frame, + &thread_token, + BufferUsageFlags::TRANSFER, + blÃ¥haj_image_data.as_slice().len(), + ); + + blÃ¥haj_buffer.copy_from_slice(blÃ¥haj_image_data.as_slice()); + let mut cmd_buffer = device.create_cmd_buffer(&frame, &thread_token); + device.cmd_barrier( + &mut cmd_buffer, + None, + &[ + ImageBarrier::layout_optimal( + &[Access::None], + &[Access::ShaderSampledImageRead], + glyph_atlas, + ImageAspectFlags::COLOR, + ), + ImageBarrier::layout_optimal( + &[Access::None], + &[Access::TransferWrite], + blÃ¥haj_image, + ImageAspectFlags::COLOR, + ), + ], + ); + + device.cmd_copy_buffer_to_image( + &mut cmd_buffer, + blÃ¥haj_buffer.into(), + blÃ¥haj_image, + ImageLayout::Optimal, + &[BufferImageCopy { + buffer_offset: 0, + buffer_row_length: 0, + buffer_image_height: 0, + image_subresource: default(), + image_offset: Offset3d { x: 0, y: 0, z: 0 }, + image_extent: Extent3d { + width: blÃ¥haj_image_data.width() as u32, + height: blÃ¥haj_image_data.width() as u32, + depth: 1, + }, + }], + ); + device.cmd_barrier( &mut cmd_buffer, None, &[ImageBarrier::layout_optimal( - &[Access::None], - &[Access::ShaderSampledImageRead], - glyph_atlas, + &[Access::TransferWrite], + &[Access::FragmentShaderSampledImageRead], + blÃ¥haj_image, ImageAspectFlags::COLOR, )], ); + device.submit(&frame, cmd_buffer); device.end_frame(frame); } @@ -391,9 +445,15 @@ pub fn main() { let width = atlas_width; let height = atlas_height; let image = glyph_atlas; - let data = texture; - let buffer = create_buffer_with_data(device.as_ref(), BufferUsageFlags::TRANSFER, data); + let mut buffer = device.request_transient_buffer( + &frame, + &thread_token, + BufferUsageFlags::TRANSFER, + texture.len(), + ); + + buffer.copy_from_slice(texture); device.cmd_barrier( &mut cmd_buffer, @@ -408,7 +468,7 @@ pub fn main() { device.cmd_copy_buffer_to_image( &mut cmd_buffer, - buffer, + buffer.into(), image, ImageLayout::Optimal, &[BufferImageCopy { @@ -435,8 +495,6 @@ pub fn main() { ImageAspectFlags::COLOR, )], ); - - device.destroy_buffer(&frame, buffer); } device.cmd_begin_rendering( diff --git a/bins/narcissus/src/pipelines/basic.rs b/bins/narcissus/src/pipelines/basic.rs index cd20116..50e56ba 100644 --- a/bins/narcissus/src/pipelines/basic.rs +++ b/bins/narcissus/src/pipelines/basic.rs @@ -15,7 +15,6 @@ const FRAG_SPV: &[u8] = include_bytes_align!(4, "../shaders/basic.frag.spv"); #[allow(unused)] #[repr(C)] -#[repr(align(16))] pub struct BasicUniforms { pub clip_from_model: Mat4, } @@ -141,7 +140,6 @@ impl BasicPipeline { thread_token, BufferUsageFlags::UNIFORM, std::mem::size_of::(), - std::mem::align_of::(), ); uniform_buffer.copy_from_slice(basic_uniforms.as_bytes()); @@ -189,6 +187,6 @@ impl BasicPipeline { ], ); - device.cmd_set_index_buffer(cmd_buffer, index_buffer, 0, IndexType::U16); + device.cmd_set_index_buffer(cmd_buffer, index_buffer.into(), 0, IndexType::U16); } } diff --git a/bins/narcissus/src/pipelines/text.rs b/bins/narcissus/src/pipelines/text.rs index cd768ed..3651fc7 100644 --- a/bins/narcissus/src/pipelines/text.rs +++ b/bins/narcissus/src/pipelines/text.rs @@ -15,7 +15,6 @@ const FRAG_SPV: &[u8] = include_bytes_align!(4, "../shaders/text.frag.spv"); #[allow(unused)] #[repr(C)] -#[repr(align(16))] pub struct TextUniforms { pub screen_width: u32, pub screen_height: u32, @@ -139,7 +138,6 @@ impl TextPipeline { thread_token, BufferUsageFlags::UNIFORM, std::mem::size_of::(), - std::mem::align_of::(), ); uniforms.copy_from_slice(text_uniforms.as_bytes()); diff --git a/libs/narcissus-gpu/src/backend/vulkan/mod.rs b/libs/narcissus-gpu/src/backend/vulkan/mod.rs index 0f5f7f0..c5d7dfa 100644 --- a/libs/narcissus-gpu/src/backend/vulkan/mod.rs +++ b/libs/narcissus-gpu/src/backend/vulkan/mod.rs @@ -18,7 +18,7 @@ use crate::{ delay_queue::DelayQueue, frame_counter::FrameCounter, tlsf::{self, Tlsf}, - Access, Bind, BindGroupLayout, BindGroupLayoutDesc, BindingType, BlendMode, Buffer, BufferBind, + Access, Bind, BindGroupLayout, BindGroupLayoutDesc, BindingType, BlendMode, Buffer, BufferArg, BufferDesc, BufferImageCopy, BufferUsageFlags, ClearValue, CmdBuffer, CompareOp, ComputePipelineDesc, CullingMode, Device, Extent2d, Extent3d, Frame, FrontFace, GlobalBarrier, GpuConcurrent, GraphicsPipelineDesc, Image, ImageAspectFlags, ImageBarrier, ImageBlit, @@ -2385,9 +2385,8 @@ impl Device for VulkanDevice { thread_token: &'a ThreadToken, usage: BufferUsageFlags, size: usize, - align: usize, ) -> TransientBuffer<'a> { - self.request_transient_buffer(frame, thread_token, usage, size as u64, align as u64) + self.request_transient_buffer(frame, thread_token, usage, size as u64) } fn create_cmd_buffer<'a, 'thread>( @@ -2484,15 +2483,22 @@ impl Device for VulkanDevice { fn cmd_copy_buffer_to_image( &self, cmd_buffer: &mut CmdBuffer, - src_buffer: Buffer, + src_buffer: BufferArg, dst_image: Image, dst_image_layout: ImageLayout, copies: &[BufferImageCopy], ) { let arena = HybridArena::<4096>::new(); + let (src_buffer, base_offset) = match src_buffer { + BufferArg::Unmanaged(buffer) => { + (self.buffer_pool.lock().get(buffer.0).unwrap().buffer, 0) + } + BufferArg::Transient(buffer) => (vk::Buffer::from_raw(buffer.buffer), buffer.offset), + }; + let regions = arena.alloc_slice_fill_iter(copies.iter().map(|copy| vk::BufferImageCopy { - buffer_offset: copy.buffer_offset, + buffer_offset: copy.buffer_offset + base_offset, buffer_row_length: copy.buffer_row_length, buffer_image_height: copy.buffer_image_height, image_subresource: vulkan_subresource_layers(©.image_subresource), @@ -2500,13 +2506,6 @@ impl Device for VulkanDevice { image_extent: copy.image_extent.into(), })); - let src_buffer = self - .buffer_pool - .lock() - .get(src_buffer.0) - .expect("invalid buffer handle") - .buffer; - let dst_image = self .image_pool .lock() @@ -2683,7 +2682,7 @@ impl Device for VulkanDevice { TypedBind::UniformBuffer(buffers) => { let buffer_pool = self.buffer_pool.lock(); let buffer_infos_iter = buffers.iter().map(|buffer| match buffer { - BufferBind::Unmanaged(buffer) => { + BufferArg::Unmanaged(buffer) => { let buffer = buffer_pool.get(buffer.0).unwrap().buffer; vk::DescriptorBufferInfo { buffer, @@ -2691,7 +2690,7 @@ impl Device for VulkanDevice { range: vk::WHOLE_SIZE, } } - BufferBind::Transient(transient) => vk::DescriptorBufferInfo { + BufferArg::Transient(transient) => vk::DescriptorBufferInfo { buffer: vk::Buffer::from_raw(transient.buffer), offset: transient.offset, range: transient.len as u64, @@ -2711,7 +2710,7 @@ impl Device for VulkanDevice { TypedBind::StorageBuffer(buffers) => { let buffer_pool = self.buffer_pool.lock(); let buffer_infos_iter = buffers.iter().map(|buffer| match buffer { - BufferBind::Unmanaged(buffer) => { + BufferArg::Unmanaged(buffer) => { let buffer = buffer_pool.get(buffer.0).unwrap().buffer; vk::DescriptorBufferInfo { buffer, @@ -2719,7 +2718,7 @@ impl Device for VulkanDevice { range: vk::WHOLE_SIZE, } } - BufferBind::Transient(transient) => vk::DescriptorBufferInfo { + BufferArg::Transient(transient) => vk::DescriptorBufferInfo { buffer: vk::Buffer::from_raw(transient.buffer), offset: transient.offset, range: transient.len as u64, @@ -2771,16 +2770,26 @@ impl Device for VulkanDevice { fn cmd_set_index_buffer( &self, cmd_buffer: &mut CmdBuffer, - buffer: Buffer, + buffer: BufferArg, offset: u64, index_type: IndexType, ) { - let buffer = self.buffer_pool.lock().get(buffer.0).unwrap().buffer; + let (buffer, base_offset) = match buffer { + BufferArg::Unmanaged(buffer) => { + (self.buffer_pool.lock().get(buffer.0).unwrap().buffer, 0) + } + BufferArg::Transient(buffer) => (vk::Buffer::from_raw(buffer.buffer), buffer.offset), + }; + let command_buffer = self.cmd_buffer_mut(cmd_buffer).command_buffer; let index_type = vulkan_index_type(index_type); unsafe { - self.device_fn - .cmd_bind_index_buffer(command_buffer, buffer, offset, index_type) + self.device_fn.cmd_bind_index_buffer( + command_buffer, + buffer, + offset + base_offset, + index_type, + ) } } @@ -3225,14 +3234,14 @@ impl VulkanDevice { thread_token: &'a ThreadToken, usage: BufferUsageFlags, size: u64, - align: u64, ) -> TransientBuffer<'a> { let frame = self.frame(frame); let per_thread = frame.per_thread.get(thread_token); let mut allocator = per_thread.transient_buffer_allocator.borrow_mut(); assert!(size <= VULKAN_CONSTANTS.transient_buffer_size); - assert!(align != 0 && align.is_power_of_two()); + + let align = 1; let align = if usage.contains(BufferUsageFlags::UNIFORM) { align.max( @@ -3292,7 +3301,7 @@ impl VulkanDevice { len: size as usize, buffer: current.buffer.as_raw(), offset: allocator.offset, - _phantom: &PhantomData, + phantom: PhantomData, } } diff --git a/libs/narcissus-gpu/src/lib.rs b/libs/narcissus-gpu/src/lib.rs index f438b4d..7cafd68 100644 --- a/libs/narcissus-gpu/src/lib.rs +++ b/libs/narcissus-gpu/src/lib.rs @@ -66,7 +66,7 @@ pub struct TransientBuffer<'a> { len: usize, buffer: u64, offset: u64, - _phantom: &'a PhantomData<()>, + phantom: PhantomData<&'a u8>, } impl<'a> TransientBuffer<'a> { @@ -477,28 +477,28 @@ pub struct Bind<'a> { pub typed: TypedBind<'a>, } -pub enum BufferBind<'a> { +pub enum BufferArg<'a> { Unmanaged(Buffer), Transient(TransientBuffer<'a>), } -impl<'a> From for BufferBind<'a> { +impl<'a> From for BufferArg<'a> { fn from(value: Buffer) -> Self { - BufferBind::Unmanaged(value) + BufferArg::Unmanaged(value) } } -impl<'a> From> for BufferBind<'a> { +impl<'a> From> for BufferArg<'a> { fn from(value: TransientBuffer<'a>) -> Self { - BufferBind::Transient(value) + BufferArg::Transient(value) } } pub enum TypedBind<'a> { Sampler(&'a [Sampler]), Image(&'a [(ImageLayout, Image)]), - UniformBuffer(&'a [BufferBind<'a>]), - StorageBuffer(&'a [BufferBind<'a>]), + UniformBuffer(&'a [BufferArg<'a>]), + StorageBuffer(&'a [BufferArg<'a>]), } #[derive(Clone, Copy, PartialEq, Eq)] @@ -749,7 +749,6 @@ pub trait Device { thread_token: &'a ThreadToken, usage: BufferUsageFlags, size: usize, - align: usize, ) -> TransientBuffer<'a>; #[must_use] @@ -771,7 +770,7 @@ pub trait Device { fn cmd_set_index_buffer( &self, cmd_buffer: &mut CmdBuffer, - buffer: Buffer, + buffer: BufferArg, offset: u64, index_type: IndexType, ); @@ -792,7 +791,7 @@ pub trait Device { fn cmd_copy_buffer_to_image( &self, cmd_buffer: &mut CmdBuffer, - src_buffer: Buffer, + src_buffer: BufferArg, dst_image: Image, dst_image_layout: ImageLayout, copies: &[BufferImageCopy],