]> git.nega.tv - josh/narcissus/commitdiff
narcissus-gpu: Expand transient buffer support
authorJoshua Simmons <josh@nega.tv>
Sat, 15 Jul 2023 19:35:26 +0000 (21:35 +0200)
committerJoshua Simmons <josh@nega.tv>
Sat, 15 Jul 2023 19:35:26 +0000 (21:35 +0200)
Use transient buffers as staging area for uploads.
Allow passing transient buffers to more functions.

bins/narcissus/src/helpers.rs
bins/narcissus/src/main.rs
bins/narcissus/src/pipelines/basic.rs
bins/narcissus/src/pipelines/text.rs
libs/narcissus-gpu/src/backend/vulkan/mod.rs
libs/narcissus-gpu/src/lib.rs

index 32f66496ffbe75ad343086a727b2f32bb91e44f4..3456b7004fc3416cae43a63290bbdf35e686d8a8 100644 (file)
@@ -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<P: AsRef<Path>>(path: P) -> image::Image {
     texture
 }
 
-pub fn create_buffer_with_data<T>(
+pub fn create_host_buffer_with_data<T>(
     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
-}
index 0e6374cd65d906b60186f1427f3cb81cfc1bdfdf..e66f7a7f32c78c6a1e37a5dd574dfb0156404297 100644 (file)
@@ -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(
index cd2011640429d4cef7f6766c63a4c1cd033b9c63..50e56ba3b3358e9f9d2865af4d52c05087bf2d42 100644 (file)
@@ -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::<BasicUniforms>(),
-            std::mem::align_of::<BasicUniforms>(),
         );
 
         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);
     }
 }
index cd768ed4423e87b3e607f1afb535526e5ad9b5fd..3651fc7cb6e4610326739800b409e5734fc27c27 100644 (file)
@@ -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::<TextUniforms>(),
-            std::mem::align_of::<TextUniforms>(),
         );
 
         uniforms.copy_from_slice(text_uniforms.as_bytes());
index 0f5f7f0d7d80a15d2f90a32a5bdc300f6c9770a0..c5d7dfabbc0664249595bf3d623961f4116d5b74 100644 (file)
@@ -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(&copy.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,
         }
     }
 
index f438b4d8a0dd46b72a3a3b4378dc49078c659a5e..7cafd680a9ef53a616dda5efe2137cdf56fa3686 100644 (file)
@@ -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<Buffer> for BufferBind<'a> {
+impl<'a> From<Buffer> for BufferArg<'a> {
     fn from(value: Buffer) -> Self {
-        BufferBind::Unmanaged(value)
+        BufferArg::Unmanaged(value)
     }
 }
 
-impl<'a> From<TransientBuffer<'a>> for BufferBind<'a> {
+impl<'a> From<TransientBuffer<'a>> 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],