]> git.nega.tv - josh/narcissus/commitdiff
narcissus-gpu: Add push constants function
authorJosh Simmons <josh@nega.tv>
Sat, 25 May 2024 08:44:30 +0000 (10:44 +0200)
committerJosh Simmons <josh@nega.tv>
Sat, 25 May 2024 08:44:30 +0000 (10:44 +0200)
engine/narcissus-gpu/src/backend/vulkan/mod.rs
engine/narcissus-gpu/src/lib.rs

index a7fbb8e9c4648dc4ad3eb529d6c83b3beb5522bb..c8f2da5ec5d7b3ce47500b5982c5462e0c9dfbf0 100644 (file)
@@ -21,8 +21,8 @@ use crate::{
     Frame, GlobalBarrier, GpuConcurrent, GraphicsPipelineDesc, Image, ImageBarrier, ImageBlit,
     ImageDesc, ImageDimension, ImageLayout, ImageTiling, ImageViewDesc, IndexType, MemoryLocation,
     Offset2d, Offset3d, PersistentBuffer, Pipeline, Sampler, SamplerAddressMode, SamplerCompareOp,
-    SamplerDesc, SamplerFilter, SwapchainConfigurator, SwapchainImage, SwapchainOutOfDateError,
-    ThreadToken, TransientBuffer, TypedBind,
+    SamplerDesc, SamplerFilter, ShaderStageFlags, SwapchainConfigurator, SwapchainImage,
+    SwapchainOutOfDateError, ThreadToken, TransientBuffer, TypedBind,
 };
 
 mod allocator;
@@ -1688,6 +1688,37 @@ impl Device for VulkanDevice {
         }
     }
 
+    unsafe fn cmd_push_constants_unchecked(
+        &self,
+        cmd_encoder: &mut CmdEncoder,
+        stage_flags: ShaderStageFlags,
+        offset: u32,
+        size: u32,
+        src: *const u8,
+    ) {
+        let cmd_encoder = self.cmd_encoder_mut(cmd_encoder);
+        let command_buffer = cmd_encoder.command_buffer;
+
+        let VulkanBoundPipeline {
+            pipeline_layout,
+            pipeline_bind_point: _,
+        } = cmd_encoder
+            .bound_pipeline
+            .as_ref()
+            .expect("cannot push constants without a pipeline bound")
+            .clone();
+
+        let stage_flags = vulkan_shader_stage_flags(stage_flags);
+        self.device_fn.cmd_push_constants(
+            command_buffer,
+            pipeline_layout,
+            stage_flags,
+            offset,
+            size,
+            src as *const std::ffi::c_void,
+        )
+    }
+
     fn cmd_copy_buffer_to_image(
         &self,
         cmd_encoder: &mut CmdEncoder,
index 784396100125a44c5b7fcf78f07d24162082712a..def3cad65b818574f438bd716caedda51b6358cc 100644 (file)
@@ -830,6 +830,15 @@ pub trait Device {
         image_barriers: &[ImageBarrier],
     );
 
+    unsafe fn cmd_push_constants_unchecked(
+        &self,
+        cmd_encoder: &mut CmdEncoder,
+        stage_flags: ShaderStageFlags,
+        offset: u32,
+        size: u32,
+        src: *const u8,
+    );
+
     fn cmd_copy_buffer_to_image(
         &self,
         cmd_encoder: &mut CmdEncoder,
@@ -887,7 +896,44 @@ pub trait Device {
     fn end_frame<'device>(&'device self, frame: Frame<'device>);
 }
 
+#[cold]
+fn overflow() -> ! {
+    panic!("overflow")
+}
+
 pub trait DeviceExt: Device {
+    fn cmd_push_constants<T: ?Sized>(
+        &self,
+        cmd_encoder: &mut CmdEncoder,
+        stage_flags: ShaderStageFlags,
+        offset: usize,
+        data: &T,
+    ) {
+        let size = std::mem::size_of_val(data);
+        let src = data as *const _ as *const u8;
+
+        // # Safety
+        //
+        // The memory region from `src` through `src` + `size` must be valid as it's
+        // directly derived from `data`.
+        //
+        // This function will propagate undefined values from T, for example, padding
+        // bytes, however we promise not to materialize a rust reference to any such
+        // data.
+        unsafe {
+            if size >= u32::MAX as usize || offset >= u32::MAX as usize {
+                overflow();
+            }
+            self.cmd_push_constants_unchecked(
+                cmd_encoder,
+                stage_flags,
+                offset as u32,
+                size as u32,
+                src,
+            )
+        }
+    }
+
     fn create_persistent_buffer_with_data<'a, T: ?Sized>(
         &'a self,
         memory_location: MemoryLocation,