From 4a4b0bda81348c4871e7abb01e6f5d4453caf783 Mon Sep 17 00:00:00 2001 From: quaternic <57393910+quaternic@users.noreply.github.com> Date: Fri, 28 Mar 2025 19:55:58 +0200 Subject: [PATCH 1/5] replace unsound gpu enums with wrapper structs --- examples/gpu-clear.rs | 6 +- examples/gpu-cube.rs | 28 ++++----- examples/gpu-texture.rs | 32 +++++----- examples/gpu-triangle.rs | 10 +-- src/sdl3/gpu/buffer.rs | 6 +- src/sdl3/gpu/device.rs | 2 +- src/sdl3/gpu/enums.rs | 131 +++++++++++++++------------------------ src/sdl3/gpu/pass.rs | 22 +++---- src/sdl3/gpu/pipeline.rs | 4 +- src/sdl3/gpu/shader.rs | 2 +- src/sdl3/gpu/texture.rs | 2 +- 11 files changed, 104 insertions(+), 141 deletions(-) diff --git a/examples/gpu-clear.rs b/examples/gpu-clear.rs index 6731fdc4..3d86126d 100644 --- a/examples/gpu-clear.rs +++ b/examples/gpu-clear.rs @@ -17,7 +17,7 @@ pub fn main() -> Result<(), Box> { // by default, and we specify that our shaders will be SPIR-V ones (even through we // aren't using any shaders) // We'll also turn on debug mode to true, so we get debug stuff - let gpu = sdl3::gpu::Device::new(sdl3::gpu::ShaderFormat::SpirV, true)?.with_window(&window)?; + let gpu = sdl3::gpu::Device::new(sdl3::gpu::ShaderFormat::SPIRV, true)?.with_window(&window)?; let mut event_pump = sdl_context.event_pump()?; println!( @@ -45,8 +45,8 @@ pub fn main() -> Result<(), Box> { let color_targets = [ sdl3::gpu::ColorTargetInfo::default() .with_texture(&swapchain) // Use swapchain texture - .with_load_op(sdl3::gpu::LoadOp::Clear) // Clear when load - .with_store_op(sdl3::gpu::StoreOp::Store) // Store back + .with_load_op(sdl3::gpu::LoadOp::CLEAR) // Clear when load + .with_store_op(sdl3::gpu::StoreOp::STORE) // Store back .with_clear_color(sdl3::pixels::Color::RGB(5, 3, 255)), //blue with small RG bias ]; // Here we do all (none) of our drawing (clearing the screen) diff --git a/examples/gpu-cube.rs b/examples/gpu-cube.rs index dd375125..78928f5a 100644 --- a/examples/gpu-cube.rs +++ b/examples/gpu-cube.rs @@ -89,7 +89,7 @@ pub fn main() -> Result<(), Box> { .map_err(|e| e.to_string())?; let gpu = Device::new( - ShaderFormat::SpirV | ShaderFormat::Dxil | ShaderFormat::Dxbc | ShaderFormat::MetalLib, + ShaderFormat::SPIRV | ShaderFormat::DXIL | ShaderFormat::DXBC | ShaderFormat::METALLIB, true, )? .with_window(&window)?; @@ -98,7 +98,7 @@ pub fn main() -> Result<(), Box> { let vert_shader = gpu .create_shader() .with_code( - ShaderFormat::SpirV, + ShaderFormat::SPIRV, include_bytes!("shaders/cube.vert.spv"), ShaderStage::Vertex, ) @@ -108,7 +108,7 @@ pub fn main() -> Result<(), Box> { let frag_shader = gpu .create_shader() .with_code( - ShaderFormat::SpirV, + ShaderFormat::SPIRV, include_bytes!("shaders/cube.frag.spv"), ShaderStage::Fragment, ) @@ -171,7 +171,7 @@ pub fn main() -> Result<(), Box> { let transfer_buffer = gpu .create_transfer_buffer() .with_size(vertices_len_bytes.max(indices_len_bytes) as u32) - .with_usage(TransferBufferUsage::Upload) + .with_usage(TransferBufferUsage::UPLOAD) .build()?; // We need to start a copy pass in order to transfer data to the GPU @@ -183,14 +183,14 @@ pub fn main() -> Result<(), Box> { &gpu, &transfer_buffer, ©_pass, - BufferUsageFlags::Vertex, + BufferUsageFlags::VERTEX, &CUBE_VERTICES, )?; let index_buffer = create_buffer_with_data( &gpu, &transfer_buffer, ©_pass, - BufferUsageFlags::Index, + BufferUsageFlags::INDEX, &CUBE_INDICES, )?; @@ -211,7 +211,7 @@ pub fn main() -> Result<(), Box> { .with_num_levels(1) .with_sample_count(SampleCount::NoMultiSampling) .with_format(TextureFormat::D16Unorm) - .with_usage(TextureUsage::Sampler | TextureUsage::DepthStencilTarget), + .with_usage(TextureUsage::SAMPLER | TextureUsage::DEPTH_STENCIL_TARGET), )?; let mut rotation = 45.0f32; @@ -238,8 +238,8 @@ pub fn main() -> Result<(), Box> { // Again, like in gpu-clear.rs, we'd want to define basic operations for our cube let color_targets = [ColorTargetInfo::default() .with_texture(&swapchain) - .with_load_op(LoadOp::Clear) - .with_store_op(StoreOp::Store) + .with_load_op(LoadOp::CLEAR) + .with_store_op(StoreOp::STORE) .with_clear_color(Color::RGB(128, 128, 128))]; // This time, however, we want depth testing, so we need to also target a depth texture buffer let depth_target = DepthStencilTargetInfo::new() @@ -247,10 +247,10 @@ pub fn main() -> Result<(), Box> { .with_cycle(true) .with_clear_depth(1.0) .with_clear_stencil(0) - .with_load_op(LoadOp::Clear) - .with_store_op(StoreOp::Store) - .with_stencil_load_op(LoadOp::Clear) - .with_stencil_store_op(StoreOp::Store); + .with_load_op(LoadOp::CLEAR) + .with_store_op(StoreOp::STORE) + .with_stencil_load_op(LoadOp::CLEAR) + .with_stencil_store_op(StoreOp::STORE); let render_pass = gpu.begin_render_pass(&command_buffer, &color_targets, Some(&depth_target))?; @@ -268,7 +268,7 @@ pub fn main() -> Result<(), Box> { &BufferBinding::new() .with_buffer(&index_buffer) .with_offset(0), - IndexElementSize::_16Bit, + IndexElementSize::_16BIT, ); // Set the rotation uniform for our cube vert shader diff --git a/examples/gpu-texture.rs b/examples/gpu-texture.rs index 710d2659..759b9984 100644 --- a/examples/gpu-texture.rs +++ b/examples/gpu-texture.rs @@ -194,7 +194,7 @@ pub fn main() -> Result<(), Box> { .map_err(|e| e.to_string())?; let gpu = sdl3::gpu::Device::new( - ShaderFormat::SpirV | ShaderFormat::Dxil | ShaderFormat::Dxbc | ShaderFormat::MetalLib, + ShaderFormat::SPIRV | ShaderFormat::DXIL | ShaderFormat::DXBC | ShaderFormat::METALLIB, true, )? .with_window(&window)?; @@ -203,7 +203,7 @@ pub fn main() -> Result<(), Box> { let vert_shader = gpu .create_shader() .with_code( - ShaderFormat::SpirV, + ShaderFormat::SPIRV, include_bytes!("shaders/cube-texture.vert.spv"), ShaderStage::Vertex, ) @@ -213,7 +213,7 @@ pub fn main() -> Result<(), Box> { let frag_shader = gpu .create_shader() .with_code( - ShaderFormat::SpirV, + ShaderFormat::SPIRV, include_bytes!("shaders/cube-texture.frag.spv"), ShaderStage::Fragment, ) @@ -284,7 +284,7 @@ pub fn main() -> Result<(), Box> { let transfer_buffer = gpu .create_transfer_buffer() .with_size(vertices_len_bytes.max(indices_len_bytes) as u32) - .with_usage(TransferBufferUsage::Upload) + .with_usage(TransferBufferUsage::UPLOAD) .build()?; // We need to start a copy pass in order to transfer data to the GPU @@ -296,14 +296,14 @@ pub fn main() -> Result<(), Box> { &gpu, &transfer_buffer, ©_pass, - BufferUsageFlags::Vertex, + BufferUsageFlags::VERTEX, &CUBE_VERTICES, )?; let index_buffer = create_buffer_with_data( &gpu, &transfer_buffer, ©_pass, - BufferUsageFlags::Index, + BufferUsageFlags::INDEX, &CUBE_INDICES, )?; @@ -338,7 +338,7 @@ pub fn main() -> Result<(), Box> { .with_num_levels(1) .with_sample_count(SampleCount::NoMultiSampling) .with_format(TextureFormat::D16Unorm) - .with_usage(TextureUsage::Sampler | TextureUsage::DepthStencilTarget), + .with_usage(TextureUsage::SAMPLER | TextureUsage::DEPTH_STENCIL_TARGET) )?; let mut rotation = 45.0f32; @@ -365,8 +365,8 @@ pub fn main() -> Result<(), Box> { // Again, like in gpu-clear.rs, we'd want to define basic operations for our cube let color_targets = [ColorTargetInfo::default() .with_texture(&swapchain) - .with_load_op(LoadOp::Clear) - .with_store_op(StoreOp::Store) + .with_load_op(LoadOp::CLEAR) + .with_store_op(StoreOp::STORE) .with_clear_color(Color::RGB(128, 128, 128))]; // This time, however, we want depth testing, so we need to also target a depth texture buffer let depth_target = DepthStencilTargetInfo::new() @@ -374,10 +374,10 @@ pub fn main() -> Result<(), Box> { .with_cycle(true) .with_clear_depth(1.0) .with_clear_stencil(0) - .with_load_op(LoadOp::Clear) - .with_store_op(StoreOp::Store) - .with_stencil_load_op(LoadOp::Clear) - .with_stencil_store_op(StoreOp::Store); + .with_load_op(LoadOp::CLEAR) + .with_store_op(StoreOp::STORE) + .with_stencil_load_op(LoadOp::CLEAR) + .with_stencil_store_op(StoreOp::STORE); let render_pass = gpu.begin_render_pass(&command_buffer, &color_targets, Some(&depth_target))?; @@ -395,7 +395,7 @@ pub fn main() -> Result<(), Box> { &BufferBinding::new() .with_buffer(&index_buffer) .with_offset(0), - IndexElementSize::_16Bit, + IndexElementSize::_16BIT, ); render_pass.bind_fragment_samplers( 0, @@ -440,13 +440,13 @@ fn create_texture_from_image( .with_height(image_size.1) .with_layer_count_or_depth(1) .with_num_levels(1) - .with_usage(TextureUsage::Sampler), + .with_usage(TextureUsage::SAMPLER), )?; let transfer_buffer = gpu .create_transfer_buffer() .with_size(size_bytes) - .with_usage(TransferBufferUsage::Upload) + .with_usage(TransferBufferUsage::UPLOAD) .build()?; let mut buffer_mem = transfer_buffer.map::(gpu, false); diff --git a/examples/gpu-triangle.rs b/examples/gpu-triangle.rs index ca1dd6f3..2011f5c5 100644 --- a/examples/gpu-triangle.rs +++ b/examples/gpu-triangle.rs @@ -25,7 +25,7 @@ pub fn main() -> Result<(), Box> { // aren't using any shaders) // We'll also turn on debug mode to true, so we get debug stuff let gpu = Device::new( - ShaderFormat::SpirV | ShaderFormat::Dxil | ShaderFormat::Dxbc | ShaderFormat::MetalLib, + ShaderFormat::SPIRV | ShaderFormat::DXIL | ShaderFormat::DXBC | ShaderFormat::METALLIB, true, )? .with_window(&window)?; @@ -36,13 +36,13 @@ pub fn main() -> Result<(), Box> { // Our shaders, require to be precompiled by a SPIR-V compiler beforehand let vs_shader = gpu .create_shader() - .with_code(ShaderFormat::SpirV, vs_source, ShaderStage::Vertex) + .with_code(ShaderFormat::SPIRV, vs_source, ShaderStage::Vertex) .with_entrypoint(c"main") .build()?; let fs_shader = gpu .create_shader() - .with_code(ShaderFormat::SpirV, fs_source, ShaderStage::Fragment) + .with_code(ShaderFormat::SPIRV, fs_source, ShaderStage::Fragment) .with_entrypoint(c"main") .build()?; @@ -95,8 +95,8 @@ pub fn main() -> Result<(), Box> { let color_targets = [ ColorTargetInfo::default() .with_texture(&swapchain) - .with_load_op(LoadOp::Clear) - .with_store_op(StoreOp::Store) + .with_load_op(LoadOp::CLEAR) + .with_store_op(StoreOp::STORE) .with_clear_color(Color::RGB(5, 3, 255)), //blue with small RG bias ]; let render_pass = gpu.begin_render_pass(&command_buffer, &color_targets, None)?; diff --git a/src/sdl3/gpu/buffer.rs b/src/sdl3/gpu/buffer.rs index 0fb37a0b..3f3434b2 100644 --- a/src/sdl3/gpu/buffer.rs +++ b/src/sdl3/gpu/buffer.rs @@ -7,7 +7,7 @@ use std::sync::Arc; use sys::gpu::{ SDL_CreateGPUBuffer, SDL_CreateGPUTransferBuffer, SDL_GPUBuffer, SDL_GPUBufferBinding, SDL_GPUBufferCreateInfo, SDL_GPUBufferRegion, SDL_GPUTransferBuffer, - SDL_GPUTransferBufferCreateInfo, SDL_GPUTransferBufferLocation, SDL_GPUTransferBufferUsage, + SDL_GPUTransferBufferCreateInfo, SDL_GPUTransferBufferLocation, SDL_GPUVertexBufferDescription, SDL_GPUVertexInputRate, SDL_MapGPUTransferBuffer, SDL_ReleaseGPUBuffer, SDL_ReleaseGPUTransferBuffer, SDL_UnmapGPUTransferBuffer, }; @@ -157,7 +157,7 @@ impl<'a> BufferBuilder<'a> { } pub fn with_usage(mut self, value: BufferUsageFlags) -> Self { - self.inner.usage = value as u32; + self.inner.usage = value.0; self } @@ -267,7 +267,7 @@ impl<'a> TransferBufferBuilder<'a> { /// How the buffer will be used. pub fn with_usage(mut self, value: TransferBufferUsage) -> Self { - self.inner.usage = SDL_GPUTransferBufferUsage(value as i32); + self.inner.usage = value; self } diff --git a/src/sdl3/gpu/device.rs b/src/sdl3/gpu/device.rs index 63384d24..6949b42c 100644 --- a/src/sdl3/gpu/device.rs +++ b/src/sdl3/gpu/device.rs @@ -52,7 +52,7 @@ impl Device { #[doc(alias = "SDL_CreateGPUDevice")] pub fn new(flags: ShaderFormat, debug_mode: bool) -> Result { - let raw_device = unsafe { SDL_CreateGPUDevice(flags as u32, debug_mode, std::ptr::null()) }; + let raw_device = unsafe { SDL_CreateGPUDevice(flags.0, debug_mode, std::ptr::null()) }; if raw_device.is_null() { Err(get_error()) } else { diff --git a/src/sdl3/gpu/enums.rs b/src/sdl3/gpu/enums.rs index 8fc49c1f..be8d898d 100644 --- a/src/sdl3/gpu/enums.rs +++ b/src/sdl3/gpu/enums.rs @@ -1,47 +1,26 @@ use crate::sys; use std::ops::{BitAnd, BitOr}; -use sys::gpu::{ - SDL_GPUBlendFactor, SDL_GPUBlendOp, SDL_GPU_COLORCOMPONENT_A, SDL_GPU_COLORCOMPONENT_B, - SDL_GPU_COLORCOMPONENT_G, SDL_GPU_COLORCOMPONENT_R, -}; +use sys::gpu::{SDL_GPUBlendFactor, SDL_GPUBlendOp}; macro_rules! impl_with { (bitwise_and_or $x:ident $prim:ident) => { impl BitOr<$x> for $x { type Output = $x; fn bitor(self, rhs: $x) -> Self::Output { - unsafe { std::mem::transmute((self as $prim) | (rhs as $prim)) } + $x (self.0 | rhs.0) } } impl BitAnd<$x> for $x { type Output = $x; fn bitand(self, rhs: $x) -> Self::Output { - unsafe { std::mem::transmute((self as $prim) & (rhs as $prim)) } + $x (self.0 & rhs.0) } } }; } -#[derive(Default, Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] -#[repr(u32)] -pub enum LoadOp { - #[default] - Load = sys::gpu::SDL_GPU_LOADOP_LOAD.0 as u32, - DontCare = sys::gpu::SDL_GPU_LOADOP_DONT_CARE.0 as u32, - Clear = sys::gpu::SDL_GPU_LOADOP_CLEAR.0 as u32, -} -impl_with!(bitwise_and_or LoadOp u32); - -#[derive(Default, Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] -#[repr(u32)] -pub enum StoreOp { - #[default] - Store = sys::gpu::SDL_GPU_STOREOP_STORE.0 as u32, - DontCare = sys::gpu::SDL_GPU_STOREOP_DONT_CARE.0 as u32, - Resolve = sys::gpu::SDL_GPU_STOREOP_RESOLVE.0 as u32, - ResolveAndStore = sys::gpu::SDL_GPU_STOREOP_RESOLVE_AND_STORE.0 as u32, -} -impl_with!(bitwise_and_or StoreOp u32); +pub type LoadOp = sys::gpu::SDL_GPULoadOp; +pub type StoreOp = sys::gpu::SDL_GPUStoreOp; #[derive(Default, Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] #[repr(u32)] @@ -153,35 +132,38 @@ pub enum TextureFormat { Astc12x10Float = sys::gpu::SDL_GPU_TEXTUREFORMAT_ASTC_12x10_FLOAT.0 as u32, Astc12x12Float = sys::gpu::SDL_GPU_TEXTUREFORMAT_ASTC_12x12_FLOAT.0 as u32, } -impl_with!(bitwise_and_or TextureFormat u32); #[derive(Default, Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] -#[repr(u32)] -pub enum ShaderFormat { - #[default] - Invalid = sys::gpu::SDL_GPU_SHADERFORMAT_INVALID as u32, - Dxbc = sys::gpu::SDL_GPU_SHADERFORMAT_DXBC as u32, - Dxil = sys::gpu::SDL_GPU_SHADERFORMAT_DXIL as u32, - MetalLib = sys::gpu::SDL_GPU_SHADERFORMAT_METALLIB as u32, - Msl = sys::gpu::SDL_GPU_SHADERFORMAT_MSL as u32, - Private = sys::gpu::SDL_GPU_SHADERFORMAT_PRIVATE as u32, - SpirV = sys::gpu::SDL_GPU_SHADERFORMAT_SPIRV as u32, +pub struct ShaderFormat(pub sys::gpu::SDL_GPUShaderFormat); +impl ShaderFormat { + pub const INVALID: Self = Self(sys::gpu::SDL_GPU_SHADERFORMAT_INVALID); + pub const DXBC: Self = Self(sys::gpu::SDL_GPU_SHADERFORMAT_DXBC); + pub const DXIL: Self = Self(sys::gpu::SDL_GPU_SHADERFORMAT_DXIL); + pub const METALLIB: Self = Self(sys::gpu::SDL_GPU_SHADERFORMAT_METALLIB); + pub const MSL: Self = Self(sys::gpu::SDL_GPU_SHADERFORMAT_MSL); + pub const PRIVATE: Self = Self(sys::gpu::SDL_GPU_SHADERFORMAT_PRIVATE); + pub const SPIRV: Self = Self(sys::gpu::SDL_GPU_SHADERFORMAT_SPIRV); } impl_with!(bitwise_and_or ShaderFormat u32); -#[derive(Default, Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] -#[repr(u32)] -pub enum TextureUsage { - #[default] - Invalid = 0, - ComputeStorageWrite = sys::gpu::SDL_GPU_TEXTUREUSAGE_COMPUTE_STORAGE_WRITE, - ComputeStorageRead = sys::gpu::SDL_GPU_TEXTUREUSAGE_COMPUTE_STORAGE_READ, - ComputeSimultaneousReadWrite = - sys::gpu::SDL_GPU_TEXTUREUSAGE_COMPUTE_STORAGE_SIMULTANEOUS_READ_WRITE, - DepthStencilTarget = sys::gpu::SDL_GPU_TEXTUREUSAGE_DEPTH_STENCIL_TARGET, - GraphicsStorageRead = sys::gpu::SDL_GPU_TEXTUREUSAGE_GRAPHICS_STORAGE_READ, - Sampler = sys::gpu::SDL_GPU_TEXTUREUSAGE_SAMPLER, - ColorTarget = sys::gpu::SDL_GPU_TEXTUREUSAGE_COLOR_TARGET, +pub struct TextureUsage(pub sys::gpu::SDL_GPUTextureUsageFlags); +impl TextureUsage { + pub const INVALID: Self = + Self(0); + pub const COMPUTE_STORAGE_WRITE: Self = + Self(sys::gpu::SDL_GPU_TEXTUREUSAGE_COMPUTE_STORAGE_WRITE); + pub const COMPUTE_STORAGE_READ: Self = + Self(sys::gpu::SDL_GPU_TEXTUREUSAGE_COMPUTE_STORAGE_READ); + pub const COMPUTE_STORAGE_SIMULTANEOUS_READ_WRITE: Self = + Self(sys::gpu::SDL_GPU_TEXTUREUSAGE_COMPUTE_STORAGE_SIMULTANEOUS_READ_WRITE); + pub const DEPTH_STENCIL_TARGET: Self = + Self(sys::gpu::SDL_GPU_TEXTUREUSAGE_DEPTH_STENCIL_TARGET); + pub const GRAPHICS_STORAGE_READ: Self = + Self(sys::gpu::SDL_GPU_TEXTUREUSAGE_GRAPHICS_STORAGE_READ); + pub const SAMPLER: Self = + Self(sys::gpu::SDL_GPU_TEXTUREUSAGE_SAMPLER); + pub const COLOR_TARGET: Self = + Self(sys::gpu::SDL_GPU_TEXTUREUSAGE_COLOR_TARGET); } impl_with!(bitwise_and_or TextureUsage u32); @@ -342,14 +324,7 @@ pub enum SamplerAddressMode { ClampToEdge = sys::gpu::SDL_GPUSamplerAddressMode::CLAMP_TO_EDGE.0 as u32, } -#[derive(Default, Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] -#[repr(u32)] -pub enum IndexElementSize { - #[default] - _16Bit = sys::gpu::SDL_GPUIndexElementSize::_16BIT.0 as u32, - _32Bit = sys::gpu::SDL_GPUIndexElementSize::_32BIT.0 as u32, -} -impl_with!(bitwise_and_or IndexElementSize u32); +pub type IndexElementSize = sys::gpu::SDL_GPUIndexElementSize; #[derive(Default, Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] #[repr(u32)] @@ -360,25 +335,17 @@ pub enum VertexInputRate { } #[derive(Default, Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] -#[repr(u32)] -pub enum BufferUsageFlags { - #[default] - Vertex = sys::gpu::SDL_GPU_BUFFERUSAGE_VERTEX as u32, - Index = sys::gpu::SDL_GPU_BUFFERUSAGE_INDEX as u32, - Indirect = sys::gpu::SDL_GPU_BUFFERUSAGE_INDIRECT as u32, - GraphicsStorageRead = sys::gpu::SDL_GPU_BUFFERUSAGE_GRAPHICS_STORAGE_READ as u32, - ComputeStorageRead = sys::gpu::SDL_GPU_BUFFERUSAGE_COMPUTE_STORAGE_READ as u32, - ComputeStorageWrite = sys::gpu::SDL_GPU_BUFFERUSAGE_COMPUTE_STORAGE_WRITE as u32, +pub struct BufferUsageFlags(pub sys::gpu::SDL_GPUBufferUsageFlags); +impl BufferUsageFlags { + pub const VERTEX : Self = Self(sys::gpu::SDL_GPU_BUFFERUSAGE_VERTEX); + pub const INDEX : Self = Self(sys::gpu::SDL_GPU_BUFFERUSAGE_INDEX); + pub const INDIRECT : Self = Self(sys::gpu::SDL_GPU_BUFFERUSAGE_INDIRECT); + pub const GRAPHICS_STORAGE_READ : Self = Self(sys::gpu::SDL_GPU_BUFFERUSAGE_GRAPHICS_STORAGE_READ); + pub const COMPUTE_STORAGE_READ : Self = Self(sys::gpu::SDL_GPU_BUFFERUSAGE_COMPUTE_STORAGE_READ); + pub const COMPUTE_STORAGE_WRITE : Self = Self(sys::gpu::SDL_GPU_BUFFERUSAGE_COMPUTE_STORAGE_WRITE); } -#[derive(Default, Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] -#[repr(u32)] -pub enum TransferBufferUsage { - #[default] - Upload = sys::gpu::SDL_GPUTransferBufferUsage::UPLOAD.0 as u32, - Download = sys::gpu::SDL_GPUTransferBufferUsage::DOWNLOAD.0 as u32, -} -impl_with!(bitwise_and_or TransferBufferUsage u32); +pub type TransferBufferUsage = sys::gpu::SDL_GPUTransferBufferUsage; #[derive(Default, Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] #[repr(u32)] @@ -413,12 +380,12 @@ pub enum BlendOp { } #[derive(Default, Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] -#[repr(u8)] -pub enum ColorComponentFlags { - #[default] - RBit = SDL_GPU_COLORCOMPONENT_R, - GBit = SDL_GPU_COLORCOMPONENT_G, - BBit = SDL_GPU_COLORCOMPONENT_B, - ABit = SDL_GPU_COLORCOMPONENT_A, +pub struct ColorComponentFlags(pub sys::gpu::SDL_GPUColorComponentFlags); + +impl ColorComponentFlags { + pub const R: Self = Self(sys::gpu::SDL_GPU_COLORCOMPONENT_R); + pub const G: Self = Self(sys::gpu::SDL_GPU_COLORCOMPONENT_G); + pub const B: Self = Self(sys::gpu::SDL_GPU_COLORCOMPONENT_B); + pub const A: Self = Self(sys::gpu::SDL_GPU_COLORCOMPONENT_A); } impl_with!(bitwise_and_or ColorComponentFlags u8); diff --git a/src/sdl3/gpu/pass.rs b/src/sdl3/gpu/pass.rs index f36ba158..d735a2ac 100644 --- a/src/sdl3/gpu/pass.rs +++ b/src/sdl3/gpu/pass.rs @@ -11,8 +11,8 @@ use sys::gpu::{ SDL_AcquireGPUSwapchainTexture, SDL_BindGPUFragmentSamplers, SDL_BindGPUIndexBuffer, SDL_BindGPUVertexBuffers, SDL_DrawGPUIndexedPrimitives, SDL_GPUBufferBinding, SDL_GPUColorTargetInfo, SDL_GPUCommandBuffer, SDL_GPUComputePass, SDL_GPUCopyPass, - SDL_GPUDepthStencilTargetInfo, SDL_GPUIndexElementSize, SDL_GPULoadOp, SDL_GPURenderPass, - SDL_GPUStoreOp, SDL_GPUTextureSamplerBinding, SDL_PushGPUComputeUniformData, + SDL_GPUDepthStencilTargetInfo, SDL_GPURenderPass, + SDL_GPUTextureSamplerBinding, SDL_PushGPUComputeUniformData, SDL_PushGPUFragmentUniformData, SDL_PushGPUVertexUniformData, SDL_UploadToGPUBuffer, SDL_UploadToGPUTexture, SDL_WaitAndAcquireGPUSwapchainTexture, }; @@ -154,24 +154,22 @@ impl DepthStencilTargetInfo { } pub fn with_load_op(mut self, value: LoadOp) -> Self { - self.inner.load_op = SDL_GPULoadOp(value as i32); + self.inner.load_op = value; self } pub fn with_store_op(mut self, value: StoreOp) -> Self { - self.inner.store_op = SDL_GPUStoreOp(value as i32); + self.inner.store_op = value; self } pub fn with_stencil_load_op(mut self, value: LoadOp) -> Self { - self.inner.stencil_load_op = - unsafe { std::mem::transmute::<_, sys::gpu::SDL_GPULoadOp>(value as u32) }; + self.inner.stencil_load_op = value; self } pub fn with_stencil_store_op(mut self, value: StoreOp) -> Self { - self.inner.stencil_store_op = - unsafe { std::mem::transmute::<_, sys::gpu::SDL_GPUStoreOp>(value as u32) }; + self.inner.stencil_store_op = value; self } @@ -197,13 +195,11 @@ impl ColorTargetInfo { self } pub fn with_load_op(mut self, value: LoadOp) -> Self { - self.inner.load_op = - unsafe { std::mem::transmute::<_, sys::gpu::SDL_GPULoadOp>(value as u32) }; + self.inner.load_op = value; self } pub fn with_store_op(mut self, value: StoreOp) -> Self { - self.inner.store_op = - unsafe { std::mem::transmute::<_, sys::gpu::SDL_GPUStoreOp>(value as u32) }; + self.inner.store_op = value; self } pub fn with_clear_color(mut self, value: Color) -> Self { @@ -273,7 +269,7 @@ impl RenderPass { SDL_BindGPUIndexBuffer( self.raw(), &binding.inner, - SDL_GPUIndexElementSize(index_element_size as i32), + index_element_size, ) } } diff --git a/src/sdl3/gpu/pipeline.rs b/src/sdl3/gpu/pipeline.rs index 12b659ce..08a41c70 100644 --- a/src/sdl3/gpu/pipeline.rs +++ b/src/sdl3/gpu/pipeline.rs @@ -256,7 +256,7 @@ impl ColorTargetBlendState { /// A bitmask specifying which of the RGBA components are enabled for writing. Writes to all channels if enable_color_write_mask is false. pub fn with_color_write_mask(mut self, flags: ColorComponentFlags) -> Self { - self.inner.color_write_mask = flags as u8; + self.inner.color_write_mask = flags.0; self } @@ -463,7 +463,7 @@ impl<'a> ComputePipelineBuilder<'a> { } pub fn with_code(mut self, fmt: ShaderFormat, code: &'a [u8]) -> Self { - self.inner.format = fmt as u32; + self.inner.format = fmt.0; self.inner.code = code.as_ptr(); self.inner.code_size = code.len(); self diff --git a/src/sdl3/gpu/shader.rs b/src/sdl3/gpu/shader.rs index 10352111..65581406 100644 --- a/src/sdl3/gpu/shader.rs +++ b/src/sdl3/gpu/shader.rs @@ -63,7 +63,7 @@ impl<'a> ShaderBuilder<'a> { } pub fn with_code(mut self, fmt: ShaderFormat, code: &'a [u8], stage: ShaderStage) -> Self { - self.inner.format = fmt as u32; + self.inner.format = fmt.0; self.inner.code = code.as_ptr(); self.inner.code_size = code.len() as usize; self.inner.stage = unsafe { std::mem::transmute(stage as u32) }; diff --git a/src/sdl3/gpu/texture.rs b/src/sdl3/gpu/texture.rs index 8c4493c3..8354c4ab 100644 --- a/src/sdl3/gpu/texture.rs +++ b/src/sdl3/gpu/texture.rs @@ -361,7 +361,7 @@ impl TextureCreateInfo { /// How the texture is intended to be used by the client. pub fn with_usage(mut self, value: TextureUsage) -> Self { - self.inner.usage = value as u32; + self.inner.usage = value.0; self } From 44179527c4fb55d8a0a494a87029e3da34fe3260 Mon Sep 17 00:00:00 2001 From: quaternic <57393910+quaternic@users.noreply.github.com> Date: Tue, 1 Apr 2025 23:59:36 +0300 Subject: [PATCH 2/5] major refactoring of the gpu module --- examples/gpu-clear.rs | 15 +- examples/gpu-cube.rs | 131 +-- examples/gpu-texture.rs | 208 ++--- examples/gpu-triangle.rs | 18 +- src/sdl3/event.rs | 2 +- src/sdl3/gpu/buffer.rs | 294 ------- src/sdl3/gpu/command_buffer.rs | 248 ++++++ src/sdl3/gpu/device.rs | 244 ------ src/sdl3/gpu/enums.rs | 112 +-- src/sdl3/gpu/info_struct.rs | 882 +++++++++++++++++++++ src/sdl3/gpu/mod.rs | 164 +++- src/sdl3/gpu/pass.rs | 439 ---------- src/sdl3/gpu/pass_compute.rs | 62 ++ src/sdl3/gpu/pass_copy.rs | 54 ++ src/sdl3/gpu/pass_render.rs | 158 ++++ src/sdl3/gpu/pipeline.rs | 600 -------------- src/sdl3/gpu/resource/buffer.rs | 50 ++ src/sdl3/gpu/resource/builders.rs | 251 ++++++ src/sdl3/gpu/resource/compute_pipeline.rs | 41 + src/sdl3/gpu/resource/device.rs | 40 + src/sdl3/gpu/resource/graphics_pipeline.rs | 41 + src/sdl3/gpu/resource/mod.rs | 43 + src/sdl3/gpu/resource/sampler.rs | 41 + src/sdl3/gpu/resource/shader.rs | 41 + src/sdl3/gpu/resource/texture.rs | 54 ++ src/sdl3/gpu/resource/transfer_buffer.rs | 72 ++ src/sdl3/gpu/shader.rs | 89 --- src/sdl3/gpu/swapchain.rs | 35 + src/sdl3/gpu/texture.rs | 397 ---------- src/sdl3/gpu/util.rs | 29 + 30 files changed, 2483 insertions(+), 2372 deletions(-) delete mode 100644 src/sdl3/gpu/buffer.rs create mode 100644 src/sdl3/gpu/command_buffer.rs delete mode 100644 src/sdl3/gpu/device.rs create mode 100644 src/sdl3/gpu/info_struct.rs delete mode 100644 src/sdl3/gpu/pass.rs create mode 100644 src/sdl3/gpu/pass_compute.rs create mode 100644 src/sdl3/gpu/pass_copy.rs create mode 100644 src/sdl3/gpu/pass_render.rs delete mode 100644 src/sdl3/gpu/pipeline.rs create mode 100644 src/sdl3/gpu/resource/buffer.rs create mode 100644 src/sdl3/gpu/resource/builders.rs create mode 100644 src/sdl3/gpu/resource/compute_pipeline.rs create mode 100644 src/sdl3/gpu/resource/device.rs create mode 100644 src/sdl3/gpu/resource/graphics_pipeline.rs create mode 100644 src/sdl3/gpu/resource/mod.rs create mode 100644 src/sdl3/gpu/resource/sampler.rs create mode 100644 src/sdl3/gpu/resource/shader.rs create mode 100644 src/sdl3/gpu/resource/texture.rs create mode 100644 src/sdl3/gpu/resource/transfer_buffer.rs delete mode 100644 src/sdl3/gpu/shader.rs create mode 100644 src/sdl3/gpu/swapchain.rs delete mode 100644 src/sdl3/gpu/texture.rs create mode 100644 src/sdl3/gpu/util.rs diff --git a/examples/gpu-clear.rs b/examples/gpu-clear.rs index 3d86126d..6c55ef63 100644 --- a/examples/gpu-clear.rs +++ b/examples/gpu-clear.rs @@ -17,7 +17,8 @@ pub fn main() -> Result<(), Box> { // by default, and we specify that our shaders will be SPIR-V ones (even through we // aren't using any shaders) // We'll also turn on debug mode to true, so we get debug stuff - let gpu = sdl3::gpu::Device::new(sdl3::gpu::ShaderFormat::SPIRV, true)?.with_window(&window)?; + let gpu = sdl3::gpu::Device::new(sdl3::gpu::ShaderFormat::SPIRV, true)?; + gpu.claim_window(&window)?; let mut event_pump = sdl_context.event_pump()?; println!( @@ -50,10 +51,14 @@ pub fn main() -> Result<(), Box> { .with_clear_color(sdl3::pixels::Color::RGB(5, 3, 255)), //blue with small RG bias ]; // Here we do all (none) of our drawing (clearing the screen) - let render_pass = gpu.begin_render_pass(&command_buffer, &color_targets, None)?; - // Do absolutely nothing -- this clears the screen because of the defined operations above - // which are ALWAYS done even through we just created and ended a render pass - gpu.end_render_pass(render_pass); + command_buffer.render_pass( + &color_targets, + None, + |_cmd, _pass| { + // Do absolutely nothing -- this clears the screen because of the defined operations above + // which are ALWAYS done even through we just created and ended a render pass + } + )?; command_buffer.submit()?; } else { // Swapchain unavailable, cancel work diff --git a/examples/gpu-cube.rs b/examples/gpu-cube.rs index 78928f5a..5bbfad30 100644 --- a/examples/gpu-cube.rs +++ b/examples/gpu-cube.rs @@ -91,8 +91,8 @@ pub fn main() -> Result<(), Box> { let gpu = Device::new( ShaderFormat::SPIRV | ShaderFormat::DXIL | ShaderFormat::DXBC | ShaderFormat::METALLIB, true, - )? - .with_window(&window)?; + )?; + gpu.claim_window(&window)?; // Our shaders, require to be precompiled by a SPIR-V compiler beforehand let vert_shader = gpu @@ -156,7 +156,7 @@ pub fn main() -> Result<(), Box> { ColorTargetDescription::new().with_format(swapchain_format) ]) .with_has_depth_stencil_target(true) - .with_depth_stencil_format(TextureFormat::D16Unorm), + .with_depth_stencil_format(TextureFormat::D16_UNORM), ) .build()?; @@ -168,49 +168,51 @@ pub fn main() -> Result<(), Box> { // our vertices or indices since we will be transferring both with it. let vertices_len_bytes = CUBE_VERTICES.len() * size_of::(); let indices_len_bytes = CUBE_INDICES.len() * size_of::(); - let transfer_buffer = gpu + let mut transfer_buffer = gpu .create_transfer_buffer() .with_size(vertices_len_bytes.max(indices_len_bytes) as u32) .with_usage(TransferBufferUsage::UPLOAD) .build()?; // We need to start a copy pass in order to transfer data to the GPU - let copy_commands = gpu.acquire_command_buffer()?; - let copy_pass = gpu.begin_copy_pass(©_commands)?; + let mut copy_commands = gpu.acquire_command_buffer()?; + let (vertex_buffer, index_buffer) = copy_commands.copy_pass( + |_cmd, copy_pass| { + // Create GPU buffers to hold our vertices and indices and transfer data to them + let vertex_buffer = create_buffer_with_data( + &gpu, + &mut transfer_buffer, + ©_pass, + BufferUsageFlags::VERTEX, + &CUBE_VERTICES, + ).unwrap(); + let index_buffer = create_buffer_with_data( + &gpu, + &mut transfer_buffer, + ©_pass, + BufferUsageFlags::INDEX, + &CUBE_INDICES, + ).unwrap(); + // We're done with the transfer buffer now, so release it. + drop(transfer_buffer); - // Create GPU buffers to hold our vertices and indices and transfer data to them - let vertex_buffer = create_buffer_with_data( - &gpu, - &transfer_buffer, - ©_pass, - BufferUsageFlags::VERTEX, - &CUBE_VERTICES, - )?; - let index_buffer = create_buffer_with_data( - &gpu, - &transfer_buffer, - ©_pass, - BufferUsageFlags::INDEX, - &CUBE_INDICES, + (vertex_buffer, index_buffer) + } )?; - // We're done with the transfer buffer now, so release it. - drop(transfer_buffer); - // Now complete and submit the copy pass commands to actually do the transfer work - gpu.end_copy_pass(copy_pass); copy_commands.submit()?; // We'll need to allocate a texture buffer for our depth buffer for depth testing to work let mut depth_texture = gpu.create_texture( - TextureCreateInfo::new() + &TextureCreateInfo::new() .with_type(TextureType::_2D) .with_width(WINDOW_SIZE) .with_height(WINDOW_SIZE) .with_layer_count_or_depth(1) .with_num_levels(1) .with_sample_count(SampleCount::NoMultiSampling) - .with_format(TextureFormat::D16Unorm) + .with_format(TextureFormat::D16_UNORM) .with_usage(TextureUsage::SAMPLER | TextureUsage::DEPTH_STENCIL_TARGET), )?; @@ -251,34 +253,35 @@ pub fn main() -> Result<(), Box> { .with_store_op(StoreOp::STORE) .with_stencil_load_op(LoadOp::CLEAR) .with_stencil_store_op(StoreOp::STORE); - let render_pass = - gpu.begin_render_pass(&command_buffer, &color_targets, Some(&depth_target))?; - - // Screen is cleared below due to the color target info - render_pass.bind_graphics_pipeline(&pipeline); - - // Now we'll bind our buffers and draw the cube - render_pass.bind_vertex_buffers( - 0, - &[BufferBinding::new() - .with_buffer(&vertex_buffer) - .with_offset(0)], - ); - render_pass.bind_index_buffer( - &BufferBinding::new() - .with_buffer(&index_buffer) - .with_offset(0), - IndexElementSize::_16BIT, - ); + command_buffer.render_pass( + &color_targets, + Some(&depth_target), + |command_buffer, render_pass| { + // Screen is cleared below due to the color target info + render_pass.bind_graphics_pipeline(&pipeline); - // Set the rotation uniform for our cube vert shader - command_buffer.push_vertex_uniform_data(0, &rotation); - rotation += 0.1f32; + // Now we'll bind our buffers and draw the cube + render_pass.bind_vertex_buffers( + 0, + &[BufferBinding::new() + .with_buffer(&vertex_buffer) + .with_offset(0)], + ); + render_pass.bind_index_buffer( + &BufferBinding::new() + .with_buffer(&index_buffer) + .with_offset(0), + IndexElementSize::_16BIT, + ); - // Finally, draw the cube - render_pass.draw_indexed_primitives(CUBE_INDICES.len() as u32, 1, 0, 0, 0); + // Set the rotation uniform for our cube vert shader + command_buffer.push_vertex_uniform_data(0, &rotation); + rotation += 0.1f32; - gpu.end_render_pass(render_pass); + // Finally, draw the cube + render_pass.draw_indexed_primitives(CUBE_INDICES.len() as u32, 1, 0, 0, 0); + } + )?; command_buffer.submit()?; } else { // Swapchain unavailable, cancel work @@ -290,13 +293,13 @@ pub fn main() -> Result<(), Box> { } /// Creates a GPU buffer and uploads data to it using the given `copy_pass` and `transfer_buffer`. -fn create_buffer_with_data( - gpu: &Device, - transfer_buffer: &TransferBuffer, +fn create_buffer_with_data<'gpu, T: Copy>( + gpu: &'gpu Device, + transfer_buffer: &mut TransferBuffer, copy_pass: &CopyPass, usage: BufferUsageFlags, data: &[T], -) -> Result { +) -> Result, Error> { // Figure out the length of the data in bytes let len_bytes = data.len() * std::mem::size_of::(); @@ -312,14 +315,16 @@ fn create_buffer_with_data( // Note: We set `cycle` to true since we're reusing the same transfer buffer to // initialize both the vertex and index buffer. This makes SDL synchronize the transfers // so that one doesn't interfere with the other. - let mut map = transfer_buffer.map::(gpu, true); - let mem = map.mem_mut(); - for (index, &value) in data.iter().enumerate() { - mem[index] = value; - } - - // Now unmap the memory since we're done copying - map.unmap(); + transfer_buffer.mapped_mut( + true, + |bytes| unsafe { + std::ptr::copy_nonoverlapping::( + data.as_ptr() as *const u8, + bytes.as_mut_ptr(), + len_bytes + ); + } + )?; // Finally, add a command to the copy pass to upload this data to the GPU // diff --git a/examples/gpu-texture.rs b/examples/gpu-texture.rs index 759b9984..04d6f2ff 100644 --- a/examples/gpu-texture.rs +++ b/examples/gpu-texture.rs @@ -196,8 +196,8 @@ pub fn main() -> Result<(), Box> { let gpu = sdl3::gpu::Device::new( ShaderFormat::SPIRV | ShaderFormat::DXIL | ShaderFormat::DXBC | ShaderFormat::METALLIB, true, - )? - .with_window(&window)?; + )?; + gpu.claim_window(&window)?; // Our shaders, require to be precompiled by a SPIR-V compiler beforehand let vert_shader = gpu @@ -269,7 +269,7 @@ pub fn main() -> Result<(), Box> { ColorTargetDescription::new().with_format(swapchain_format) ]) .with_has_depth_stencil_target(true) - .with_depth_stencil_format(TextureFormat::D16Unorm), + .with_depth_stencil_format(TextureFormat::D16_UNORM), ) .build()?; @@ -281,63 +281,65 @@ pub fn main() -> Result<(), Box> { // our vertices or indices since we will be transferring both with it. let vertices_len_bytes = CUBE_VERTICES.len() * size_of::(); let indices_len_bytes = CUBE_INDICES.len() * size_of::(); - let transfer_buffer = gpu + let mut transfer_buffer = gpu .create_transfer_buffer() .with_size(vertices_len_bytes.max(indices_len_bytes) as u32) .with_usage(TransferBufferUsage::UPLOAD) .build()?; // We need to start a copy pass in order to transfer data to the GPU - let copy_commands = gpu.acquire_command_buffer()?; - let copy_pass = gpu.begin_copy_pass(©_commands)?; - - // Create GPU buffers to hold our vertices and indices and transfer data to them - let vertex_buffer = create_buffer_with_data( - &gpu, - &transfer_buffer, - ©_pass, - BufferUsageFlags::VERTEX, - &CUBE_VERTICES, - )?; - let index_buffer = create_buffer_with_data( - &gpu, - &transfer_buffer, - ©_pass, - BufferUsageFlags::INDEX, - &CUBE_INDICES, - )?; - - // We're done with the transfer buffer now, so release it. - drop(transfer_buffer); - - // Load up a texture to put on the cube - let cube_texture = create_texture_from_image(&gpu, "./assets/texture.bmp", ©_pass)?; - - // And configure a sampler for pulling pixels from that texture in the frag shader - let cube_texture_sampler = gpu.create_sampler( - SamplerCreateInfo::new() - .with_min_filter(Filter::Nearest) - .with_mag_filter(Filter::Nearest) - .with_mipmap_mode(SamplerMipmapMode::Nearest) - .with_address_mode_u(SamplerAddressMode::Repeat) - .with_address_mode_v(SamplerAddressMode::Repeat) - .with_address_mode_w(SamplerAddressMode::Repeat), - )?; + let mut copy_commands = gpu.acquire_command_buffer()?; + let (vertex_buffer, index_buffer, cube_texture, cube_texture_sampler) + = copy_commands.copy_pass(|_cmd, copy_pass| { + // Create GPU buffers to hold our vertices and indices and transfer data to them + let vertex_buffer = create_buffer_with_data( + &gpu, + &mut transfer_buffer, + ©_pass, + BufferUsageFlags::VERTEX, + &CUBE_VERTICES, + ).unwrap(); + let index_buffer = create_buffer_with_data( + &gpu, + &mut transfer_buffer, + ©_pass, + BufferUsageFlags::INDEX, + &CUBE_INDICES, + ).unwrap(); + + // We're done with the transfer buffer now, so release it. + drop(transfer_buffer); + + // Load up a texture to put on the cube + let cube_texture = create_texture_from_image(&gpu, "./assets/texture.bmp", ©_pass).unwrap(); + + // And configure a sampler for pulling pixels from that texture in the frag shader + let cube_texture_sampler = gpu.create_sampler( + SamplerCreateInfo::new() + .with_min_filter(Filter::Nearest) + .with_mag_filter(Filter::Nearest) + .with_mipmap_mode(SamplerMipmapMode::Nearest) + .with_address_mode_u(SamplerAddressMode::Repeat) + .with_address_mode_v(SamplerAddressMode::Repeat) + .with_address_mode_w(SamplerAddressMode::Repeat), + ).unwrap(); + + (vertex_buffer, index_buffer, cube_texture, cube_texture_sampler) + })?; // Now complete and submit the copy pass commands to actually do the transfer work - gpu.end_copy_pass(copy_pass); copy_commands.submit()?; // We'll need to allocate a texture buffer for our depth buffer for depth testing to work let mut depth_texture = gpu.create_texture( - TextureCreateInfo::new() + &TextureCreateInfo::new() .with_type(TextureType::_2D) .with_width(WINDOW_SIZE) .with_height(WINDOW_SIZE) .with_layer_count_or_depth(1) .with_num_levels(1) .with_sample_count(SampleCount::NoMultiSampling) - .with_format(TextureFormat::D16Unorm) + .with_format(TextureFormat::D16_UNORM) .with_usage(TextureUsage::SAMPLER | TextureUsage::DEPTH_STENCIL_TARGET) )?; @@ -378,40 +380,43 @@ pub fn main() -> Result<(), Box> { .with_store_op(StoreOp::STORE) .with_stencil_load_op(LoadOp::CLEAR) .with_stencil_store_op(StoreOp::STORE); - let render_pass = - gpu.begin_render_pass(&command_buffer, &color_targets, Some(&depth_target))?; - - // Screen is cleared below due to the color target info - render_pass.bind_graphics_pipeline(&pipeline); - - // Now we'll bind our buffers/sampler and draw the cube - render_pass.bind_vertex_buffers( - 0, - &[BufferBinding::new() - .with_buffer(&vertex_buffer) - .with_offset(0)], - ); - render_pass.bind_index_buffer( - &BufferBinding::new() - .with_buffer(&index_buffer) - .with_offset(0), - IndexElementSize::_16BIT, - ); - render_pass.bind_fragment_samplers( - 0, - &[TextureSamplerBinding::new() - .with_texture(&cube_texture) - .with_sampler(&cube_texture_sampler)], - ); - - // Set the rotation uniform for our cube vert shader - command_buffer.push_vertex_uniform_data(0, &rotation); - rotation += 0.1f32; - - // Finally, draw the cube - render_pass.draw_indexed_primitives(CUBE_INDICES.len() as u32, 1, 0, 0, 0); + + command_buffer.render_pass( + &color_targets, + Some(&depth_target), + |command_buffer, render_pass| { + // Screen is cleared below due to the color target info + render_pass.bind_graphics_pipeline(&pipeline); + + // Now we'll bind our buffers/sampler and draw the cube + render_pass.bind_vertex_buffers( + 0, + &[BufferBinding::new() + .with_buffer(&vertex_buffer) + .with_offset(0)], + ); + render_pass.bind_index_buffer( + &BufferBinding::new() + .with_buffer(&index_buffer) + .with_offset(0), + IndexElementSize::_16BIT, + ); + render_pass.bind_fragment_samplers( + 0, + &[TextureSamplerBinding::new() + .with_texture(&cube_texture) + .with_sampler(&cube_texture_sampler)], + ); + + // Set the rotation uniform for our cube vert shader + command_buffer.push_vertex_uniform_data(0, &rotation); + rotation += 0.1f32; + + // Finally, draw the cube + render_pass.draw_indexed_primitives(CUBE_INDICES.len() as u32, 1, 0, 0, 0); + } + )?; - gpu.end_render_pass(render_pass); command_buffer.submit()?; } else { // Swapchain unavailable, cancel work @@ -422,19 +427,19 @@ pub fn main() -> Result<(), Box> { Ok(()) } -fn create_texture_from_image( - gpu: &Device, +fn create_texture_from_image<'gpu>( + gpu: &'gpu Device, image_path: impl AsRef, copy_pass: &CopyPass, -) -> Result, Error> { +) -> Result, Error> { let image = Surface::load_bmp(image_path.as_ref())?; let image_size = image.size(); let size_bytes = image.pixel_format().byte_size_per_pixel() as u32 * image_size.0 * image_size.1; let texture = gpu.create_texture( - TextureCreateInfo::new() - .with_format(TextureFormat::R8g8b8a8Unorm) + &TextureCreateInfo::new() + .with_format(TextureFormat::R8G8B8A8_UNORM) .with_type(TextureType::_2D) .with_width(image_size.0) .with_height(image_size.1) @@ -443,17 +448,22 @@ fn create_texture_from_image( .with_usage(TextureUsage::SAMPLER), )?; - let transfer_buffer = gpu + let mut transfer_buffer = gpu .create_transfer_buffer() .with_size(size_bytes) .with_usage(TransferBufferUsage::UPLOAD) .build()?; - let mut buffer_mem = transfer_buffer.map::(gpu, false); - image.with_lock(|image_bytes| { - buffer_mem.mem_mut().copy_from_slice(image_bytes); - }); - buffer_mem.unmap(); + transfer_buffer.mapped_mut( + false, + |bytes| image.with_lock(|image_bytes| unsafe { + std::ptr::copy_nonoverlapping::( + image_bytes.as_ptr(), + bytes.as_mut_ptr(), + image_bytes.len() + ); + }) + )?; copy_pass.upload_to_gpu_texture( TextureTransferInfo::new() @@ -472,13 +482,13 @@ fn create_texture_from_image( } /// Creates a GPU buffer and uploads data to it using the given `copy_pass` and `transfer_buffer`. -fn create_buffer_with_data( - gpu: &Device, - transfer_buffer: &TransferBuffer, +fn create_buffer_with_data<'gpu, T: Copy>( + gpu: &'gpu Device, + transfer_buffer: &mut TransferBuffer, copy_pass: &CopyPass, usage: BufferUsageFlags, data: &[T], -) -> Result { +) -> Result, Error> { // Figure out the length of the data in bytes let len_bytes = data.len() * std::mem::size_of::(); @@ -494,14 +504,16 @@ fn create_buffer_with_data( // Note: We set `cycle` to true since we're reusing the same transfer buffer to // initialize both the vertex and index buffer. This makes SDL synchronize the transfers // so that one doesn't interfere with the other. - let mut map = transfer_buffer.map::(gpu, true); - let mem = map.mem_mut(); - for (index, &value) in data.iter().enumerate() { - mem[index] = value; - } - - // Now unmap the memory since we're done copying - map.unmap(); + transfer_buffer.mapped_mut( + true, + |bytes| unsafe { + std::ptr::copy_nonoverlapping::( + data.as_ptr() as *const u8, + bytes.as_mut_ptr(), + len_bytes + ); + } + )?; // Finally, add a command to the copy pass to upload this data to the GPU // diff --git a/examples/gpu-triangle.rs b/examples/gpu-triangle.rs index 2011f5c5..6779a1ef 100644 --- a/examples/gpu-triangle.rs +++ b/examples/gpu-triangle.rs @@ -27,8 +27,8 @@ pub fn main() -> Result<(), Box> { let gpu = Device::new( ShaderFormat::SPIRV | ShaderFormat::DXIL | ShaderFormat::DXBC | ShaderFormat::METALLIB, true, - )? - .with_window(&window)?; + )?; + gpu.claim_window(&window)?; let fs_source = include_bytes!("shaders/triangle.frag.spv"); let vs_source = include_bytes!("shaders/triangle.vert.spv"); @@ -99,12 +99,14 @@ pub fn main() -> Result<(), Box> { .with_store_op(StoreOp::STORE) .with_clear_color(Color::RGB(5, 3, 255)), //blue with small RG bias ]; - let render_pass = gpu.begin_render_pass(&command_buffer, &color_targets, None)?; - render_pass.bind_graphics_pipeline(&pipeline); - // Screen is cleared here due to the color target info - // Now we'll draw the triangle primitives - render_pass.draw_primitives(3, 1, 0, 0); - gpu.end_render_pass(render_pass); + + command_buffer.render_pass(&color_targets, None, |_cmd, render_pass| { + render_pass.bind_graphics_pipeline(&pipeline); + // Screen is cleared here due to the color target info + // Now we'll draw the triangle primitives + render_pass.draw_primitives(3, 1, 0, 0); + })?; + command_buffer.submit()?; } else { // Swapchain unavailable, cancel work diff --git a/src/sdl3/event.rs b/src/sdl3/event.rs index 2873be66..a0caa5cd 100644 --- a/src/sdl3/event.rs +++ b/src/sdl3/event.rs @@ -1005,7 +1005,7 @@ unsafe impl Sync for Event {} // This would honestly be nice if it took &self instead of self, // but Event::User's raw pointers kind of removes that possibility. impl Event { - fn to_ll(&self) -> Option { + pub fn to_ll(&self) -> Option { let mut ret = mem::MaybeUninit::uninit(); match *self { Event::User { diff --git a/src/sdl3/gpu/buffer.rs b/src/sdl3/gpu/buffer.rs deleted file mode 100644 index 3f3434b2..00000000 --- a/src/sdl3/gpu/buffer.rs +++ /dev/null @@ -1,294 +0,0 @@ -use crate::{ - get_error, - gpu::{device::WeakDevice, BufferUsageFlags, Device, TransferBufferUsage, VertexInputRate}, - sys, Error, -}; -use std::sync::Arc; -use sys::gpu::{ - SDL_CreateGPUBuffer, SDL_CreateGPUTransferBuffer, SDL_GPUBuffer, SDL_GPUBufferBinding, - SDL_GPUBufferCreateInfo, SDL_GPUBufferRegion, SDL_GPUTransferBuffer, - SDL_GPUTransferBufferCreateInfo, SDL_GPUTransferBufferLocation, - SDL_GPUVertexBufferDescription, SDL_GPUVertexInputRate, SDL_MapGPUTransferBuffer, - SDL_ReleaseGPUBuffer, SDL_ReleaseGPUTransferBuffer, SDL_UnmapGPUTransferBuffer, -}; - -#[repr(C)] -#[derive(Default)] -pub struct BufferBinding { - pub(super) inner: SDL_GPUBufferBinding, -} -impl BufferBinding { - pub fn new() -> Self { - Default::default() - } - - pub fn with_buffer(mut self, buffer: &Buffer) -> Self { - self.inner.buffer = buffer.raw(); - self - } - - pub fn with_offset(mut self, offset: u32) -> Self { - self.inner.offset = offset; - self - } -} - -#[derive(Default)] -pub struct TransferBufferLocation { - pub(super) inner: SDL_GPUTransferBufferLocation, -} -impl TransferBufferLocation { - pub fn new() -> Self { - Default::default() - } - - pub fn with_transfer_buffer(mut self, transfer_buffer: &TransferBuffer) -> Self { - self.inner.transfer_buffer = transfer_buffer.raw(); - self - } - - pub fn with_offset(mut self, offset: u32) -> Self { - self.inner.offset = offset; - self - } -} - -#[derive(Default)] -pub struct BufferRegion { - pub(super) inner: SDL_GPUBufferRegion, -} -impl BufferRegion { - pub fn new() -> Self { - Default::default() - } - - pub fn with_buffer(mut self, buffer: &Buffer) -> Self { - self.inner.buffer = buffer.raw(); - self - } - - pub fn with_offset(mut self, offset: u32) -> Self { - self.inner.offset = offset; - self - } - - pub fn with_size(mut self, size: u32) -> Self { - self.inner.size = size; - self - } -} - -#[repr(C)] -#[derive(Clone, Default)] -pub struct VertexBufferDescription { - inner: SDL_GPUVertexBufferDescription, -} -impl VertexBufferDescription { - pub fn new() -> Self { - Default::default() - } - - pub fn with_slot(mut self, value: u32) -> Self { - self.inner.slot = value; - self - } - - pub fn with_pitch(mut self, value: u32) -> Self { - self.inner.pitch = value; - self - } - - pub fn with_input_rate(mut self, value: VertexInputRate) -> Self { - self.inner.input_rate = SDL_GPUVertexInputRate(value as i32); - self - } - - pub fn with_instance_step_rate(mut self, value: u32) -> Self { - self.inner.instance_step_rate = value; - self - } -} - -/// Manages the raw `SDL_GPUBuffer` pointer and releases it on drop -struct BufferContainer { - raw: *mut SDL_GPUBuffer, - device: WeakDevice, -} -impl Drop for BufferContainer { - #[doc(alias = "SDL_ReleaseGPUBuffer")] - fn drop(&mut self) { - if let Some(device) = self.device.upgrade() { - unsafe { - SDL_ReleaseGPUBuffer(device.raw(), self.raw); - } - } - } -} - -#[doc(alias = "SDL_GPUBuffer")] -#[derive(Clone)] -pub struct Buffer { - inner: Arc, - len: u32, -} -impl Buffer { - /// Yields the raw SDL_GPUBuffer pointer. - #[inline] - pub fn raw(&self) -> *mut SDL_GPUBuffer { - self.inner.raw - } - - /// The length of this buffer in bytes. - pub fn len(&self) -> u32 { - self.len - } -} - -pub struct BufferBuilder<'a> { - device: &'a Device, - inner: SDL_GPUBufferCreateInfo, -} -impl<'a> BufferBuilder<'a> { - pub(super) fn new(device: &'a Device) -> Self { - Self { - device, - inner: Default::default(), - } - } - - pub fn with_usage(mut self, value: BufferUsageFlags) -> Self { - self.inner.usage = value.0; - self - } - - pub fn with_size(mut self, value: u32) -> Self { - self.inner.size = value; - self - } - - pub fn build(self) -> Result { - let raw_buffer = unsafe { SDL_CreateGPUBuffer(self.device.raw(), &self.inner) }; - if raw_buffer.is_null() { - Err(get_error()) - } else { - Ok(Buffer { - len: self.inner.size, - inner: Arc::new(BufferContainer { - raw: raw_buffer, - device: self.device.weak(), - }), - }) - } - } -} - -/// Mapped memory for a transfer buffer. -pub struct BufferMemMap<'a, T> { - device: &'a Device, - transfer_buffer: &'a TransferBuffer, - mem: *mut T, -} - -impl<'a, T> BufferMemMap<'a, T> -where - T: Copy, -{ - /// Access the memory as a readonly slice. - pub fn mem(&self) -> &[T] { - let count = self.transfer_buffer.len() as usize / std::mem::size_of::(); - unsafe { std::slice::from_raw_parts(self.mem, count) } - } - - /// Access the memory as a mutable slice. - pub fn mem_mut(&mut self) -> &mut [T] { - let count = self.transfer_buffer.len() as usize / std::mem::size_of::(); - unsafe { std::slice::from_raw_parts_mut(self.mem, count) } - } - - #[doc(alias = "SDL_UnmapGPUTransferBuffer")] - pub fn unmap(self) { - unsafe { SDL_UnmapGPUTransferBuffer(self.device.raw(), self.transfer_buffer.raw()) }; - } -} - -/// Manages the raw `SDL_GPUTransferBuffer` pointer and releases it on drop -struct TransferBufferContainer { - raw: *mut SDL_GPUTransferBuffer, - device: WeakDevice, -} -impl Drop for TransferBufferContainer { - #[doc(alias = "SDL_ReleaseGPUTransferBuffer")] - fn drop(&mut self) { - if let Some(device) = self.device.upgrade() { - unsafe { - SDL_ReleaseGPUTransferBuffer(device.raw(), self.raw); - } - } - } -} - -#[derive(Clone)] -pub struct TransferBuffer { - inner: Arc, - len: u32, -} -impl TransferBuffer { - #[inline] - pub fn raw(&self) -> *mut SDL_GPUTransferBuffer { - self.inner.raw - } - - #[doc(alias = "SDL_MapGPUTransferBuffer")] - pub fn map<'a, T: Copy>(&'a self, device: &'a Device, cycle: bool) -> BufferMemMap<'a, T> { - BufferMemMap { - device, - transfer_buffer: self, - mem: unsafe { SDL_MapGPUTransferBuffer(device.raw(), self.raw(), cycle) } as *mut T, - } - } - - /// The length of this buffer in bytes. - pub fn len(&self) -> u32 { - self.len - } -} - -pub struct TransferBufferBuilder<'a> { - device: &'a Device, - inner: SDL_GPUTransferBufferCreateInfo, -} -impl<'a> TransferBufferBuilder<'a> { - pub(super) fn new(device: &'a Device) -> Self { - Self { - device, - inner: Default::default(), - } - } - - /// How the buffer will be used. - pub fn with_usage(mut self, value: TransferBufferUsage) -> Self { - self.inner.usage = value; - self - } - - /// Desired size of the buffer in bytes. - pub fn with_size(mut self, value: u32) -> Self { - self.inner.size = value; - self - } - - pub fn build(self) -> Result { - let raw_buffer = unsafe { SDL_CreateGPUTransferBuffer(self.device.raw(), &self.inner) }; - if raw_buffer.is_null() { - Err(get_error()) - } else { - Ok(TransferBuffer { - inner: Arc::new(TransferBufferContainer { - raw: raw_buffer, - device: self.device.weak(), - }), - len: self.inner.size, - }) - } - } -} diff --git a/src/sdl3/gpu/command_buffer.rs b/src/sdl3/gpu/command_buffer.rs new file mode 100644 index 00000000..bcf4bf6b --- /dev/null +++ b/src/sdl3/gpu/command_buffer.rs @@ -0,0 +1,248 @@ + +use std::{marker::PhantomData, ops::{Deref, DerefMut}, ptr::NonNull}; + +use crate::{get_error, gpu::{util::nonnull_ext_or_get_error, ComputePass}, Error}; + +use super::{ + swapchain::SwapchainTexture, util::Defer, ColorTargetInfo, CopyPass, + DepthStencilTargetInfo, Extern, ExternDevice, RenderPass, + StorageBufferReadWriteBinding, StorageTextureReadWriteBinding +}; + +use sys::gpu::{ + SDL_AcquireGPUCommandBuffer, SDL_AcquireGPUSwapchainTexture, + SDL_BeginGPUComputePass, SDL_BeginGPUCopyPass, + SDL_BeginGPURenderPass, SDL_GPUColorTargetInfo, + SDL_GPUCommandBuffer, SDL_GPUDepthStencilTargetInfo, + SDL_GPUDevice, SDL_PushGPUComputeUniformData, SDL_PushGPUFragmentUniformData, + SDL_PushGPUVertexUniformData, SDL_WaitAndAcquireGPUSwapchainTexture +}; + +#[repr(transparent)] +pub struct CommandBuffer<'gpu> { + pub(super) raw: NonNull>, + pub(super) _marker: std::marker::PhantomData<&'gpu SDL_GPUDevice>, +} + +impl<'gpu> Deref for CommandBuffer<'gpu> { + type Target = Extern; + + fn deref(&self) -> &Self::Target { + unsafe { self.raw.as_ref() } + } +} + +impl<'gpu> DerefMut for CommandBuffer<'gpu> { + fn deref_mut(&mut self) -> &mut Self::Target { + unsafe { self.raw.as_mut() } + } +} + +impl<'gpu> CommandBuffer<'gpu> { + pub(crate) fn new(device: &'gpu ExternDevice) -> Result { + let raw = nonnull_ext_or_get_error(unsafe { + SDL_AcquireGPUCommandBuffer(device.raw()) + })?; + Ok(CommandBuffer { raw, _marker: PhantomData } ) + } + + #[doc(alias = "SDL_SubmitGPUCommandBuffer")] + pub fn submit(self) -> Result<(), Error> { + if unsafe { sys::gpu::SDL_SubmitGPUCommandBuffer(self.raw()) } { + Ok(()) + } else { + Err(get_error()) + } + } + + #[doc(alias = "SDL_CancelGPUCommandBuffer")] + pub fn cancel(self) { + unsafe { + sys::gpu::SDL_CancelGPUCommandBuffer(self.raw()); + } + } +} + +impl Extern { + #[doc(alias = "SDL_BeginGPUComputePass")] + pub fn compute_pass( + &mut self, + storage_texture_bindings: &[StorageTextureReadWriteBinding], + storage_buffer_bindings: &[StorageBufferReadWriteBinding], + pass: impl for<'a> FnOnce(&'a Extern, &'a mut ComputePass) -> R, + ) -> Result { + let raw = nonnull_ext_or_get_error(unsafe { + SDL_BeginGPUComputePass( + self.raw(), + storage_texture_bindings.as_ptr().cast(), + storage_buffer_bindings.len() as u32, + storage_buffer_bindings.as_ptr().cast(), + storage_buffer_bindings.len() as u32, + ) + })?; + + let _defer = Defer::new(|| unsafe { + sys::gpu::SDL_EndGPUComputePass(raw.as_ptr().cast()); + }); + + Ok(pass(&*self, &mut ComputePass { raw })) + } + + #[doc(alias = "SDL_BeginGPURenderPass")] + pub fn render_pass( + &mut self, + color_info: &[ColorTargetInfo], + depth_stencil_target: Option<&DepthStencilTargetInfo>, + pass: impl for<'a> FnOnce(&'a Extern, &'a mut RenderPass) -> R, + ) -> Result { + let raw = nonnull_ext_or_get_error(unsafe { + SDL_BeginGPURenderPass( + self.raw(), + color_info.as_ptr() as *const SDL_GPUColorTargetInfo, //heavy promise + color_info.len() as u32, + if let Some(p) = depth_stencil_target { + p as *const _ as *const SDL_GPUDepthStencilTargetInfo //heavy promise + } else { + std::ptr::null() + }, + ) + })?; + + let _defer = Defer::new(|| unsafe { + sys::gpu::SDL_EndGPURenderPass(raw.as_ptr().cast()); + }); + + Ok(pass(&*self, &mut RenderPass { raw })) + } + + #[doc(alias = "SDL_BeginGPUCopyPass")] + pub fn copy_pass( + &mut self, + pass: impl for<'a> FnOnce(&'a Extern, &'a mut CopyPass) -> R, + ) -> Result { + let raw = nonnull_ext_or_get_error(unsafe { + SDL_BeginGPUCopyPass(self.raw()) + })?; + + let _defer = Defer::new(|| unsafe { + sys::gpu::SDL_EndGPUCopyPass(raw.as_ptr().cast()); + }); + + Ok(pass(&*self, &mut CopyPass { raw })) + } + + // FIXME: + // The lifetime here isn't quite right. + // The swapchain texture can only be used with the command buffer it + // was obtained from, but we also can't borrow the command buffer here + // without preventing you from running passes. + #[doc(alias = "SDL_WaitAndAcquireGPUSwapchainTexture")] + pub fn wait_and_acquire_swapchain_texture<'a>( + &mut self, + w: &'a crate::video::Window, + ) -> Result, Option> { + let mut raw = std::ptr::null_mut(); + let mut width = 0; + let mut height = 0; + let success = unsafe { + SDL_WaitAndAcquireGPUSwapchainTexture( + self.raw(), + w.raw(), + &mut raw, + &mut width, + &mut height, + ) + }; + let raw = raw.cast(); + if success { + if let Some(raw) = NonNull::new(raw) { + Ok( + SwapchainTexture { + raw, + width, + height, + _marker: PhantomData, + } + ) + } else { + Err(None) + } + } else { + Err(Some(get_error())) + } + } + + #[doc(alias = "SDL_AcquireGPUSwapchainTexture")] + pub fn acquire_swapchain_texture<'a>( + &mut self, + w: &'a crate::video::Window, + ) -> Result, Option> { + let mut raw = std::ptr::null_mut(); + let mut width = 0; + let mut height = 0; + let success = unsafe { + SDL_AcquireGPUSwapchainTexture( + self.raw(), + w.raw(), + &mut raw, + &mut width, + &mut height, + ) + }; + let raw = raw.cast(); + if success { + if let Some(raw) = NonNull::new(raw) { + Ok( + SwapchainTexture { + raw, + width, + height, + _marker: PhantomData, + } + ) + } else { + Err(None) + } + } else { + Err(Some(get_error())) + } + } +} + +impl Extern { + #[doc(alias = "SDL_PushGPUVertexUniformData")] + pub fn push_vertex_uniform_data(&self, slot_index: u32, data: &T) { + unsafe { + SDL_PushGPUVertexUniformData( + self.raw(), + slot_index, + (data as *const T) as *const std::ffi::c_void, + size_of::() as u32, + ) + } + } + + #[doc(alias = "SDL_PushGPUFragmentUniformData")] + pub fn push_fragment_uniform_data(&self, slot_index: u32, data: &T) { + unsafe { + SDL_PushGPUFragmentUniformData( + self.raw(), + slot_index, + (data as *const T) as *const std::ffi::c_void, + size_of::() as u32, + ) + } + } + + #[doc(alias = "SDL_PushGPUComputeUniformData")] + pub fn push_compute_uniform_data(&self, slot_index: u32, data: &T) { + unsafe { + SDL_PushGPUComputeUniformData( + self.raw(), + slot_index, + (data as *const T) as *const std::ffi::c_void, + size_of::() as u32, + ) + } + } +} diff --git a/src/sdl3/gpu/device.rs b/src/sdl3/gpu/device.rs deleted file mode 100644 index 6949b42c..00000000 --- a/src/sdl3/gpu/device.rs +++ /dev/null @@ -1,244 +0,0 @@ -use crate::{ - get_error, - gpu::{ - BufferBuilder, ColorTargetInfo, CommandBuffer, CopyPass, DepthStencilTargetInfo, - GraphicsPipelineBuilder, RenderPass, Sampler, SamplerCreateInfo, ShaderBuilder, - ShaderFormat, Texture, TextureCreateInfo, TextureFormat, TransferBufferBuilder, - }, - sys, Error, -}; -use std::sync::{Arc, Weak}; -use sys::gpu::{ - SDL_BeginGPUComputePass, SDL_BeginGPUCopyPass, SDL_BeginGPURenderPass, SDL_CreateGPUDevice, - SDL_CreateGPUSampler, SDL_CreateGPUTexture, SDL_DestroyGPUDevice, SDL_GPUColorTargetInfo, - SDL_GPUDepthStencilTargetInfo, SDL_GPUDevice, SDL_GPUViewport, - SDL_GetGPUSwapchainTextureFormat, SDL_SetGPUViewport, -}; - -use super::{ - pipeline::{StorageBufferReadWriteBinding, StorageTextureReadWriteBinding}, - ComputePass, ComputePipelineBuilder, -}; - -/// Manages the raw `SDL_GPUDevice` pointer and releases it on drop -pub(super) struct DeviceContainer(*mut SDL_GPUDevice); -impl DeviceContainer { - pub(super) fn raw(&self) -> *mut SDL_GPUDevice { - self.0 - } -} -impl Drop for DeviceContainer { - #[doc(alias = "SDL_DestroyGPUDevice")] - fn drop(&mut self) { - unsafe { SDL_DestroyGPUDevice(self.0) } - } -} - -pub(super) type WeakDevice = Weak; - -#[derive(Clone)] -pub struct Device { - inner: Arc, -} -impl Device { - #[inline] - pub fn raw(&self) -> *mut SDL_GPUDevice { - self.inner.0 - } - - pub(super) fn weak(&self) -> WeakDevice { - Arc::downgrade(&self.inner) - } - - #[doc(alias = "SDL_CreateGPUDevice")] - pub fn new(flags: ShaderFormat, debug_mode: bool) -> Result { - let raw_device = unsafe { SDL_CreateGPUDevice(flags.0, debug_mode, std::ptr::null()) }; - if raw_device.is_null() { - Err(get_error()) - } else { - Ok(Self { - inner: Arc::new(DeviceContainer(raw_device)), - }) - } - } - - #[doc(alias = "SDL_ClaimWindowForGPUDevice")] - pub fn with_window(self, w: &crate::video::Window) -> Result { - let p = unsafe { sys::gpu::SDL_ClaimWindowForGPUDevice(self.inner.0, w.raw()) }; - if p { - Ok(self) - } else { - Err(get_error()) - } - } - - #[doc(alias = "SDL_AcquireGPUCommandBuffer")] - pub fn acquire_command_buffer(&self) -> Result { - let raw_buffer = unsafe { sys::gpu::SDL_AcquireGPUCommandBuffer(self.inner.0) }; - if raw_buffer.is_null() { - Err(get_error()) - } else { - Ok(CommandBuffer::new(raw_buffer)) - } - } - - pub fn create_shader(&self) -> ShaderBuilder { - ShaderBuilder::new(self) - } - - #[doc(alias = "SDL_CreateGPUBuffer")] - pub fn create_buffer(&self) -> BufferBuilder { - BufferBuilder::new(self) - } - - #[doc(alias = "SDL_CreateGPUTransferBuffer")] - pub fn create_transfer_buffer(&self) -> TransferBufferBuilder { - TransferBufferBuilder::new(self) - } - - #[doc(alias = "SDL_CreateGPUSampler")] - pub fn create_sampler(&self, create_info: SamplerCreateInfo) -> Result { - let raw_sampler = unsafe { SDL_CreateGPUSampler(self.raw(), &create_info.inner) }; - if raw_sampler.is_null() { - Err(get_error()) - } else { - Ok(Sampler::new(self, raw_sampler)) - } - } - - #[doc(alias = "SDL_CreateGPUTexture")] - pub fn create_texture( - &self, - create_info: TextureCreateInfo, - ) -> Result, Error> { - let raw_texture = unsafe { SDL_CreateGPUTexture(self.raw(), &create_info.inner) }; - if raw_texture.is_null() { - Err(get_error()) - } else { - Ok(Texture::new( - self, - raw_texture, - create_info.inner.width, - create_info.inner.height, - )) - } - } - - #[doc(alias = "SDL_SetGPUViewport")] - pub fn set_viewport(&self, render_pass: &RenderPass, viewport: SDL_GPUViewport) { - unsafe { SDL_SetGPUViewport(render_pass.inner, &viewport) } - } - - pub fn get_swapchain_texture_format(&self, w: &crate::video::Window) -> TextureFormat { - unsafe { std::mem::transmute(SDL_GetGPUSwapchainTextureFormat(self.inner.0, w.raw()).0) } - } - - // You cannot begin another render pass, or begin a compute pass or copy pass until you have ended the render pass. - #[doc(alias = "SDL_BeginGPURenderPass")] - pub fn begin_render_pass( - &self, - command_buffer: &CommandBuffer, - color_info: &[ColorTargetInfo], - depth_stencil_target: Option<&DepthStencilTargetInfo>, - ) -> Result { - let p = unsafe { - SDL_BeginGPURenderPass( - command_buffer.inner, - color_info.as_ptr() as *const SDL_GPUColorTargetInfo, //heavy promise - color_info.len() as u32, - if let Some(p) = depth_stencil_target { - p as *const _ as *const SDL_GPUDepthStencilTargetInfo //heavy promise - } else { - std::ptr::null() - }, - ) - }; - if !p.is_null() { - Ok(RenderPass { inner: p }) - } else { - Err(get_error()) - } - } - - #[doc(alias = "SDL_EndGPURenderPass")] - pub fn end_render_pass(&self, pass: RenderPass) { - unsafe { - sys::gpu::SDL_EndGPURenderPass(pass.inner); - } - } - - #[doc(alias = "SDL_BeginGPUCopyPass")] - pub fn begin_copy_pass(&self, command_buffer: &CommandBuffer) -> Result { - let p = unsafe { SDL_BeginGPUCopyPass(command_buffer.inner) }; - if !p.is_null() { - Ok(CopyPass { inner: p }) - } else { - Err(get_error()) - } - } - #[doc(alias = "SDL_EndGPUCopyPass")] - pub fn end_copy_pass(&self, pass: CopyPass) { - unsafe { - sys::gpu::SDL_EndGPUCopyPass(pass.inner); - } - } - - #[doc(alias = "SDL_BeginGPUComputePass")] - pub fn begin_compute_pass( - &self, - command_buffer: &CommandBuffer, - storage_texture_bindings: &[StorageTextureReadWriteBinding], - storage_buffer_bindings: &[StorageBufferReadWriteBinding], - ) -> Result { - let p = unsafe { - SDL_BeginGPUComputePass( - command_buffer.inner, - storage_texture_bindings.as_ptr().cast(), - storage_buffer_bindings.len() as u32, - storage_buffer_bindings.as_ptr().cast(), - storage_buffer_bindings.len() as u32, - ) - }; - if !p.is_null() { - Ok(ComputePass { inner: p }) - } else { - Err(get_error()) - } - } - #[doc(alias = "SDL_EndGPUComputePass")] - pub fn end_compute_pass(&self, pass: ComputePass) { - unsafe { - sys::gpu::SDL_EndGPUComputePass(pass.inner); - } - } - - pub fn create_graphics_pipeline<'a>(&'a self) -> GraphicsPipelineBuilder<'a> { - GraphicsPipelineBuilder::new(self) - } - - pub fn create_compute_pipeline<'a>(&'a self) -> ComputePipelineBuilder<'a> { - ComputePipelineBuilder::new(self) - } - - #[doc(alias = "SDL_GetGPUShaderFormats")] - pub fn get_shader_formats(&self) -> ShaderFormat { - unsafe { std::mem::transmute(sys::gpu::SDL_GetGPUShaderFormats(self.raw())) } - } - - // NOTE: for Xbox builds, the target is a UWP, e.g.: x86_64-uwp-windows-msvc - #[cfg(target_vendor = "uwp")] - #[doc(alias = "SDL_GDKSuspendGPU")] - pub fn gdk_suspend(&self) { - unsafe { - sys::gpu::SDL_GDKSuspendGPU(self.inner); - } - } - - #[cfg(target_vendor = "uwp")] - #[doc(alias = "SDL_GDKResumeGPU")] - pub fn gdk_resume(&self) { - unsafe { - sys::gpu::SDL_GDKResumeGPU(self.inner); - } - } -} diff --git a/src/sdl3/gpu/enums.rs b/src/sdl3/gpu/enums.rs index be8d898d..26ad639d 100644 --- a/src/sdl3/gpu/enums.rs +++ b/src/sdl3/gpu/enums.rs @@ -21,117 +21,7 @@ macro_rules! impl_with { pub type LoadOp = sys::gpu::SDL_GPULoadOp; pub type StoreOp = sys::gpu::SDL_GPUStoreOp; - -#[derive(Default, Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] -#[repr(u32)] -pub enum TextureFormat { - #[default] - Invalid = sys::gpu::SDL_GPU_TEXTUREFORMAT_INVALID.0 as u32, - A8Unorm = sys::gpu::SDL_GPU_TEXTUREFORMAT_A8_UNORM.0 as u32, - R8Unorm = sys::gpu::SDL_GPU_TEXTUREFORMAT_R8_UNORM.0 as u32, - R8g8Unorm = sys::gpu::SDL_GPU_TEXTUREFORMAT_R8G8_UNORM.0 as u32, - R8g8b8a8Unorm = sys::gpu::SDL_GPU_TEXTUREFORMAT_R8G8B8A8_UNORM.0 as u32, - R16Unorm = sys::gpu::SDL_GPU_TEXTUREFORMAT_R16_UNORM.0 as u32, - R16g16Unorm = sys::gpu::SDL_GPU_TEXTUREFORMAT_R16G16_UNORM.0 as u32, - R16g16b16a16Unorm = sys::gpu::SDL_GPU_TEXTUREFORMAT_R16G16B16A16_UNORM.0 as u32, - R10g10b10a2Unorm = sys::gpu::SDL_GPU_TEXTUREFORMAT_R10G10B10A2_UNORM.0 as u32, - B5g6r5Unorm = sys::gpu::SDL_GPU_TEXTUREFORMAT_B5G6R5_UNORM.0 as u32, - B5g5r5a1Unorm = sys::gpu::SDL_GPU_TEXTUREFORMAT_B5G5R5A1_UNORM.0 as u32, - B4g4r4a4Unorm = sys::gpu::SDL_GPU_TEXTUREFORMAT_B4G4R4A4_UNORM.0 as u32, - B8g8r8a8Unorm = sys::gpu::SDL_GPU_TEXTUREFORMAT_B8G8R8A8_UNORM.0 as u32, - Bc1RgbaUnorm = sys::gpu::SDL_GPU_TEXTUREFORMAT_BC1_RGBA_UNORM.0 as u32, - Bc2RgbaUnorm = sys::gpu::SDL_GPU_TEXTUREFORMAT_BC2_RGBA_UNORM.0 as u32, - Bc3RgbaUnorm = sys::gpu::SDL_GPU_TEXTUREFORMAT_BC3_RGBA_UNORM.0 as u32, - Bc4RUnorm = sys::gpu::SDL_GPU_TEXTUREFORMAT_BC4_R_UNORM.0 as u32, - Bc5RgUnorm = sys::gpu::SDL_GPU_TEXTUREFORMAT_BC5_RG_UNORM.0 as u32, - Bc7RgbaUnorm = sys::gpu::SDL_GPU_TEXTUREFORMAT_BC7_RGBA_UNORM.0 as u32, - Bc6hRgbFloat = sys::gpu::SDL_GPU_TEXTUREFORMAT_BC6H_RGB_FLOAT.0 as u32, - Bc6hRgbUfloat = sys::gpu::SDL_GPU_TEXTUREFORMAT_BC6H_RGB_UFLOAT.0 as u32, - R8Snorm = sys::gpu::SDL_GPU_TEXTUREFORMAT_R8_SNORM.0 as u32, - R8g8Snorm = sys::gpu::SDL_GPU_TEXTUREFORMAT_R8G8_SNORM.0 as u32, - R8g8b8a8Snorm = sys::gpu::SDL_GPU_TEXTUREFORMAT_R8G8B8A8_SNORM.0 as u32, - R16Snorm = sys::gpu::SDL_GPU_TEXTUREFORMAT_R16_SNORM.0 as u32, - R16g16Snorm = sys::gpu::SDL_GPU_TEXTUREFORMAT_R16G16_SNORM.0 as u32, - R16g16b16a16Snorm = sys::gpu::SDL_GPU_TEXTUREFORMAT_R16G16B16A16_SNORM.0 as u32, - R16Float = sys::gpu::SDL_GPU_TEXTUREFORMAT_R16_FLOAT.0 as u32, - R16g16Float = sys::gpu::SDL_GPU_TEXTUREFORMAT_R16G16_FLOAT.0 as u32, - R16g16b16a16Float = sys::gpu::SDL_GPU_TEXTUREFORMAT_R16G16B16A16_FLOAT.0 as u32, - R32Float = sys::gpu::SDL_GPU_TEXTUREFORMAT_R32_FLOAT.0 as u32, - R32g32Float = sys::gpu::SDL_GPU_TEXTUREFORMAT_R32G32_FLOAT.0 as u32, - R32g32b32a32Float = sys::gpu::SDL_GPU_TEXTUREFORMAT_R32G32B32A32_FLOAT.0 as u32, - R11g11b10Ufloat = sys::gpu::SDL_GPU_TEXTUREFORMAT_R11G11B10_UFLOAT.0 as u32, - R8Uint = sys::gpu::SDL_GPU_TEXTUREFORMAT_R8_UINT.0 as u32, - R8g8Uint = sys::gpu::SDL_GPU_TEXTUREFORMAT_R8G8_UINT.0 as u32, - R8g8b8a8Uint = sys::gpu::SDL_GPU_TEXTUREFORMAT_R8G8B8A8_UINT.0 as u32, - R16Uint = sys::gpu::SDL_GPU_TEXTUREFORMAT_R16_UINT.0 as u32, - R16g16Uint = sys::gpu::SDL_GPU_TEXTUREFORMAT_R16G16_UINT.0 as u32, - R16g16b16a16Uint = sys::gpu::SDL_GPU_TEXTUREFORMAT_R16G16B16A16_UINT.0 as u32, - R32Uint = sys::gpu::SDL_GPU_TEXTUREFORMAT_R32_UINT.0 as u32, - R32g32Uint = sys::gpu::SDL_GPU_TEXTUREFORMAT_R32G32_UINT.0 as u32, - R32g32b32a32Uint = sys::gpu::SDL_GPU_TEXTUREFORMAT_R32G32B32A32_UINT.0 as u32, - R8Int = sys::gpu::SDL_GPU_TEXTUREFORMAT_R8_INT.0 as u32, - R8g8Int = sys::gpu::SDL_GPU_TEXTUREFORMAT_R8G8_INT.0 as u32, - R8g8b8a8Int = sys::gpu::SDL_GPU_TEXTUREFORMAT_R8G8B8A8_INT.0 as u32, - R16Int = sys::gpu::SDL_GPU_TEXTUREFORMAT_R16_INT.0 as u32, - R16g16Int = sys::gpu::SDL_GPU_TEXTUREFORMAT_R16G16_INT.0 as u32, - R16g16b16a16Int = sys::gpu::SDL_GPU_TEXTUREFORMAT_R16G16B16A16_INT.0 as u32, - R32Int = sys::gpu::SDL_GPU_TEXTUREFORMAT_R32_INT.0 as u32, - R32g32Int = sys::gpu::SDL_GPU_TEXTUREFORMAT_R32G32_INT.0 as u32, - R32g32b32a32Int = sys::gpu::SDL_GPU_TEXTUREFORMAT_R32G32B32A32_INT.0 as u32, - R8g8b8a8UnormSrgb = sys::gpu::SDL_GPU_TEXTUREFORMAT_R8G8B8A8_UNORM_SRGB.0 as u32, - B8g8r8a8UnormSrgb = sys::gpu::SDL_GPU_TEXTUREFORMAT_B8G8R8A8_UNORM_SRGB.0 as u32, - Bc1RgbaUnormSrgb = sys::gpu::SDL_GPU_TEXTUREFORMAT_BC1_RGBA_UNORM_SRGB.0 as u32, - Bc2RgbaUnormSrgb = sys::gpu::SDL_GPU_TEXTUREFORMAT_BC2_RGBA_UNORM_SRGB.0 as u32, - Bc3RgbaUnormSrgb = sys::gpu::SDL_GPU_TEXTUREFORMAT_BC3_RGBA_UNORM_SRGB.0 as u32, - Bc7RgbaUnormSrgb = sys::gpu::SDL_GPU_TEXTUREFORMAT_BC7_RGBA_UNORM_SRGB.0 as u32, - D16Unorm = sys::gpu::SDL_GPU_TEXTUREFORMAT_D16_UNORM.0 as u32, - D24Unorm = sys::gpu::SDL_GPU_TEXTUREFORMAT_D24_UNORM.0 as u32, - D32Float = sys::gpu::SDL_GPU_TEXTUREFORMAT_D32_FLOAT.0 as u32, - D24UnormS8Uint = sys::gpu::SDL_GPU_TEXTUREFORMAT_D24_UNORM_S8_UINT.0 as u32, - D32FloatS8Uint = sys::gpu::SDL_GPU_TEXTUREFORMAT_D32_FLOAT_S8_UINT.0 as u32, - Astc4x4Unorm = sys::gpu::SDL_GPU_TEXTUREFORMAT_ASTC_4x4_UNORM.0 as u32, - Astc5x4Unorm = sys::gpu::SDL_GPU_TEXTUREFORMAT_ASTC_5x4_UNORM.0 as u32, - Astc5x5Unorm = sys::gpu::SDL_GPU_TEXTUREFORMAT_ASTC_5x5_UNORM.0 as u32, - Astc6x5Unorm = sys::gpu::SDL_GPU_TEXTUREFORMAT_ASTC_6x5_UNORM.0 as u32, - Astc6x6Unorm = sys::gpu::SDL_GPU_TEXTUREFORMAT_ASTC_6x6_UNORM.0 as u32, - Astc8x5Unorm = sys::gpu::SDL_GPU_TEXTUREFORMAT_ASTC_8x5_UNORM.0 as u32, - Astc8x6Unorm = sys::gpu::SDL_GPU_TEXTUREFORMAT_ASTC_8x6_UNORM.0 as u32, - Astc8x8Unorm = sys::gpu::SDL_GPU_TEXTUREFORMAT_ASTC_8x8_UNORM.0 as u32, - Astc10x5Unorm = sys::gpu::SDL_GPU_TEXTUREFORMAT_ASTC_10x5_UNORM.0 as u32, - Astc10x6Unorm = sys::gpu::SDL_GPU_TEXTUREFORMAT_ASTC_10x6_UNORM.0 as u32, - Astc10x8Unorm = sys::gpu::SDL_GPU_TEXTUREFORMAT_ASTC_10x8_UNORM.0 as u32, - Astc10x10Unorm = sys::gpu::SDL_GPU_TEXTUREFORMAT_ASTC_10x10_UNORM.0 as u32, - Astc12x10Unorm = sys::gpu::SDL_GPU_TEXTUREFORMAT_ASTC_12x10_UNORM.0 as u32, - Astc12x12Unorm = sys::gpu::SDL_GPU_TEXTUREFORMAT_ASTC_12x12_UNORM.0 as u32, - Astc4x4UnormSrgb = sys::gpu::SDL_GPU_TEXTUREFORMAT_ASTC_4x4_UNORM_SRGB.0 as u32, - Astc5x4UnormSrgb = sys::gpu::SDL_GPU_TEXTUREFORMAT_ASTC_5x4_UNORM_SRGB.0 as u32, - Astc5x5UnormSrgb = sys::gpu::SDL_GPU_TEXTUREFORMAT_ASTC_5x5_UNORM_SRGB.0 as u32, - Astc6x5UnormSrgb = sys::gpu::SDL_GPU_TEXTUREFORMAT_ASTC_6x5_UNORM_SRGB.0 as u32, - Astc6x6UnormSrgb = sys::gpu::SDL_GPU_TEXTUREFORMAT_ASTC_6x6_UNORM_SRGB.0 as u32, - Astc8x5UnormSrgb = sys::gpu::SDL_GPU_TEXTUREFORMAT_ASTC_8x5_UNORM_SRGB.0 as u32, - Astc8x6UnormSrgb = sys::gpu::SDL_GPU_TEXTUREFORMAT_ASTC_8x6_UNORM_SRGB.0 as u32, - Astc8x8UnormSrgb = sys::gpu::SDL_GPU_TEXTUREFORMAT_ASTC_8x8_UNORM_SRGB.0 as u32, - Astc10x5UnormSrgb = sys::gpu::SDL_GPU_TEXTUREFORMAT_ASTC_10x5_UNORM_SRGB.0 as u32, - Astc10x6UnormSrgb = sys::gpu::SDL_GPU_TEXTUREFORMAT_ASTC_10x6_UNORM_SRGB.0 as u32, - Astc10x8UnormSrgb = sys::gpu::SDL_GPU_TEXTUREFORMAT_ASTC_10x8_UNORM_SRGB.0 as u32, - Astc10x10UnormSrgb = sys::gpu::SDL_GPU_TEXTUREFORMAT_ASTC_10x10_UNORM_SRGB.0 as u32, - Astc12x10UnormSrgb = sys::gpu::SDL_GPU_TEXTUREFORMAT_ASTC_12x10_UNORM_SRGB.0 as u32, - Astc12x12UnormSrgb = sys::gpu::SDL_GPU_TEXTUREFORMAT_ASTC_12x12_UNORM_SRGB.0 as u32, - Astc4x4Float = sys::gpu::SDL_GPU_TEXTUREFORMAT_ASTC_4x4_FLOAT.0 as u32, - Astc5x4Float = sys::gpu::SDL_GPU_TEXTUREFORMAT_ASTC_5x4_FLOAT.0 as u32, - Astc5x5Float = sys::gpu::SDL_GPU_TEXTUREFORMAT_ASTC_5x5_FLOAT.0 as u32, - Astc6x5Float = sys::gpu::SDL_GPU_TEXTUREFORMAT_ASTC_6x5_FLOAT.0 as u32, - Astc6x6Float = sys::gpu::SDL_GPU_TEXTUREFORMAT_ASTC_6x6_FLOAT.0 as u32, - Astc8x5Float = sys::gpu::SDL_GPU_TEXTUREFORMAT_ASTC_8x5_FLOAT.0 as u32, - Astc8x6Float = sys::gpu::SDL_GPU_TEXTUREFORMAT_ASTC_8x6_FLOAT.0 as u32, - Astc8x8Float = sys::gpu::SDL_GPU_TEXTUREFORMAT_ASTC_8x8_FLOAT.0 as u32, - Astc10x5Float = sys::gpu::SDL_GPU_TEXTUREFORMAT_ASTC_10x5_FLOAT.0 as u32, - Astc10x6Float = sys::gpu::SDL_GPU_TEXTUREFORMAT_ASTC_10x6_FLOAT.0 as u32, - Astc10x8Float = sys::gpu::SDL_GPU_TEXTUREFORMAT_ASTC_10x8_FLOAT.0 as u32, - Astc10x10Float = sys::gpu::SDL_GPU_TEXTUREFORMAT_ASTC_10x10_FLOAT.0 as u32, - Astc12x10Float = sys::gpu::SDL_GPU_TEXTUREFORMAT_ASTC_12x10_FLOAT.0 as u32, - Astc12x12Float = sys::gpu::SDL_GPU_TEXTUREFORMAT_ASTC_12x12_FLOAT.0 as u32, -} +pub type TextureFormat = sys::gpu::SDL_GPUTextureFormat; #[derive(Default, Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] pub struct ShaderFormat(pub sys::gpu::SDL_GPUShaderFormat); diff --git a/src/sdl3/gpu/info_struct.rs b/src/sdl3/gpu/info_struct.rs new file mode 100644 index 00000000..cb82c664 --- /dev/null +++ b/src/sdl3/gpu/info_struct.rs @@ -0,0 +1,882 @@ +//! Types which hold data but don't own any GPU-resources. +//! There are no calls to SDL here. +//! + +use std::marker::PhantomData; + +use sys::gpu::{ + SDL_GPUBlendFactor, SDL_GPUBlendOp, SDL_GPUBuffer, SDL_GPUBufferBinding, + SDL_GPUBufferRegion, SDL_GPUColorTargetBlendState, SDL_GPUColorTargetDescription, + SDL_GPUColorTargetInfo, SDL_GPUCompareOp, SDL_GPUCullMode, SDL_GPUDepthStencilState, + SDL_GPUDepthStencilTargetInfo, SDL_GPUFillMode, SDL_GPUFilter, SDL_GPUFrontFace, + SDL_GPUGraphicsPipelineTargetInfo, SDL_GPURasterizerState, SDL_GPUSampleCount, + SDL_GPUSampler, SDL_GPUSamplerAddressMode, SDL_GPUSamplerCreateInfo, + SDL_GPUSamplerMipmapMode, SDL_GPUStencilOp, SDL_GPUStencilOpState, + SDL_GPUStorageBufferReadWriteBinding, SDL_GPUStorageTextureReadWriteBinding, + SDL_GPUTexture, SDL_GPUTextureCreateInfo, SDL_GPUTextureRegion, + SDL_GPUTextureSamplerBinding, SDL_GPUTextureTransferInfo, SDL_GPUTextureType, + SDL_GPUTransferBuffer, SDL_GPUTransferBufferLocation, SDL_GPUVertexAttribute, + SDL_GPUVertexBufferDescription, SDL_GPUVertexInputRate, SDL_GPUVertexInputState, +}; + +use crate::pixels::Color; + +use super::{ + BlendFactor, BlendOp, ColorComponentFlags, CompareOp, CullMode, Extern, + FillMode, Filter, FrontFace, LoadOp, SampleCount, Sampler, SamplerAddressMode, + SamplerMipmapMode, StencilOp, StoreOp, Texture, TextureFormat, TextureType, + TextureUsage, VertexElementFormat, VertexInputRate +}; + +#[repr(C)] +#[derive(Default)] +pub struct DepthStencilTargetInfo<'a> { + inner: SDL_GPUDepthStencilTargetInfo, + _marker: PhantomData<&'a Extern>, +} +impl<'a> DepthStencilTargetInfo<'a> { + pub fn new() -> Self { + Default::default() + } + + pub fn with_texture(mut self, texture: &'a Extern) -> Self { + self.inner.texture = texture.raw(); + self + } + + pub fn with_clear_depth(mut self, clear_depth: f32) -> Self { + self.inner.clear_depth = clear_depth; + self + } + + pub fn with_load_op(mut self, value: LoadOp) -> Self { + self.inner.load_op = value; + self + } + + pub fn with_store_op(mut self, value: StoreOp) -> Self { + self.inner.store_op = value; + self + } + + pub fn with_stencil_load_op(mut self, value: LoadOp) -> Self { + self.inner.stencil_load_op = value; + self + } + + pub fn with_stencil_store_op(mut self, value: StoreOp) -> Self { + self.inner.stencil_store_op = value; + self + } + + pub fn with_cycle(mut self, cycle: bool) -> Self { + self.inner.cycle = cycle; + self + } + + pub fn with_clear_stencil(mut self, clear_stencil: u8) -> Self { + self.inner.clear_stencil = clear_stencil; + self + } +} + +#[repr(C)] +#[derive(Default)] +pub struct ColorTargetInfo<'a> { + inner: SDL_GPUColorTargetInfo, + _marker: PhantomData<&'a Extern>, +} +impl<'a> ColorTargetInfo<'a> { + pub fn new() -> Self { + Default::default() + } + + pub fn with_texture(mut self, texture: &'a Extern) -> Self { + self.inner.texture = texture.raw(); + self + } + + pub fn with_load_op(mut self, value: LoadOp) -> Self { + self.inner.load_op = value; + self + } + + pub fn with_store_op(mut self, value: StoreOp) -> Self { + self.inner.store_op = value; + self + } + + pub fn with_clear_color(mut self, value: Color) -> Self { + self.inner.clear_color.r = (value.r as f32) / 255.0; + self.inner.clear_color.g = (value.g as f32) / 255.0; + self.inner.clear_color.b = (value.b as f32) / 255.0; + self.inner.clear_color.a = (value.a as f32) / 255.0; + self + } +} + + +#[derive(Default)] +pub struct TextureCreateInfo { + pub(super) inner: SDL_GPUTextureCreateInfo, +} +impl TextureCreateInfo { + pub fn new() -> Self { + Default::default() + } + + /// The base dimensionality of the texture. + pub fn with_type(mut self, value: TextureType) -> Self { + self.inner.r#type = SDL_GPUTextureType(value as i32); + self + } + + /// The pixel format of the texture. + pub fn with_format(mut self, format: TextureFormat) -> Self { + self.inner.format = format; + self + } + + /// How the texture is intended to be used by the client. + pub fn with_usage(mut self, value: TextureUsage) -> Self { + self.inner.usage = value.0; + self + } + + /// The width of the texture. + pub fn with_width(mut self, value: u32) -> Self { + self.inner.width = value; + self + } + + /// The height of the texture. + pub fn with_height(mut self, value: u32) -> Self { + self.inner.height = value; + self + } + + /// The layer count or depth of the texture. This value is treated as a layer count on 2D array textures, and as a depth value on 3D textures. + pub fn with_layer_count_or_depth(mut self, value: u32) -> Self { + self.inner.layer_count_or_depth = value; + self + } + + /// The number of mip levels in the texture. + pub fn with_num_levels(mut self, value: u32) -> Self { + self.inner.num_levels = value; + self + } + + /// The number of samples per texel. Only applies if the texture is used as a render target. + pub fn with_sample_count(mut self, value: SampleCount) -> Self { + self.inner.sample_count = SDL_GPUSampleCount(value as i32); + self + } +} + + +#[derive(Default)] +pub struct SamplerCreateInfo { + pub(super) inner: SDL_GPUSamplerCreateInfo, +} +impl SamplerCreateInfo { + pub fn new() -> Self { + Default::default() + } + + /// The minification filter to apply to lookups. + pub fn with_min_filter(mut self, filter: Filter) -> Self { + self.inner.min_filter = SDL_GPUFilter(filter as i32); + self + } + + /// The magnification filter to apply to lookups. + pub fn with_mag_filter(mut self, filter: Filter) -> Self { + self.inner.mag_filter = SDL_GPUFilter(filter as i32); + self + } + + /// The mipmap filter to apply to lookups. + pub fn with_mipmap_mode(mut self, mode: SamplerMipmapMode) -> Self { + self.inner.mipmap_mode = SDL_GPUSamplerMipmapMode(mode as i32); + self + } + + /// The addressing mode for U coordinates outside [0, 1). + pub fn with_address_mode_u(mut self, mode: SamplerAddressMode) -> Self { + self.inner.address_mode_u = SDL_GPUSamplerAddressMode(mode as i32); + self + } + + /// The addressing mode for V coordinates outside [0, 1). + pub fn with_address_mode_v(mut self, mode: SamplerAddressMode) -> Self { + self.inner.address_mode_v = SDL_GPUSamplerAddressMode(mode as i32); + self + } + + /// The addressing mode for W coordinates outside [0, 1). + pub fn with_address_mode_w(mut self, mode: SamplerAddressMode) -> Self { + self.inner.address_mode_w = SDL_GPUSamplerAddressMode(mode as i32); + self + } + + /// The bias to be added to mipmap LOD calculation. + pub fn with_mip_lod_bias(mut self, value: f32) -> Self { + self.inner.mip_lod_bias = value; + self + } + + /// The anisotropy value clamp used by the sampler. If enable_anisotropy is false, this is ignored. + pub fn with_max_anisotropy(mut self, value: f32) -> Self { + self.inner.max_anisotropy = value; + self + } + + /// The comparison operator to apply to fetched data before filtering. + pub fn with_compare_op(mut self, value: CompareOp) -> Self { + self.inner.compare_op = SDL_GPUCompareOp(value as i32); + self + } + + /// Clamps the minimum of the computed LOD value. + pub fn with_min_lod(mut self, value: f32) -> Self { + self.inner.min_lod = value; + self + } + + /// Clamps the maximum of the computed LOD value. + pub fn with_max_lod(mut self, value: f32) -> Self { + self.inner.max_lod = value; + self + } + + /// True to enable anisotropic filtering. + pub fn with_enable_anisotropy(mut self, enable: bool) -> Self { + self.inner.enable_anisotropy = enable; + self + } + + /// True to enable comparison against a reference value during lookups. + pub fn with_enable_compare(mut self, enable: bool) -> Self { + self.inner.enable_compare = enable; + self + } +} + +#[derive(Default)] +pub struct TextureRegion<'a> { + pub(super) inner: SDL_GPUTextureRegion, + _marker: PhantomData<&'a Extern>, +} +impl<'a> TextureRegion<'a> { + pub fn new() -> Self { + Default::default() + } + + /// The texture used in the copy operation. + pub fn with_texture(mut self, texture: &'a Extern) -> Self { + self.inner.texture = texture.raw(); + self + } + + /// The mip level index to transfer. + pub fn with_mip_level(mut self, mip_level: u32) -> Self { + self.inner.mip_level = mip_level; + self + } + + /// The layer index to transfer. + pub fn with_layer(mut self, layer: u32) -> Self { + self.inner.layer = layer; + self + } + + /// The left offset of the region. + pub fn with_x(mut self, x: u32) -> Self { + self.inner.x = x; + self + } + + /// The top offset of the region. + pub fn with_y(mut self, y: u32) -> Self { + self.inner.y = y; + self + } + + /// The front offset of the region. + pub fn with_z(mut self, z: u32) -> Self { + self.inner.z = z; + self + } + + /// The width of the region. + pub fn with_width(mut self, width: u32) -> Self { + self.inner.w = width; + self + } + + /// The height of the region. + pub fn with_height(mut self, height: u32) -> Self { + self.inner.h = height; + self + } + + /// The depth of the region. + pub fn with_depth(mut self, depth: u32) -> Self { + self.inner.d = depth; + self + } +} + +#[derive(Default)] +pub struct TextureTransferInfo<'a> { + pub(super) inner: SDL_GPUTextureTransferInfo, + _marker: PhantomData<&'a Extern>, +} +impl<'a> TextureTransferInfo<'a> { + pub fn new() -> Self { + Default::default() + } + + /// The transfer buffer used in the transfer operation. + pub fn with_transfer_buffer(mut self, buffer: &'a Extern) -> Self { + self.inner.transfer_buffer = buffer.raw(); + self + } + + /// The starting byte of the image data in the transfer buffer. + pub fn with_offset(mut self, offset: u32) -> Self { + self.inner.offset = offset; + self + } + + /// The number of pixels from one row to the next. + pub fn with_pixels_per_row(mut self, value: u32) -> Self { + self.inner.pixels_per_row = value; + self + } + + /// The number of rows from one layer/depth-slice to the next. + pub fn with_rows_per_layer(mut self, value: u32) -> Self { + self.inner.rows_per_layer = value; + self + } +} + + +#[repr(C)] +#[derive(Default)] +pub struct BufferBinding<'a> { + pub(super) inner: SDL_GPUBufferBinding, + _marker: PhantomData<&'a Extern>, +} +impl<'a> BufferBinding<'a> { + pub fn new() -> Self { + Default::default() + } + + pub fn with_buffer(mut self, buffer: &'a Extern) -> Self { + self.inner.buffer = buffer.raw(); + self + } + + pub fn with_offset(mut self, offset: u32) -> Self { + self.inner.offset = offset; + self + } +} + +#[derive(Default)] +pub struct TransferBufferLocation<'a> { + pub(super) inner: SDL_GPUTransferBufferLocation, + _marker: PhantomData<&'a Extern>, +} +impl<'a> TransferBufferLocation<'a> { + pub fn new() -> Self { + Default::default() + } + + pub fn with_transfer_buffer(mut self, transfer_buffer: &'a Extern) -> Self { + self.inner.transfer_buffer = transfer_buffer.raw(); + self + } + + pub fn with_offset(mut self, offset: u32) -> Self { + self.inner.offset = offset; + self + } +} + +#[derive(Default)] +pub struct BufferRegion<'a> { + pub(super) inner: SDL_GPUBufferRegion, + _marker: PhantomData<&'a Extern>, +} +impl<'a> BufferRegion<'a> { + pub fn new() -> Self { + Default::default() + } + + pub fn with_buffer(mut self, buffer: &'a Extern) -> Self { + self.inner.buffer = buffer.raw(); + self + } + + pub fn with_offset(mut self, offset: u32) -> Self { + self.inner.offset = offset; + self + } + + pub fn with_size(mut self, size: u32) -> Self { + self.inner.size = size; + self + } +} + +#[repr(C)] +#[derive(Clone, Default)] +pub struct VertexBufferDescription { + inner: SDL_GPUVertexBufferDescription, +} +impl VertexBufferDescription { + pub fn new() -> Self { + Default::default() + } + + pub fn with_slot(mut self, value: u32) -> Self { + self.inner.slot = value; + self + } + + pub fn with_pitch(mut self, value: u32) -> Self { + self.inner.pitch = value; + self + } + + pub fn with_input_rate(mut self, value: VertexInputRate) -> Self { + self.inner.input_rate = SDL_GPUVertexInputRate(value as i32); + self + } + + pub fn with_instance_step_rate(mut self, value: u32) -> Self { + self.inner.instance_step_rate = value; + self + } +} + + + +#[repr(C)] +#[derive(Default)] +pub struct VertexInputState<'a> { + pub(super) inner: SDL_GPUVertexInputState, + _marker: PhantomData<&'a [VertexBufferDescription]>, +} +impl<'a> VertexInputState<'a> { + pub fn new() -> Self { + Default::default() + } + + pub fn with_vertex_buffer_descriptions(mut self, value: &'a [VertexBufferDescription]) -> Self { + self.inner.vertex_buffer_descriptions = + value.as_ptr() as *const SDL_GPUVertexBufferDescription; + self.inner.num_vertex_buffers = value.len() as u32; + self + } + + pub fn with_vertex_attributes(mut self, value: &[VertexAttribute]) -> Self { + self.inner.vertex_attributes = value.as_ptr() as *const SDL_GPUVertexAttribute; + self.inner.num_vertex_attributes = value.len() as u32; + self + } +} + + +#[repr(C)] +#[derive(Default)] +pub struct RasterizerState { + pub(super) inner: SDL_GPURasterizerState, +} +impl RasterizerState { + pub fn new() -> Self { + Default::default() + } + + /// Whether polygons will be filled in or drawn as lines. + pub fn with_fill_mode(mut self, fill_mode: FillMode) -> Self { + self.inner.fill_mode = SDL_GPUFillMode(fill_mode as i32); + self + } + + /// The facing direction in which triangles will be culled. + pub fn with_cull_mode(mut self, cull_mode: CullMode) -> Self { + self.inner.cull_mode = SDL_GPUCullMode(cull_mode as i32); + self + } + + /// The vertex winding that will cause a triangle to be determined as front-facing. + pub fn with_front_face(mut self, front_face: FrontFace) -> Self { + self.inner.front_face = SDL_GPUFrontFace(front_face as i32); + self + } + + /// A scalar factor controlling the depth value added to each fragment. + pub fn with_depth_bias_constant_factor(mut self, value: f32) -> Self { + self.inner.depth_bias_constant_factor = value; + self + } + + /// The maximum depth bias of a fragment. + pub fn with_depth_bias_clamp(mut self, value: f32) -> Self { + self.inner.depth_bias_clamp = value; + self + } + + /// A scalar factor applied to a fragment's slope in depth calculations. + pub fn with_depth_slope_factor(mut self, value: f32) -> Self { + self.inner.depth_bias_slope_factor = value; + self + } + + /// True to bias fragment depth values. + pub fn with_enable_depth_bias(mut self, value: bool) -> Self { + self.inner.enable_depth_bias = value; + self + } + + /// True to enable depth clip, false to enable depth clamp. + pub fn with_enable_depth_clip(mut self, value: bool) -> Self { + self.inner.enable_depth_clip = value; + self + } +} + +#[repr(C)] +#[derive(Default)] +pub struct StencilOpState { + pub(super) inner: SDL_GPUStencilOpState, +} +impl StencilOpState { + pub fn new() -> Self { + Default::default() + } + + /// The action performed on samples that fail the stencil test. + pub fn with_fail_op(mut self, value: StencilOp) -> Self { + self.inner.fail_op = SDL_GPUStencilOp(value as i32); + self + } + + /// The action performed on samples that pass the depth and stencil tests. + pub fn with_pass_op(mut self, value: StencilOp) -> Self { + self.inner.pass_op = SDL_GPUStencilOp(value as i32); + self + } + + /// The action performed on samples that pass the stencil test and fail the depth test. + pub fn with_depth_fail_op(mut self, value: StencilOp) -> Self { + self.inner.depth_fail_op = SDL_GPUStencilOp(value as i32); + self + } + + /// The comparison operator used in the stencil test. + pub fn compare_op(mut self, value: CompareOp) -> Self { + self.inner.compare_op = SDL_GPUCompareOp(value as i32); + self + } +} + +#[repr(C)] +#[derive(Default)] +pub struct DepthStencilState { + pub(super) inner: SDL_GPUDepthStencilState, +} +impl DepthStencilState { + pub fn new() -> Self { + Default::default() + } + + /// The comparison operator used for depth testing. + pub fn with_compare_op(mut self, value: CompareOp) -> Self { + self.inner.compare_op = SDL_GPUCompareOp(value as i32); + self + } + + /// The stencil op state for back-facing triangles. + pub fn with_back_stencil_state(mut self, value: StencilOpState) -> Self { + self.inner.back_stencil_state = value.inner; + self + } + + /// The stencil op state for front-facing triangles. + pub fn with_front_stencil_state(mut self, value: StencilOpState) -> Self { + self.inner.front_stencil_state = value.inner; + self + } + + /// Selects the bits of the stencil values participating in the stencil test. + pub fn with_compare_mask(mut self, value: u8) -> Self { + self.inner.compare_mask = value; + self + } + + /// Selects the bits of the stencil values updated by the stencil test. + pub fn with_write_mask(mut self, value: u8) -> Self { + self.inner.write_mask = value; + self + } + + /// True enables the depth test. + pub fn with_enable_depth_test(mut self, value: bool) -> Self { + self.inner.enable_depth_test = value; + self + } + + /// True enables depth writes. + pub fn with_enable_depth_write(mut self, value: bool) -> Self { + self.inner.enable_depth_write = value; + self + } + + /// True enables the stencil test. + pub fn with_enable_stencil_test(mut self, value: bool) -> Self { + self.inner.enable_stencil_test = value; + self + } +} + + +#[derive(Default)] +pub struct GraphicsPipelineTargetInfo<'a> { + pub(super) inner: SDL_GPUGraphicsPipelineTargetInfo, + _marker: PhantomData<&'a [ColorTargetDescription]>, +} +impl<'a> GraphicsPipelineTargetInfo<'a> { + pub fn new() -> Self { + Default::default() + } + + /// A pointer to an array of color target descriptions. + pub fn with_color_target_descriptions(mut self, value: &'a [ColorTargetDescription]) -> Self { + self.inner.color_target_descriptions = + value.as_ptr() as *const SDL_GPUColorTargetDescription; + self.inner.num_color_targets = value.len() as u32; + self + } + + /// The pixel format of the depth-stencil target. Ignored if has_depth_stencil_target is false. + pub fn with_depth_stencil_format(mut self, value: TextureFormat) -> Self { + self.inner.depth_stencil_format = value; + self + } + + /// true specifies that the pipeline uses a depth-stencil target. + pub fn with_has_depth_stencil_target(mut self, value: bool) -> Self { + self.inner.has_depth_stencil_target = value; + self + } +} + + +#[repr(C)] +#[derive(Clone, Default)] +pub struct VertexAttribute { + inner: SDL_GPUVertexAttribute, +} +impl VertexAttribute { + pub fn new() -> Self { + Default::default() + } + + /// The shader input location index. + pub fn with_location(mut self, value: u32) -> Self { + self.inner.location = value; + self + } + + /// The binding slot of the associated vertex buffer. + pub fn with_buffer_slot(mut self, value: u32) -> Self { + self.inner.buffer_slot = value; + self + } + + /// The size and type of the attribute data. + pub fn with_format(mut self, value: VertexElementFormat) -> Self { + self.inner.format = unsafe { std::mem::transmute(value as u32) }; + self + } + + /// The byte offset of this attribute relative to the start of the vertex element. + pub fn with_offset(mut self, value: u32) -> Self { + self.inner.offset = value; + self + } +} + + +#[derive(Default)] +pub struct ColorTargetBlendState { + inner: SDL_GPUColorTargetBlendState, +} +impl ColorTargetBlendState { + pub fn new() -> Self { + Self::default() + } + + /// The value to be multiplied by the source RGB value. + pub fn with_src_color_blendfactor(mut self, blend_factor: BlendFactor) -> Self { + self.inner.src_color_blendfactor = SDL_GPUBlendFactor(blend_factor as i32); + self + } + + /// The value to be multiplied by the destination RGB value. + pub fn with_dst_color_blendfactor(mut self, blend_factor: BlendFactor) -> Self { + self.inner.dst_color_blendfactor = SDL_GPUBlendFactor(blend_factor as i32); + self + } + + /// The blend operation for the RGB components. + pub fn with_color_blend_op(mut self, blend_op: BlendOp) -> Self { + self.inner.color_blend_op = SDL_GPUBlendOp(blend_op as i32); + self + } + + /// The value to be multiplied by the source alpha. + pub fn with_src_alpha_blendfactor(mut self, blend_factor: BlendFactor) -> Self { + self.inner.src_alpha_blendfactor = SDL_GPUBlendFactor(blend_factor as i32); + self + } + + /// The value to be multiplied by the destination alpha. + pub fn with_dst_alpha_blendfactor(mut self, blend_factor: BlendFactor) -> Self { + self.inner.dst_alpha_blendfactor = SDL_GPUBlendFactor(blend_factor as i32); + self + } + + /// The blend operation for the alpha component. + pub fn with_alpha_blend_op(mut self, blend_op: BlendOp) -> Self { + self.inner.alpha_blend_op = SDL_GPUBlendOp(blend_op as i32); + self + } + + /// A bitmask specifying which of the RGBA components are enabled for writing. Writes to all channels if enable_color_write_mask is false. + pub fn with_color_write_mask(mut self, flags: ColorComponentFlags) -> Self { + self.inner.color_write_mask = flags.0; + self + } + + /// Whether blending is enabled for the color target. + pub fn with_enable_blend(mut self, enable: bool) -> Self { + self.inner.enable_blend = enable; + self + } + + /// Whether the color write mask is enabled. + pub fn with_enable_color_write_mask(mut self, enable: bool) -> Self { + self.inner.enable_color_write_mask = enable; + self + } +} + +#[repr(C)] +#[derive(Default)] +pub struct ColorTargetDescription { + inner: SDL_GPUColorTargetDescription, +} +impl ColorTargetDescription { + pub fn new() -> Self { + Self::default() + } + + /// The pixel format of the texture to be used as a color target. + pub fn with_format(mut self, value: TextureFormat) -> Self { + self.inner.format = value; + self + } + + /// The blend state to be used for the color target. + pub fn with_blend_state(mut self, value: ColorTargetBlendState) -> Self { + self.inner.blend_state = value.inner; + self + } +} + + +#[repr(C)] +#[derive(Default)] +pub struct TextureSamplerBinding<'a> { + inner: SDL_GPUTextureSamplerBinding, + _marker: PhantomData<&'a Extern<(SDL_GPUTexture, SDL_GPUSampler)>>, +} +impl<'a> TextureSamplerBinding<'a> { + pub fn new() -> Self { + Default::default() + } + + /// The texture to bind. Must have been created with [`SDL_GPU_TEXTUREUSAGE_SAMPLER`]. + pub fn with_texture(mut self, texture: &'a Texture) -> Self { + self.inner.texture = texture.raw(); + self + } + + /// The sampler to bind. + pub fn with_sampler(mut self, sampler: &'a Sampler) -> Self { + self.inner.sampler = sampler.raw(); + self + } +} + + +#[repr(C)] +#[derive(Default)] +pub struct StorageTextureReadWriteBinding<'a> { + inner: SDL_GPUStorageTextureReadWriteBinding, + _marker: PhantomData<&'a Extern>, +} +impl<'a> StorageTextureReadWriteBinding<'a> { + pub fn new() -> Self { + Default::default() + } + + pub fn with_texture(mut self, texture: &'a Extern) -> Self { + self.inner.texture = texture.raw(); + self + } + + pub fn with_mip_level(mut self, mip_level: u32) -> Self { + self.inner.mip_level = mip_level; + self + } + + pub fn with_layer(mut self, layer: u32) -> Self { + self.inner.layer = layer; + self + } + + pub fn with_cycle(mut self, cycle: bool) -> Self { + self.inner.cycle = cycle; + self + } +} + +#[repr(C)] +#[derive(Default)] +pub struct StorageBufferReadWriteBinding<'a> { + inner: SDL_GPUStorageBufferReadWriteBinding, + _marker: PhantomData<&'a Extern>, +} +impl<'a> StorageBufferReadWriteBinding<'a> { + pub fn new() -> Self { + Default::default() + } + + pub fn with_buffer(mut self, buffer: &'a Extern) -> Self { + self.inner.buffer = buffer.raw(); + self + } + + pub fn with_cycle(mut self, cycle: bool) -> Self { + self.inner.cycle = cycle; + self + } +} diff --git a/src/sdl3/gpu/mod.rs b/src/sdl3/gpu/mod.rs index cf7b36b7..49cad828 100644 --- a/src/sdl3/gpu/mod.rs +++ b/src/sdl3/gpu/mod.rs @@ -1,13 +1,25 @@ -use crate::gpu::device::WeakDevice; +mod resource; +mod swapchain; +use std::cell::UnsafeCell; -mod buffer; -pub use buffer::{ - Buffer, BufferBinding, BufferBuilder, BufferMemMap, BufferRegion, TransferBuffer, - TransferBufferBuilder, TransferBufferLocation, VertexBufferDescription, +pub use resource::{ + Buffer, + TransferBuffer, + /* FIXME: BufferMemMap, */ + GraphicsPipeline, + ComputePipeline, + Texture, + Sampler, + Shader, + Device, +}; +pub use resource::{ + ComputePipelineBuilder, GraphicsPipelineBuilder, ShaderBuilder, BufferBuilder, + TransferBufferBuilder, }; -mod device; -pub use device::Device; +mod command_buffer; +pub use command_buffer::CommandBuffer; mod enums; pub use enums::{ @@ -17,23 +29,129 @@ pub use enums::{ TextureUsage, TransferBufferUsage, VertexElementFormat, VertexInputRate, }; -mod pass; -pub use pass::{ - ColorTargetInfo, CommandBuffer, ComputePass, CopyPass, DepthStencilTargetInfo, RenderPass, +mod info_struct; +pub use info_struct::{ + BufferBinding, BufferRegion, ColorTargetInfo, DepthStencilTargetInfo, SamplerCreateInfo, + TextureCreateInfo, TextureRegion, TextureTransferInfo, TransferBufferLocation, + VertexBufferDescription, RasterizerState, + StencilOpState, VertexAttribute, VertexInputState, + ColorTargetBlendState, ColorTargetDescription, GraphicsPipelineTargetInfo, + DepthStencilState, TextureSamplerBinding, + StorageBufferReadWriteBinding, StorageTextureReadWriteBinding, }; -mod pipeline; -pub use pipeline::{ - ColorTargetBlendState, ColorTargetDescription, ComputePipeline, ComputePipelineBuilder, - DepthStencilState, GraphicsPipeline, GraphicsPipelineBuilder, GraphicsPipelineTargetInfo, - RasterizerState, StencilOpState, VertexAttribute, VertexInputState, -}; +mod pass_render; +pub use pass_render::RenderPass; -mod texture; -pub use texture::{ - Sampler, SamplerCreateInfo, Texture, TextureCreateInfo, TextureRegion, TextureSamplerBinding, - TextureTransferInfo, -}; +mod pass_copy; +pub use pass_copy::CopyPass; + +mod pass_compute; +pub use pass_compute::ComputePass; +use sys::gpu::{SDL_ClaimWindowForGPUDevice, SDL_GetGPUSwapchainTextureFormat, SDL_ReleaseWindowFromGPUDevice}; + +use crate::{get_error, Error}; + +mod util; + +pub type ExternDevice = Extern; + +// We need some wrapper to be able to implement (inherent) methods for the type. +// The UnsafeCell doesn't actually do anything for &mut Extern, but the wrapped types +// are also zero-sized, so safe code still can't access any bytes with that. +#[repr(transparent)] +pub struct Extern(UnsafeCell); + +impl Extern { + pub fn raw(&self) -> *mut T { + self.0.get() + } +} + +impl ExternDevice { + #[doc(alias = "SDL_CreateGPUShader")] + pub fn create_shader(&self) -> ShaderBuilder { + ShaderBuilder::new(self) + } + + #[doc(alias = "SDL_CreateGPUBuffer")] + pub fn create_buffer(&self) -> BufferBuilder { + BufferBuilder::new(self) + } + + #[doc(alias = "SDL_CreateGPUTransferBuffer")] + pub fn create_transfer_buffer(&self) -> TransferBufferBuilder { + TransferBufferBuilder::new(self) + } + + #[doc(alias = "SDL_CreateGPUSampler")] + pub fn create_sampler(&self, create_info: SamplerCreateInfo) -> Result { + Sampler::new(self, &create_info.inner) + } + + #[doc(alias = "SDL_CreateGPUGraphicsPipeline")] + pub fn create_graphics_pipeline<'gpu,'a>(&'gpu self) -> GraphicsPipelineBuilder<'gpu, 'a> { + GraphicsPipelineBuilder::new(self) + } + + #[doc(alias = "SDL_CreateGPUComputePipeline")] + pub fn create_compute_pipeline<'gpu,'a>(&'gpu self) -> ComputePipelineBuilder<'gpu, 'a> { + ComputePipelineBuilder::new(self) + } + + #[doc(alias = "SDL_CreateGPUTexture")] + pub fn create_texture( + &self, + create_info: &TextureCreateInfo, + ) -> Result { + Texture::new(self, &create_info.inner) + } + + #[doc(alias = "SDL_AcquireGPUCommandBuffer")] + pub fn acquire_command_buffer<'gpu>(&'gpu self) -> Result, Error> { + CommandBuffer::new(self) + } + + #[doc(alias = "SDL_ClaimWindowForGPUDevice")] + pub fn claim_window(&self, w: &crate::video::Window) -> Result<(), Error> { + let p = unsafe { SDL_ClaimWindowForGPUDevice(self.raw(), w.raw()) }; + if p { + Ok(()) + } else { + Err(get_error()) + } + } + + #[doc(alias = "SDL_ClaimWindowForGPUDevice")] + pub fn release_window(&self, w: &crate::video::Window) { + unsafe { SDL_ReleaseWindowFromGPUDevice(self.raw(), w.raw()) }; + } + + + #[doc(alias = "SDL_GetGPUSwapchainTextureFormat")] + pub fn get_swapchain_texture_format(&self, w: &crate::video::Window) -> TextureFormat { + unsafe { SDL_GetGPUSwapchainTextureFormat(self.raw(), w.raw()) } + } + + #[doc(alias = "SDL_GetGPUShaderFormats")] + pub fn get_shader_formats(&self) -> ShaderFormat { + unsafe { ShaderFormat(sys::gpu::SDL_GetGPUShaderFormats(self.raw())) } + } + + #[cfg(target_os = "xbox")] + #[doc(alias = "SDL_GDKSuspendGPU")] + pub fn gdk_suspend(&self) { + unsafe { + sys::gpu::SDL_GDKSuspendGPU(self.raw()); + } + } + + #[cfg(target_os = "xbox")] + #[doc(alias = "SDL_GDKResumeGPU")] + pub fn gdk_resume(&self) { + unsafe { + sys::gpu::SDL_GDKResumeGPU(self.raw()); + } + } -mod shader; -pub use shader::{Shader, ShaderBuilder}; +} diff --git a/src/sdl3/gpu/pass.rs b/src/sdl3/gpu/pass.rs deleted file mode 100644 index d735a2ac..00000000 --- a/src/sdl3/gpu/pass.rs +++ /dev/null @@ -1,439 +0,0 @@ -use crate::{ - get_error, - gpu::{ - BufferBinding, BufferRegion, GraphicsPipeline, IndexElementSize, LoadOp, StoreOp, Texture, - TextureRegion, TextureSamplerBinding, TextureTransferInfo, TransferBufferLocation, - }, - pixels::Color, - Error, -}; -use sys::gpu::{ - SDL_AcquireGPUSwapchainTexture, SDL_BindGPUFragmentSamplers, SDL_BindGPUIndexBuffer, - SDL_BindGPUVertexBuffers, SDL_DrawGPUIndexedPrimitives, SDL_GPUBufferBinding, - SDL_GPUColorTargetInfo, SDL_GPUCommandBuffer, SDL_GPUComputePass, SDL_GPUCopyPass, - SDL_GPUDepthStencilTargetInfo, SDL_GPURenderPass, - SDL_GPUTextureSamplerBinding, SDL_PushGPUComputeUniformData, - SDL_PushGPUFragmentUniformData, SDL_PushGPUVertexUniformData, SDL_UploadToGPUBuffer, - SDL_UploadToGPUTexture, SDL_WaitAndAcquireGPUSwapchainTexture, -}; - -use super::{Buffer, ComputePipeline}; - -pub struct CommandBuffer { - pub(super) inner: *mut SDL_GPUCommandBuffer, -} -impl CommandBuffer { - pub(super) fn new(inner: *mut SDL_GPUCommandBuffer) -> Self { - Self { inner } - } - - #[inline] - pub fn raw(&self) -> *mut SDL_GPUCommandBuffer { - self.inner - } - - #[doc(alias = "SDL_PushGPUVertexUniformData")] - pub fn push_vertex_uniform_data(&self, slot_index: u32, data: &T) { - unsafe { - SDL_PushGPUVertexUniformData( - self.raw(), - slot_index, - (data as *const T) as *const std::ffi::c_void, - size_of::() as u32, - ) - } - } - - #[doc(alias = "SDL_PushGPUFragmentUniformData")] - pub fn push_fragment_uniform_data(&self, slot_index: u32, data: &T) { - unsafe { - SDL_PushGPUFragmentUniformData( - self.raw(), - slot_index, - (data as *const T) as *const std::ffi::c_void, - size_of::() as u32, - ) - } - } - - #[doc(alias = "SDL_PushGPUComputeUniformData")] - pub fn push_compute_uniform_data(&self, slot_index: u32, data: &T) { - unsafe { - SDL_PushGPUComputeUniformData( - self.raw(), - slot_index, - (data as *const T) as *const std::ffi::c_void, - size_of::() as u32, - ) - } - } - - #[doc(alias = "SDL_WaitAndAcquireGPUSwapchainTexture")] - pub fn wait_and_acquire_swapchain_texture<'a>( - &'a mut self, - w: &crate::video::Window, - ) -> Result, Error> { - let mut swapchain = std::ptr::null_mut(); - let mut width = 0; - let mut height = 0; - let success = unsafe { - SDL_WaitAndAcquireGPUSwapchainTexture( - self.inner, - w.raw(), - &mut swapchain, - &mut width, - &mut height, - ) - }; - if success { - Ok(Texture::new_sdl_managed(swapchain, width, height)) - } else { - Err(get_error()) - } - } - - #[doc(alias = "SDL_AcquireGPUSwapchainTexture")] - pub fn acquire_swapchain_texture<'a>( - &'a mut self, - w: &crate::video::Window, - ) -> Result, Error> { - let mut swapchain = std::ptr::null_mut(); - let mut width = 0; - let mut height = 0; - let success = unsafe { - SDL_AcquireGPUSwapchainTexture( - self.inner, - w.raw(), - &mut swapchain, - &mut width, - &mut height, - ) - }; - if success { - Ok(Texture::new_sdl_managed(swapchain, width, height)) - } else { - Err(get_error()) - } - } - - #[doc(alias = "SDL_SubmitGPUCommandBuffer")] - pub fn submit(self) -> Result<(), Error> { - if unsafe { sys::gpu::SDL_SubmitGPUCommandBuffer(self.inner) } { - Ok(()) - } else { - Err(get_error()) - } - } - - #[doc(alias = "SDL_CancelGPUCommandBuffer")] - pub fn cancel(&mut self) { - unsafe { - sys::gpu::SDL_CancelGPUCommandBuffer(self.inner); - } - } -} - -#[repr(C)] -#[derive(Default)] -pub struct DepthStencilTargetInfo { - inner: SDL_GPUDepthStencilTargetInfo, -} -impl DepthStencilTargetInfo { - pub fn new() -> Self { - Default::default() - } - - pub fn with_texture(mut self, texture: &mut Texture) -> Self { - self.inner.texture = texture.raw(); - self - } - - pub fn with_clear_depth(mut self, clear_depth: f32) -> Self { - self.inner.clear_depth = clear_depth; - self - } - - pub fn with_load_op(mut self, value: LoadOp) -> Self { - self.inner.load_op = value; - self - } - - pub fn with_store_op(mut self, value: StoreOp) -> Self { - self.inner.store_op = value; - self - } - - pub fn with_stencil_load_op(mut self, value: LoadOp) -> Self { - self.inner.stencil_load_op = value; - self - } - - pub fn with_stencil_store_op(mut self, value: StoreOp) -> Self { - self.inner.stencil_store_op = value; - self - } - - pub fn with_cycle(mut self, cycle: bool) -> Self { - self.inner.cycle = cycle; - self - } - - pub fn with_clear_stencil(mut self, clear_stencil: u8) -> Self { - self.inner.clear_stencil = clear_stencil; - self - } -} - -#[repr(C)] -#[derive(Default)] -pub struct ColorTargetInfo { - inner: SDL_GPUColorTargetInfo, -} -impl ColorTargetInfo { - pub fn with_texture(mut self, texture: &Texture) -> Self { - self.inner.texture = texture.raw(); - self - } - pub fn with_load_op(mut self, value: LoadOp) -> Self { - self.inner.load_op = value; - self - } - pub fn with_store_op(mut self, value: StoreOp) -> Self { - self.inner.store_op = value; - self - } - pub fn with_clear_color(mut self, value: Color) -> Self { - self.inner.clear_color.r = (value.r as f32) / 255.0; - self.inner.clear_color.g = (value.g as f32) / 255.0; - self.inner.clear_color.b = (value.b as f32) / 255.0; - self.inner.clear_color.a = (value.a as f32) / 255.0; - self - } -} - -pub struct RenderPass { - pub(super) inner: *mut SDL_GPURenderPass, -} -impl RenderPass { - #[inline] - pub fn raw(&self) -> *mut SDL_GPURenderPass { - self.inner - } - - #[doc(alias = "SDL_BindGPUGraphicsPipeline")] - pub fn bind_graphics_pipeline(&self, pipeline: &GraphicsPipeline) { - unsafe { sys::gpu::SDL_BindGPUGraphicsPipeline(self.inner, pipeline.raw()) } - } - - #[doc(alias = "SDL_BindGPUVertexBuffers")] - pub fn bind_vertex_buffers(&self, first_slot: u32, bindings: &[BufferBinding]) { - unsafe { - SDL_BindGPUVertexBuffers( - self.raw(), - first_slot, - bindings.as_ptr() as *mut SDL_GPUBufferBinding, - bindings.len() as u32, - ) - } - } - - #[doc(alias = "SDL_BindGPUVertexStorageBuffers")] - pub fn bind_vertex_storage_buffers(&self, first_slot: u32, storage_buffers: &[Buffer]) { - let buffer_handles = storage_buffers.iter().map(|x| x.raw()).collect::>(); - unsafe { - sys::gpu::SDL_BindGPUVertexStorageBuffers( - self.inner, - first_slot, - buffer_handles.as_ptr(), - buffer_handles.len() as u32, - ) - } - } - - #[doc(alias = "SDL_BindGPUVertexStorageTextures")] - pub fn bind_vertex_storage_textures(&self, first_slot: u32, storage_textures: &[Texture]) { - let texture_handles = storage_textures.iter().map(|x| x.raw()).collect::>(); - unsafe { - sys::gpu::SDL_BindGPUVertexStorageTextures( - self.inner, - first_slot, - texture_handles.as_ptr(), - texture_handles.len() as u32, - ) - } - } - - #[doc(alias = "SDL_BindGPUIndexBuffer")] - pub fn bind_index_buffer(&self, binding: &BufferBinding, index_element_size: IndexElementSize) { - unsafe { - SDL_BindGPUIndexBuffer( - self.raw(), - &binding.inner, - index_element_size, - ) - } - } - - #[doc(alias = "SDL_BindGPUFragmentSamplers")] - pub fn bind_fragment_samplers(&self, first_slot: u32, bindings: &[TextureSamplerBinding]) { - unsafe { - SDL_BindGPUFragmentSamplers( - self.raw(), - first_slot, - bindings.as_ptr() as *const SDL_GPUTextureSamplerBinding, - bindings.len() as u32, - ); - } - } - - #[doc(alias = "SDL_BindGPUFragmentStorageBuffers")] - pub fn bind_fragment_storage_buffers(&self, first_slot: u32, storage_buffers: &[Buffer]) { - let buffer_handles = storage_buffers.iter().map(|x| x.raw()).collect::>(); - unsafe { - sys::gpu::SDL_BindGPUFragmentStorageBuffers( - self.inner, - first_slot, - buffer_handles.as_ptr(), - buffer_handles.len() as u32, - ) - } - } - - #[doc(alias = "SDL_BindGPUFragmentStorageTextures")] - pub fn bind_fragment_storage_textures(&self, first_slot: u32, storage_textures: &[Texture]) { - let texture_handles = storage_textures.iter().map(|x| x.raw()).collect::>(); - unsafe { - sys::gpu::SDL_BindGPUFragmentStorageTextures( - self.inner, - first_slot, - texture_handles.as_ptr(), - texture_handles.len() as u32, - ) - } - } - - #[doc(alias = "SDL_DrawGPUIndexedPrimitives")] - pub fn draw_indexed_primitives( - &self, - num_indices: u32, - num_instances: u32, - first_index: u32, - vertex_offset: i32, - first_instance: u32, - ) { - unsafe { - SDL_DrawGPUIndexedPrimitives( - self.raw(), - num_indices, - num_instances, - first_index, - vertex_offset, - first_instance, - ); - } - } - - #[doc(alias = "SDL_DrawGPUPrimitives")] - pub fn draw_primitives( - &self, - num_vertices: usize, - num_instances: usize, - first_vertex: usize, - first_instance: usize, - ) { - unsafe { - sys::gpu::SDL_DrawGPUPrimitives( - self.inner, - num_vertices as u32, - num_instances as u32, - first_vertex as u32, - first_instance as u32, - ); - } - } -} - -pub struct CopyPass { - pub(super) inner: *mut SDL_GPUCopyPass, -} -impl CopyPass { - #[inline] - pub fn raw(&self) -> *mut SDL_GPUCopyPass { - self.inner - } - - #[doc(alias = "SDL_UploadToGPUBuffer")] - pub fn upload_to_gpu_buffer( - &self, - transfer_buf_location: TransferBufferLocation, - buffer_region: BufferRegion, - cycle: bool, - ) { - unsafe { - SDL_UploadToGPUBuffer( - self.raw(), - &transfer_buf_location.inner, - &buffer_region.inner, - cycle, - ) - } - } - - #[doc(alias = "SDL_UploadToGPUTexture")] - pub fn upload_to_gpu_texture( - &self, - source: TextureTransferInfo, - destination: TextureRegion, - cycle: bool, - ) { - unsafe { SDL_UploadToGPUTexture(self.raw(), &source.inner, &destination.inner, cycle) } - } -} - -pub struct ComputePass { - pub(super) inner: *mut SDL_GPUComputePass, -} -impl ComputePass { - #[inline] - pub fn raw(&self) -> *mut SDL_GPUComputePass { - self.inner - } - - #[doc(alias = "SDL_BindGPUComputePipeline")] - pub fn bind_compute_pipeline(&self, pipeline: &ComputePipeline) { - unsafe { sys::gpu::SDL_BindGPUComputePipeline(self.inner, pipeline.raw()) } - } - - #[doc(alias = "SDL_BindGPUComputeStorageBuffers")] - pub fn bind_compute_storage_buffers(&self, first_slot: u32, storage_buffers: &[Buffer]) { - let buffer_handles = storage_buffers.iter().map(|x| x.raw()).collect::>(); - unsafe { - sys::gpu::SDL_BindGPUComputeStorageBuffers( - self.inner, - first_slot, - buffer_handles.as_ptr(), - buffer_handles.len() as u32, - ) - } - } - - #[doc(alias = "SDL_BindGPUComputeStorageTextures")] - pub fn bind_compute_storage_textures(&self, first_slot: u32, storage_textures: &[Texture]) { - let texture_handles = storage_textures.iter().map(|x| x.raw()).collect::>(); - unsafe { - sys::gpu::SDL_BindGPUComputeStorageTextures( - self.inner, - first_slot, - texture_handles.as_ptr(), - texture_handles.len() as u32, - ) - } - } - - #[doc(alias = "SDL_DispatchGPUCompute")] - pub fn dispatch(&self, groupcount_x: u32, groupcount_y: u32, groupcount_z: u32) { - unsafe { - sys::gpu::SDL_DispatchGPUCompute(self.inner, groupcount_x, groupcount_y, groupcount_z) - } - } -} diff --git a/src/sdl3/gpu/pass_compute.rs b/src/sdl3/gpu/pass_compute.rs new file mode 100644 index 00000000..c5721ea6 --- /dev/null +++ b/src/sdl3/gpu/pass_compute.rs @@ -0,0 +1,62 @@ + +use std::{ops::Deref, ptr::NonNull}; + +use sys::gpu::{ + SDL_BindGPUComputePipeline, + SDL_BindGPUComputeStorageBuffers, + SDL_BindGPUComputeStorageTextures, + SDL_DispatchGPUCompute, + SDL_GPUBuffer, SDL_GPUComputePass, SDL_GPUTexture +}; + +use super::{ComputePipeline, Extern}; + +pub struct ComputePass { + pub(super) raw: NonNull>, +} + +impl<'gpu> Deref for ComputePass { + type Target = Extern; + + fn deref(&self) -> &Self::Target { + unsafe { self.raw.as_ref() } + } +} + +impl ComputePass { + #[doc(alias = "SDL_BindGPUComputePipeline")] + pub fn bind_compute_pipeline(&self, pipeline: &ComputePipeline) { + unsafe { SDL_BindGPUComputePipeline(self.raw(), pipeline.raw()) } + } + + #[doc(alias = "SDL_BindGPUComputeStorageBuffers")] + pub fn bind_compute_storage_buffers(&self, first_slot: u32, storage_buffers: &[&Extern]) { + unsafe { + SDL_BindGPUComputeStorageBuffers( + self.raw(), + first_slot, + storage_buffers.as_ptr().cast(), + storage_buffers.len() as u32, + ) + } + } + + #[doc(alias = "SDL_BindGPUComputeStorageTextures")] + pub fn bind_compute_storage_textures(&self, first_slot: u32, storage_textures: &[&Extern]) { + unsafe { + SDL_BindGPUComputeStorageTextures( + self.raw(), + first_slot, + storage_textures.as_ptr().cast(), + storage_textures.len() as u32, + ) + } + } + + #[doc(alias = "SDL_DispatchGPUCompute")] + pub fn dispatch(&self, groupcount_x: u32, groupcount_y: u32, groupcount_z: u32) { + unsafe { + SDL_DispatchGPUCompute(self.raw(), groupcount_x, groupcount_y, groupcount_z) + } + } +} diff --git a/src/sdl3/gpu/pass_copy.rs b/src/sdl3/gpu/pass_copy.rs new file mode 100644 index 00000000..1fd2611c --- /dev/null +++ b/src/sdl3/gpu/pass_copy.rs @@ -0,0 +1,54 @@ + +use std::{ops::Deref, ptr::NonNull}; + +use crate::gpu::{ + BufferRegion, TextureTransferInfo, TransferBufferLocation, +}; +use sys::gpu::{ + SDL_GPUCopyPass, + SDL_UploadToGPUBuffer, + SDL_UploadToGPUTexture, +}; + +use super::{Extern, TextureRegion}; + +pub struct CopyPass { + pub(super) raw: NonNull>, +} + +impl<'gpu> Deref for CopyPass { + type Target = Extern; + + fn deref(&self) -> &Self::Target { + unsafe { self.raw.as_ref() } + } +} + +impl CopyPass { + #[doc(alias = "SDL_UploadToGPUBuffer")] + pub fn upload_to_gpu_buffer( + &self, + transfer_buf_location: TransferBufferLocation, + buffer_region: BufferRegion, + cycle: bool, + ) { + unsafe { + SDL_UploadToGPUBuffer( + self.raw(), + &transfer_buf_location.inner, + &buffer_region.inner, + cycle, + ) + } + } + + #[doc(alias = "SDL_UploadToGPUTexture")] + pub fn upload_to_gpu_texture( + &self, + source: TextureTransferInfo, + destination: TextureRegion, + cycle: bool, + ) { + unsafe { SDL_UploadToGPUTexture(self.raw(), &source.inner, &destination.inner, cycle) } + } +} diff --git a/src/sdl3/gpu/pass_render.rs b/src/sdl3/gpu/pass_render.rs new file mode 100644 index 00000000..b9fb5ffd --- /dev/null +++ b/src/sdl3/gpu/pass_render.rs @@ -0,0 +1,158 @@ + +use std::{ops::Deref, ptr::NonNull}; + +use crate::gpu::{ + BufferBinding, GraphicsPipeline, IndexElementSize, + TextureSamplerBinding, +}; +use sys::gpu::{ + SDL_BindGPUFragmentSamplers, SDL_BindGPUIndexBuffer, SDL_BindGPUVertexBuffers, SDL_DrawGPUIndexedPrimitives, SDL_GPUBuffer, SDL_GPUBufferBinding, SDL_GPURenderPass, SDL_GPUTexture, SDL_GPUTextureSamplerBinding, SDL_GPUViewport, SDL_SetGPUViewport +}; + +use super::Extern; + + +pub struct RenderPass { + pub(super) raw: NonNull>, +} +impl<'gpu> Deref for RenderPass { + type Target = Extern; + + fn deref(&self) -> &Self::Target { + unsafe { self.raw.as_ref() } + } +} +impl RenderPass { + #[doc(alias = "SDL_SetGPUViewport")] + pub fn set_viewport(&mut self, viewport: &SDL_GPUViewport) { + unsafe { SDL_SetGPUViewport(self.raw(), viewport) } + } + + #[doc(alias = "SDL_BindGPUGraphicsPipeline")] + pub fn bind_graphics_pipeline(&self, pipeline: &GraphicsPipeline) { + unsafe { sys::gpu::SDL_BindGPUGraphicsPipeline(self.raw(), pipeline.raw()) } + } + + #[doc(alias = "SDL_BindGPUVertexBuffers")] + pub fn bind_vertex_buffers(&self, first_slot: u32, bindings: &[BufferBinding]) { + unsafe { + SDL_BindGPUVertexBuffers( + self.raw(), + first_slot, + bindings.as_ptr() as *mut SDL_GPUBufferBinding, + bindings.len() as u32, + ) + } + } + + #[doc(alias = "SDL_BindGPUVertexStorageBuffers")] + pub fn bind_vertex_storage_buffers(&self, first_slot: u32, storage_buffers: &[&Extern]) { + unsafe { + sys::gpu::SDL_BindGPUVertexStorageBuffers( + self.raw(), + first_slot, + storage_buffers.as_ptr().cast(), + storage_buffers.len() as u32, + ) + } + } + + #[doc(alias = "SDL_BindGPUVertexStorageTextures")] + pub fn bind_vertex_storage_textures(&self, first_slot: u32, storage_textures: &[&Extern]) { + unsafe { + sys::gpu::SDL_BindGPUVertexStorageTextures( + self.raw(), + first_slot, + storage_textures.as_ptr().cast(), + storage_textures.len() as u32, + ) + } + } + + #[doc(alias = "SDL_BindGPUIndexBuffer")] + pub fn bind_index_buffer(&self, binding: &BufferBinding, index_element_size: IndexElementSize) { + unsafe { + SDL_BindGPUIndexBuffer( + self.raw(), + &binding.inner, + index_element_size, + ) + } + } + + #[doc(alias = "SDL_BindGPUFragmentSamplers")] + pub fn bind_fragment_samplers(&self, first_slot: u32, bindings: &[TextureSamplerBinding]) { + unsafe { + SDL_BindGPUFragmentSamplers( + self.raw(), + first_slot, + bindings.as_ptr() as *const SDL_GPUTextureSamplerBinding, + bindings.len() as u32, + ); + } + } + + #[doc(alias = "SDL_BindGPUFragmentStorageBuffers")] + pub fn bind_fragment_storage_buffers(&self, first_slot: u32, storage_buffers: &[&Extern]) { + unsafe { + sys::gpu::SDL_BindGPUFragmentStorageBuffers( + self.raw(), + first_slot, + storage_buffers.as_ptr().cast(), + storage_buffers.len() as u32, + ) + } + } + + #[doc(alias = "SDL_BindGPUFragmentStorageTextures")] + pub fn bind_fragment_storage_textures(&self, first_slot: u32, storage_textures: &[&Extern]) { + unsafe { + sys::gpu::SDL_BindGPUFragmentStorageTextures( + self.raw(), + first_slot, + storage_textures.as_ptr().cast(), + storage_textures.len() as u32, + ) + } + } + + #[doc(alias = "SDL_DrawGPUIndexedPrimitives")] + pub fn draw_indexed_primitives( + &self, + num_indices: u32, + num_instances: u32, + first_index: u32, + vertex_offset: i32, + first_instance: u32, + ) { + unsafe { + SDL_DrawGPUIndexedPrimitives( + self.raw(), + num_indices, + num_instances, + first_index, + vertex_offset, + first_instance, + ); + } + } + + #[doc(alias = "SDL_DrawGPUPrimitives")] + pub fn draw_primitives( + &self, + num_vertices: usize, + num_instances: usize, + first_vertex: usize, + first_instance: usize, + ) { + unsafe { + sys::gpu::SDL_DrawGPUPrimitives( + self.raw(), + num_vertices as u32, + num_instances as u32, + first_vertex as u32, + first_instance as u32, + ); + } + } +} diff --git a/src/sdl3/gpu/pipeline.rs b/src/sdl3/gpu/pipeline.rs deleted file mode 100644 index 08a41c70..00000000 --- a/src/sdl3/gpu/pipeline.rs +++ /dev/null @@ -1,600 +0,0 @@ -use crate::{ - get_error, - gpu::{ - device::WeakDevice, BlendFactor, BlendOp, ColorComponentFlags, CompareOp, CullMode, Device, - FillMode, FrontFace, PrimitiveType, Shader, StencilOp, TextureFormat, - VertexBufferDescription, VertexElementFormat, - }, - sys, Error, -}; -use std::{ffi::CStr, sync::Arc}; -use sys::gpu::{ - SDL_GPUBlendFactor, SDL_GPUBlendOp, SDL_GPUColorTargetBlendState, - SDL_GPUColorTargetDescription, SDL_GPUCompareOp, SDL_GPUComputePipeline, - SDL_GPUComputePipelineCreateInfo, SDL_GPUCullMode, SDL_GPUDepthStencilState, SDL_GPUFillMode, - SDL_GPUFrontFace, SDL_GPUGraphicsPipeline, SDL_GPUGraphicsPipelineCreateInfo, - SDL_GPUGraphicsPipelineTargetInfo, SDL_GPUPrimitiveType, SDL_GPURasterizerState, - SDL_GPUStencilOp, SDL_GPUStencilOpState, SDL_GPUStorageBufferReadWriteBinding, - SDL_GPUStorageTextureReadWriteBinding, SDL_GPUTextureFormat, SDL_GPUVertexAttribute, - SDL_GPUVertexBufferDescription, SDL_GPUVertexInputState, SDL_ReleaseGPUComputePipeline, - SDL_ReleaseGPUGraphicsPipeline, -}; - -use super::{Buffer, ShaderFormat, Texture}; - -#[derive(Default)] -pub struct GraphicsPipelineTargetInfo { - inner: SDL_GPUGraphicsPipelineTargetInfo, -} -impl GraphicsPipelineTargetInfo { - pub fn new() -> Self { - Default::default() - } - - /// A pointer to an array of color target descriptions. - pub fn with_color_target_descriptions(mut self, value: &[ColorTargetDescription]) -> Self { - self.inner.color_target_descriptions = - value.as_ptr() as *const SDL_GPUColorTargetDescription; - self.inner.num_color_targets = value.len() as u32; - self - } - - /// The pixel format of the depth-stencil target. Ignored if has_depth_stencil_target is false. - pub fn with_depth_stencil_format(mut self, value: TextureFormat) -> Self { - self.inner.depth_stencil_format = SDL_GPUTextureFormat(value as i32); - self - } - - /// true specifies that the pipeline uses a depth-stencil target. - pub fn with_has_depth_stencil_target(mut self, value: bool) -> Self { - self.inner.has_depth_stencil_target = value; - self - } -} - -#[repr(C)] -pub struct GraphicsPipelineBuilder<'a> { - device: &'a Device, - inner: SDL_GPUGraphicsPipelineCreateInfo, -} -impl<'a> GraphicsPipelineBuilder<'a> { - pub(super) fn new(device: &'a Device) -> Self { - Self { - device, - inner: Default::default(), - } - } - - pub fn with_fragment_shader(mut self, value: &'a Shader) -> Self { - self.inner.fragment_shader = value.raw(); - self - } - pub fn with_vertex_shader(mut self, value: &'a Shader) -> Self { - self.inner.vertex_shader = value.raw(); - self - } - pub fn with_primitive_type(mut self, value: PrimitiveType) -> Self { - self.inner.primitive_type = SDL_GPUPrimitiveType(value as i32); - self - } - - /// Whether polygons will be filled in or drawn as lines. - /// - /// Note: this will override the value set in `with_rasterizer_state` if called after. - pub fn with_fill_mode(mut self, value: FillMode) -> Self { - self.inner.rasterizer_state.fill_mode = SDL_GPUFillMode(value as i32); - self - } - - /// Sets the parameters of the graphics pipeline rasterizer state. - /// - /// Note: this will override the value set in `with_fill_mode` if called after. - pub fn with_rasterizer_state(mut self, value: RasterizerState) -> Self { - self.inner.rasterizer_state = value.inner; - self - } - - pub fn with_depth_stencil_state(mut self, value: DepthStencilState) -> Self { - self.inner.depth_stencil_state = value.inner; - self - } - - pub fn with_vertex_input_state(mut self, value: VertexInputState) -> Self { - self.inner.vertex_input_state = value.inner; - self - } - - pub fn with_target_info(mut self, value: GraphicsPipelineTargetInfo) -> Self { - self.inner.target_info = value.inner; - self - } - - pub fn build(self) -> Result { - let raw_pipeline = - unsafe { sys::gpu::SDL_CreateGPUGraphicsPipeline(self.device.raw(), &self.inner) }; - if raw_pipeline.is_null() { - Err(get_error()) - } else { - Ok(GraphicsPipeline { - inner: Arc::new(GraphicsPipelineContainer { - raw: raw_pipeline, - device: self.device.weak(), - }), - }) - } - } -} - -/// Manages the raw `SDL_GPUGraphicsPipeline` pointer and releases it on drop -struct GraphicsPipelineContainer { - raw: *mut SDL_GPUGraphicsPipeline, - device: WeakDevice, -} -impl Drop for GraphicsPipelineContainer { - #[doc(alias = "SDL_ReleaseGPUGraphicsPipeline")] - fn drop(&mut self) { - if let Some(device) = self.device.upgrade() { - unsafe { SDL_ReleaseGPUGraphicsPipeline(device.raw(), self.raw) } - } - } -} - -#[derive(Clone)] -pub struct GraphicsPipeline { - inner: Arc, -} -impl GraphicsPipeline { - #[inline] - pub fn raw(&self) -> *mut SDL_GPUGraphicsPipeline { - self.inner.raw - } -} - -#[repr(C)] -#[derive(Clone, Default)] -pub struct VertexAttribute { - inner: SDL_GPUVertexAttribute, -} -impl VertexAttribute { - pub fn new() -> Self { - Default::default() - } - - /// The shader input location index. - pub fn with_location(mut self, value: u32) -> Self { - self.inner.location = value; - self - } - - /// The binding slot of the associated vertex buffer. - pub fn with_buffer_slot(mut self, value: u32) -> Self { - self.inner.buffer_slot = value; - self - } - - /// The size and type of the attribute data. - pub fn with_format(mut self, value: VertexElementFormat) -> Self { - self.inner.format = unsafe { std::mem::transmute(value as u32) }; - self - } - - /// The byte offset of this attribute relative to the start of the vertex element. - pub fn with_offset(mut self, value: u32) -> Self { - self.inner.offset = value; - self - } -} - -#[repr(C)] -#[derive(Default)] -pub struct VertexInputState { - inner: SDL_GPUVertexInputState, -} -impl VertexInputState { - pub fn new() -> Self { - Default::default() - } - - pub fn with_vertex_buffer_descriptions(mut self, value: &[VertexBufferDescription]) -> Self { - self.inner.vertex_buffer_descriptions = - value.as_ptr() as *const SDL_GPUVertexBufferDescription; - self.inner.num_vertex_buffers = value.len() as u32; - self - } - - pub fn with_vertex_attributes(mut self, value: &[VertexAttribute]) -> Self { - self.inner.vertex_attributes = value.as_ptr() as *const SDL_GPUVertexAttribute; - self.inner.num_vertex_attributes = value.len() as u32; - self - } -} - -#[derive(Default)] -pub struct ColorTargetBlendState { - inner: SDL_GPUColorTargetBlendState, -} -impl ColorTargetBlendState { - pub fn new() -> Self { - Self::default() - } - - /// The value to be multiplied by the source RGB value. - pub fn with_src_color_blendfactor(mut self, blend_factor: BlendFactor) -> Self { - self.inner.src_color_blendfactor = SDL_GPUBlendFactor(blend_factor as i32); - self - } - - /// The value to be multiplied by the destination RGB value. - pub fn with_dst_color_blendfactor(mut self, blend_factor: BlendFactor) -> Self { - self.inner.dst_color_blendfactor = SDL_GPUBlendFactor(blend_factor as i32); - self - } - - /// The blend operation for the RGB components. - pub fn with_color_blend_op(mut self, blend_op: BlendOp) -> Self { - self.inner.color_blend_op = SDL_GPUBlendOp(blend_op as i32); - self - } - - /// The value to be multiplied by the source alpha. - pub fn with_src_alpha_blendfactor(mut self, blend_factor: BlendFactor) -> Self { - self.inner.src_alpha_blendfactor = SDL_GPUBlendFactor(blend_factor as i32); - self - } - - /// The value to be multiplied by the destination alpha. - pub fn with_dst_alpha_blendfactor(mut self, blend_factor: BlendFactor) -> Self { - self.inner.dst_alpha_blendfactor = SDL_GPUBlendFactor(blend_factor as i32); - self - } - - /// The blend operation for the alpha component. - pub fn with_alpha_blend_op(mut self, blend_op: BlendOp) -> Self { - self.inner.alpha_blend_op = SDL_GPUBlendOp(blend_op as i32); - self - } - - /// A bitmask specifying which of the RGBA components are enabled for writing. Writes to all channels if enable_color_write_mask is false. - pub fn with_color_write_mask(mut self, flags: ColorComponentFlags) -> Self { - self.inner.color_write_mask = flags.0; - self - } - - /// Whether blending is enabled for the color target. - pub fn with_enable_blend(mut self, enable: bool) -> Self { - self.inner.enable_blend = enable; - self - } - - /// Whether the color write mask is enabled. - pub fn with_enable_color_write_mask(mut self, enable: bool) -> Self { - self.inner.enable_color_write_mask = enable; - self - } -} - -#[repr(C)] -#[derive(Default)] -pub struct ColorTargetDescription { - inner: SDL_GPUColorTargetDescription, -} -impl ColorTargetDescription { - pub fn new() -> Self { - Self::default() - } - - /// The pixel format of the texture to be used as a color target. - pub fn with_format(mut self, value: TextureFormat) -> Self { - self.inner.format = SDL_GPUTextureFormat(value as i32); - self - } - - /// The blend state to be used for the color target. - pub fn with_blend_state(mut self, value: ColorTargetBlendState) -> Self { - self.inner.blend_state = value.inner; - self - } -} - -#[repr(C)] -#[derive(Default)] -pub struct RasterizerState { - inner: SDL_GPURasterizerState, -} -impl RasterizerState { - pub fn new() -> Self { - Default::default() - } - - /// Whether polygons will be filled in or drawn as lines. - pub fn with_fill_mode(mut self, fill_mode: FillMode) -> Self { - self.inner.fill_mode = SDL_GPUFillMode(fill_mode as i32); - self - } - - /// The facing direction in which triangles will be culled. - pub fn with_cull_mode(mut self, cull_mode: CullMode) -> Self { - self.inner.cull_mode = SDL_GPUCullMode(cull_mode as i32); - self - } - - /// The vertex winding that will cause a triangle to be determined as front-facing. - pub fn with_front_face(mut self, front_face: FrontFace) -> Self { - self.inner.front_face = SDL_GPUFrontFace(front_face as i32); - self - } - - /// A scalar factor controlling the depth value added to each fragment. - pub fn with_depth_bias_constant_factor(mut self, value: f32) -> Self { - self.inner.depth_bias_constant_factor = value; - self - } - - /// The maximum depth bias of a fragment. - pub fn with_depth_bias_clamp(mut self, value: f32) -> Self { - self.inner.depth_bias_clamp = value; - self - } - - /// A scalar factor applied to a fragment's slope in depth calculations. - pub fn with_depth_slope_factor(mut self, value: f32) -> Self { - self.inner.depth_bias_slope_factor = value; - self - } - - /// True to bias fragment depth values. - pub fn with_enable_depth_bias(mut self, value: bool) -> Self { - self.inner.enable_depth_bias = value; - self - } - - /// True to enable depth clip, false to enable depth clamp. - pub fn with_enable_depth_clip(mut self, value: bool) -> Self { - self.inner.enable_depth_clip = value; - self - } -} - -#[repr(C)] -#[derive(Default)] -pub struct StencilOpState { - inner: SDL_GPUStencilOpState, -} -impl StencilOpState { - pub fn new() -> Self { - Default::default() - } - - /// The action performed on samples that fail the stencil test. - pub fn with_fail_op(mut self, value: StencilOp) -> Self { - self.inner.fail_op = SDL_GPUStencilOp(value as i32); - self - } - - /// The action performed on samples that pass the depth and stencil tests. - pub fn with_pass_op(mut self, value: StencilOp) -> Self { - self.inner.pass_op = SDL_GPUStencilOp(value as i32); - self - } - - /// The action performed on samples that pass the stencil test and fail the depth test. - pub fn with_depth_fail_op(mut self, value: StencilOp) -> Self { - self.inner.depth_fail_op = SDL_GPUStencilOp(value as i32); - self - } - - /// The comparison operator used in the stencil test. - pub fn compare_op(mut self, value: CompareOp) -> Self { - self.inner.compare_op = SDL_GPUCompareOp(value as i32); - self - } -} - -#[repr(C)] -#[derive(Default)] -pub struct DepthStencilState { - inner: SDL_GPUDepthStencilState, -} -impl DepthStencilState { - pub fn new() -> Self { - Default::default() - } - - /// The comparison operator used for depth testing. - pub fn with_compare_op(mut self, value: CompareOp) -> Self { - self.inner.compare_op = SDL_GPUCompareOp(value as i32); - self - } - - /// The stencil op state for back-facing triangles. - pub fn with_back_stencil_state(mut self, value: StencilOpState) -> Self { - self.inner.back_stencil_state = value.inner; - self - } - - /// The stencil op state for front-facing triangles. - pub fn with_front_stencil_state(mut self, value: StencilOpState) -> Self { - self.inner.front_stencil_state = value.inner; - self - } - - /// Selects the bits of the stencil values participating in the stencil test. - pub fn with_compare_mask(mut self, value: u8) -> Self { - self.inner.compare_mask = value; - self - } - - /// Selects the bits of the stencil values updated by the stencil test. - pub fn with_write_mask(mut self, value: u8) -> Self { - self.inner.write_mask = value; - self - } - - /// True enables the depth test. - pub fn with_enable_depth_test(mut self, value: bool) -> Self { - self.inner.enable_depth_test = value; - self - } - - /// True enables depth writes. - pub fn with_enable_depth_write(mut self, value: bool) -> Self { - self.inner.enable_depth_write = value; - self - } - - /// True enables the stencil test. - pub fn with_enable_stencil_test(mut self, value: bool) -> Self { - self.inner.enable_stencil_test = value; - self - } -} - -#[repr(C)] -pub struct ComputePipelineBuilder<'a> { - device: &'a Device, - inner: SDL_GPUComputePipelineCreateInfo, -} -impl<'a> ComputePipelineBuilder<'a> { - pub(super) fn new(device: &'a Device) -> Self { - Self { - device, - inner: Default::default(), - } - } - - pub fn with_code(mut self, fmt: ShaderFormat, code: &'a [u8]) -> Self { - self.inner.format = fmt.0; - self.inner.code = code.as_ptr(); - self.inner.code_size = code.len(); - self - } - - pub fn with_entrypoint(mut self, entry_point: &'a CStr) -> Self { - self.inner.entrypoint = entry_point.as_ptr(); - self - } - - pub fn with_readonly_storage_textures(mut self, value: u32) -> Self { - self.inner.num_readonly_storage_textures = value; - self - } - - pub fn with_readonly_storage_buffers(mut self, value: u32) -> Self { - self.inner.num_readonly_storage_buffers = value; - self - } - - pub fn with_readwrite_storage_textures(mut self, value: u32) -> Self { - self.inner.num_readwrite_storage_textures = value; - self - } - - pub fn with_readwrite_storage_buffers(mut self, value: u32) -> Self { - self.inner.num_readwrite_storage_buffers = value; - self - } - - pub fn with_uniform_buffers(mut self, value: u32) -> Self { - self.inner.num_uniform_buffers = value; - self - } - - pub fn with_thread_count(mut self, x: u32, y: u32, z: u32) -> Self { - self.inner.threadcount_x = x; - self.inner.threadcount_y = y; - self.inner.threadcount_z = z; - self - } - - pub fn build(self) -> Result { - let raw_pipeline = - unsafe { sys::gpu::SDL_CreateGPUComputePipeline(self.device.raw(), &self.inner) }; - if raw_pipeline.is_null() { - Err(get_error()) - } else { - Ok(ComputePipeline { - inner: Arc::new(ComputePipelineContainer { - raw: raw_pipeline, - device: self.device.weak(), - }), - }) - } - } -} - -/// Manages the raw `SDL_GPUComputePipeline` pointer and releases it on drop -struct ComputePipelineContainer { - raw: *mut SDL_GPUComputePipeline, - device: WeakDevice, -} -impl Drop for ComputePipelineContainer { - #[doc(alias = "SDL_ReleaseGPUComputePipeline")] - fn drop(&mut self) { - if let Some(device) = self.device.upgrade() { - unsafe { SDL_ReleaseGPUComputePipeline(device.raw(), self.raw) } - } - } -} - -#[derive(Clone)] -pub struct ComputePipeline { - inner: Arc, -} -impl ComputePipeline { - #[inline] - pub fn raw(&self) -> *mut SDL_GPUComputePipeline { - self.inner.raw - } -} - -#[repr(C)] -#[derive(Default)] -pub struct StorageTextureReadWriteBinding { - inner: SDL_GPUStorageTextureReadWriteBinding, -} -impl StorageTextureReadWriteBinding { - pub fn new() -> Self { - Default::default() - } - - pub fn with_texture(mut self, texture: &Texture) -> Self { - self.inner.texture = texture.raw(); - self - } - - pub fn with_mip_level(mut self, mip_level: u32) -> Self { - self.inner.mip_level = mip_level; - self - } - - pub fn with_layer(mut self, layer: u32) -> Self { - self.inner.layer = layer; - self - } - - pub fn with_cycle(mut self, cycle: bool) -> Self { - self.inner.cycle = cycle; - self - } -} - -#[repr(C)] -#[derive(Default)] -pub struct StorageBufferReadWriteBinding { - inner: SDL_GPUStorageBufferReadWriteBinding, -} -impl StorageBufferReadWriteBinding { - pub fn new() -> Self { - Default::default() - } - - pub fn with_buffer(mut self, buffer: &Buffer) -> Self { - self.inner.buffer = buffer.raw(); - self - } - - pub fn with_cycle(mut self, cycle: bool) -> Self { - self.inner.cycle = cycle; - self - } -} diff --git a/src/sdl3/gpu/resource/buffer.rs b/src/sdl3/gpu/resource/buffer.rs new file mode 100644 index 00000000..dd4c8750 --- /dev/null +++ b/src/sdl3/gpu/resource/buffer.rs @@ -0,0 +1,50 @@ +use super::util::*; + +use sys::gpu::{ + SDL_GPUBuffer, + SDL_GPUBufferCreateInfo, + SDL_CreateGPUBuffer, + SDL_ReleaseGPUBuffer, +}; + +#[doc(alias = "SDL_GPUBuffer")] +pub struct Buffer<'gpu> { + raw: NonNull>, + device: &'gpu ExternDevice, + len: u32, +} + +impl<'gpu> Drop for Buffer<'gpu> { + #[doc(alias = "SDL_ReleaseGPUBuffer")] + fn drop(&mut self) { + unsafe { + SDL_ReleaseGPUBuffer(self.device.raw(), self.raw()); + } + } +} + +impl<'gpu> Deref for Buffer<'gpu> { + type Target = Extern; + + fn deref(&self) -> &Self::Target { + unsafe { self.raw.as_ref() } + } +} + +impl<'gpu> Buffer<'gpu> { + pub(crate) fn new(device: &'gpu ExternDevice, create_info: &'_ SDL_GPUBufferCreateInfo) -> Result { + let raw = nonnull_ext_or_get_error(unsafe { + SDL_CreateGPUBuffer(device.raw(), create_info) + })?; + Ok(Buffer { + raw, + device, + len: create_info.size, + }) + } + + /// The length of this buffer in bytes. + pub fn len(&self) -> u32 { + self.len + } +} diff --git a/src/sdl3/gpu/resource/builders.rs b/src/sdl3/gpu/resource/builders.rs new file mode 100644 index 00000000..59889f00 --- /dev/null +++ b/src/sdl3/gpu/resource/builders.rs @@ -0,0 +1,251 @@ +//! Defines builders for various GPU-resources. +//! +//! + +use std::{ffi::CStr, marker::PhantomData}; + +use sys::gpu::{ + SDL_GPUBufferCreateInfo, SDL_GPUComputePipelineCreateInfo, SDL_GPUFillMode, SDL_GPUGraphicsPipelineCreateInfo, SDL_GPUPrimitiveType, SDL_GPUShaderCreateInfo, SDL_GPUTransferBufferCreateInfo +}; + +use crate::Error; + +use super::super::{ + Buffer, BufferUsageFlags, ComputePipeline, DepthStencilState, FillMode, GraphicsPipeline, GraphicsPipelineTargetInfo, PrimitiveType, RasterizerState, Shader, ShaderFormat, ShaderStage, TransferBuffer, TransferBufferUsage, VertexInputState +}; +use super::util::ExternDevice; +#[repr(C)] +pub struct ComputePipelineBuilder<'gpu, 'builder> { + device: &'gpu ExternDevice, + inner: SDL_GPUComputePipelineCreateInfo, + _marker: PhantomData<&'builder Shader<'gpu>>, +} +impl<'gpu, 'builder> ComputePipelineBuilder<'gpu, 'builder> { + pub(in crate::gpu) fn new(device: &'gpu ExternDevice) -> Self { + Self { + device, + inner: Default::default(), + _marker: PhantomData, + } + } + + pub fn with_code(mut self, fmt: ShaderFormat, code: &'builder [u8]) -> Self { + self.inner.format = fmt.0; + self.inner.code = code.as_ptr(); + self.inner.code_size = code.len(); + self + } + + pub fn with_entrypoint(mut self, entry_point: &'builder CStr) -> Self { + self.inner.entrypoint = entry_point.as_ptr(); + self + } + + pub fn with_readonly_storage_textures(mut self, value: u32) -> Self { + self.inner.num_readonly_storage_textures = value; + self + } + + pub fn with_readonly_storage_buffers(mut self, value: u32) -> Self { + self.inner.num_readonly_storage_buffers = value; + self + } + + pub fn with_readwrite_storage_textures(mut self, value: u32) -> Self { + self.inner.num_readwrite_storage_textures = value; + self + } + + pub fn with_readwrite_storage_buffers(mut self, value: u32) -> Self { + self.inner.num_readwrite_storage_buffers = value; + self + } + + pub fn with_uniform_buffers(mut self, value: u32) -> Self { + self.inner.num_uniform_buffers = value; + self + } + + pub fn with_thread_count(mut self, x: u32, y: u32, z: u32) -> Self { + self.inner.threadcount_x = x; + self.inner.threadcount_y = y; + self.inner.threadcount_z = z; + self + } + + pub fn build(self) -> Result, Error> { + ComputePipeline::new(self.device, &self.inner) + } +} + +pub struct ShaderBuilder<'gpu> { + device: &'gpu ExternDevice, + inner: SDL_GPUShaderCreateInfo, +} + +impl<'gpu> ShaderBuilder<'gpu> { + pub(in crate::gpu) fn new(device: &'gpu ExternDevice) -> Self { + Self { + device, + inner: Default::default(), + } + } + + pub fn with_samplers(mut self, value: u32) -> Self { + self.inner.num_samplers = value; + self + } + + pub fn with_storage_buffers(mut self, value: u32) -> Self { + self.inner.num_storage_buffers = value; + self + } + + pub fn with_storage_textures(mut self, value: u32) -> Self { + self.inner.num_storage_textures = value; + self + } + + pub fn with_uniform_buffers(mut self, value: u32) -> Self { + self.inner.num_uniform_buffers = value; + self + } + + pub fn with_code(mut self, fmt: ShaderFormat, code: &'gpu [u8], stage: ShaderStage) -> Self { + self.inner.format = fmt.0; + self.inner.code = code.as_ptr(); + self.inner.code_size = code.len() as usize; + self.inner.stage = unsafe { std::mem::transmute(stage as u32) }; + self + } + pub fn with_entrypoint(mut self, entry_point: &'gpu CStr) -> Self { + self.inner.entrypoint = entry_point.as_ptr(); + self + } + pub fn build(self) -> Result, Error> { + Shader::new(self.device, &self.inner) + } +} + + +pub struct TransferBufferBuilder<'gpu> { + device: &'gpu ExternDevice, + inner: SDL_GPUTransferBufferCreateInfo, +} +impl<'gpu> TransferBufferBuilder<'gpu> { + pub(in crate::gpu) fn new(device: &'gpu ExternDevice) -> Self { + Self { + device, + inner: Default::default(), + } + } + + /// How the buffer will be used. + pub fn with_usage(mut self, value: TransferBufferUsage) -> Self { + self.inner.usage = value; + self + } + + /// Desired size of the buffer in bytes. + pub fn with_size(mut self, value: u32) -> Self { + self.inner.size = value; + self + } + + pub fn build(self) -> Result, Error> { + TransferBuffer::new(self.device, &self.inner) + } +} + + +pub struct BufferBuilder<'gpu> { + device: &'gpu ExternDevice, + inner: SDL_GPUBufferCreateInfo, +} +impl<'gpu> BufferBuilder<'gpu> { + pub(in crate::gpu) fn new(device: &'gpu ExternDevice) -> Self { + Self { + device, + inner: Default::default(), + } + } + + pub fn with_usage(mut self, value: BufferUsageFlags) -> Self { + self.inner.usage = value.0; + self + } + + pub fn with_size(mut self, value: u32) -> Self { + self.inner.size = value; + self + } + + pub fn build(self) -> Result, Error> { + Buffer::new(self.device, &self.inner) + } +} + +#[repr(C)] +pub struct GraphicsPipelineBuilder<'gpu, 'builder> { + device: &'gpu ExternDevice, + inner: SDL_GPUGraphicsPipelineCreateInfo, + _marker: PhantomData<&'builder Shader<'gpu>>, +} + +impl<'gpu, 'builder> GraphicsPipelineBuilder<'gpu, 'builder> { + pub(in crate::gpu) fn new(device: &'gpu ExternDevice) -> Self { + Self { + device, + inner: Default::default(), + _marker: PhantomData, + } + } + + pub fn with_fragment_shader(mut self, value: &'builder Shader<'gpu>) -> Self { + self.inner.fragment_shader = value.raw(); + self + } + pub fn with_vertex_shader(mut self, value: &'builder Shader<'gpu>) -> Self { + self.inner.vertex_shader = value.raw(); + self + } + pub fn with_primitive_type(mut self, value: PrimitiveType) -> Self { + self.inner.primitive_type = SDL_GPUPrimitiveType(value as i32); + self + } + + /// Whether polygons will be filled in or drawn as lines. + /// + /// Note: this will override the value set in `with_rasterizer_state` if called after. + pub fn with_fill_mode(mut self, value: FillMode) -> Self { + self.inner.rasterizer_state.fill_mode = SDL_GPUFillMode(value as i32); + self + } + + /// Sets the parameters of the graphics pipeline rasterizer state. + /// + /// Note: this will override the value set in `with_fill_mode` if called after. + pub fn with_rasterizer_state(mut self, value: RasterizerState) -> Self { + self.inner.rasterizer_state = value.inner; + self + } + + pub fn with_depth_stencil_state(mut self, value: DepthStencilState) -> Self { + self.inner.depth_stencil_state = value.inner; + self + } + + pub fn with_vertex_input_state(mut self, value: VertexInputState) -> Self { + self.inner.vertex_input_state = value.inner; + self + } + + pub fn with_target_info(mut self, value: GraphicsPipelineTargetInfo) -> Self { + self.inner.target_info = value.inner; + self + } + + pub fn build(self) -> Result, Error> { + GraphicsPipeline::new(self.device, &self.inner) + } +} \ No newline at end of file diff --git a/src/sdl3/gpu/resource/compute_pipeline.rs b/src/sdl3/gpu/resource/compute_pipeline.rs new file mode 100644 index 00000000..da62ee87 --- /dev/null +++ b/src/sdl3/gpu/resource/compute_pipeline.rs @@ -0,0 +1,41 @@ +use super::util::*; + +use sys::gpu::{ + SDL_GPUComputePipeline, + SDL_GPUComputePipelineCreateInfo, + SDL_CreateGPUComputePipeline, + SDL_ReleaseGPUComputePipeline, +}; + +#[doc(alias = "SDL_GPUComputePipeline")] +pub struct ComputePipeline<'gpu> { + raw: NonNull>, + device: &'gpu ExternDevice, +} + +impl<'gpu> Drop for ComputePipeline<'gpu> { + #[doc(alias = "SDL_ReleaseGPUComputePipeline")] + fn drop(&mut self) { + unsafe { SDL_ReleaseGPUComputePipeline(self.device.raw(), self.raw()) } + } +} + +impl<'gpu> Deref for ComputePipeline<'gpu> { + type Target = Extern; + + fn deref(&self) -> &Self::Target { + unsafe { self.raw.as_ref() } + } +} + +impl<'gpu> ComputePipeline<'gpu> { + pub(crate) fn new(device: &'gpu ExternDevice, create_info: &'_ SDL_GPUComputePipelineCreateInfo) -> Result { + let raw = nonnull_ext_or_get_error(unsafe { + SDL_CreateGPUComputePipeline(device.raw(), create_info) + })?; + Ok(ComputePipeline { + raw, + device, + }) + } +} diff --git a/src/sdl3/gpu/resource/device.rs b/src/sdl3/gpu/resource/device.rs new file mode 100644 index 00000000..8e9a8593 --- /dev/null +++ b/src/sdl3/gpu/resource/device.rs @@ -0,0 +1,40 @@ + +use super::util::*; + +use super::super::ShaderFormat; + +use sys::gpu::{ + SDL_GPUDevice, + SDL_CreateGPUDevice, + SDL_DestroyGPUDevice +}; + +pub struct Device { + raw: NonNull>, +} + +impl Device { + #[doc(alias = "SDL_CreateGPUDevice")] + pub fn new(flags: ShaderFormat, debug_mode: bool) -> Result { + let raw = nonnull_ext_or_get_error(unsafe { + SDL_CreateGPUDevice(flags.0, debug_mode, std::ptr::null()) + })?.cast(); + Ok(Self { raw }) + } +} + +impl Drop for Device { + #[doc(alias = "SDL_DestroyGPUDevice")] + fn drop(&mut self) { + unsafe { SDL_DestroyGPUDevice(self.raw()) } + } +} + +impl Deref for Device { + type Target = Extern; + + fn deref(&self) -> &Self::Target { + unsafe { self.raw.as_ref() } + } +} + diff --git a/src/sdl3/gpu/resource/graphics_pipeline.rs b/src/sdl3/gpu/resource/graphics_pipeline.rs new file mode 100644 index 00000000..a2553c73 --- /dev/null +++ b/src/sdl3/gpu/resource/graphics_pipeline.rs @@ -0,0 +1,41 @@ +use super::util::*; + +use sys::gpu::{ + SDL_GPUGraphicsPipeline, + SDL_GPUGraphicsPipelineCreateInfo, + SDL_CreateGPUGraphicsPipeline, + SDL_ReleaseGPUGraphicsPipeline, +}; + +#[doc(alias = "SDL_GPUGraphicsPipeline")] +pub struct GraphicsPipeline<'gpu> { + raw: NonNull>, + device: &'gpu ExternDevice, +} + +impl<'gpu> Drop for GraphicsPipeline<'gpu> { + #[doc(alias = "SDL_ReleaseGPUGraphicsPipeline")] + fn drop(&mut self) { + unsafe { SDL_ReleaseGPUGraphicsPipeline(self.device.raw(), self.raw()) } + } +} + +impl<'gpu> Deref for GraphicsPipeline<'gpu> { + type Target = Extern; + + fn deref(&self) -> &Self::Target { + unsafe { self.raw.as_ref() } + } +} + +impl<'gpu> GraphicsPipeline<'gpu> { + pub(crate) fn new(device: &'gpu ExternDevice, create_info: &'_ SDL_GPUGraphicsPipelineCreateInfo) -> Result { + let raw = nonnull_ext_or_get_error(unsafe { + SDL_CreateGPUGraphicsPipeline(device.raw(), create_info) + })?; + Ok(GraphicsPipeline { + raw, + device, + }) + } +} diff --git a/src/sdl3/gpu/resource/mod.rs b/src/sdl3/gpu/resource/mod.rs new file mode 100644 index 00000000..4e94831f --- /dev/null +++ b/src/sdl3/gpu/resource/mod.rs @@ -0,0 +1,43 @@ +//! GPU-resources +//! +mod util { + pub(super) use std::ptr::NonNull; + pub(super) use std::ops::Deref; + pub(super) use crate::Error; + + pub(super) use super::super::util::*; + + pub(super) use super::super::Extern; + pub(super) use super::super::ExternDevice; + +} + +mod builders; +pub use builders::{ + ComputePipelineBuilder, GraphicsPipelineBuilder, ShaderBuilder, BufferBuilder, + TransferBufferBuilder, +}; + +mod buffer; +pub use buffer::Buffer; + +mod shader; +pub use shader::Shader; + +mod compute_pipeline; +pub use compute_pipeline::ComputePipeline; + +mod graphics_pipeline; +pub use graphics_pipeline::GraphicsPipeline; + +mod sampler; +pub use sampler::Sampler; + +mod texture; +pub use texture::Texture; + +mod transfer_buffer; +pub use transfer_buffer::TransferBuffer; + +mod device; +pub use device::Device; diff --git a/src/sdl3/gpu/resource/sampler.rs b/src/sdl3/gpu/resource/sampler.rs new file mode 100644 index 00000000..f5463c1b --- /dev/null +++ b/src/sdl3/gpu/resource/sampler.rs @@ -0,0 +1,41 @@ +use super::util::*; + +use sys::gpu::{ + SDL_GPUSampler, + SDL_GPUSamplerCreateInfo, + SDL_CreateGPUSampler, + SDL_ReleaseGPUSampler +}; + +#[doc(alias = "SDL_GPUSampler")] +pub struct Sampler<'gpu> { + raw: NonNull>, + device: &'gpu ExternDevice, +} + +impl<'gpu> Drop for Sampler<'gpu> { + #[doc(alias = "SDL_ReleaseGPUSampler")] + fn drop(&mut self) { + unsafe { SDL_ReleaseGPUSampler(self.device.raw(), self.raw()) } + } +} + +impl<'gpu> Deref for Sampler<'gpu> { + type Target = Extern; + + fn deref(&self) -> &Self::Target { + unsafe { self.raw.as_ref() } + } +} + +impl<'gpu> Sampler<'gpu> { + pub(crate) fn new(device: &'gpu ExternDevice, create_info: &'_ SDL_GPUSamplerCreateInfo) -> Result { + let raw = nonnull_ext_or_get_error(unsafe { + SDL_CreateGPUSampler(device.raw(), create_info) + })?; + Ok(Sampler { + raw, + device, + }) + } +} diff --git a/src/sdl3/gpu/resource/shader.rs b/src/sdl3/gpu/resource/shader.rs new file mode 100644 index 00000000..4847337b --- /dev/null +++ b/src/sdl3/gpu/resource/shader.rs @@ -0,0 +1,41 @@ +use super::util::*; + +use sys::gpu::{ + SDL_GPUShader, + SDL_GPUShaderCreateInfo, + SDL_CreateGPUShader, + SDL_ReleaseGPUShader, +}; + +#[doc(alias = "SDL_GPUShader")] +pub struct Shader<'gpu> { + raw: NonNull>, + device: &'gpu ExternDevice, +} + +impl<'gpu> Drop for Shader<'gpu> { + #[doc(alias = "SDL_ReleaseGPUShader")] + fn drop(&mut self) { + unsafe { SDL_ReleaseGPUShader(self.device.raw(), self.raw()) } + } +} + +impl<'gpu> Deref for Shader<'gpu> { + type Target = Extern; + + fn deref(&self) -> &Self::Target { + unsafe { self.raw.as_ref() } + } +} + +impl<'gpu> Shader<'gpu> { + pub(crate) fn new(device: &'gpu ExternDevice, create_info: &'_ SDL_GPUShaderCreateInfo) -> Result { + let raw = nonnull_ext_or_get_error(unsafe { + SDL_CreateGPUShader(device.raw(), create_info) + })?; + Ok(Shader { + raw, + device, + }) + } +} diff --git a/src/sdl3/gpu/resource/texture.rs b/src/sdl3/gpu/resource/texture.rs new file mode 100644 index 00000000..e3b2106f --- /dev/null +++ b/src/sdl3/gpu/resource/texture.rs @@ -0,0 +1,54 @@ +use super::util::*; + +use sys::gpu::{ + SDL_GPUTexture, + SDL_GPUTextureCreateInfo, + SDL_CreateGPUTexture, + SDL_ReleaseGPUTexture, +}; + +#[doc(alias = "SDL_Texture")] +pub struct Texture<'gpu> { + pub(super) raw: NonNull>, + // the GPU to release this from + pub(super) device: &'gpu ExternDevice, + pub(super) width: u32, + pub(super) height: u32, +} + +impl<'gpu> Drop for Texture<'gpu> { + #[doc(alias = "SDL_ReleaseGPUTexture")] + fn drop(&mut self) { + unsafe { SDL_ReleaseGPUTexture(self.device.raw(), self.raw()) }; + } +} + +impl<'gpu> Deref for Texture<'gpu> { + type Target = Extern; + + fn deref(&self) -> &Self::Target { + unsafe { self.raw.as_ref() } + } +} + +impl<'gpu> Texture<'gpu> { + pub(crate) fn new(device: &'gpu ExternDevice, create_info: &'_ SDL_GPUTextureCreateInfo) -> Result { + let raw = nonnull_ext_or_get_error(unsafe { + SDL_CreateGPUTexture(device.raw(), create_info) + })?; + Ok(Texture { + raw, + width: create_info.width, + height: create_info.height, + device, + }) + } + + pub fn width(&self) -> u32 { + self.width + } + + pub fn height(&self) -> u32 { + self.height + } +} diff --git a/src/sdl3/gpu/resource/transfer_buffer.rs b/src/sdl3/gpu/resource/transfer_buffer.rs new file mode 100644 index 00000000..61e17815 --- /dev/null +++ b/src/sdl3/gpu/resource/transfer_buffer.rs @@ -0,0 +1,72 @@ +use crate::get_error; + +use super::util::*; + +use sys::gpu::{ + SDL_CreateGPUTransferBuffer, SDL_GPUTransferBuffer, SDL_GPUTransferBufferCreateInfo, SDL_MapGPUTransferBuffer, SDL_ReleaseGPUTransferBuffer, SDL_UnmapGPUTransferBuffer +}; + +#[doc(alias = "SDL_GPUTransferBuffer")] +pub struct TransferBuffer<'gpu> { + raw: NonNull>, + device: &'gpu ExternDevice, + len: u32, +} + +impl<'gpu> Drop for TransferBuffer<'gpu> { + #[doc(alias = "SDL_ReleaseGPUTransferBuffer")] + fn drop(&mut self) { + unsafe { + SDL_ReleaseGPUTransferBuffer(self.device.raw(), self.raw()); + } + } +} + +impl<'gpu> Deref for TransferBuffer<'gpu> { + type Target = Extern; + + fn deref(&self) -> &Self::Target { + unsafe { self.raw.as_ref() } + } +} + + +impl<'gpu> TransferBuffer<'gpu> { + pub(crate) fn new(device: &'gpu ExternDevice, create_info: &'_ SDL_GPUTransferBufferCreateInfo) -> Result { + let raw = nonnull_ext_or_get_error(unsafe { + SDL_CreateGPUTransferBuffer(device.raw(), create_info) + })?; + Ok(TransferBuffer { + raw, + device, + len: create_info.size, + }) + } + + #[doc(alias = "SDL_MapGPUTransferBuffer")] + pub fn mapped_mut( + &mut self, + cycle: bool, + f: impl for<'a> FnOnce(&'a mut [u8]) -> R, + ) -> Result { + unsafe { + let raw = SDL_MapGPUTransferBuffer(self.device.raw(), self.raw(), cycle); + if raw.is_null() { + return Err(get_error()); + } + + let bytes = std::slice::from_raw_parts_mut(raw as *mut u8, self.len as usize); + + let _defer = Defer::new(|| + SDL_UnmapGPUTransferBuffer(self.device.raw(), self.raw()) + ); + + Ok(f(bytes)) + } + } + + /// The length of this buffer in bytes. + pub fn len(&self) -> u32 { + self.len + } +} diff --git a/src/sdl3/gpu/shader.rs b/src/sdl3/gpu/shader.rs deleted file mode 100644 index 65581406..00000000 --- a/src/sdl3/gpu/shader.rs +++ /dev/null @@ -1,89 +0,0 @@ -use crate::{ - get_error, - gpu::{Device, ShaderFormat, ShaderStage, WeakDevice}, - Error, -}; -use std::{ffi::CStr, sync::Arc}; -use sys::gpu::{SDL_GPUShader, SDL_GPUShaderCreateInfo}; - -/// Manages the raw `SDL_GPUShader` pointer and releases it on drop -struct ShaderContainer { - raw: *mut SDL_GPUShader, - device: WeakDevice, -} -impl Drop for ShaderContainer { - fn drop(&mut self) { - if let Some(device) = self.device.upgrade() { - unsafe { sys::gpu::SDL_ReleaseGPUShader(device.raw(), self.raw) } - } - } -} - -#[derive(Clone)] -pub struct Shader { - inner: Arc, -} -impl Shader { - #[inline] - pub fn raw(&self) -> *mut SDL_GPUShader { - self.inner.raw - } -} - -pub struct ShaderBuilder<'a> { - device: &'a Device, - inner: SDL_GPUShaderCreateInfo, -} -impl<'a> ShaderBuilder<'a> { - pub(super) fn new(device: &'a Device) -> Self { - Self { - device, - inner: Default::default(), - } - } - - pub fn with_samplers(mut self, value: u32) -> Self { - self.inner.num_samplers = value; - self - } - - pub fn with_storage_buffers(mut self, value: u32) -> Self { - self.inner.num_storage_buffers = value; - self - } - - pub fn with_storage_textures(mut self, value: u32) -> Self { - self.inner.num_storage_textures = value; - self - } - - pub fn with_uniform_buffers(mut self, value: u32) -> Self { - self.inner.num_uniform_buffers = value; - self - } - - pub fn with_code(mut self, fmt: ShaderFormat, code: &'a [u8], stage: ShaderStage) -> Self { - self.inner.format = fmt.0; - self.inner.code = code.as_ptr(); - self.inner.code_size = code.len() as usize; - self.inner.stage = unsafe { std::mem::transmute(stage as u32) }; - self - } - pub fn with_entrypoint(mut self, entry_point: &'a CStr) -> Self { - self.inner.entrypoint = entry_point.as_ptr(); - self - } - pub fn build(self) -> Result { - let raw_shader = unsafe { sys::gpu::SDL_CreateGPUShader(self.device.raw(), &self.inner) }; - if !raw_shader.is_null() { - Ok(Shader { - inner: Arc::new(ShaderContainer { - raw: raw_shader, - device: self.device.weak(), - }), - }) - } else { - Err(get_error()) - } - } -} diff --git a/src/sdl3/gpu/swapchain.rs b/src/sdl3/gpu/swapchain.rs new file mode 100644 index 00000000..18b05d06 --- /dev/null +++ b/src/sdl3/gpu/swapchain.rs @@ -0,0 +1,35 @@ +use std::{marker::PhantomData, ops::Deref, ptr::NonNull}; + +use sys::gpu::SDL_GPUTexture; + +use super::Extern; + + +type Invariant<'a> = PhantomData &'a ()>; + + +#[doc(alias = "SDL_Texture")] +pub struct SwapchainTexture<'cmd_buf> { + pub(super) raw: NonNull>, + pub(super) width: u32, + pub(super) height: u32, + pub(super) _marker: Invariant<'cmd_buf>, +} + +impl<'cmd_buf> Deref for SwapchainTexture<'cmd_buf> { + type Target = Extern; + + fn deref(&self) -> &Self::Target { + unsafe { self.raw.as_ref() } + } +} + +impl<'cmd_buf> SwapchainTexture<'cmd_buf> { + pub fn width(&self) -> u32 { + self.width + } + + pub fn height(&self) -> u32 { + self.height + } +} diff --git a/src/sdl3/gpu/texture.rs b/src/sdl3/gpu/texture.rs deleted file mode 100644 index 8354c4ab..00000000 --- a/src/sdl3/gpu/texture.rs +++ /dev/null @@ -1,397 +0,0 @@ -use crate::gpu::{ - CompareOp, Device, Filter, SampleCount, SamplerAddressMode, SamplerMipmapMode, TextureFormat, - TextureType, TextureUsage, TransferBuffer, WeakDevice, -}; -use std::{marker::PhantomData, sync::Arc}; -use sys::gpu::{ - SDL_GPUCompareOp, SDL_GPUFilter, SDL_GPUSampleCount, SDL_GPUSampler, SDL_GPUSamplerAddressMode, - SDL_GPUSamplerCreateInfo, SDL_GPUSamplerMipmapMode, SDL_GPUTexture, SDL_GPUTextureCreateInfo, - SDL_GPUTextureFormat, SDL_GPUTextureRegion, SDL_GPUTextureSamplerBinding, - SDL_GPUTextureTransferInfo, SDL_GPUTextureType, SDL_ReleaseGPUSampler, SDL_ReleaseGPUTexture, -}; - -#[derive(Default)] -pub struct TextureTransferInfo { - pub(super) inner: SDL_GPUTextureTransferInfo, -} -impl TextureTransferInfo { - pub fn new() -> Self { - Default::default() - } - - /// The transfer buffer used in the transfer operation. - pub fn with_transfer_buffer(mut self, buffer: &TransferBuffer) -> Self { - self.inner.transfer_buffer = buffer.raw(); - self - } - - /// The starting byte of the image data in the transfer buffer. - pub fn with_offset(mut self, offset: u32) -> Self { - self.inner.offset = offset; - self - } - - /// The number of pixels from one row to the next. - pub fn with_pixels_per_row(mut self, value: u32) -> Self { - self.inner.pixels_per_row = value; - self - } - - /// The number of rows from one layer/depth-slice to the next. - pub fn with_rows_per_layer(mut self, value: u32) -> Self { - self.inner.rows_per_layer = value; - self - } -} - -#[derive(Default)] -pub struct TextureRegion { - pub(super) inner: SDL_GPUTextureRegion, -} -impl TextureRegion { - pub fn new() -> Self { - Default::default() - } - - /// The texture used in the copy operation. - pub fn with_texture(mut self, texture: &Texture) -> Self { - self.inner.texture = texture.raw(); - self - } - - /// The mip level index to transfer. - pub fn with_mip_level(mut self, mip_level: u32) -> Self { - self.inner.mip_level = mip_level; - self - } - - /// The layer index to transfer. - pub fn with_layer(mut self, layer: u32) -> Self { - self.inner.layer = layer; - self - } - - /// The left offset of the region. - pub fn with_x(mut self, x: u32) -> Self { - self.inner.x = x; - self - } - - /// The top offset of the region. - pub fn with_y(mut self, y: u32) -> Self { - self.inner.y = y; - self - } - - /// The front offset of the region. - pub fn with_z(mut self, z: u32) -> Self { - self.inner.z = z; - self - } - - /// The width of the region. - pub fn with_width(mut self, width: u32) -> Self { - self.inner.w = width; - self - } - - /// The height of the region. - pub fn with_height(mut self, height: u32) -> Self { - self.inner.h = height; - self - } - - /// The depth of the region. - pub fn with_depth(mut self, depth: u32) -> Self { - self.inner.d = depth; - self - } -} - -#[derive(Default)] -pub struct SamplerCreateInfo { - pub(super) inner: SDL_GPUSamplerCreateInfo, -} -impl SamplerCreateInfo { - pub fn new() -> Self { - Default::default() - } - - /// The minification filter to apply to lookups. - pub fn with_min_filter(mut self, filter: Filter) -> Self { - self.inner.min_filter = SDL_GPUFilter(filter as i32); - self - } - - /// The magnification filter to apply to lookups. - pub fn with_mag_filter(mut self, filter: Filter) -> Self { - self.inner.mag_filter = SDL_GPUFilter(filter as i32); - self - } - - /// The mipmap filter to apply to lookups. - pub fn with_mipmap_mode(mut self, mode: SamplerMipmapMode) -> Self { - self.inner.mipmap_mode = SDL_GPUSamplerMipmapMode(mode as i32); - self - } - - /// The addressing mode for U coordinates outside [0, 1). - pub fn with_address_mode_u(mut self, mode: SamplerAddressMode) -> Self { - self.inner.address_mode_u = SDL_GPUSamplerAddressMode(mode as i32); - self - } - - /// The addressing mode for V coordinates outside [0, 1). - pub fn with_address_mode_v(mut self, mode: SamplerAddressMode) -> Self { - self.inner.address_mode_v = SDL_GPUSamplerAddressMode(mode as i32); - self - } - - /// The addressing mode for W coordinates outside [0, 1). - pub fn with_address_mode_w(mut self, mode: SamplerAddressMode) -> Self { - self.inner.address_mode_w = SDL_GPUSamplerAddressMode(mode as i32); - self - } - - /// The bias to be added to mipmap LOD calculation. - pub fn with_mip_lod_bias(mut self, value: f32) -> Self { - self.inner.mip_lod_bias = value; - self - } - - /// The anisotropy value clamp used by the sampler. If enable_anisotropy is false, this is ignored. - pub fn with_max_anisotropy(mut self, value: f32) -> Self { - self.inner.max_anisotropy = value; - self - } - - /// The comparison operator to apply to fetched data before filtering. - pub fn with_compare_op(mut self, value: CompareOp) -> Self { - self.inner.compare_op = SDL_GPUCompareOp(value as i32); - self - } - - /// Clamps the minimum of the computed LOD value. - pub fn with_min_lod(mut self, value: f32) -> Self { - self.inner.min_lod = value; - self - } - - /// Clamps the maximum of the computed LOD value. - pub fn with_max_lod(mut self, value: f32) -> Self { - self.inner.max_lod = value; - self - } - - /// True to enable anisotropic filtering. - pub fn with_enable_anisotropy(mut self, enable: bool) -> Self { - self.inner.enable_anisotropy = enable; - self - } - - /// True to enable comparison against a reference value during lookups. - pub fn with_enable_compare(mut self, enable: bool) -> Self { - self.inner.enable_compare = enable; - self - } -} - -/// Manages the raw `SDL_GPUSampler` pointer and releases it on drop -struct SamplerContainer { - raw: *mut SDL_GPUSampler, - device: WeakDevice, -} -impl Drop for SamplerContainer { - fn drop(&mut self) { - if let Some(device) = self.device.upgrade() { - unsafe { SDL_ReleaseGPUSampler(device.raw(), self.raw) } - } - } -} - -#[derive(Clone)] -pub struct Sampler { - inner: Arc, -} -impl Sampler { - pub(super) fn new(device: &Device, raw_sampler: *mut SDL_GPUSampler) -> Self { - Self { - inner: Arc::new(SamplerContainer { - raw: raw_sampler, - device: device.weak(), - }), - } - } - - #[inline] - fn raw(&self) -> *mut SDL_GPUSampler { - self.inner.raw - } -} - -#[repr(C)] -#[derive(Default)] -pub struct TextureSamplerBinding { - inner: SDL_GPUTextureSamplerBinding, -} -impl TextureSamplerBinding { - pub fn new() -> Self { - Default::default() - } - - /// The texture to bind. Must have been created with [`SDL_GPU_TEXTUREUSAGE_SAMPLER`]. - pub fn with_texture(mut self, texture: &Texture<'static>) -> Self { - self.inner.texture = texture.raw(); - self - } - - /// The sampler to bind. - pub fn with_sampler(mut self, sampler: &Sampler) -> Self { - self.inner.sampler = sampler.raw(); - self - } -} - -/// Manages the raw `SDL_GPUTexture` pointer and releases it on drop (if necessary) -enum TextureContainer { - /// The user is responsible for releasing this texture - UserManaged { - raw: *mut SDL_GPUTexture, - device: WeakDevice, - }, - /// SDL owns this texture and is responsible for releasing it - SdlManaged { raw: *mut SDL_GPUTexture }, -} -impl TextureContainer { - fn raw(&self) -> *mut SDL_GPUTexture { - match self { - Self::UserManaged { raw, .. } => *raw, - Self::SdlManaged { raw } => *raw, - } - } -} -impl Drop for TextureContainer { - #[doc(alias = "SDL_ReleaseGPUTexture")] - fn drop(&mut self) { - match self { - Self::UserManaged { raw, device } => { - if let Some(device) = device.upgrade() { - unsafe { SDL_ReleaseGPUTexture(device.raw(), *raw) }; - } - } - _ => {} - } - } -} - -// Texture has a lifetime for the case of the special swapchain texture that must not -// live longer than the command buffer it is bound to. Otherwise, it is always 'static. -#[derive(Clone)] -pub struct Texture<'a> { - inner: Arc, - width: u32, - height: u32, - _phantom: PhantomData<&'a ()>, -} -impl<'a> Texture<'a> { - pub(super) fn new( - device: &Device, - raw: *mut SDL_GPUTexture, - width: u32, - height: u32, - ) -> Texture<'a> { - Texture { - inner: Arc::new(TextureContainer::UserManaged { - raw, - device: device.weak(), - }), - width, - height, - _phantom: Default::default(), - } - } - - pub(super) fn new_sdl_managed( - raw: *mut SDL_GPUTexture, - width: u32, - height: u32, - ) -> Texture<'a> { - Texture { - inner: Arc::new(TextureContainer::SdlManaged { raw }), - width, - height, - _phantom: Default::default(), - } - } - - #[inline] - pub fn raw(&self) -> *mut SDL_GPUTexture { - self.inner.raw() - } - - pub fn width(&self) -> u32 { - self.width - } - - pub fn height(&self) -> u32 { - self.height - } -} - -#[derive(Default)] -pub struct TextureCreateInfo { - pub(super) inner: SDL_GPUTextureCreateInfo, -} -impl TextureCreateInfo { - pub fn new() -> Self { - Default::default() - } - - /// The base dimensionality of the texture. - pub fn with_type(mut self, value: TextureType) -> Self { - self.inner.r#type = SDL_GPUTextureType(value as i32); - self - } - - /// The pixel format of the texture. - pub fn with_format(mut self, format: TextureFormat) -> Self { - self.inner.format = SDL_GPUTextureFormat(format as i32); - self - } - - /// How the texture is intended to be used by the client. - pub fn with_usage(mut self, value: TextureUsage) -> Self { - self.inner.usage = value.0; - self - } - - /// The width of the texture. - pub fn with_width(mut self, value: u32) -> Self { - self.inner.width = value; - self - } - - /// The height of the texture. - pub fn with_height(mut self, value: u32) -> Self { - self.inner.height = value; - self - } - - /// The layer count or depth of the texture. This value is treated as a layer count on 2D array textures, and as a depth value on 3D textures. - pub fn with_layer_count_or_depth(mut self, value: u32) -> Self { - self.inner.layer_count_or_depth = value; - self - } - - /// The number of mip levels in the texture. - pub fn with_num_levels(mut self, value: u32) -> Self { - self.inner.num_levels = value; - self - } - - /// The number of samples per texel. Only applies if the texture is used as a render target. - pub fn with_sample_count(mut self, value: SampleCount) -> Self { - self.inner.sample_count = SDL_GPUSampleCount(value as i32); - self - } -} diff --git a/src/sdl3/gpu/util.rs b/src/sdl3/gpu/util.rs new file mode 100644 index 00000000..2c652a7d --- /dev/null +++ b/src/sdl3/gpu/util.rs @@ -0,0 +1,29 @@ +use std::{mem::ManuallyDrop, ptr::NonNull}; + +use crate::{get_error, Error}; + +use super::Extern; + + +#[inline(always)] +pub(super) fn nonnull_ext_or_get_error(ptr: *mut T) -> Result>, Error> { + NonNull::new(ptr.cast()).ok_or_else(|| get_error()) +} + +/// Calls the closure when being dropped +pub(super) struct Defer(ManuallyDrop); +impl Defer { + pub(super) fn new(f: F) -> Self { + Self(ManuallyDrop::new(f)) + } +} + +impl Drop for Defer { + fn drop(&mut self) { + // Safety: This is the last (and only) use of the value + unsafe { + let f = ManuallyDrop::take(&mut self.0); + f(); + } + } +} \ No newline at end of file From 321aaf59e92fea5b160e4b2f9e3334d0334b1961 Mon Sep 17 00:00:00 2001 From: quaternic <57393910+quaternic@users.noreply.github.com> Date: Mon, 7 Apr 2025 21:34:33 +0300 Subject: [PATCH 3/5] more refactoring --- examples/gpu-clear.rs | 2 +- examples/gpu-cube.rs | 41 +-- examples/gpu-texture.rs | 34 +- examples/gpu-triangle.rs | 4 +- src/sdl3/audio.rs | 1 + .../compute.rs} | 50 ++- .../{pass_copy.rs => command_buffer/copy.rs} | 28 +- src/sdl3/gpu/command_buffer/fence.rs | 15 + .../mod.rs} | 158 ++++----- .../render.rs} | 86 +++-- .../gpu/{ => command_buffer}/swapchain.rs | 7 +- src/sdl3/gpu/enums.rs | 9 +- src/sdl3/gpu/info_struct.rs | 194 +++++------ src/sdl3/gpu/mod.rs | 81 ++--- src/sdl3/gpu/resource/buffer.rs | 50 --- src/sdl3/gpu/resource/builders.rs | 119 +++++-- src/sdl3/gpu/resource/compute_pipeline.rs | 41 --- src/sdl3/gpu/resource/device.rs | 22 +- src/sdl3/gpu/resource/graphics_pipeline.rs | 41 --- src/sdl3/gpu/resource/mod.rs | 303 ++++++++++++++++-- src/sdl3/gpu/resource/sampler.rs | 41 --- src/sdl3/gpu/resource/shader.rs | 41 --- src/sdl3/gpu/resource/texture.rs | 54 ---- src/sdl3/gpu/resource/transfer_buffer.rs | 72 ----- 24 files changed, 676 insertions(+), 818 deletions(-) rename src/sdl3/gpu/{pass_compute.rs => command_buffer/compute.rs} (52%) rename src/sdl3/gpu/{pass_copy.rs => command_buffer/copy.rs} (52%) create mode 100644 src/sdl3/gpu/command_buffer/fence.rs rename src/sdl3/gpu/{command_buffer.rs => command_buffer/mod.rs} (60%) rename src/sdl3/gpu/{pass_render.rs => command_buffer/render.rs} (69%) rename src/sdl3/gpu/{ => command_buffer}/swapchain.rs (80%) delete mode 100644 src/sdl3/gpu/resource/buffer.rs delete mode 100644 src/sdl3/gpu/resource/compute_pipeline.rs delete mode 100644 src/sdl3/gpu/resource/graphics_pipeline.rs delete mode 100644 src/sdl3/gpu/resource/sampler.rs delete mode 100644 src/sdl3/gpu/resource/shader.rs delete mode 100644 src/sdl3/gpu/resource/texture.rs delete mode 100644 src/sdl3/gpu/resource/transfer_buffer.rs diff --git a/examples/gpu-clear.rs b/examples/gpu-clear.rs index 6c55ef63..a24704af 100644 --- a/examples/gpu-clear.rs +++ b/examples/gpu-clear.rs @@ -17,7 +17,7 @@ pub fn main() -> Result<(), Box> { // by default, and we specify that our shaders will be SPIR-V ones (even through we // aren't using any shaders) // We'll also turn on debug mode to true, so we get debug stuff - let gpu = sdl3::gpu::Device::new(sdl3::gpu::ShaderFormat::SPIRV, true)?; + let gpu = sdl3::gpu::OwnedDevice::new(sdl3::gpu::ShaderFormat::SPIRV, true)?; gpu.claim_window(&window)?; let mut event_pump = sdl_context.event_pump()?; diff --git a/examples/gpu-cube.rs b/examples/gpu-cube.rs index 5bbfad30..0e4dfe98 100644 --- a/examples/gpu-cube.rs +++ b/examples/gpu-cube.rs @@ -1,13 +1,7 @@ use sdl3::{ event::Event, gpu::{ - Buffer, BufferBinding, BufferRegion, BufferUsageFlags, ColorTargetDescription, - ColorTargetInfo, CompareOp, CopyPass, CullMode, DepthStencilState, DepthStencilTargetInfo, - Device, FillMode, GraphicsPipelineTargetInfo, IndexElementSize, LoadOp, PrimitiveType, - RasterizerState, SampleCount, ShaderFormat, ShaderStage, StoreOp, TextureCreateInfo, - TextureFormat, TextureType, TextureUsage, TransferBuffer, TransferBufferLocation, - TransferBufferUsage, VertexAttribute, VertexBufferDescription, VertexElementFormat, - VertexInputRate, VertexInputState, + Buffer, BufferBinding, BufferRegion, BufferUsageFlags, ColorTargetDescription, ColorTargetInfo, CompareOp, CopyPass, CullMode, DepthStencilState, DepthStencilTargetInfo, FillMode, GraphicsPipelineTargetInfo, IndexElementSize, LoadOp, Owned, OwnedDevice, PrimitiveType, RasterizerState, SampleCount, ShaderFormat, ShaderStage, StoreOp, TextureCreateInfo, TextureFormat, TextureType, TextureUsage, TransferBuffer, TransferBufferLocation, TransferBufferUsage, VertexAttribute, VertexBufferDescription, VertexElementFormat, VertexInputRate, VertexInputState }, keyboard::Keycode, pixels::Color, @@ -88,7 +82,7 @@ pub fn main() -> Result<(), Box> { .build() .map_err(|e| e.to_string())?; - let gpu = Device::new( + let gpu = OwnedDevice::new( ShaderFormat::SPIRV | ShaderFormat::DXIL | ShaderFormat::DXBC | ShaderFormat::METALLIB, true, )?; @@ -261,18 +255,12 @@ pub fn main() -> Result<(), Box> { render_pass.bind_graphics_pipeline(&pipeline); // Now we'll bind our buffers and draw the cube - render_pass.bind_vertex_buffers( - 0, - &[BufferBinding::new() - .with_buffer(&vertex_buffer) - .with_offset(0)], - ); + render_pass.bind_vertex_buffers( 0, &[ + BufferBinding::new().with_buffer(&vertex_buffer) + ]); render_pass.bind_index_buffer( - &BufferBinding::new() - .with_buffer(&index_buffer) - .with_offset(0), - IndexElementSize::_16BIT, - ); + &BufferBinding::new().with_buffer(&index_buffer), + IndexElementSize::_16BIT); // Set the rotation uniform for our cube vert shader command_buffer.push_vertex_uniform_data(0, &rotation); @@ -294,12 +282,12 @@ pub fn main() -> Result<(), Box> { /// Creates a GPU buffer and uploads data to it using the given `copy_pass` and `transfer_buffer`. fn create_buffer_with_data<'gpu, T: Copy>( - gpu: &'gpu Device, - transfer_buffer: &mut TransferBuffer, + gpu: &'gpu OwnedDevice, + transfer_buffer: &mut Owned<'_, TransferBuffer>, copy_pass: &CopyPass, usage: BufferUsageFlags, data: &[T], -) -> Result, Error> { +) -> Result, Error> { // Figure out the length of the data in bytes let len_bytes = data.len() * std::mem::size_of::(); @@ -330,13 +318,8 @@ fn create_buffer_with_data<'gpu, T: Copy>( // // Note: We also set `cycle` to true here for the same reason. copy_pass.upload_to_gpu_buffer( - TransferBufferLocation::new() - .with_offset(0) - .with_transfer_buffer(transfer_buffer), - BufferRegion::new() - .with_offset(0) - .with_size(len_bytes as u32) - .with_buffer(&buffer), + transfer_buffer.get(0..), + buffer.get(0..len_bytes as u32), true, ); diff --git a/examples/gpu-texture.rs b/examples/gpu-texture.rs index 04d6f2ff..f25f5c93 100644 --- a/examples/gpu-texture.rs +++ b/examples/gpu-texture.rs @@ -1,14 +1,7 @@ use sdl3::{ event::Event, gpu::{ - Buffer, BufferBinding, BufferRegion, BufferUsageFlags, ColorTargetDescription, - ColorTargetInfo, CompareOp, CopyPass, CullMode, DepthStencilState, DepthStencilTargetInfo, - Device, FillMode, Filter, GraphicsPipelineTargetInfo, IndexElementSize, LoadOp, - PrimitiveType, RasterizerState, SampleCount, SamplerAddressMode, SamplerCreateInfo, - SamplerMipmapMode, ShaderFormat, ShaderStage, StoreOp, Texture, TextureCreateInfo, - TextureFormat, TextureRegion, TextureSamplerBinding, TextureTransferInfo, TextureType, - TextureUsage, TransferBuffer, TransferBufferLocation, TransferBufferUsage, VertexAttribute, - VertexBufferDescription, VertexElementFormat, VertexInputRate, VertexInputState, + Buffer, BufferBinding, BufferUsageFlags, ColorTargetDescription, ColorTargetInfo, CompareOp, CopyPass, CullMode, DepthStencilState, DepthStencilTargetInfo, FillMode, Filter, GraphicsPipelineTargetInfo, IndexElementSize, LoadOp, Owned, OwnedDevice, PrimitiveType, RasterizerState, SampleCount, SamplerAddressMode, SamplerCreateInfo, SamplerMipmapMode, ShaderFormat, ShaderStage, StoreOp, Texture, TextureCreateInfo, TextureFormat, TextureRegion, TextureSamplerBinding, TextureTransferInfo, TextureType, TextureUsage, TransferBuffer, TransferBufferLocation, TransferBufferUsage, VertexAttribute, VertexBufferDescription, VertexElementFormat, VertexInputRate, VertexInputState }, keyboard::Keycode, pixels::Color, @@ -193,7 +186,7 @@ pub fn main() -> Result<(), Box> { .build() .map_err(|e| e.to_string())?; - let gpu = sdl3::gpu::Device::new( + let gpu = sdl3::gpu::OwnedDevice::new( ShaderFormat::SPIRV | ShaderFormat::DXIL | ShaderFormat::DXBC | ShaderFormat::METALLIB, true, )?; @@ -403,9 +396,7 @@ pub fn main() -> Result<(), Box> { ); render_pass.bind_fragment_samplers( 0, - &[TextureSamplerBinding::new() - .with_texture(&cube_texture) - .with_sampler(&cube_texture_sampler)], + &[cube_texture.with_sampler(&cube_texture_sampler)], ); // Set the rotation uniform for our cube vert shader @@ -428,10 +419,10 @@ pub fn main() -> Result<(), Box> { } fn create_texture_from_image<'gpu>( - gpu: &'gpu Device, + gpu: &'gpu OwnedDevice, image_path: impl AsRef, copy_pass: &CopyPass, -) -> Result, Error> { +) -> Result, Error> { let image = Surface::load_bmp(image_path.as_ref())?; let image_size = image.size(); let size_bytes = @@ -483,12 +474,12 @@ fn create_texture_from_image<'gpu>( /// Creates a GPU buffer and uploads data to it using the given `copy_pass` and `transfer_buffer`. fn create_buffer_with_data<'gpu, T: Copy>( - gpu: &'gpu Device, - transfer_buffer: &mut TransferBuffer, + gpu: &'gpu OwnedDevice, + transfer_buffer: &mut Owned<'_, TransferBuffer>, copy_pass: &CopyPass, usage: BufferUsageFlags, data: &[T], -) -> Result, Error> { +) -> Result, Error> { // Figure out the length of the data in bytes let len_bytes = data.len() * std::mem::size_of::(); @@ -519,13 +510,8 @@ fn create_buffer_with_data<'gpu, T: Copy>( // // Note: We also set `cycle` to true here for the same reason. copy_pass.upload_to_gpu_buffer( - TransferBufferLocation::new() - .with_offset(0) - .with_transfer_buffer(transfer_buffer), - BufferRegion::new() - .with_offset(0) - .with_size(len_bytes as u32) - .with_buffer(&buffer), + transfer_buffer.get(0..), + buffer.get(0..len_bytes as u32), true, ); diff --git a/examples/gpu-triangle.rs b/examples/gpu-triangle.rs index 6779a1ef..5220f256 100644 --- a/examples/gpu-triangle.rs +++ b/examples/gpu-triangle.rs @@ -3,7 +3,7 @@ extern crate sdl3; use sdl3::{ event::Event, gpu::{ - ColorTargetDescription, ColorTargetInfo, Device, FillMode, GraphicsPipelineTargetInfo, + ColorTargetDescription, ColorTargetInfo, OwnedDevice, FillMode, GraphicsPipelineTargetInfo, LoadOp, PrimitiveType, ShaderFormat, ShaderStage, StoreOp, }, keyboard::Keycode, @@ -24,7 +24,7 @@ pub fn main() -> Result<(), Box> { // by default, and we specify that our shaders will be SPIR-V ones (even through we // aren't using any shaders) // We'll also turn on debug mode to true, so we get debug stuff - let gpu = Device::new( + let gpu = OwnedDevice::new( ShaderFormat::SPIRV | ShaderFormat::DXIL | ShaderFormat::DXBC | ShaderFormat::METALLIB, true, )?; diff --git a/src/sdl3/audio.rs b/src/sdl3/audio.rs index 2a0fa34d..f97ec14f 100644 --- a/src/sdl3/audio.rs +++ b/src/sdl3/audio.rs @@ -1012,6 +1012,7 @@ pub struct AudioStreamOwner { #[expect(dead_code)] audio_subsystem: Option, } +unsafe impl Send for AudioStreamOwner {} pub struct AudioStream { stream: *mut sys::audio::SDL_AudioStream, diff --git a/src/sdl3/gpu/pass_compute.rs b/src/sdl3/gpu/command_buffer/compute.rs similarity index 52% rename from src/sdl3/gpu/pass_compute.rs rename to src/sdl3/gpu/command_buffer/compute.rs index c5721ea6..59d46646 100644 --- a/src/sdl3/gpu/pass_compute.rs +++ b/src/sdl3/gpu/command_buffer/compute.rs @@ -1,39 +1,35 @@ - -use std::{ops::Deref, ptr::NonNull}; - use sys::gpu::{ - SDL_BindGPUComputePipeline, - SDL_BindGPUComputeStorageBuffers, - SDL_BindGPUComputeStorageTextures, - SDL_DispatchGPUCompute, - SDL_GPUBuffer, SDL_GPUComputePass, SDL_GPUTexture + SDL_BindGPUComputePipeline, SDL_BindGPUComputeSamplers, SDL_BindGPUComputeStorageBuffers, + SDL_BindGPUComputeStorageTextures, SDL_DispatchGPUCompute, SDL_GPUComputePass, }; -use super::{ComputePipeline, Extern}; - -pub struct ComputePass { - pub(super) raw: NonNull>, -} - -impl<'gpu> Deref for ComputePass { - type Target = Extern; +use crate::gpu::{Buffer, ComputePipeline, Extern, Texture, TextureSamplerBinding}; - fn deref(&self) -> &Self::Target { - unsafe { self.raw.as_ref() } - } -} +pub type ComputePass = Extern; impl ComputePass { #[doc(alias = "SDL_BindGPUComputePipeline")] pub fn bind_compute_pipeline(&self, pipeline: &ComputePipeline) { - unsafe { SDL_BindGPUComputePipeline(self.raw(), pipeline.raw()) } + unsafe { SDL_BindGPUComputePipeline(self.ll(), pipeline.ll()) } + } + + #[doc(alias = "SDL_BindGPUComputeSamplers")] + pub fn bind_compute_samplers(&self, first_slot: u32, samplers: &[&TextureSamplerBinding]) { + unsafe { + SDL_BindGPUComputeSamplers( + self.ll(), + first_slot, + samplers.as_ptr().cast(), + samplers.len() as u32, + ) + } } #[doc(alias = "SDL_BindGPUComputeStorageBuffers")] - pub fn bind_compute_storage_buffers(&self, first_slot: u32, storage_buffers: &[&Extern]) { + pub fn bind_compute_storage_buffers(&self, first_slot: u32, storage_buffers: &[&Buffer]) { unsafe { SDL_BindGPUComputeStorageBuffers( - self.raw(), + self.ll(), first_slot, storage_buffers.as_ptr().cast(), storage_buffers.len() as u32, @@ -42,10 +38,10 @@ impl ComputePass { } #[doc(alias = "SDL_BindGPUComputeStorageTextures")] - pub fn bind_compute_storage_textures(&self, first_slot: u32, storage_textures: &[&Extern]) { + pub fn bind_compute_storage_textures(&self, first_slot: u32, storage_textures: &[&Texture]) { unsafe { SDL_BindGPUComputeStorageTextures( - self.raw(), + self.ll(), first_slot, storage_textures.as_ptr().cast(), storage_textures.len() as u32, @@ -55,8 +51,6 @@ impl ComputePass { #[doc(alias = "SDL_DispatchGPUCompute")] pub fn dispatch(&self, groupcount_x: u32, groupcount_y: u32, groupcount_z: u32) { - unsafe { - SDL_DispatchGPUCompute(self.raw(), groupcount_x, groupcount_y, groupcount_z) - } + unsafe { SDL_DispatchGPUCompute(self.ll(), groupcount_x, groupcount_y, groupcount_z) } } } diff --git a/src/sdl3/gpu/pass_copy.rs b/src/sdl3/gpu/command_buffer/copy.rs similarity index 52% rename from src/sdl3/gpu/pass_copy.rs rename to src/sdl3/gpu/command_buffer/copy.rs index 1fd2611c..220b0c49 100644 --- a/src/sdl3/gpu/pass_copy.rs +++ b/src/sdl3/gpu/command_buffer/copy.rs @@ -1,28 +1,10 @@ - -use std::{ops::Deref, ptr::NonNull}; - use crate::gpu::{ - BufferRegion, TextureTransferInfo, TransferBufferLocation, + BufferRegion, Extern, TextureRegion, TextureTransferInfo, TransferBufferLocation, }; -use sys::gpu::{ - SDL_GPUCopyPass, - SDL_UploadToGPUBuffer, - SDL_UploadToGPUTexture, -}; - -use super::{Extern, TextureRegion}; -pub struct CopyPass { - pub(super) raw: NonNull>, -} - -impl<'gpu> Deref for CopyPass { - type Target = Extern; +use sys::gpu::{SDL_GPUCopyPass, SDL_UploadToGPUBuffer, SDL_UploadToGPUTexture}; - fn deref(&self) -> &Self::Target { - unsafe { self.raw.as_ref() } - } -} +pub type CopyPass = Extern; impl CopyPass { #[doc(alias = "SDL_UploadToGPUBuffer")] @@ -34,7 +16,7 @@ impl CopyPass { ) { unsafe { SDL_UploadToGPUBuffer( - self.raw(), + self.ll(), &transfer_buf_location.inner, &buffer_region.inner, cycle, @@ -49,6 +31,6 @@ impl CopyPass { destination: TextureRegion, cycle: bool, ) { - unsafe { SDL_UploadToGPUTexture(self.raw(), &source.inner, &destination.inner, cycle) } + unsafe { SDL_UploadToGPUTexture(self.ll(), &source.inner, &destination.inner, cycle) } } } diff --git a/src/sdl3/gpu/command_buffer/fence.rs b/src/sdl3/gpu/command_buffer/fence.rs new file mode 100644 index 00000000..ff7f4294 --- /dev/null +++ b/src/sdl3/gpu/command_buffer/fence.rs @@ -0,0 +1,15 @@ +use sys::gpu::SDL_GPUFence; + +use crate::gpu::{resource::GpuRelease, Extern}; + + +pub type Fence = Extern; + +unsafe impl GpuRelease for Fence { + type SDLType = SDL_GPUFence; + + const RELEASE: unsafe extern "C" fn(*mut sys::gpu::SDL_GPUDevice, *mut Self::SDLType) + = sys::gpu::SDL_ReleaseGPUFence; + + type ExtraState = (); +} \ No newline at end of file diff --git a/src/sdl3/gpu/command_buffer.rs b/src/sdl3/gpu/command_buffer/mod.rs similarity index 60% rename from src/sdl3/gpu/command_buffer.rs rename to src/sdl3/gpu/command_buffer/mod.rs index bcf4bf6b..ee89a1dc 100644 --- a/src/sdl3/gpu/command_buffer.rs +++ b/src/sdl3/gpu/command_buffer/mod.rs @@ -1,54 +1,73 @@ +use std::{ + marker::PhantomData, + ops::{Deref, DerefMut}, + ptr::NonNull, +}; -use std::{marker::PhantomData, ops::{Deref, DerefMut}, ptr::NonNull}; - -use crate::{get_error, gpu::{util::nonnull_ext_or_get_error, ComputePass}, Error}; +use crate::{get_error, gpu::util::nonnull_ext_or_get_error, Error}; use super::{ - swapchain::SwapchainTexture, util::Defer, ColorTargetInfo, CopyPass, - DepthStencilTargetInfo, Extern, ExternDevice, RenderPass, - StorageBufferReadWriteBinding, StorageTextureReadWriteBinding + util::Defer, ColorTargetInfo, DepthStencilTargetInfo, Device, Extern, + StorageBufferReadWriteBinding, StorageTextureReadWriteBinding, }; use sys::gpu::{ - SDL_AcquireGPUCommandBuffer, SDL_AcquireGPUSwapchainTexture, - SDL_BeginGPUComputePass, SDL_BeginGPUCopyPass, - SDL_BeginGPURenderPass, SDL_GPUColorTargetInfo, - SDL_GPUCommandBuffer, SDL_GPUDepthStencilTargetInfo, - SDL_GPUDevice, SDL_PushGPUComputeUniformData, SDL_PushGPUFragmentUniformData, - SDL_PushGPUVertexUniformData, SDL_WaitAndAcquireGPUSwapchainTexture + SDL_AcquireGPUCommandBuffer, SDL_AcquireGPUSwapchainTexture, SDL_BeginGPUComputePass, + SDL_BeginGPUCopyPass, SDL_BeginGPURenderPass, SDL_GPUColorTargetInfo, SDL_GPUCommandBuffer, + SDL_GPUDevice, SDL_PushGPUComputeUniformData, + SDL_PushGPUFragmentUniformData, SDL_PushGPUVertexUniformData, + SDL_WaitAndAcquireGPUSwapchainTexture, }; +mod compute; +pub use compute::ComputePass; + +mod render; +pub use render::RenderPass; + +mod copy; +pub use copy::CopyPass; + +mod swapchain; +pub use swapchain::SwapchainTexture; + +mod fence; +pub use fence::Fence; + +pub type CommandBuffer = Extern; + #[repr(transparent)] -pub struct CommandBuffer<'gpu> { +pub struct OwnedCommandBuffer<'gpu> { pub(super) raw: NonNull>, pub(super) _marker: std::marker::PhantomData<&'gpu SDL_GPUDevice>, } -impl<'gpu> Deref for CommandBuffer<'gpu> { - type Target = Extern; +impl<'gpu> Deref for OwnedCommandBuffer<'gpu> { + type Target = CommandBuffer; fn deref(&self) -> &Self::Target { unsafe { self.raw.as_ref() } } } -impl<'gpu> DerefMut for CommandBuffer<'gpu> { +impl<'gpu> DerefMut for OwnedCommandBuffer<'gpu> { fn deref_mut(&mut self) -> &mut Self::Target { unsafe { self.raw.as_mut() } } } -impl<'gpu> CommandBuffer<'gpu> { - pub(crate) fn new(device: &'gpu ExternDevice) -> Result { - let raw = nonnull_ext_or_get_error(unsafe { - SDL_AcquireGPUCommandBuffer(device.raw()) - })?; - Ok(CommandBuffer { raw, _marker: PhantomData } ) +impl<'gpu> OwnedCommandBuffer<'gpu> { + pub(crate) fn new(device: &'gpu Device) -> Result { + let raw = nonnull_ext_or_get_error(unsafe { SDL_AcquireGPUCommandBuffer(device.ll()) })?; + Ok(OwnedCommandBuffer { + raw, + _marker: PhantomData, + }) } #[doc(alias = "SDL_SubmitGPUCommandBuffer")] pub fn submit(self) -> Result<(), Error> { - if unsafe { sys::gpu::SDL_SubmitGPUCommandBuffer(self.raw()) } { + if unsafe { sys::gpu::SDL_SubmitGPUCommandBuffer(self.ll()) } { Ok(()) } else { Err(get_error()) @@ -58,34 +77,34 @@ impl<'gpu> CommandBuffer<'gpu> { #[doc(alias = "SDL_CancelGPUCommandBuffer")] pub fn cancel(self) { unsafe { - sys::gpu::SDL_CancelGPUCommandBuffer(self.raw()); + sys::gpu::SDL_CancelGPUCommandBuffer(self.ll()); } } } -impl Extern { +impl CommandBuffer { #[doc(alias = "SDL_BeginGPUComputePass")] pub fn compute_pass( &mut self, storage_texture_bindings: &[StorageTextureReadWriteBinding], storage_buffer_bindings: &[StorageBufferReadWriteBinding], - pass: impl for<'a> FnOnce(&'a Extern, &'a mut ComputePass) -> R, + func: impl for<'a> FnOnce(&'a Extern, &'a mut ComputePass) -> R, ) -> Result { - let raw = nonnull_ext_or_get_error(unsafe { + let mut raw = nonnull_ext_or_get_error(unsafe { SDL_BeginGPUComputePass( - self.raw(), + self.ll(), storage_texture_bindings.as_ptr().cast(), - storage_buffer_bindings.len() as u32, + storage_texture_bindings.len() as u32, storage_buffer_bindings.as_ptr().cast(), storage_buffer_bindings.len() as u32, ) })?; - let _defer = Defer::new(|| unsafe { + let _defer = Defer::new(move || unsafe { sys::gpu::SDL_EndGPUComputePass(raw.as_ptr().cast()); }); - Ok(pass(&*self, &mut ComputePass { raw })) + Ok(unsafe { func(self, raw.as_mut()) }) } #[doc(alias = "SDL_BeginGPURenderPass")] @@ -93,42 +112,39 @@ impl Extern { &mut self, color_info: &[ColorTargetInfo], depth_stencil_target: Option<&DepthStencilTargetInfo>, - pass: impl for<'a> FnOnce(&'a Extern, &'a mut RenderPass) -> R, + func: impl for<'a> FnOnce(&'a CommandBuffer, &'a mut RenderPass) -> R, ) -> Result { - let raw = nonnull_ext_or_get_error(unsafe { + let mut raw = nonnull_ext_or_get_error(unsafe { SDL_BeginGPURenderPass( - self.raw(), - color_info.as_ptr() as *const SDL_GPUColorTargetInfo, //heavy promise + self.ll(), + color_info.as_ptr() as *const SDL_GPUColorTargetInfo, color_info.len() as u32, - if let Some(p) = depth_stencil_target { - p as *const _ as *const SDL_GPUDepthStencilTargetInfo //heavy promise - } else { - std::ptr::null() - }, + depth_stencil_target + .map(std::ptr::from_ref) + .unwrap_or(std::ptr::null()) + .cast(), ) })?; - let _defer = Defer::new(|| unsafe { + let _defer = Defer::new(move || unsafe { sys::gpu::SDL_EndGPURenderPass(raw.as_ptr().cast()); }); - Ok(pass(&*self, &mut RenderPass { raw })) + Ok(unsafe { func(self, raw.as_mut()) }) } #[doc(alias = "SDL_BeginGPUCopyPass")] pub fn copy_pass( &mut self, - pass: impl for<'a> FnOnce(&'a Extern, &'a mut CopyPass) -> R, + func: impl for<'a> FnOnce(&'a Extern, &'a mut CopyPass) -> R, ) -> Result { - let raw = nonnull_ext_or_get_error(unsafe { - SDL_BeginGPUCopyPass(self.raw()) - })?; + let mut raw = nonnull_ext_or_get_error(unsafe { SDL_BeginGPUCopyPass(self.ll()) })?; - let _defer = Defer::new(|| unsafe { + let _defer = Defer::new(move || unsafe { sys::gpu::SDL_EndGPUCopyPass(raw.as_ptr().cast()); }); - Ok(pass(&*self, &mut CopyPass { raw })) + Ok(unsafe { func(self, raw.as_mut()) }) } // FIXME: @@ -146,7 +162,7 @@ impl Extern { let mut height = 0; let success = unsafe { SDL_WaitAndAcquireGPUSwapchainTexture( - self.raw(), + self.ll(), w.raw(), &mut raw, &mut width, @@ -156,14 +172,12 @@ impl Extern { let raw = raw.cast(); if success { if let Some(raw) = NonNull::new(raw) { - Ok( - SwapchainTexture { - raw, - width, - height, - _marker: PhantomData, - } - ) + Ok(SwapchainTexture { + raw, + width, + height, + _marker: PhantomData, + }) } else { Err(None) } @@ -181,25 +195,17 @@ impl Extern { let mut width = 0; let mut height = 0; let success = unsafe { - SDL_AcquireGPUSwapchainTexture( - self.raw(), - w.raw(), - &mut raw, - &mut width, - &mut height, - ) + SDL_AcquireGPUSwapchainTexture(self.ll(), w.raw(), &mut raw, &mut width, &mut height) }; let raw = raw.cast(); if success { if let Some(raw) = NonNull::new(raw) { - Ok( - SwapchainTexture { - raw, - width, - height, - _marker: PhantomData, - } - ) + Ok(SwapchainTexture { + raw, + width, + height, + _marker: PhantomData, + }) } else { Err(None) } @@ -207,14 +213,12 @@ impl Extern { Err(Some(get_error())) } } -} -impl Extern { #[doc(alias = "SDL_PushGPUVertexUniformData")] pub fn push_vertex_uniform_data(&self, slot_index: u32, data: &T) { unsafe { SDL_PushGPUVertexUniformData( - self.raw(), + self.ll(), slot_index, (data as *const T) as *const std::ffi::c_void, size_of::() as u32, @@ -226,7 +230,7 @@ impl Extern { pub fn push_fragment_uniform_data(&self, slot_index: u32, data: &T) { unsafe { SDL_PushGPUFragmentUniformData( - self.raw(), + self.ll(), slot_index, (data as *const T) as *const std::ffi::c_void, size_of::() as u32, @@ -238,7 +242,7 @@ impl Extern { pub fn push_compute_uniform_data(&self, slot_index: u32, data: &T) { unsafe { SDL_PushGPUComputeUniformData( - self.raw(), + self.ll(), slot_index, (data as *const T) as *const std::ffi::c_void, size_of::() as u32, diff --git a/src/sdl3/gpu/pass_render.rs b/src/sdl3/gpu/command_buffer/render.rs similarity index 69% rename from src/sdl3/gpu/pass_render.rs rename to src/sdl3/gpu/command_buffer/render.rs index b9fb5ffd..3d1622c5 100644 --- a/src/sdl3/gpu/pass_render.rs +++ b/src/sdl3/gpu/command_buffer/render.rs @@ -1,55 +1,55 @@ - -use std::{ops::Deref, ptr::NonNull}; - use crate::gpu::{ - BufferBinding, GraphicsPipeline, IndexElementSize, + Buffer, BufferBinding, Extern, GraphicsPipeline, IndexElementSize, Texture, TextureSamplerBinding, }; + use sys::gpu::{ - SDL_BindGPUFragmentSamplers, SDL_BindGPUIndexBuffer, SDL_BindGPUVertexBuffers, SDL_DrawGPUIndexedPrimitives, SDL_GPUBuffer, SDL_GPUBufferBinding, SDL_GPURenderPass, SDL_GPUTexture, SDL_GPUTextureSamplerBinding, SDL_GPUViewport, SDL_SetGPUViewport + SDL_BindGPUFragmentSamplers, SDL_BindGPUIndexBuffer, SDL_BindGPUVertexBuffers, + SDL_DrawGPUIndexedPrimitives, SDL_GPUBufferBinding, SDL_GPURenderPass, + SDL_GPUTextureSamplerBinding, SDL_GPUViewport, SDL_SetGPUViewport, }; -use super::Extern; - - -pub struct RenderPass { - pub(super) raw: NonNull>, -} -impl<'gpu> Deref for RenderPass { - type Target = Extern; +pub type RenderPass = Extern; - fn deref(&self) -> &Self::Target { - unsafe { self.raw.as_ref() } - } -} impl RenderPass { #[doc(alias = "SDL_SetGPUViewport")] pub fn set_viewport(&mut self, viewport: &SDL_GPUViewport) { - unsafe { SDL_SetGPUViewport(self.raw(), viewport) } + unsafe { SDL_SetGPUViewport(self.ll(), viewport) } } #[doc(alias = "SDL_BindGPUGraphicsPipeline")] pub fn bind_graphics_pipeline(&self, pipeline: &GraphicsPipeline) { - unsafe { sys::gpu::SDL_BindGPUGraphicsPipeline(self.raw(), pipeline.raw()) } + unsafe { sys::gpu::SDL_BindGPUGraphicsPipeline(self.ll(), pipeline.ll()) } } #[doc(alias = "SDL_BindGPUVertexBuffers")] pub fn bind_vertex_buffers(&self, first_slot: u32, bindings: &[BufferBinding]) { unsafe { SDL_BindGPUVertexBuffers( - self.raw(), + self.ll(), first_slot, bindings.as_ptr() as *mut SDL_GPUBufferBinding, bindings.len() as u32, ) } } + #[doc(alias = "SDL_BindGPUFragmentSamplers")] + pub fn bind_vertex_samplers(&self, first_slot: u32, bindings: &[&TextureSamplerBinding]) { + unsafe { + SDL_BindGPUFragmentSamplers( + self.ll(), + first_slot, + bindings.as_ptr() as *const SDL_GPUTextureSamplerBinding, + bindings.len() as u32, + ); + } + } #[doc(alias = "SDL_BindGPUVertexStorageBuffers")] - pub fn bind_vertex_storage_buffers(&self, first_slot: u32, storage_buffers: &[&Extern]) { + pub fn bind_vertex_storage_buffers(&self, first_slot: u32, storage_buffers: &[&Buffer]) { unsafe { sys::gpu::SDL_BindGPUVertexStorageBuffers( - self.raw(), + self.ll(), first_slot, storage_buffers.as_ptr().cast(), storage_buffers.len() as u32, @@ -58,10 +58,10 @@ impl RenderPass { } #[doc(alias = "SDL_BindGPUVertexStorageTextures")] - pub fn bind_vertex_storage_textures(&self, first_slot: u32, storage_textures: &[&Extern]) { + pub fn bind_vertex_storage_textures(&self, first_slot: u32, storage_textures: &[&Texture]) { unsafe { sys::gpu::SDL_BindGPUVertexStorageTextures( - self.raw(), + self.ll(), first_slot, storage_textures.as_ptr().cast(), storage_textures.len() as u32, @@ -71,20 +71,14 @@ impl RenderPass { #[doc(alias = "SDL_BindGPUIndexBuffer")] pub fn bind_index_buffer(&self, binding: &BufferBinding, index_element_size: IndexElementSize) { - unsafe { - SDL_BindGPUIndexBuffer( - self.raw(), - &binding.inner, - index_element_size, - ) - } + unsafe { SDL_BindGPUIndexBuffer(self.ll(), &binding.inner, index_element_size) } } #[doc(alias = "SDL_BindGPUFragmentSamplers")] pub fn bind_fragment_samplers(&self, first_slot: u32, bindings: &[TextureSamplerBinding]) { unsafe { SDL_BindGPUFragmentSamplers( - self.raw(), + self.ll(), first_slot, bindings.as_ptr() as *const SDL_GPUTextureSamplerBinding, bindings.len() as u32, @@ -93,10 +87,10 @@ impl RenderPass { } #[doc(alias = "SDL_BindGPUFragmentStorageBuffers")] - pub fn bind_fragment_storage_buffers(&self, first_slot: u32, storage_buffers: &[&Extern]) { + pub fn bind_fragment_storage_buffers(&self, first_slot: u32, storage_buffers: &[&Buffer]) { unsafe { sys::gpu::SDL_BindGPUFragmentStorageBuffers( - self.raw(), + self.ll(), first_slot, storage_buffers.as_ptr().cast(), storage_buffers.len() as u32, @@ -105,10 +99,10 @@ impl RenderPass { } #[doc(alias = "SDL_BindGPUFragmentStorageTextures")] - pub fn bind_fragment_storage_textures(&self, first_slot: u32, storage_textures: &[&Extern]) { + pub fn bind_fragment_storage_textures(&self, first_slot: u32, storage_textures: &[&Texture]) { unsafe { sys::gpu::SDL_BindGPUFragmentStorageTextures( - self.raw(), + self.ll(), first_slot, storage_textures.as_ptr().cast(), storage_textures.len() as u32, @@ -127,7 +121,7 @@ impl RenderPass { ) { unsafe { SDL_DrawGPUIndexedPrimitives( - self.raw(), + self.ll(), num_indices, num_instances, first_index, @@ -140,18 +134,18 @@ impl RenderPass { #[doc(alias = "SDL_DrawGPUPrimitives")] pub fn draw_primitives( &self, - num_vertices: usize, - num_instances: usize, - first_vertex: usize, - first_instance: usize, + num_vertices: u32, + num_instances: u32, + first_vertex: u32, + first_instance: u32, ) { unsafe { sys::gpu::SDL_DrawGPUPrimitives( - self.raw(), - num_vertices as u32, - num_instances as u32, - first_vertex as u32, - first_instance as u32, + self.ll(), + num_vertices, + num_instances, + first_vertex, + first_instance, ); } } diff --git a/src/sdl3/gpu/swapchain.rs b/src/sdl3/gpu/command_buffer/swapchain.rs similarity index 80% rename from src/sdl3/gpu/swapchain.rs rename to src/sdl3/gpu/command_buffer/swapchain.rs index 18b05d06..bca52e7b 100644 --- a/src/sdl3/gpu/swapchain.rs +++ b/src/sdl3/gpu/command_buffer/swapchain.rs @@ -1,8 +1,7 @@ use std::{marker::PhantomData, ops::Deref, ptr::NonNull}; -use sys::gpu::SDL_GPUTexture; +use crate::gpu::Texture; -use super::Extern; type Invariant<'a> = PhantomData &'a ()>; @@ -10,14 +9,14 @@ type Invariant<'a> = PhantomData &'a ()>; #[doc(alias = "SDL_Texture")] pub struct SwapchainTexture<'cmd_buf> { - pub(super) raw: NonNull>, + pub(super) raw: NonNull, pub(super) width: u32, pub(super) height: u32, pub(super) _marker: Invariant<'cmd_buf>, } impl<'cmd_buf> Deref for SwapchainTexture<'cmd_buf> { - type Target = Extern; + type Target = Texture; fn deref(&self) -> &Self::Target { unsafe { self.raw.as_ref() } diff --git a/src/sdl3/gpu/enums.rs b/src/sdl3/gpu/enums.rs index 26ad639d..2f16c067 100644 --- a/src/sdl3/gpu/enums.rs +++ b/src/sdl3/gpu/enums.rs @@ -3,7 +3,7 @@ use std::ops::{BitAnd, BitOr}; use sys::gpu::{SDL_GPUBlendFactor, SDL_GPUBlendOp}; macro_rules! impl_with { - (bitwise_and_or $x:ident $prim:ident) => { + (bitwise_and_or $x:ident) => { impl BitOr<$x> for $x { type Output = $x; fn bitor(self, rhs: $x) -> Self::Output { @@ -34,7 +34,7 @@ impl ShaderFormat { pub const PRIVATE: Self = Self(sys::gpu::SDL_GPU_SHADERFORMAT_PRIVATE); pub const SPIRV: Self = Self(sys::gpu::SDL_GPU_SHADERFORMAT_SPIRV); } -impl_with!(bitwise_and_or ShaderFormat u32); +impl_with!(bitwise_and_or ShaderFormat); pub struct TextureUsage(pub sys::gpu::SDL_GPUTextureUsageFlags); impl TextureUsage { @@ -55,7 +55,7 @@ impl TextureUsage { pub const COLOR_TARGET: Self = Self(sys::gpu::SDL_GPU_TEXTUREUSAGE_COLOR_TARGET); } -impl_with!(bitwise_and_or TextureUsage u32); +impl_with!(bitwise_and_or TextureUsage); #[derive(Default, Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] #[repr(u32)] @@ -234,6 +234,7 @@ impl BufferUsageFlags { pub const COMPUTE_STORAGE_READ : Self = Self(sys::gpu::SDL_GPU_BUFFERUSAGE_COMPUTE_STORAGE_READ); pub const COMPUTE_STORAGE_WRITE : Self = Self(sys::gpu::SDL_GPU_BUFFERUSAGE_COMPUTE_STORAGE_WRITE); } +impl_with!(bitwise_and_or BufferUsageFlags); pub type TransferBufferUsage = sys::gpu::SDL_GPUTransferBufferUsage; @@ -278,4 +279,4 @@ impl ColorComponentFlags { pub const B: Self = Self(sys::gpu::SDL_GPU_COLORCOMPONENT_B); pub const A: Self = Self(sys::gpu::SDL_GPU_COLORCOMPONENT_A); } -impl_with!(bitwise_and_or ColorComponentFlags u8); +impl_with!(bitwise_and_or ColorComponentFlags); diff --git a/src/sdl3/gpu/info_struct.rs b/src/sdl3/gpu/info_struct.rs index cb82c664..fa7d6faf 100644 --- a/src/sdl3/gpu/info_struct.rs +++ b/src/sdl3/gpu/info_struct.rs @@ -5,42 +5,39 @@ use std::marker::PhantomData; use sys::gpu::{ - SDL_GPUBlendFactor, SDL_GPUBlendOp, SDL_GPUBuffer, SDL_GPUBufferBinding, + SDL_GPUBlendFactor, SDL_GPUBlendOp, SDL_GPUBufferBinding, SDL_GPUBufferRegion, SDL_GPUColorTargetBlendState, SDL_GPUColorTargetDescription, SDL_GPUColorTargetInfo, SDL_GPUCompareOp, SDL_GPUCullMode, SDL_GPUDepthStencilState, SDL_GPUDepthStencilTargetInfo, SDL_GPUFillMode, SDL_GPUFilter, SDL_GPUFrontFace, SDL_GPUGraphicsPipelineTargetInfo, SDL_GPURasterizerState, SDL_GPUSampleCount, - SDL_GPUSampler, SDL_GPUSamplerAddressMode, SDL_GPUSamplerCreateInfo, + SDL_GPUSamplerAddressMode, SDL_GPUSamplerCreateInfo, SDL_GPUSamplerMipmapMode, SDL_GPUStencilOp, SDL_GPUStencilOpState, SDL_GPUStorageBufferReadWriteBinding, SDL_GPUStorageTextureReadWriteBinding, - SDL_GPUTexture, SDL_GPUTextureCreateInfo, SDL_GPUTextureRegion, + SDL_GPUTextureCreateInfo, SDL_GPUTextureRegion, SDL_GPUTextureSamplerBinding, SDL_GPUTextureTransferInfo, SDL_GPUTextureType, - SDL_GPUTransferBuffer, SDL_GPUTransferBufferLocation, SDL_GPUVertexAttribute, + SDL_GPUTransferBufferLocation, SDL_GPUVertexAttribute, SDL_GPUVertexBufferDescription, SDL_GPUVertexInputRate, SDL_GPUVertexInputState, }; use crate::pixels::Color; use super::{ - BlendFactor, BlendOp, ColorComponentFlags, CompareOp, CullMode, Extern, - FillMode, Filter, FrontFace, LoadOp, SampleCount, Sampler, SamplerAddressMode, - SamplerMipmapMode, StencilOp, StoreOp, Texture, TextureFormat, TextureType, - TextureUsage, VertexElementFormat, VertexInputRate + BlendFactor, BlendOp, Buffer, ColorComponentFlags, CompareOp, CullMode, FillMode, Filter, FrontFace, LoadOp, SampleCount, Sampler, SamplerAddressMode, SamplerMipmapMode, StencilOp, StoreOp, Texture, TextureFormat, TextureType, TextureUsage, TransferBuffer, VertexElementFormat, VertexInputRate }; -#[repr(C)] +#[repr(transparent)] #[derive(Default)] pub struct DepthStencilTargetInfo<'a> { inner: SDL_GPUDepthStencilTargetInfo, - _marker: PhantomData<&'a Extern>, + _marker: PhantomData<&'a Texture>, } impl<'a> DepthStencilTargetInfo<'a> { pub fn new() -> Self { Default::default() } - pub fn with_texture(mut self, texture: &'a Extern) -> Self { - self.inner.texture = texture.raw(); + pub fn with_texture(mut self, texture: &'a Texture) -> Self { + self.inner.texture = texture.ll(); self } @@ -84,15 +81,15 @@ impl<'a> DepthStencilTargetInfo<'a> { #[derive(Default)] pub struct ColorTargetInfo<'a> { inner: SDL_GPUColorTargetInfo, - _marker: PhantomData<&'a Extern>, + _marker: PhantomData<&'a Texture>, } impl<'a> ColorTargetInfo<'a> { pub fn new() -> Self { Default::default() } - pub fn with_texture(mut self, texture: &'a Extern) -> Self { - self.inner.texture = texture.raw(); + pub fn with_texture(mut self, texture: &'a Texture) -> Self { + self.inner.texture = texture.ll(); self } @@ -116,6 +113,7 @@ impl<'a> ColorTargetInfo<'a> { } +#[repr(C)] #[derive(Default)] pub struct TextureCreateInfo { pub(super) inner: SDL_GPUTextureCreateInfo, @@ -175,6 +173,7 @@ impl TextureCreateInfo { } +#[repr(C)] #[derive(Default)] pub struct SamplerCreateInfo { pub(super) inner: SDL_GPUSamplerCreateInfo, @@ -263,10 +262,11 @@ impl SamplerCreateInfo { } } +#[repr(C)] #[derive(Default)] pub struct TextureRegion<'a> { pub(super) inner: SDL_GPUTextureRegion, - _marker: PhantomData<&'a Extern>, + _marker: PhantomData<&'a Texture>, } impl<'a> TextureRegion<'a> { pub fn new() -> Self { @@ -274,8 +274,8 @@ impl<'a> TextureRegion<'a> { } /// The texture used in the copy operation. - pub fn with_texture(mut self, texture: &'a Extern) -> Self { - self.inner.texture = texture.raw(); + pub fn with_texture(mut self, texture: &'a Texture) -> Self { + self.inner.texture = texture.ll(); self } @@ -328,10 +328,11 @@ impl<'a> TextureRegion<'a> { } } +#[repr(C)] #[derive(Default)] pub struct TextureTransferInfo<'a> { pub(super) inner: SDL_GPUTextureTransferInfo, - _marker: PhantomData<&'a Extern>, + _marker: PhantomData<&'a TransferBuffer>, } impl<'a> TextureTransferInfo<'a> { pub fn new() -> Self { @@ -339,8 +340,8 @@ impl<'a> TextureTransferInfo<'a> { } /// The transfer buffer used in the transfer operation. - pub fn with_transfer_buffer(mut self, buffer: &'a Extern) -> Self { - self.inner.transfer_buffer = buffer.raw(); + pub fn with_transfer_buffer(mut self, buffer: &'a TransferBuffer) -> Self { + self.inner.transfer_buffer = buffer.ll(); self } @@ -368,15 +369,15 @@ impl<'a> TextureTransferInfo<'a> { #[derive(Default)] pub struct BufferBinding<'a> { pub(super) inner: SDL_GPUBufferBinding, - _marker: PhantomData<&'a Extern>, + _marker: PhantomData<&'a Buffer>, } impl<'a> BufferBinding<'a> { pub fn new() -> Self { Default::default() } - pub fn with_buffer(mut self, buffer: &'a Extern) -> Self { - self.inner.buffer = buffer.raw(); + pub fn with_buffer(mut self, buffer: &'a Buffer) -> Self { + self.inner.buffer = buffer.ll(); self } @@ -386,51 +387,18 @@ impl<'a> BufferBinding<'a> { } } +#[repr(C)] #[derive(Default)] pub struct TransferBufferLocation<'a> { pub(super) inner: SDL_GPUTransferBufferLocation, - _marker: PhantomData<&'a Extern>, -} -impl<'a> TransferBufferLocation<'a> { - pub fn new() -> Self { - Default::default() - } - - pub fn with_transfer_buffer(mut self, transfer_buffer: &'a Extern) -> Self { - self.inner.transfer_buffer = transfer_buffer.raw(); - self - } - - pub fn with_offset(mut self, offset: u32) -> Self { - self.inner.offset = offset; - self - } + pub(super) _marker: PhantomData<&'a TransferBuffer>, } +#[repr(C)] #[derive(Default)] pub struct BufferRegion<'a> { pub(super) inner: SDL_GPUBufferRegion, - _marker: PhantomData<&'a Extern>, -} -impl<'a> BufferRegion<'a> { - pub fn new() -> Self { - Default::default() - } - - pub fn with_buffer(mut self, buffer: &'a Extern) -> Self { - self.inner.buffer = buffer.raw(); - self - } - - pub fn with_offset(mut self, offset: u32) -> Self { - self.inner.offset = offset; - self - } - - pub fn with_size(mut self, size: u32) -> Self { - self.inner.size = size; - self - } + pub(super) _marker: PhantomData<&'a Buffer>, } #[repr(C)] @@ -470,7 +438,7 @@ impl VertexBufferDescription { #[derive(Default)] pub struct VertexInputState<'a> { pub(super) inner: SDL_GPUVertexInputState, - _marker: PhantomData<&'a [VertexBufferDescription]>, + _marker: PhantomData<(&'a [VertexBufferDescription],&'a [VertexAttribute])>, } impl<'a> VertexInputState<'a> { pub fn new() -> Self { @@ -484,7 +452,7 @@ impl<'a> VertexInputState<'a> { self } - pub fn with_vertex_attributes(mut self, value: &[VertexAttribute]) -> Self { + pub fn with_vertex_attributes(mut self, value: &'a [VertexAttribute]) -> Self { self.inner.vertex_attributes = value.as_ptr() as *const SDL_GPUVertexAttribute; self.inner.num_vertex_attributes = value.len() as u32; self @@ -561,6 +529,12 @@ impl StencilOpState { Default::default() } + /// The comparison operator used in the stencil test. + pub fn with_compare_op(mut self, value: CompareOp) -> Self { + self.inner.compare_op = SDL_GPUCompareOp(value as i32); + self + } + /// The action performed on samples that fail the stencil test. pub fn with_fail_op(mut self, value: StencilOp) -> Self { self.inner.fail_op = SDL_GPUStencilOp(value as i32); @@ -578,12 +552,6 @@ impl StencilOpState { self.inner.depth_fail_op = SDL_GPUStencilOp(value as i32); self } - - /// The comparison operator used in the stencil test. - pub fn compare_op(mut self, value: CompareOp) -> Self { - self.inner.compare_op = SDL_GPUCompareOp(value as i32); - self - } } #[repr(C)] @@ -646,6 +614,7 @@ impl DepthStencilState { } +#[repr(C)] #[derive(Default)] pub struct GraphicsPipelineTargetInfo<'a> { pub(super) inner: SDL_GPUGraphicsPipelineTargetInfo, @@ -714,6 +683,7 @@ impl VertexAttribute { } +#[repr(C)] #[derive(Default)] pub struct ColorTargetBlendState { inner: SDL_GPUColorTargetBlendState, @@ -805,43 +775,43 @@ impl ColorTargetDescription { #[repr(C)] #[derive(Default)] pub struct TextureSamplerBinding<'a> { - inner: SDL_GPUTextureSamplerBinding, - _marker: PhantomData<&'a Extern<(SDL_GPUTexture, SDL_GPUSampler)>>, + pub(crate) inner: SDL_GPUTextureSamplerBinding, + _marker: PhantomData<(&'a Texture, &'a Sampler)>, } impl<'a> TextureSamplerBinding<'a> { - pub fn new() -> Self { - Default::default() - } + // pub fn new() -> Self { + // Default::default() + // } - /// The texture to bind. Must have been created with [`SDL_GPU_TEXTUREUSAGE_SAMPLER`]. - pub fn with_texture(mut self, texture: &'a Texture) -> Self { - self.inner.texture = texture.raw(); - self - } + // /// The texture to bind. Must have been created with [`SDL_GPU_TEXTUREUSAGE_SAMPLER`]. + // pub fn with_texture(mut self, texture: &'a Texture) -> Self { + // self.inner.texture = texture.ll(); + // self + // } - /// The sampler to bind. - pub fn with_sampler(mut self, sampler: &'a Sampler) -> Self { - self.inner.sampler = sampler.raw(); - self - } + // /// The sampler to bind. + // pub fn with_sampler(mut self, sampler: &'a Sampler) -> Self { + // self.inner.sampler = sampler.ll(); + // self + // } } #[repr(C)] #[derive(Default)] pub struct StorageTextureReadWriteBinding<'a> { - inner: SDL_GPUStorageTextureReadWriteBinding, - _marker: PhantomData<&'a Extern>, + pub(crate) inner: SDL_GPUStorageTextureReadWriteBinding, + pub(crate) _marker: PhantomData<&'a Texture>, } impl<'a> StorageTextureReadWriteBinding<'a> { - pub fn new() -> Self { - Default::default() - } + // pub fn new() -> Self { + // Default::default() + // } - pub fn with_texture(mut self, texture: &'a Extern) -> Self { - self.inner.texture = texture.raw(); - self - } + // pub fn with_texture(mut self, texture: &'a Texture) -> Self { + // self.inner.texture = texture.ll(); + // self + // } pub fn with_mip_level(mut self, mip_level: u32) -> Self { self.inner.mip_level = mip_level; @@ -853,30 +823,30 @@ impl<'a> StorageTextureReadWriteBinding<'a> { self } - pub fn with_cycle(mut self, cycle: bool) -> Self { - self.inner.cycle = cycle; - self - } + // pub fn with_cycle(mut self, cycle: bool) -> Self { + // self.inner.cycle = cycle; + // self + // } } #[repr(C)] #[derive(Default)] pub struct StorageBufferReadWriteBinding<'a> { - inner: SDL_GPUStorageBufferReadWriteBinding, - _marker: PhantomData<&'a Extern>, + pub(crate) inner: SDL_GPUStorageBufferReadWriteBinding, + pub(crate) _marker: PhantomData<&'a Buffer>, } impl<'a> StorageBufferReadWriteBinding<'a> { - pub fn new() -> Self { - Default::default() - } - - pub fn with_buffer(mut self, buffer: &'a Extern) -> Self { - self.inner.buffer = buffer.raw(); - self - } - - pub fn with_cycle(mut self, cycle: bool) -> Self { - self.inner.cycle = cycle; - self - } + // pub fn new() -> Self { + // Default::default() + // } + + // pub fn with_buffer(mut self, buffer: &'a Buffer) -> Self { + // self.inner.buffer = buffer.ll(); + // self + // } + + // pub fn with_cycle(mut self, cycle: bool) -> Self { + // self.inner.cycle = cycle; + // self + // } } diff --git a/src/sdl3/gpu/mod.rs b/src/sdl3/gpu/mod.rs index 49cad828..0a53feb1 100644 --- a/src/sdl3/gpu/mod.rs +++ b/src/sdl3/gpu/mod.rs @@ -1,17 +1,16 @@ mod resource; -mod swapchain; use std::cell::UnsafeCell; pub use resource::{ + Owned, Buffer, TransferBuffer, - /* FIXME: BufferMemMap, */ GraphicsPipeline, ComputePipeline, Texture, Sampler, Shader, - Device, + OwnedDevice, Device, }; pub use resource::{ ComputePipelineBuilder, GraphicsPipelineBuilder, ShaderBuilder, BufferBuilder, @@ -19,7 +18,14 @@ pub use resource::{ }; mod command_buffer; -pub use command_buffer::CommandBuffer; +pub use command_buffer::{ + OwnedCommandBuffer, + CommandBuffer, + ComputePass, + RenderPass, + CopyPass, + Fence, +}; mod enums; pub use enums::{ @@ -40,21 +46,17 @@ pub use info_struct::{ StorageBufferReadWriteBinding, StorageTextureReadWriteBinding, }; -mod pass_render; -pub use pass_render::RenderPass; - -mod pass_copy; -pub use pass_copy::CopyPass; -mod pass_compute; -pub use pass_compute::ComputePass; use sys::gpu::{SDL_ClaimWindowForGPUDevice, SDL_GetGPUSwapchainTextureFormat, SDL_ReleaseWindowFromGPUDevice}; use crate::{get_error, Error}; mod util; -pub type ExternDevice = Extern; + + +unsafe impl Sync for Device {} +unsafe impl Sync for Buffer {} // We need some wrapper to be able to implement (inherent) methods for the type. // The UnsafeCell doesn't actually do anything for &mut Extern, but the wrapped types @@ -63,58 +65,21 @@ pub type ExternDevice = Extern; pub struct Extern(UnsafeCell); impl Extern { - pub fn raw(&self) -> *mut T { + pub fn ll(&self) -> *mut T { self.0.get() } } -impl ExternDevice { - #[doc(alias = "SDL_CreateGPUShader")] - pub fn create_shader(&self) -> ShaderBuilder { - ShaderBuilder::new(self) - } - - #[doc(alias = "SDL_CreateGPUBuffer")] - pub fn create_buffer(&self) -> BufferBuilder { - BufferBuilder::new(self) - } - - #[doc(alias = "SDL_CreateGPUTransferBuffer")] - pub fn create_transfer_buffer(&self) -> TransferBufferBuilder { - TransferBufferBuilder::new(self) - } - - #[doc(alias = "SDL_CreateGPUSampler")] - pub fn create_sampler(&self, create_info: SamplerCreateInfo) -> Result { - Sampler::new(self, &create_info.inner) - } - - #[doc(alias = "SDL_CreateGPUGraphicsPipeline")] - pub fn create_graphics_pipeline<'gpu,'a>(&'gpu self) -> GraphicsPipelineBuilder<'gpu, 'a> { - GraphicsPipelineBuilder::new(self) - } - - #[doc(alias = "SDL_CreateGPUComputePipeline")] - pub fn create_compute_pipeline<'gpu,'a>(&'gpu self) -> ComputePipelineBuilder<'gpu, 'a> { - ComputePipelineBuilder::new(self) - } - - #[doc(alias = "SDL_CreateGPUTexture")] - pub fn create_texture( - &self, - create_info: &TextureCreateInfo, - ) -> Result { - Texture::new(self, &create_info.inner) - } - +impl Device { + #[doc(alias = "SDL_AcquireGPUCommandBuffer")] - pub fn acquire_command_buffer<'gpu>(&'gpu self) -> Result, Error> { - CommandBuffer::new(self) + pub fn acquire_command_buffer<'gpu>(&'gpu self) -> Result, Error> { + OwnedCommandBuffer::new(self) } #[doc(alias = "SDL_ClaimWindowForGPUDevice")] pub fn claim_window(&self, w: &crate::video::Window) -> Result<(), Error> { - let p = unsafe { SDL_ClaimWindowForGPUDevice(self.raw(), w.raw()) }; + let p = unsafe { SDL_ClaimWindowForGPUDevice(self.ll(), w.raw()) }; if p { Ok(()) } else { @@ -124,18 +89,18 @@ impl ExternDevice { #[doc(alias = "SDL_ClaimWindowForGPUDevice")] pub fn release_window(&self, w: &crate::video::Window) { - unsafe { SDL_ReleaseWindowFromGPUDevice(self.raw(), w.raw()) }; + unsafe { SDL_ReleaseWindowFromGPUDevice(self.ll(), w.raw()) }; } #[doc(alias = "SDL_GetGPUSwapchainTextureFormat")] pub fn get_swapchain_texture_format(&self, w: &crate::video::Window) -> TextureFormat { - unsafe { SDL_GetGPUSwapchainTextureFormat(self.raw(), w.raw()) } + unsafe { SDL_GetGPUSwapchainTextureFormat(self.ll(), w.raw()) } } #[doc(alias = "SDL_GetGPUShaderFormats")] pub fn get_shader_formats(&self) -> ShaderFormat { - unsafe { ShaderFormat(sys::gpu::SDL_GetGPUShaderFormats(self.raw())) } + unsafe { ShaderFormat(sys::gpu::SDL_GetGPUShaderFormats(self.ll())) } } #[cfg(target_os = "xbox")] diff --git a/src/sdl3/gpu/resource/buffer.rs b/src/sdl3/gpu/resource/buffer.rs deleted file mode 100644 index dd4c8750..00000000 --- a/src/sdl3/gpu/resource/buffer.rs +++ /dev/null @@ -1,50 +0,0 @@ -use super::util::*; - -use sys::gpu::{ - SDL_GPUBuffer, - SDL_GPUBufferCreateInfo, - SDL_CreateGPUBuffer, - SDL_ReleaseGPUBuffer, -}; - -#[doc(alias = "SDL_GPUBuffer")] -pub struct Buffer<'gpu> { - raw: NonNull>, - device: &'gpu ExternDevice, - len: u32, -} - -impl<'gpu> Drop for Buffer<'gpu> { - #[doc(alias = "SDL_ReleaseGPUBuffer")] - fn drop(&mut self) { - unsafe { - SDL_ReleaseGPUBuffer(self.device.raw(), self.raw()); - } - } -} - -impl<'gpu> Deref for Buffer<'gpu> { - type Target = Extern; - - fn deref(&self) -> &Self::Target { - unsafe { self.raw.as_ref() } - } -} - -impl<'gpu> Buffer<'gpu> { - pub(crate) fn new(device: &'gpu ExternDevice, create_info: &'_ SDL_GPUBufferCreateInfo) -> Result { - let raw = nonnull_ext_or_get_error(unsafe { - SDL_CreateGPUBuffer(device.raw(), create_info) - })?; - Ok(Buffer { - raw, - device, - len: create_info.size, - }) - } - - /// The length of this buffer in bytes. - pub fn len(&self) -> u32 { - self.len - } -} diff --git a/src/sdl3/gpu/resource/builders.rs b/src/sdl3/gpu/resource/builders.rs index 59889f00..69ea55af 100644 --- a/src/sdl3/gpu/resource/builders.rs +++ b/src/sdl3/gpu/resource/builders.rs @@ -5,23 +5,69 @@ use std::{ffi::CStr, marker::PhantomData}; use sys::gpu::{ - SDL_GPUBufferCreateInfo, SDL_GPUComputePipelineCreateInfo, SDL_GPUFillMode, SDL_GPUGraphicsPipelineCreateInfo, SDL_GPUPrimitiveType, SDL_GPUShaderCreateInfo, SDL_GPUTransferBufferCreateInfo + SDL_GPUBufferCreateInfo, SDL_GPUComputePipelineCreateInfo, + SDL_GPUFillMode, SDL_GPUGraphicsPipelineCreateInfo, + SDL_GPUPrimitiveType, SDL_GPUShaderCreateInfo, SDL_GPUTransferBufferCreateInfo }; +use crate::gpu::{SamplerCreateInfo, TextureCreateInfo}; use crate::Error; use super::super::{ - Buffer, BufferUsageFlags, ComputePipeline, DepthStencilState, FillMode, GraphicsPipeline, GraphicsPipelineTargetInfo, PrimitiveType, RasterizerState, Shader, ShaderFormat, ShaderStage, TransferBuffer, TransferBufferUsage, VertexInputState + BufferUsageFlags, ComputePipeline, DepthStencilState, FillMode, GraphicsPipeline, GraphicsPipelineTargetInfo, PrimitiveType, RasterizerState, Shader, ShaderFormat, ShaderStage, TransferBuffer, TransferBufferUsage, VertexInputState }; -use super::util::ExternDevice; + +impl Device { + #[doc(alias = "SDL_CreateGPUShader")] + pub fn create_shader(&self) -> ShaderBuilder { + ShaderBuilder::new(self) + } + + #[doc(alias = "SDL_CreateGPUBuffer")] + pub fn create_buffer(&self) -> BufferBuilder { + BufferBuilder::new(self) + } + + #[doc(alias = "SDL_CreateGPUTransferBuffer")] + pub fn create_transfer_buffer(&self) -> TransferBufferBuilder { + TransferBufferBuilder::new(self) + } + + #[doc(alias = "SDL_CreateGPUSampler")] + pub fn create_sampler<'gpu>(&'gpu self, create_info: SamplerCreateInfo) -> Result, Error> { + Owned::new(self, &create_info.inner, ()) + } + + #[doc(alias = "SDL_CreateGPUGraphicsPipeline")] + pub fn create_graphics_pipeline<'gpu,'a>(&'gpu self) -> GraphicsPipelineBuilder<'gpu, 'a> { + GraphicsPipelineBuilder::new(self) + } + + #[doc(alias = "SDL_CreateGPUComputePipeline")] + pub fn create_compute_pipeline<'gpu,'a>(&'gpu self) -> ComputePipelineBuilder<'gpu, 'a> { + ComputePipelineBuilder::new(self) + } + + #[doc(alias = "SDL_CreateGPUTexture")] + pub fn create_texture<'gpu>( + &'gpu self, + create_info: &TextureCreateInfo, + ) -> Result, Error> { + Owned::new(self, &create_info.inner, (create_info.inner.width, create_info.inner.height)) + } + +} + + +use super::{Buffer, Device, Owned, Sampler, Texture}; #[repr(C)] pub struct ComputePipelineBuilder<'gpu, 'builder> { - device: &'gpu ExternDevice, + device: &'gpu Device, inner: SDL_GPUComputePipelineCreateInfo, - _marker: PhantomData<&'builder Shader<'gpu>>, + _marker: PhantomData<&'builder Shader>, } impl<'gpu, 'builder> ComputePipelineBuilder<'gpu, 'builder> { - pub(in crate::gpu) fn new(device: &'gpu ExternDevice) -> Self { + pub(in crate::gpu) fn new(device: &'gpu Device) -> Self { Self { device, inner: Default::default(), @@ -73,21 +119,23 @@ impl<'gpu, 'builder> ComputePipelineBuilder<'gpu, 'builder> { self } - pub fn build(self) -> Result, Error> { - ComputePipeline::new(self.device, &self.inner) + pub fn build(self) -> Result, Error> { + Owned::new(self.device, &self.inner, ()) } } -pub struct ShaderBuilder<'gpu> { - device: &'gpu ExternDevice, +pub struct ShaderBuilder<'builder, 'gpu> { + device: &'gpu Device, inner: SDL_GPUShaderCreateInfo, + _marker: PhantomData<&'builder [u8]>, } -impl<'gpu> ShaderBuilder<'gpu> { - pub(in crate::gpu) fn new(device: &'gpu ExternDevice) -> Self { +impl<'gpu, 'builder> ShaderBuilder<'builder, 'gpu> { + pub(in crate::gpu) fn new(device: &'gpu Device) -> Self { Self { device, inner: Default::default(), + _marker: PhantomData, } } @@ -111,7 +159,7 @@ impl<'gpu> ShaderBuilder<'gpu> { self } - pub fn with_code(mut self, fmt: ShaderFormat, code: &'gpu [u8], stage: ShaderStage) -> Self { + pub fn with_code(mut self, fmt: ShaderFormat, code: &'builder [u8], stage: ShaderStage) -> Self { self.inner.format = fmt.0; self.inner.code = code.as_ptr(); self.inner.code_size = code.len() as usize; @@ -122,18 +170,18 @@ impl<'gpu> ShaderBuilder<'gpu> { self.inner.entrypoint = entry_point.as_ptr(); self } - pub fn build(self) -> Result, Error> { - Shader::new(self.device, &self.inner) + pub fn build(self) -> Result, Error> { + Owned::new(self.device, &self.inner, ()) } } pub struct TransferBufferBuilder<'gpu> { - device: &'gpu ExternDevice, + device: &'gpu Device, inner: SDL_GPUTransferBufferCreateInfo, } impl<'gpu> TransferBufferBuilder<'gpu> { - pub(in crate::gpu) fn new(device: &'gpu ExternDevice) -> Self { + pub(in crate::gpu) fn new(device: &'gpu Device) -> Self { Self { device, inner: Default::default(), @@ -152,18 +200,18 @@ impl<'gpu> TransferBufferBuilder<'gpu> { self } - pub fn build(self) -> Result, Error> { - TransferBuffer::new(self.device, &self.inner) + pub fn build(self) -> Result, Error> { + Owned::new(self.device, &self.inner, self.inner.size) } } pub struct BufferBuilder<'gpu> { - device: &'gpu ExternDevice, + device: &'gpu Device, inner: SDL_GPUBufferCreateInfo, } impl<'gpu> BufferBuilder<'gpu> { - pub(in crate::gpu) fn new(device: &'gpu ExternDevice) -> Self { + pub(in crate::gpu) fn new(device: &'gpu Device) -> Self { Self { device, inner: Default::default(), @@ -180,20 +228,23 @@ impl<'gpu> BufferBuilder<'gpu> { self } - pub fn build(self) -> Result, Error> { - Buffer::new(self.device, &self.inner) + pub fn build(self) -> Result, Error> { + Owned::new(self.device, &self.inner, self.inner.size) } } #[repr(C)] pub struct GraphicsPipelineBuilder<'gpu, 'builder> { - device: &'gpu ExternDevice, + device: &'gpu Device, inner: SDL_GPUGraphicsPipelineCreateInfo, - _marker: PhantomData<&'builder Shader<'gpu>>, + _marker: PhantomData<( + &'builder Shader, + GraphicsPipelineTargetInfo<'builder>, + )>, } impl<'gpu, 'builder> GraphicsPipelineBuilder<'gpu, 'builder> { - pub(in crate::gpu) fn new(device: &'gpu ExternDevice) -> Self { + pub(in crate::gpu) fn new(device: &'gpu Device) -> Self { Self { device, inner: Default::default(), @@ -201,12 +252,12 @@ impl<'gpu, 'builder> GraphicsPipelineBuilder<'gpu, 'builder> { } } - pub fn with_fragment_shader(mut self, value: &'builder Shader<'gpu>) -> Self { - self.inner.fragment_shader = value.raw(); + pub fn with_fragment_shader(mut self, value: &'builder Shader) -> Self { + self.inner.fragment_shader = value.ll(); self } - pub fn with_vertex_shader(mut self, value: &'builder Shader<'gpu>) -> Self { - self.inner.vertex_shader = value.raw(); + pub fn with_vertex_shader(mut self, value: &'builder Shader) -> Self { + self.inner.vertex_shader = value.ll(); self } pub fn with_primitive_type(mut self, value: PrimitiveType) -> Self { @@ -235,17 +286,17 @@ impl<'gpu, 'builder> GraphicsPipelineBuilder<'gpu, 'builder> { self } - pub fn with_vertex_input_state(mut self, value: VertexInputState) -> Self { + pub fn with_vertex_input_state(mut self, value: VertexInputState<'builder>) -> Self { self.inner.vertex_input_state = value.inner; self } - pub fn with_target_info(mut self, value: GraphicsPipelineTargetInfo) -> Self { + pub fn with_target_info(mut self, value: GraphicsPipelineTargetInfo<'builder>) -> Self { self.inner.target_info = value.inner; self } - pub fn build(self) -> Result, Error> { - GraphicsPipeline::new(self.device, &self.inner) + pub fn build(self) -> Result, Error> { + Owned::new(self.device, &self.inner, ()) } } \ No newline at end of file diff --git a/src/sdl3/gpu/resource/compute_pipeline.rs b/src/sdl3/gpu/resource/compute_pipeline.rs deleted file mode 100644 index da62ee87..00000000 --- a/src/sdl3/gpu/resource/compute_pipeline.rs +++ /dev/null @@ -1,41 +0,0 @@ -use super::util::*; - -use sys::gpu::{ - SDL_GPUComputePipeline, - SDL_GPUComputePipelineCreateInfo, - SDL_CreateGPUComputePipeline, - SDL_ReleaseGPUComputePipeline, -}; - -#[doc(alias = "SDL_GPUComputePipeline")] -pub struct ComputePipeline<'gpu> { - raw: NonNull>, - device: &'gpu ExternDevice, -} - -impl<'gpu> Drop for ComputePipeline<'gpu> { - #[doc(alias = "SDL_ReleaseGPUComputePipeline")] - fn drop(&mut self) { - unsafe { SDL_ReleaseGPUComputePipeline(self.device.raw(), self.raw()) } - } -} - -impl<'gpu> Deref for ComputePipeline<'gpu> { - type Target = Extern; - - fn deref(&self) -> &Self::Target { - unsafe { self.raw.as_ref() } - } -} - -impl<'gpu> ComputePipeline<'gpu> { - pub(crate) fn new(device: &'gpu ExternDevice, create_info: &'_ SDL_GPUComputePipelineCreateInfo) -> Result { - let raw = nonnull_ext_or_get_error(unsafe { - SDL_CreateGPUComputePipeline(device.raw(), create_info) - })?; - Ok(ComputePipeline { - raw, - device, - }) - } -} diff --git a/src/sdl3/gpu/resource/device.rs b/src/sdl3/gpu/resource/device.rs index 8e9a8593..3ae4773b 100644 --- a/src/sdl3/gpu/resource/device.rs +++ b/src/sdl3/gpu/resource/device.rs @@ -1,5 +1,9 @@ -use super::util::*; + + +use std::{ops::Deref, ptr::NonNull}; + +use crate::{gpu::{util::nonnull_ext_or_get_error, Extern}, Error}; use super::super::ShaderFormat; @@ -9,11 +13,13 @@ use sys::gpu::{ SDL_DestroyGPUDevice }; -pub struct Device { - raw: NonNull>, +pub type Device = Extern; + +pub struct OwnedDevice { + raw: NonNull, } -impl Device { +impl OwnedDevice { #[doc(alias = "SDL_CreateGPUDevice")] pub fn new(flags: ShaderFormat, debug_mode: bool) -> Result { let raw = nonnull_ext_or_get_error(unsafe { @@ -23,15 +29,15 @@ impl Device { } } -impl Drop for Device { +impl Drop for OwnedDevice { #[doc(alias = "SDL_DestroyGPUDevice")] fn drop(&mut self) { - unsafe { SDL_DestroyGPUDevice(self.raw()) } + unsafe { SDL_DestroyGPUDevice(self.ll()) } } } -impl Deref for Device { - type Target = Extern; +impl Deref for OwnedDevice { + type Target = Device; fn deref(&self) -> &Self::Target { unsafe { self.raw.as_ref() } diff --git a/src/sdl3/gpu/resource/graphics_pipeline.rs b/src/sdl3/gpu/resource/graphics_pipeline.rs deleted file mode 100644 index a2553c73..00000000 --- a/src/sdl3/gpu/resource/graphics_pipeline.rs +++ /dev/null @@ -1,41 +0,0 @@ -use super::util::*; - -use sys::gpu::{ - SDL_GPUGraphicsPipeline, - SDL_GPUGraphicsPipelineCreateInfo, - SDL_CreateGPUGraphicsPipeline, - SDL_ReleaseGPUGraphicsPipeline, -}; - -#[doc(alias = "SDL_GPUGraphicsPipeline")] -pub struct GraphicsPipeline<'gpu> { - raw: NonNull>, - device: &'gpu ExternDevice, -} - -impl<'gpu> Drop for GraphicsPipeline<'gpu> { - #[doc(alias = "SDL_ReleaseGPUGraphicsPipeline")] - fn drop(&mut self) { - unsafe { SDL_ReleaseGPUGraphicsPipeline(self.device.raw(), self.raw()) } - } -} - -impl<'gpu> Deref for GraphicsPipeline<'gpu> { - type Target = Extern; - - fn deref(&self) -> &Self::Target { - unsafe { self.raw.as_ref() } - } -} - -impl<'gpu> GraphicsPipeline<'gpu> { - pub(crate) fn new(device: &'gpu ExternDevice, create_info: &'_ SDL_GPUGraphicsPipelineCreateInfo) -> Result { - let raw = nonnull_ext_or_get_error(unsafe { - SDL_CreateGPUGraphicsPipeline(device.raw(), create_info) - })?; - Ok(GraphicsPipeline { - raw, - device, - }) - } -} diff --git a/src/sdl3/gpu/resource/mod.rs b/src/sdl3/gpu/resource/mod.rs index 4e94831f..c9266a7c 100644 --- a/src/sdl3/gpu/resource/mod.rs +++ b/src/sdl3/gpu/resource/mod.rs @@ -1,43 +1,290 @@ //! GPU-resources //! -mod util { - pub(super) use std::ptr::NonNull; - pub(super) use std::ops::Deref; - pub(super) use crate::Error; - - pub(super) use super::super::util::*; - - pub(super) use super::super::Extern; - pub(super) use super::super::ExternDevice; - -} - +//! mod builders; +use std::{marker::PhantomData, ptr::NonNull}; + pub use builders::{ ComputePipelineBuilder, GraphicsPipelineBuilder, ShaderBuilder, BufferBuilder, TransferBufferBuilder, }; -mod buffer; -pub use buffer::Buffer; -mod shader; -pub use shader::Shader; +mod device; +pub use device::OwnedDevice; +pub use device::Device; -mod compute_pipeline; -pub use compute_pipeline::ComputePipeline; +use sys::gpu::{SDL_GPUBufferRegion, SDL_GPUDevice, SDL_GPUStorageBufferReadWriteBinding, SDL_GPUStorageTextureReadWriteBinding, SDL_GPUTransferBufferLocation, SDL_MapGPUTransferBuffer, SDL_UnmapGPUTransferBuffer}; -mod graphics_pipeline; -pub use graphics_pipeline::GraphicsPipeline; -mod sampler; -pub use sampler::Sampler; +use crate::Error; +use crate::{get_error, gpu::BufferRegion}; -mod texture; -pub use texture::Texture; +use super::util::Defer; +use super::Extern; +use super::{StorageBufferReadWriteBinding, StorageTextureReadWriteBinding, TextureSamplerBinding, TransferBufferLocation}; -mod transfer_buffer; -pub use transfer_buffer::TransferBuffer; -mod device; -pub use device::Device; +pub unsafe trait GpuCreate: GpuRelease { + type CreateInfo; + const CREATE: unsafe extern "C" fn(*mut SDL_GPUDevice, *const Self::CreateInfo) -> *mut Self::SDLType; +} + +pub unsafe trait GpuRelease { + type SDLType; + const RELEASE: unsafe extern "C" fn(*mut SDL_GPUDevice, *mut Self::SDLType); + + // any additional state that `Owned` will keep + type ExtraState; +} + +pub struct Owned<'gpu, T: GpuRelease> +{ + raw: NonNull, + ctx: &'gpu Device, + extra: T::ExtraState, +} + +impl<'gpu, T: GpuCreate + GpuRelease> Owned<'gpu, T> { + pub(crate) fn new(ctx: &'gpu Device, info: &T::CreateInfo, extra: T::ExtraState) -> Result { + unsafe { + let raw: *mut T::SDLType = T::CREATE(ctx.ll(), info); + let raw: *mut T = raw.cast(); + if let Some(raw) = NonNull::new(raw) { + Ok(Owned { + raw, + ctx, + extra, + }) + } else { + Err(get_error()) + } + } + } +} + +impl<'gpu, T: GpuRelease> ::core::ops::Deref for Owned<'gpu, T> { + type Target = Extern; + + fn deref(&self) -> &Self::Target { + unsafe { self.raw.cast().as_ref() } + } +} + +impl<'gpu, T: GpuRelease> Drop for Owned<'gpu, T> { + fn drop(&mut self) { + unsafe { + T::RELEASE(self.ctx.ll(), self.raw.as_ptr().cast()); + } + } +} + +macro_rules! gpu_resource { + ($rust_name:ident, $sdl_name:path, $info:path, $create:path, $release:path, $extra:ty) => { + + const _: () = assert!(size_of::<$sdl_name>() == 0); + + pub type $rust_name = Extern<$sdl_name>; + unsafe impl GpuCreate for $rust_name { + type CreateInfo = $info; + + const CREATE: unsafe extern "C" fn(*mut SDL_GPUDevice, *const Self::CreateInfo) -> *mut Self::SDLType + = $create; + } + unsafe impl GpuRelease for $rust_name { + type SDLType = $sdl_name; + type ExtraState = $extra; + + const RELEASE: unsafe extern "C" fn(*mut SDL_GPUDevice, *mut Self::SDLType) + = $release; + } + }; +} + +gpu_resource!(ComputePipeline, + sys::gpu::SDL_GPUComputePipeline, + sys::gpu::SDL_GPUComputePipelineCreateInfo, + sys::gpu::SDL_CreateGPUComputePipeline, + sys::gpu::SDL_ReleaseGPUComputePipeline, + () +); + +gpu_resource!(GraphicsPipeline, + sys::gpu::SDL_GPUGraphicsPipeline, + sys::gpu::SDL_GPUGraphicsPipelineCreateInfo, + sys::gpu::SDL_CreateGPUGraphicsPipeline, + sys::gpu::SDL_ReleaseGPUGraphicsPipeline, + () +); + + +gpu_resource!(Sampler, + sys::gpu::SDL_GPUSampler, + sys::gpu::SDL_GPUSamplerCreateInfo, + sys::gpu::SDL_CreateGPUSampler, + sys::gpu::SDL_ReleaseGPUSampler, + () +); + +gpu_resource!(Shader, + sys::gpu::SDL_GPUShader, + sys::gpu::SDL_GPUShaderCreateInfo, + sys::gpu::SDL_CreateGPUShader, + sys::gpu::SDL_ReleaseGPUShader, + () +); + +gpu_resource!(Texture, + sys::gpu::SDL_GPUTexture, + sys::gpu::SDL_GPUTextureCreateInfo, + sys::gpu::SDL_CreateGPUTexture, + sys::gpu::SDL_ReleaseGPUTexture, + (u32, u32) +); + +gpu_resource!(TransferBuffer, + sys::gpu::SDL_GPUTransferBuffer, + sys::gpu::SDL_GPUTransferBufferCreateInfo, + sys::gpu::SDL_CreateGPUTransferBuffer, + sys::gpu::SDL_ReleaseGPUTransferBuffer, + u32 +); + +gpu_resource!(Buffer, + sys::gpu::SDL_GPUBuffer, + sys::gpu::SDL_GPUBufferCreateInfo, + sys::gpu::SDL_CreateGPUBuffer, + sys::gpu::SDL_ReleaseGPUBuffer, + u32 +); + + + +impl<'a> Owned<'a, Texture> { + pub fn width(&self) -> u32 { + self.extra.0 + } + + pub fn height(&self) -> u32 { + self.extra.1 + } +} + + +impl<'gpu> Owned<'gpu, Buffer> { + + /// The length of this buffer in bytes. + pub fn len(&self) -> u32 { + self.extra + } +} + +impl Buffer { + pub fn get(&self, range: std::ops::Range) -> BufferRegion<'_> { + assert!(range.end >= range.start); + BufferRegion { + inner: SDL_GPUBufferRegion { + buffer: self.ll(), + offset: range.start, + size: range.end - range.start, + ..Default::default() + }, + _marker: PhantomData, + } + } + + /// Create a read-write binding that cycles this buffer when bound + pub fn cycled(&self) -> StorageBufferReadWriteBinding<'_> { + let mut inner = SDL_GPUStorageBufferReadWriteBinding::default(); + inner.cycle = true; + inner.buffer = self.ll(); + StorageBufferReadWriteBinding { + inner, + _marker: PhantomData, + } + } + + /// Create a read-write binding that refers to the current contents of the buffer + pub fn preserved(&self) -> StorageBufferReadWriteBinding<'_> { + let mut inner = SDL_GPUStorageBufferReadWriteBinding::default(); + inner.cycle = false; + inner.buffer = self.ll(); + StorageBufferReadWriteBinding { + inner, + _marker: PhantomData, + } + } +} + +impl Texture { + /// Create a read-write binding that cycles this texture when bound + pub fn cycled(&self) -> StorageTextureReadWriteBinding<'_> { + let mut inner = SDL_GPUStorageTextureReadWriteBinding::default(); + inner.cycle = true; + inner.texture = self.ll(); + StorageTextureReadWriteBinding { + inner, + _marker: PhantomData, + } + } + + /// Create a read-write binding that refers to the current contents of the texture + pub fn preserved(&self) -> StorageTextureReadWriteBinding<'_> { + let mut inner = SDL_GPUStorageTextureReadWriteBinding::default(); + inner.cycle = false; + inner.texture = self.ll(); + StorageTextureReadWriteBinding { + inner, + _marker: PhantomData, + } + } + + pub fn with_sampler<'a>(&'a self, sampler: &'a Sampler) -> TextureSamplerBinding<'a> { + let mut binding = TextureSamplerBinding::default(); + binding.inner.texture = self.ll(); + binding.inner.sampler = sampler.ll(); + binding + } +} + + +impl TransferBuffer { + pub fn get<'a>(&'a self, from: std::ops::RangeFrom) -> TransferBufferLocation<'a> { + TransferBufferLocation { + inner: SDL_GPUTransferBufferLocation { + transfer_buffer: self.ll(), + offset: from.start, + ..Default::default() + }, + _marker: PhantomData, + } + } +} + +impl<'gpu> Owned<'gpu, TransferBuffer> { + #[doc(alias = "SDL_MapGPUTransferBuffer")] + pub fn mapped_mut( + &mut self, + cycle: bool, + f: impl for<'a> FnOnce(&'a mut [u8]) -> R, + ) -> Result { + unsafe { + let raw = SDL_MapGPUTransferBuffer(self.ctx.ll(), self.ll(), cycle); + if raw.is_null() { + return Err(get_error()); + } + + let bytes = std::slice::from_raw_parts_mut(raw as *mut u8, self.extra as usize); + + let _defer = Defer::new(|| + SDL_UnmapGPUTransferBuffer(self.ctx.ll(), self.ll()) + ); + + Ok(f(bytes)) + } + } + + pub fn len(&self) -> u32 { + self.extra + } +} diff --git a/src/sdl3/gpu/resource/sampler.rs b/src/sdl3/gpu/resource/sampler.rs deleted file mode 100644 index f5463c1b..00000000 --- a/src/sdl3/gpu/resource/sampler.rs +++ /dev/null @@ -1,41 +0,0 @@ -use super::util::*; - -use sys::gpu::{ - SDL_GPUSampler, - SDL_GPUSamplerCreateInfo, - SDL_CreateGPUSampler, - SDL_ReleaseGPUSampler -}; - -#[doc(alias = "SDL_GPUSampler")] -pub struct Sampler<'gpu> { - raw: NonNull>, - device: &'gpu ExternDevice, -} - -impl<'gpu> Drop for Sampler<'gpu> { - #[doc(alias = "SDL_ReleaseGPUSampler")] - fn drop(&mut self) { - unsafe { SDL_ReleaseGPUSampler(self.device.raw(), self.raw()) } - } -} - -impl<'gpu> Deref for Sampler<'gpu> { - type Target = Extern; - - fn deref(&self) -> &Self::Target { - unsafe { self.raw.as_ref() } - } -} - -impl<'gpu> Sampler<'gpu> { - pub(crate) fn new(device: &'gpu ExternDevice, create_info: &'_ SDL_GPUSamplerCreateInfo) -> Result { - let raw = nonnull_ext_or_get_error(unsafe { - SDL_CreateGPUSampler(device.raw(), create_info) - })?; - Ok(Sampler { - raw, - device, - }) - } -} diff --git a/src/sdl3/gpu/resource/shader.rs b/src/sdl3/gpu/resource/shader.rs deleted file mode 100644 index 4847337b..00000000 --- a/src/sdl3/gpu/resource/shader.rs +++ /dev/null @@ -1,41 +0,0 @@ -use super::util::*; - -use sys::gpu::{ - SDL_GPUShader, - SDL_GPUShaderCreateInfo, - SDL_CreateGPUShader, - SDL_ReleaseGPUShader, -}; - -#[doc(alias = "SDL_GPUShader")] -pub struct Shader<'gpu> { - raw: NonNull>, - device: &'gpu ExternDevice, -} - -impl<'gpu> Drop for Shader<'gpu> { - #[doc(alias = "SDL_ReleaseGPUShader")] - fn drop(&mut self) { - unsafe { SDL_ReleaseGPUShader(self.device.raw(), self.raw()) } - } -} - -impl<'gpu> Deref for Shader<'gpu> { - type Target = Extern; - - fn deref(&self) -> &Self::Target { - unsafe { self.raw.as_ref() } - } -} - -impl<'gpu> Shader<'gpu> { - pub(crate) fn new(device: &'gpu ExternDevice, create_info: &'_ SDL_GPUShaderCreateInfo) -> Result { - let raw = nonnull_ext_or_get_error(unsafe { - SDL_CreateGPUShader(device.raw(), create_info) - })?; - Ok(Shader { - raw, - device, - }) - } -} diff --git a/src/sdl3/gpu/resource/texture.rs b/src/sdl3/gpu/resource/texture.rs deleted file mode 100644 index e3b2106f..00000000 --- a/src/sdl3/gpu/resource/texture.rs +++ /dev/null @@ -1,54 +0,0 @@ -use super::util::*; - -use sys::gpu::{ - SDL_GPUTexture, - SDL_GPUTextureCreateInfo, - SDL_CreateGPUTexture, - SDL_ReleaseGPUTexture, -}; - -#[doc(alias = "SDL_Texture")] -pub struct Texture<'gpu> { - pub(super) raw: NonNull>, - // the GPU to release this from - pub(super) device: &'gpu ExternDevice, - pub(super) width: u32, - pub(super) height: u32, -} - -impl<'gpu> Drop for Texture<'gpu> { - #[doc(alias = "SDL_ReleaseGPUTexture")] - fn drop(&mut self) { - unsafe { SDL_ReleaseGPUTexture(self.device.raw(), self.raw()) }; - } -} - -impl<'gpu> Deref for Texture<'gpu> { - type Target = Extern; - - fn deref(&self) -> &Self::Target { - unsafe { self.raw.as_ref() } - } -} - -impl<'gpu> Texture<'gpu> { - pub(crate) fn new(device: &'gpu ExternDevice, create_info: &'_ SDL_GPUTextureCreateInfo) -> Result { - let raw = nonnull_ext_or_get_error(unsafe { - SDL_CreateGPUTexture(device.raw(), create_info) - })?; - Ok(Texture { - raw, - width: create_info.width, - height: create_info.height, - device, - }) - } - - pub fn width(&self) -> u32 { - self.width - } - - pub fn height(&self) -> u32 { - self.height - } -} diff --git a/src/sdl3/gpu/resource/transfer_buffer.rs b/src/sdl3/gpu/resource/transfer_buffer.rs deleted file mode 100644 index 61e17815..00000000 --- a/src/sdl3/gpu/resource/transfer_buffer.rs +++ /dev/null @@ -1,72 +0,0 @@ -use crate::get_error; - -use super::util::*; - -use sys::gpu::{ - SDL_CreateGPUTransferBuffer, SDL_GPUTransferBuffer, SDL_GPUTransferBufferCreateInfo, SDL_MapGPUTransferBuffer, SDL_ReleaseGPUTransferBuffer, SDL_UnmapGPUTransferBuffer -}; - -#[doc(alias = "SDL_GPUTransferBuffer")] -pub struct TransferBuffer<'gpu> { - raw: NonNull>, - device: &'gpu ExternDevice, - len: u32, -} - -impl<'gpu> Drop for TransferBuffer<'gpu> { - #[doc(alias = "SDL_ReleaseGPUTransferBuffer")] - fn drop(&mut self) { - unsafe { - SDL_ReleaseGPUTransferBuffer(self.device.raw(), self.raw()); - } - } -} - -impl<'gpu> Deref for TransferBuffer<'gpu> { - type Target = Extern; - - fn deref(&self) -> &Self::Target { - unsafe { self.raw.as_ref() } - } -} - - -impl<'gpu> TransferBuffer<'gpu> { - pub(crate) fn new(device: &'gpu ExternDevice, create_info: &'_ SDL_GPUTransferBufferCreateInfo) -> Result { - let raw = nonnull_ext_or_get_error(unsafe { - SDL_CreateGPUTransferBuffer(device.raw(), create_info) - })?; - Ok(TransferBuffer { - raw, - device, - len: create_info.size, - }) - } - - #[doc(alias = "SDL_MapGPUTransferBuffer")] - pub fn mapped_mut( - &mut self, - cycle: bool, - f: impl for<'a> FnOnce(&'a mut [u8]) -> R, - ) -> Result { - unsafe { - let raw = SDL_MapGPUTransferBuffer(self.device.raw(), self.raw(), cycle); - if raw.is_null() { - return Err(get_error()); - } - - let bytes = std::slice::from_raw_parts_mut(raw as *mut u8, self.len as usize); - - let _defer = Defer::new(|| - SDL_UnmapGPUTransferBuffer(self.device.raw(), self.raw()) - ); - - Ok(f(bytes)) - } - } - - /// The length of this buffer in bytes. - pub fn len(&self) -> u32 { - self.len - } -} From 1bf2dd6fd0f7c87b108188b9e19d926db0b4bc46 Mon Sep 17 00:00:00 2001 From: quaternic <57393910+quaternic@users.noreply.github.com> Date: Sat, 31 May 2025 22:42:39 +0300 Subject: [PATCH 4/5] wip --- Cargo.lock | 3 +- Cargo.toml | 1 + src/sdl3/gpu/abstraction.rs | 12 +++++ src/sdl3/gpu/auto_trait.rs | 51 +++++++++++++++++++++ src/sdl3/gpu/command_buffer/compute.rs | 15 ++++++- src/sdl3/gpu/command_buffer/copy.rs | 45 ++++++++++++++++--- src/sdl3/gpu/command_buffer/mod.rs | 56 +++++++++++++++++------- src/sdl3/gpu/command_buffer/swapchain.rs | 18 +++----- src/sdl3/gpu/info_struct.rs | 30 +++++++------ src/sdl3/gpu/mod.rs | 23 +++++----- src/sdl3/gpu/resource/builders.rs | 3 +- 11 files changed, 197 insertions(+), 60 deletions(-) create mode 100644 src/sdl3/gpu/abstraction.rs create mode 100644 src/sdl3/gpu/auto_trait.rs diff --git a/Cargo.lock b/Cargo.lock index aededcec..b775e9cb 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -868,7 +868,7 @@ checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" [[package]] name = "sdl3" -version = "0.14.27" +version = "0.14.26" dependencies = [ "bitflags 2.9.0", "c_vec", @@ -882,6 +882,7 @@ dependencies = [ "sdl3-image-sys", "sdl3-sys", "sdl3-ttf-sys", + "static_assertions", "wgpu", ] diff --git a/Cargo.toml b/Cargo.toml index f87ab4d9..f77ce670 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -55,6 +55,7 @@ rand = "0.8.5" wgpu = { version = "24.0.0", features = ["spirv"] } pollster = "0.4.0" env_logger = "0.11.6" +static_assertions = "1.1.0" [features] diff --git a/src/sdl3/gpu/abstraction.rs b/src/sdl3/gpu/abstraction.rs new file mode 100644 index 00000000..3ccf7cc3 --- /dev/null +++ b/src/sdl3/gpu/abstraction.rs @@ -0,0 +1,12 @@ +use std::marker::PhantomData; + +use crate::gpu::Buffer; + + + +// a typed pseudo-reference to an object located in a `Buffer` on the GPU +pub struct Ref<'a, T> { + pub(crate) buf: &'a Buffer, + pub(crate) offset: u32, + pub(crate) marker: PhantomData<&'a T>, +} \ No newline at end of file diff --git a/src/sdl3/gpu/auto_trait.rs b/src/sdl3/gpu/auto_trait.rs new file mode 100644 index 00000000..085f244d --- /dev/null +++ b/src/sdl3/gpu/auto_trait.rs @@ -0,0 +1,51 @@ + + +// manually checking auto-traits for a type +type _X = u32; +const _: () = _copy::<_X>(); +const _: () = _send::<_X>(); +const _: () = _sync::<_X>(); +const _: () = _unpin::<_X>(); + + +const fn _copy() {} +const fn _send() {} +const fn _sync() {} +const fn _unpin() {} + +#[cfg(test)] +mod assertions { + use static_assertions::{assert_impl_all, assert_not_impl_any}; + + macro_rules! thread_safe { + ($t:ty) => { + assert_impl_all!($t: Sync); + assert_not_impl_any!($t: Copy, Send, Unpin); + }; + } + macro_rules! thread_unsafe { + ($t:ty) => { + assert_not_impl_any!($t: Copy, Sync, Send, Unpin); + }; + } + + use crate::gpu::*; + + // definitely not thread-safe + thread_unsafe!(CommandBuffer); + + // at least SDL_GetGPUDeviceProperties is documented as + // "safe to call from any thread", which implies that the device can be shared + thread_safe!(Device); + + // these are ambiguous + thread_safe!(Buffer); + thread_safe!(Texture); + + // possibly thread-safe, but haven't checked yet + thread_unsafe!(Sampler); + thread_unsafe!(TransferBuffer); + thread_unsafe!(GraphicsPipeline); + thread_unsafe!(ComputePipeline); + thread_unsafe!(Shader); +} \ No newline at end of file diff --git a/src/sdl3/gpu/command_buffer/compute.rs b/src/sdl3/gpu/command_buffer/compute.rs index 59d46646..787d6439 100644 --- a/src/sdl3/gpu/command_buffer/compute.rs +++ b/src/sdl3/gpu/command_buffer/compute.rs @@ -1,9 +1,13 @@ use sys::gpu::{ SDL_BindGPUComputePipeline, SDL_BindGPUComputeSamplers, SDL_BindGPUComputeStorageBuffers, - SDL_BindGPUComputeStorageTextures, SDL_DispatchGPUCompute, SDL_GPUComputePass, + SDL_BindGPUComputeStorageTextures, SDL_DispatchGPUCompute, SDL_DispatchGPUComputeIndirect, + SDL_GPUComputePass, }; -use crate::gpu::{Buffer, ComputePipeline, Extern, Texture, TextureSamplerBinding}; +use crate::gpu::{ + info_struct::IndirectDispatchCommand, Buffer, ComputePipeline, Extern, Texture, + TextureSamplerBinding, +}; pub type ComputePass = Extern; @@ -49,8 +53,15 @@ impl ComputePass { } } + /// Dispatch compute work #[doc(alias = "SDL_DispatchGPUCompute")] pub fn dispatch(&self, groupcount_x: u32, groupcount_y: u32, groupcount_z: u32) { unsafe { SDL_DispatchGPUCompute(self.ll(), groupcount_x, groupcount_y, groupcount_z) } } + + /// Dispatch compute work. Same as `dispatch`, except the dispatch parameters are read from GPU memory. + #[doc(alias = "SDL_DispatchGPUComputeIndirect")] + pub fn dispatch_indirect(&self, dispatch: crate::gpu::Ref<'_, IndirectDispatchCommand>) { + unsafe { SDL_DispatchGPUComputeIndirect(self.ll(), dispatch.buf.ll(), dispatch.offset) } + } } diff --git a/src/sdl3/gpu/command_buffer/copy.rs b/src/sdl3/gpu/command_buffer/copy.rs index 220b0c49..1680d143 100644 --- a/src/sdl3/gpu/command_buffer/copy.rs +++ b/src/sdl3/gpu/command_buffer/copy.rs @@ -1,8 +1,12 @@ use crate::gpu::{ + info_struct::{BufferLocation, TextureLocation}, BufferRegion, Extern, TextureRegion, TextureTransferInfo, TransferBufferLocation, }; -use sys::gpu::{SDL_GPUCopyPass, SDL_UploadToGPUBuffer, SDL_UploadToGPUTexture}; +use sys::gpu::{ + SDL_CopyGPUBufferToBuffer, SDL_CopyGPUTextureToTexture, SDL_DownloadFromGPUBuffer, + SDL_DownloadFromGPUTexture, SDL_GPUCopyPass, SDL_UploadToGPUBuffer, SDL_UploadToGPUTexture, +}; pub type CopyPass = Extern; @@ -25,12 +29,43 @@ impl CopyPass { } #[doc(alias = "SDL_UploadToGPUTexture")] - pub fn upload_to_gpu_texture( + pub fn upload_to_gpu_texture(&self, src: TextureTransferInfo, dst: TextureRegion, cycle: bool) { + unsafe { SDL_UploadToGPUTexture(self.ll(), &src.inner, &dst.inner, cycle) } + } + + #[doc(alias = "SDL_CopyGPUTextureToTexture")] + pub fn copy_texture_to_texture( + &self, + src: TextureLocation<'_>, + dst: TextureLocation<'_>, + w: u32, + h: u32, + d: u32, + cycle: bool, + ) { + unsafe { SDL_CopyGPUTextureToTexture(self.ll(), &src.inner, &dst.inner, w, h, d, cycle) } + } + + #[doc(alias = "SDL_CopyGPUBufferToBuffer")] + pub fn copy_buffer_to_buffer( &self, - source: TextureTransferInfo, - destination: TextureRegion, + src: BufferLocation<'_>, + dst: BufferLocation<'_>, + size: u32, cycle: bool, ) { - unsafe { SDL_UploadToGPUTexture(self.ll(), &source.inner, &destination.inner, cycle) } + unsafe { SDL_CopyGPUBufferToBuffer(self.ll(), &src.inner, &dst.inner, size, cycle) } + } + + /// Note: The data is not guaranteed to be copied until the command buffer fence is signaled. + #[doc(alias = "SDL_DownloadFromGPUBuffer")] + pub fn download_from_gpu_buffer(&self, src: BufferRegion<'_>, dst: TransferBufferLocation<'_>) { + unsafe { SDL_DownloadFromGPUBuffer(self.ll(), &src.inner, &dst.inner) } + } + + /// Note: The data is not guaranteed to be copied until the command buffer fence is signaled. + #[doc(alias = "SDL_DownloadFromGPUTexture")] + pub fn download_from_gpu_texture(&self, src: TextureRegion<'_>, dst: TextureTransferInfo<'_>) { + unsafe { SDL_DownloadFromGPUTexture(self.ll(), &src.inner, &dst.inner) } } } diff --git a/src/sdl3/gpu/command_buffer/mod.rs b/src/sdl3/gpu/command_buffer/mod.rs index ee89a1dc..9ce37749 100644 --- a/src/sdl3/gpu/command_buffer/mod.rs +++ b/src/sdl3/gpu/command_buffer/mod.rs @@ -8,7 +8,7 @@ use crate::{get_error, gpu::util::nonnull_ext_or_get_error, Error}; use super::{ util::Defer, ColorTargetInfo, DepthStencilTargetInfo, Device, Extern, - StorageBufferReadWriteBinding, StorageTextureReadWriteBinding, + StorageBufferReadWriteBinding, StorageTextureReadWriteBinding, Texture, }; use sys::gpu::{ @@ -55,19 +55,36 @@ impl<'gpu> DerefMut for OwnedCommandBuffer<'gpu> { unsafe { self.raw.as_mut() } } } - -impl<'gpu> OwnedCommandBuffer<'gpu> { - pub(crate) fn new(device: &'gpu Device) -> Result { - let raw = nonnull_ext_or_get_error(unsafe { SDL_AcquireGPUCommandBuffer(device.ll()) })?; +impl Device { + #[doc(alias = "SDL_AcquireGPUCommandBuffer")] + pub fn acquire_command_buffer<'gpu>(&'gpu self) -> Result, Error> { + let raw = nonnull_ext_or_get_error(unsafe { SDL_AcquireGPUCommandBuffer(self.ll()) })?; Ok(OwnedCommandBuffer { raw, _marker: PhantomData, }) } +} +impl<'gpu> Drop for OwnedCommandBuffer<'gpu> { + fn drop(&mut self) { + if std::thread::panicking() { + // if already panicking, let's not make it worse + return; + } else { + panic!("A command buffer was implicitly dropped, + but should be explicitly submitted or cancelled."); + } + } +} + +impl<'gpu> OwnedCommandBuffer<'gpu> { #[doc(alias = "SDL_SubmitGPUCommandBuffer")] pub fn submit(self) -> Result<(), Error> { - if unsafe { sys::gpu::SDL_SubmitGPUCommandBuffer(self.ll()) } { + let raw = self.ll(); + std::mem::forget(self); + + if unsafe { sys::gpu::SDL_SubmitGPUCommandBuffer(raw) } { Ok(()) } else { Err(get_error()) @@ -76,13 +93,20 @@ impl<'gpu> OwnedCommandBuffer<'gpu> { #[doc(alias = "SDL_CancelGPUCommandBuffer")] pub fn cancel(self) { + let raw = self.ll(); + std::mem::forget(self); + unsafe { - sys::gpu::SDL_CancelGPUCommandBuffer(self.ll()); + sys::gpu::SDL_CancelGPUCommandBuffer(raw); } } } impl CommandBuffer { + /// Run a compute pass on this command buffer. + /// + /// Note that *writeable* resources are bound at the start of the pass for the whole pass, + /// whereas readonly resources are bound separately and can be rebound during the pass. #[doc(alias = "SDL_BeginGPUComputePass")] pub fn compute_pass( &mut self, @@ -107,6 +131,7 @@ impl CommandBuffer { Ok(unsafe { func(self, raw.as_mut()) }) } + /// Run a render pass on this command buffer. #[doc(alias = "SDL_BeginGPURenderPass")] pub fn render_pass( &mut self, @@ -133,10 +158,11 @@ impl CommandBuffer { Ok(unsafe { func(self, raw.as_mut()) }) } + /// Run a copy pass on this command buffer. #[doc(alias = "SDL_BeginGPUCopyPass")] pub fn copy_pass( &mut self, - func: impl for<'a> FnOnce(&'a Extern, &'a mut CopyPass) -> R, + func: impl for<'a> FnOnce(&'a CommandBuffer, &'a mut CopyPass) -> R, ) -> Result { let mut raw = nonnull_ext_or_get_error(unsafe { SDL_BeginGPUCopyPass(self.ll()) })?; @@ -169,14 +195,13 @@ impl CommandBuffer { &mut height, ) }; - let raw = raw.cast(); + let raw: *mut Texture = raw.cast(); if success { - if let Some(raw) = NonNull::new(raw) { + if let Some(tex) = unsafe { raw.as_ref() } { Ok(SwapchainTexture { - raw, + tex, width, height, - _marker: PhantomData, }) } else { Err(None) @@ -197,14 +222,13 @@ impl CommandBuffer { let success = unsafe { SDL_AcquireGPUSwapchainTexture(self.ll(), w.raw(), &mut raw, &mut width, &mut height) }; - let raw = raw.cast(); + let raw: *mut Texture = raw.cast(); if success { - if let Some(raw) = NonNull::new(raw) { + if let Some(tex) = unsafe { raw.as_ref() } { Ok(SwapchainTexture { - raw, + tex, width, height, - _marker: PhantomData, }) } else { Err(None) diff --git a/src/sdl3/gpu/command_buffer/swapchain.rs b/src/sdl3/gpu/command_buffer/swapchain.rs index bca52e7b..adf6f7c7 100644 --- a/src/sdl3/gpu/command_buffer/swapchain.rs +++ b/src/sdl3/gpu/command_buffer/swapchain.rs @@ -1,29 +1,23 @@ -use std::{marker::PhantomData, ops::Deref, ptr::NonNull}; +use std::ops::Deref; use crate::gpu::Texture; - - -type Invariant<'a> = PhantomData &'a ()>; - - #[doc(alias = "SDL_Texture")] -pub struct SwapchainTexture<'cmd_buf> { - pub(super) raw: NonNull, +pub struct SwapchainTexture<'a> { + pub(super) tex: &'a Texture, pub(super) width: u32, pub(super) height: u32, - pub(super) _marker: Invariant<'cmd_buf>, } -impl<'cmd_buf> Deref for SwapchainTexture<'cmd_buf> { +impl<'a> Deref for SwapchainTexture<'a> { type Target = Texture; fn deref(&self) -> &Self::Target { - unsafe { self.raw.as_ref() } + &self.tex } } -impl<'cmd_buf> SwapchainTexture<'cmd_buf> { +impl<'a> SwapchainTexture<'a> { pub fn width(&self) -> u32 { self.width } diff --git a/src/sdl3/gpu/info_struct.rs b/src/sdl3/gpu/info_struct.rs index fa7d6faf..a246ef65 100644 --- a/src/sdl3/gpu/info_struct.rs +++ b/src/sdl3/gpu/info_struct.rs @@ -5,18 +5,7 @@ use std::marker::PhantomData; use sys::gpu::{ - SDL_GPUBlendFactor, SDL_GPUBlendOp, SDL_GPUBufferBinding, - SDL_GPUBufferRegion, SDL_GPUColorTargetBlendState, SDL_GPUColorTargetDescription, - SDL_GPUColorTargetInfo, SDL_GPUCompareOp, SDL_GPUCullMode, SDL_GPUDepthStencilState, - SDL_GPUDepthStencilTargetInfo, SDL_GPUFillMode, SDL_GPUFilter, SDL_GPUFrontFace, - SDL_GPUGraphicsPipelineTargetInfo, SDL_GPURasterizerState, SDL_GPUSampleCount, - SDL_GPUSamplerAddressMode, SDL_GPUSamplerCreateInfo, - SDL_GPUSamplerMipmapMode, SDL_GPUStencilOp, SDL_GPUStencilOpState, - SDL_GPUStorageBufferReadWriteBinding, SDL_GPUStorageTextureReadWriteBinding, - SDL_GPUTextureCreateInfo, SDL_GPUTextureRegion, - SDL_GPUTextureSamplerBinding, SDL_GPUTextureTransferInfo, SDL_GPUTextureType, - SDL_GPUTransferBufferLocation, SDL_GPUVertexAttribute, - SDL_GPUVertexBufferDescription, SDL_GPUVertexInputRate, SDL_GPUVertexInputState, + SDL_GPUBlendFactor, SDL_GPUBlendOp, SDL_GPUBufferBinding, SDL_GPUBufferLocation, SDL_GPUBufferRegion, SDL_GPUColorTargetBlendState, SDL_GPUColorTargetDescription, SDL_GPUColorTargetInfo, SDL_GPUCompareOp, SDL_GPUCullMode, SDL_GPUDepthStencilState, SDL_GPUDepthStencilTargetInfo, SDL_GPUFillMode, SDL_GPUFilter, SDL_GPUFrontFace, SDL_GPUGraphicsPipelineTargetInfo, SDL_GPUIndirectDispatchCommand, SDL_GPURasterizerState, SDL_GPUSampleCount, SDL_GPUSamplerAddressMode, SDL_GPUSamplerCreateInfo, SDL_GPUSamplerMipmapMode, SDL_GPUStencilOp, SDL_GPUStencilOpState, SDL_GPUStorageBufferReadWriteBinding, SDL_GPUStorageTextureReadWriteBinding, SDL_GPUTextureCreateInfo, SDL_GPUTextureLocation, SDL_GPUTextureRegion, SDL_GPUTextureSamplerBinding, SDL_GPUTextureTransferInfo, SDL_GPUTextureType, SDL_GPUTransferBufferLocation, SDL_GPUVertexAttribute, SDL_GPUVertexBufferDescription, SDL_GPUVertexInputRate, SDL_GPUVertexInputState }; use crate::pixels::Color; @@ -394,6 +383,13 @@ pub struct TransferBufferLocation<'a> { pub(super) _marker: PhantomData<&'a TransferBuffer>, } +#[repr(C)] +#[derive(Default)] +pub struct BufferLocation<'a> { + pub(super) inner: SDL_GPUBufferLocation, + pub(super) _marker: PhantomData<&'a Buffer>, +} + #[repr(C)] #[derive(Default)] pub struct BufferRegion<'a> { @@ -749,7 +745,7 @@ impl ColorTargetBlendState { } #[repr(C)] -#[derive(Default)] +#[derive(Default,Copy,Clone)] pub struct ColorTargetDescription { inner: SDL_GPUColorTargetDescription, } @@ -850,3 +846,11 @@ impl<'a> StorageBufferReadWriteBinding<'a> { // self // } } + + +pub type IndirectDispatchCommand = SDL_GPUIndirectDispatchCommand; + +pub struct TextureLocation<'a> { + pub(crate) inner: SDL_GPUTextureLocation, + pub(crate) _marker: PhantomData<&'a Texture>, +} \ No newline at end of file diff --git a/src/sdl3/gpu/mod.rs b/src/sdl3/gpu/mod.rs index 0a53feb1..cb48a9fb 100644 --- a/src/sdl3/gpu/mod.rs +++ b/src/sdl3/gpu/mod.rs @@ -1,6 +1,14 @@ -mod resource; + use std::cell::UnsafeCell; +use std::marker::{PhantomData, PhantomPinned}; + +mod abstraction; + +mod auto_trait; + +pub use abstraction::Ref; +mod resource; pub use resource::{ Owned, Buffer, @@ -19,7 +27,6 @@ pub use resource::{ mod command_buffer; pub use command_buffer::{ - OwnedCommandBuffer, CommandBuffer, ComputePass, RenderPass, @@ -53,16 +60,17 @@ use crate::{get_error, Error}; mod util; - - unsafe impl Sync for Device {} unsafe impl Sync for Buffer {} +unsafe impl Sync for Texture {} +unsafe impl<'a, T: resource::GpuRelease + Sync> Sync for Owned<'a, T> {} // We need some wrapper to be able to implement (inherent) methods for the type. // The UnsafeCell doesn't actually do anything for &mut Extern, but the wrapped types // are also zero-sized, so safe code still can't access any bytes with that. +// Also, PhantomPinned so that we can safely give out Pin<&mut Extern> #[repr(transparent)] -pub struct Extern(UnsafeCell); +pub struct Extern(UnsafeCell, PhantomPinned, PhantomData<*mut ()>); impl Extern { pub fn ll(&self) -> *mut T { @@ -71,11 +79,6 @@ impl Extern { } impl Device { - - #[doc(alias = "SDL_AcquireGPUCommandBuffer")] - pub fn acquire_command_buffer<'gpu>(&'gpu self) -> Result, Error> { - OwnedCommandBuffer::new(self) - } #[doc(alias = "SDL_ClaimWindowForGPUDevice")] pub fn claim_window(&self, w: &crate::video::Window) -> Result<(), Error> { diff --git a/src/sdl3/gpu/resource/builders.rs b/src/sdl3/gpu/resource/builders.rs index 69ea55af..4389abaf 100644 --- a/src/sdl3/gpu/resource/builders.rs +++ b/src/sdl3/gpu/resource/builders.rs @@ -233,6 +233,7 @@ impl<'gpu> BufferBuilder<'gpu> { } } +#[derive(Copy,Clone)] #[repr(C)] pub struct GraphicsPipelineBuilder<'gpu, 'builder> { device: &'gpu Device, @@ -296,7 +297,7 @@ impl<'gpu, 'builder> GraphicsPipelineBuilder<'gpu, 'builder> { self } - pub fn build(self) -> Result, Error> { + pub fn build(&self) -> Result, Error> { Owned::new(self.device, &self.inner, ()) } } \ No newline at end of file From e06c0b57bddf3cbaea0cd644fdd3107790c913ff Mon Sep 17 00:00:00 2001 From: quaternic <57393910+quaternic@users.noreply.github.com> Date: Sat, 31 May 2025 22:43:16 +0300 Subject: [PATCH 5/5] cargo fmt --- examples/gpu-clear.rs | 12 +-- examples/gpu-cube.rs | 81 +++++++++-------- examples/gpu-texture.rs | 125 +++++++++++++++------------ examples/gpu-triangle.rs | 6 +- src/sdl3/gpu/abstraction.rs | 6 +- src/sdl3/gpu/auto_trait.rs | 7 +- src/sdl3/gpu/command_buffer/fence.rs | 7 +- src/sdl3/gpu/command_buffer/mod.rs | 23 ++--- src/sdl3/gpu/enums.rs | 27 +++--- src/sdl3/gpu/info_struct.rs | 38 ++++---- src/sdl3/gpu/mod.rs | 43 +++------ src/sdl3/gpu/resource/builders.rs | 49 ++++++----- src/sdl3/gpu/resource/device.rs | 18 ++-- src/sdl3/gpu/resource/mod.rs | 91 ++++++++++--------- src/sdl3/gpu/util.rs | 3 +- 15 files changed, 264 insertions(+), 272 deletions(-) diff --git a/examples/gpu-clear.rs b/examples/gpu-clear.rs index a24704af..b5a7fadb 100644 --- a/examples/gpu-clear.rs +++ b/examples/gpu-clear.rs @@ -51,14 +51,10 @@ pub fn main() -> Result<(), Box> { .with_clear_color(sdl3::pixels::Color::RGB(5, 3, 255)), //blue with small RG bias ]; // Here we do all (none) of our drawing (clearing the screen) - command_buffer.render_pass( - &color_targets, - None, - |_cmd, _pass| { - // Do absolutely nothing -- this clears the screen because of the defined operations above - // which are ALWAYS done even through we just created and ended a render pass - } - )?; + command_buffer.render_pass(&color_targets, None, |_cmd, _pass| { + // Do absolutely nothing -- this clears the screen because of the defined operations above + // which are ALWAYS done even through we just created and ended a render pass + })?; command_buffer.submit()?; } else { // Swapchain unavailable, cancel work diff --git a/examples/gpu-cube.rs b/examples/gpu-cube.rs index 0e4dfe98..e77e19dc 100644 --- a/examples/gpu-cube.rs +++ b/examples/gpu-cube.rs @@ -1,7 +1,13 @@ use sdl3::{ event::Event, gpu::{ - Buffer, BufferBinding, BufferRegion, BufferUsageFlags, ColorTargetDescription, ColorTargetInfo, CompareOp, CopyPass, CullMode, DepthStencilState, DepthStencilTargetInfo, FillMode, GraphicsPipelineTargetInfo, IndexElementSize, LoadOp, Owned, OwnedDevice, PrimitiveType, RasterizerState, SampleCount, ShaderFormat, ShaderStage, StoreOp, TextureCreateInfo, TextureFormat, TextureType, TextureUsage, TransferBuffer, TransferBufferLocation, TransferBufferUsage, VertexAttribute, VertexBufferDescription, VertexElementFormat, VertexInputRate, VertexInputState + Buffer, BufferBinding, BufferRegion, BufferUsageFlags, ColorTargetDescription, + ColorTargetInfo, CompareOp, CopyPass, CullMode, DepthStencilState, DepthStencilTargetInfo, + FillMode, GraphicsPipelineTargetInfo, IndexElementSize, LoadOp, Owned, OwnedDevice, + PrimitiveType, RasterizerState, SampleCount, ShaderFormat, ShaderStage, StoreOp, + TextureCreateInfo, TextureFormat, TextureType, TextureUsage, TransferBuffer, + TransferBufferLocation, TransferBufferUsage, VertexAttribute, VertexBufferDescription, + VertexElementFormat, VertexInputRate, VertexInputState, }, keyboard::Keycode, pixels::Color, @@ -170,29 +176,29 @@ pub fn main() -> Result<(), Box> { // We need to start a copy pass in order to transfer data to the GPU let mut copy_commands = gpu.acquire_command_buffer()?; - let (vertex_buffer, index_buffer) = copy_commands.copy_pass( - |_cmd, copy_pass| { - // Create GPU buffers to hold our vertices and indices and transfer data to them - let vertex_buffer = create_buffer_with_data( - &gpu, - &mut transfer_buffer, - ©_pass, - BufferUsageFlags::VERTEX, - &CUBE_VERTICES, - ).unwrap(); - let index_buffer = create_buffer_with_data( - &gpu, - &mut transfer_buffer, - ©_pass, - BufferUsageFlags::INDEX, - &CUBE_INDICES, - ).unwrap(); - // We're done with the transfer buffer now, so release it. - drop(transfer_buffer); + let (vertex_buffer, index_buffer) = copy_commands.copy_pass(|_cmd, copy_pass| { + // Create GPU buffers to hold our vertices and indices and transfer data to them + let vertex_buffer = create_buffer_with_data( + &gpu, + &mut transfer_buffer, + ©_pass, + BufferUsageFlags::VERTEX, + &CUBE_VERTICES, + ) + .unwrap(); + let index_buffer = create_buffer_with_data( + &gpu, + &mut transfer_buffer, + ©_pass, + BufferUsageFlags::INDEX, + &CUBE_INDICES, + ) + .unwrap(); + // We're done with the transfer buffer now, so release it. + drop(transfer_buffer); - (vertex_buffer, index_buffer) - } - )?; + (vertex_buffer, index_buffer) + })?; // Now complete and submit the copy pass commands to actually do the transfer work copy_commands.submit()?; @@ -255,12 +261,14 @@ pub fn main() -> Result<(), Box> { render_pass.bind_graphics_pipeline(&pipeline); // Now we'll bind our buffers and draw the cube - render_pass.bind_vertex_buffers( 0, &[ - BufferBinding::new().with_buffer(&vertex_buffer) - ]); + render_pass.bind_vertex_buffers( + 0, + &[BufferBinding::new().with_buffer(&vertex_buffer)], + ); render_pass.bind_index_buffer( &BufferBinding::new().with_buffer(&index_buffer), - IndexElementSize::_16BIT); + IndexElementSize::_16BIT, + ); // Set the rotation uniform for our cube vert shader command_buffer.push_vertex_uniform_data(0, &rotation); @@ -268,7 +276,7 @@ pub fn main() -> Result<(), Box> { // Finally, draw the cube render_pass.draw_indexed_primitives(CUBE_INDICES.len() as u32, 1, 0, 0, 0); - } + }, )?; command_buffer.submit()?; } else { @@ -303,16 +311,13 @@ fn create_buffer_with_data<'gpu, T: Copy>( // Note: We set `cycle` to true since we're reusing the same transfer buffer to // initialize both the vertex and index buffer. This makes SDL synchronize the transfers // so that one doesn't interfere with the other. - transfer_buffer.mapped_mut( - true, - |bytes| unsafe { - std::ptr::copy_nonoverlapping::( - data.as_ptr() as *const u8, - bytes.as_mut_ptr(), - len_bytes - ); - } - )?; + transfer_buffer.mapped_mut(true, |bytes| unsafe { + std::ptr::copy_nonoverlapping::( + data.as_ptr() as *const u8, + bytes.as_mut_ptr(), + len_bytes, + ); + })?; // Finally, add a command to the copy pass to upload this data to the GPU // diff --git a/examples/gpu-texture.rs b/examples/gpu-texture.rs index f25f5c93..fe1082f6 100644 --- a/examples/gpu-texture.rs +++ b/examples/gpu-texture.rs @@ -1,7 +1,14 @@ use sdl3::{ event::Event, gpu::{ - Buffer, BufferBinding, BufferUsageFlags, ColorTargetDescription, ColorTargetInfo, CompareOp, CopyPass, CullMode, DepthStencilState, DepthStencilTargetInfo, FillMode, Filter, GraphicsPipelineTargetInfo, IndexElementSize, LoadOp, Owned, OwnedDevice, PrimitiveType, RasterizerState, SampleCount, SamplerAddressMode, SamplerCreateInfo, SamplerMipmapMode, ShaderFormat, ShaderStage, StoreOp, Texture, TextureCreateInfo, TextureFormat, TextureRegion, TextureSamplerBinding, TextureTransferInfo, TextureType, TextureUsage, TransferBuffer, TransferBufferLocation, TransferBufferUsage, VertexAttribute, VertexBufferDescription, VertexElementFormat, VertexInputRate, VertexInputState + Buffer, BufferBinding, BufferUsageFlags, ColorTargetDescription, ColorTargetInfo, + CompareOp, CopyPass, CullMode, DepthStencilState, DepthStencilTargetInfo, FillMode, Filter, + GraphicsPipelineTargetInfo, IndexElementSize, LoadOp, Owned, OwnedDevice, PrimitiveType, + RasterizerState, SampleCount, SamplerAddressMode, SamplerCreateInfo, SamplerMipmapMode, + ShaderFormat, ShaderStage, StoreOp, Texture, TextureCreateInfo, TextureFormat, + TextureRegion, TextureSamplerBinding, TextureTransferInfo, TextureType, TextureUsage, + TransferBuffer, TransferBufferLocation, TransferBufferUsage, VertexAttribute, + VertexBufferDescription, VertexElementFormat, VertexInputRate, VertexInputState, }, keyboard::Keycode, pixels::Color, @@ -282,43 +289,53 @@ pub fn main() -> Result<(), Box> { // We need to start a copy pass in order to transfer data to the GPU let mut copy_commands = gpu.acquire_command_buffer()?; - let (vertex_buffer, index_buffer, cube_texture, cube_texture_sampler) - = copy_commands.copy_pass(|_cmd, copy_pass| { - // Create GPU buffers to hold our vertices and indices and transfer data to them - let vertex_buffer = create_buffer_with_data( - &gpu, - &mut transfer_buffer, - ©_pass, - BufferUsageFlags::VERTEX, - &CUBE_VERTICES, - ).unwrap(); - let index_buffer = create_buffer_with_data( - &gpu, - &mut transfer_buffer, - ©_pass, - BufferUsageFlags::INDEX, - &CUBE_INDICES, - ).unwrap(); - - // We're done with the transfer buffer now, so release it. - drop(transfer_buffer); - - // Load up a texture to put on the cube - let cube_texture = create_texture_from_image(&gpu, "./assets/texture.bmp", ©_pass).unwrap(); - - // And configure a sampler for pulling pixels from that texture in the frag shader - let cube_texture_sampler = gpu.create_sampler( - SamplerCreateInfo::new() - .with_min_filter(Filter::Nearest) - .with_mag_filter(Filter::Nearest) - .with_mipmap_mode(SamplerMipmapMode::Nearest) - .with_address_mode_u(SamplerAddressMode::Repeat) - .with_address_mode_v(SamplerAddressMode::Repeat) - .with_address_mode_w(SamplerAddressMode::Repeat), - ).unwrap(); - - (vertex_buffer, index_buffer, cube_texture, cube_texture_sampler) - })?; + let (vertex_buffer, index_buffer, cube_texture, cube_texture_sampler) = copy_commands + .copy_pass(|_cmd, copy_pass| { + // Create GPU buffers to hold our vertices and indices and transfer data to them + let vertex_buffer = create_buffer_with_data( + &gpu, + &mut transfer_buffer, + ©_pass, + BufferUsageFlags::VERTEX, + &CUBE_VERTICES, + ) + .unwrap(); + let index_buffer = create_buffer_with_data( + &gpu, + &mut transfer_buffer, + ©_pass, + BufferUsageFlags::INDEX, + &CUBE_INDICES, + ) + .unwrap(); + + // We're done with the transfer buffer now, so release it. + drop(transfer_buffer); + + // Load up a texture to put on the cube + let cube_texture = + create_texture_from_image(&gpu, "./assets/texture.bmp", ©_pass).unwrap(); + + // And configure a sampler for pulling pixels from that texture in the frag shader + let cube_texture_sampler = gpu + .create_sampler( + SamplerCreateInfo::new() + .with_min_filter(Filter::Nearest) + .with_mag_filter(Filter::Nearest) + .with_mipmap_mode(SamplerMipmapMode::Nearest) + .with_address_mode_u(SamplerAddressMode::Repeat) + .with_address_mode_v(SamplerAddressMode::Repeat) + .with_address_mode_w(SamplerAddressMode::Repeat), + ) + .unwrap(); + + ( + vertex_buffer, + index_buffer, + cube_texture, + cube_texture_sampler, + ) + })?; // Now complete and submit the copy pass commands to actually do the transfer work copy_commands.submit()?; @@ -333,7 +350,7 @@ pub fn main() -> Result<(), Box> { .with_num_levels(1) .with_sample_count(SampleCount::NoMultiSampling) .with_format(TextureFormat::D16_UNORM) - .with_usage(TextureUsage::SAMPLER | TextureUsage::DEPTH_STENCIL_TARGET) + .with_usage(TextureUsage::SAMPLER | TextureUsage::DEPTH_STENCIL_TARGET), )?; let mut rotation = 45.0f32; @@ -373,7 +390,7 @@ pub fn main() -> Result<(), Box> { .with_store_op(StoreOp::STORE) .with_stencil_load_op(LoadOp::CLEAR) .with_stencil_store_op(StoreOp::STORE); - + command_buffer.render_pass( &color_targets, Some(&depth_target), @@ -405,7 +422,7 @@ pub fn main() -> Result<(), Box> { // Finally, draw the cube render_pass.draw_indexed_primitives(CUBE_INDICES.len() as u32, 1, 0, 0, 0); - } + }, )?; command_buffer.submit()?; @@ -445,16 +462,15 @@ fn create_texture_from_image<'gpu>( .with_usage(TransferBufferUsage::UPLOAD) .build()?; - transfer_buffer.mapped_mut( - false, - |bytes| image.with_lock(|image_bytes| unsafe { + transfer_buffer.mapped_mut(false, |bytes| { + image.with_lock(|image_bytes| unsafe { std::ptr::copy_nonoverlapping::( image_bytes.as_ptr(), bytes.as_mut_ptr(), - image_bytes.len() + image_bytes.len(), ); }) - )?; + })?; copy_pass.upload_to_gpu_texture( TextureTransferInfo::new() @@ -495,16 +511,13 @@ fn create_buffer_with_data<'gpu, T: Copy>( // Note: We set `cycle` to true since we're reusing the same transfer buffer to // initialize both the vertex and index buffer. This makes SDL synchronize the transfers // so that one doesn't interfere with the other. - transfer_buffer.mapped_mut( - true, - |bytes| unsafe { - std::ptr::copy_nonoverlapping::( - data.as_ptr() as *const u8, - bytes.as_mut_ptr(), - len_bytes - ); - } - )?; + transfer_buffer.mapped_mut(true, |bytes| unsafe { + std::ptr::copy_nonoverlapping::( + data.as_ptr() as *const u8, + bytes.as_mut_ptr(), + len_bytes, + ); + })?; // Finally, add a command to the copy pass to upload this data to the GPU // diff --git a/examples/gpu-triangle.rs b/examples/gpu-triangle.rs index 5220f256..6dc43420 100644 --- a/examples/gpu-triangle.rs +++ b/examples/gpu-triangle.rs @@ -3,8 +3,8 @@ extern crate sdl3; use sdl3::{ event::Event, gpu::{ - ColorTargetDescription, ColorTargetInfo, OwnedDevice, FillMode, GraphicsPipelineTargetInfo, - LoadOp, PrimitiveType, ShaderFormat, ShaderStage, StoreOp, + ColorTargetDescription, ColorTargetInfo, FillMode, GraphicsPipelineTargetInfo, LoadOp, + OwnedDevice, PrimitiveType, ShaderFormat, ShaderStage, StoreOp, }, keyboard::Keycode, pixels::Color, @@ -99,7 +99,7 @@ pub fn main() -> Result<(), Box> { .with_store_op(StoreOp::STORE) .with_clear_color(Color::RGB(5, 3, 255)), //blue with small RG bias ]; - + command_buffer.render_pass(&color_targets, None, |_cmd, render_pass| { render_pass.bind_graphics_pipeline(&pipeline); // Screen is cleared here due to the color target info diff --git a/src/sdl3/gpu/abstraction.rs b/src/sdl3/gpu/abstraction.rs index 3ccf7cc3..e6e39cc4 100644 --- a/src/sdl3/gpu/abstraction.rs +++ b/src/sdl3/gpu/abstraction.rs @@ -2,11 +2,9 @@ use std::marker::PhantomData; use crate::gpu::Buffer; - - -// a typed pseudo-reference to an object located in a `Buffer` on the GPU +// a typed pseudo-reference to an object located in a `Buffer` on the GPU pub struct Ref<'a, T> { pub(crate) buf: &'a Buffer, pub(crate) offset: u32, pub(crate) marker: PhantomData<&'a T>, -} \ No newline at end of file +} diff --git a/src/sdl3/gpu/auto_trait.rs b/src/sdl3/gpu/auto_trait.rs index 085f244d..54b6cbad 100644 --- a/src/sdl3/gpu/auto_trait.rs +++ b/src/sdl3/gpu/auto_trait.rs @@ -1,5 +1,3 @@ - - // manually checking auto-traits for a type type _X = u32; const _: () = _copy::<_X>(); @@ -7,7 +5,6 @@ const _: () = _send::<_X>(); const _: () = _sync::<_X>(); const _: () = _unpin::<_X>(); - const fn _copy() {} const fn _send() {} const fn _sync() {} @@ -30,7 +27,7 @@ mod assertions { } use crate::gpu::*; - + // definitely not thread-safe thread_unsafe!(CommandBuffer); @@ -48,4 +45,4 @@ mod assertions { thread_unsafe!(GraphicsPipeline); thread_unsafe!(ComputePipeline); thread_unsafe!(Shader); -} \ No newline at end of file +} diff --git a/src/sdl3/gpu/command_buffer/fence.rs b/src/sdl3/gpu/command_buffer/fence.rs index ff7f4294..d188e52e 100644 --- a/src/sdl3/gpu/command_buffer/fence.rs +++ b/src/sdl3/gpu/command_buffer/fence.rs @@ -2,14 +2,13 @@ use sys::gpu::SDL_GPUFence; use crate::gpu::{resource::GpuRelease, Extern}; - pub type Fence = Extern; unsafe impl GpuRelease for Fence { type SDLType = SDL_GPUFence; - const RELEASE: unsafe extern "C" fn(*mut sys::gpu::SDL_GPUDevice, *mut Self::SDLType) - = sys::gpu::SDL_ReleaseGPUFence; + const RELEASE: unsafe extern "C" fn(*mut sys::gpu::SDL_GPUDevice, *mut Self::SDLType) = + sys::gpu::SDL_ReleaseGPUFence; type ExtraState = (); -} \ No newline at end of file +} diff --git a/src/sdl3/gpu/command_buffer/mod.rs b/src/sdl3/gpu/command_buffer/mod.rs index 9ce37749..c84d167c 100644 --- a/src/sdl3/gpu/command_buffer/mod.rs +++ b/src/sdl3/gpu/command_buffer/mod.rs @@ -14,9 +14,8 @@ use super::{ use sys::gpu::{ SDL_AcquireGPUCommandBuffer, SDL_AcquireGPUSwapchainTexture, SDL_BeginGPUComputePass, SDL_BeginGPUCopyPass, SDL_BeginGPURenderPass, SDL_GPUColorTargetInfo, SDL_GPUCommandBuffer, - SDL_GPUDevice, SDL_PushGPUComputeUniformData, - SDL_PushGPUFragmentUniformData, SDL_PushGPUVertexUniformData, - SDL_WaitAndAcquireGPUSwapchainTexture, + SDL_GPUDevice, SDL_PushGPUComputeUniformData, SDL_PushGPUFragmentUniformData, + SDL_PushGPUVertexUniformData, SDL_WaitAndAcquireGPUSwapchainTexture, }; mod compute; @@ -72,8 +71,10 @@ impl<'gpu> Drop for OwnedCommandBuffer<'gpu> { // if already panicking, let's not make it worse return; } else { - panic!("A command buffer was implicitly dropped, - but should be explicitly submitted or cancelled."); + panic!( + "A command buffer was implicitly dropped, + but should be explicitly submitted or cancelled." + ); } } } @@ -198,11 +199,7 @@ impl CommandBuffer { let raw: *mut Texture = raw.cast(); if success { if let Some(tex) = unsafe { raw.as_ref() } { - Ok(SwapchainTexture { - tex, - width, - height, - }) + Ok(SwapchainTexture { tex, width, height }) } else { Err(None) } @@ -225,11 +222,7 @@ impl CommandBuffer { let raw: *mut Texture = raw.cast(); if success { if let Some(tex) = unsafe { raw.as_ref() } { - Ok(SwapchainTexture { - tex, - width, - height, - }) + Ok(SwapchainTexture { tex, width, height }) } else { Err(None) } diff --git a/src/sdl3/gpu/enums.rs b/src/sdl3/gpu/enums.rs index 2f16c067..8584ee85 100644 --- a/src/sdl3/gpu/enums.rs +++ b/src/sdl3/gpu/enums.rs @@ -7,13 +7,13 @@ macro_rules! impl_with { impl BitOr<$x> for $x { type Output = $x; fn bitor(self, rhs: $x) -> Self::Output { - $x (self.0 | rhs.0) + $x(self.0 | rhs.0) } } impl BitAnd<$x> for $x { type Output = $x; fn bitand(self, rhs: $x) -> Self::Output { - $x (self.0 & rhs.0) + $x(self.0 & rhs.0) } } }; @@ -38,8 +38,7 @@ impl_with!(bitwise_and_or ShaderFormat); pub struct TextureUsage(pub sys::gpu::SDL_GPUTextureUsageFlags); impl TextureUsage { - pub const INVALID: Self = - Self(0); + pub const INVALID: Self = Self(0); pub const COMPUTE_STORAGE_WRITE: Self = Self(sys::gpu::SDL_GPU_TEXTUREUSAGE_COMPUTE_STORAGE_WRITE); pub const COMPUTE_STORAGE_READ: Self = @@ -50,10 +49,8 @@ impl TextureUsage { Self(sys::gpu::SDL_GPU_TEXTUREUSAGE_DEPTH_STENCIL_TARGET); pub const GRAPHICS_STORAGE_READ: Self = Self(sys::gpu::SDL_GPU_TEXTUREUSAGE_GRAPHICS_STORAGE_READ); - pub const SAMPLER: Self = - Self(sys::gpu::SDL_GPU_TEXTUREUSAGE_SAMPLER); - pub const COLOR_TARGET: Self = - Self(sys::gpu::SDL_GPU_TEXTUREUSAGE_COLOR_TARGET); + pub const SAMPLER: Self = Self(sys::gpu::SDL_GPU_TEXTUREUSAGE_SAMPLER); + pub const COLOR_TARGET: Self = Self(sys::gpu::SDL_GPU_TEXTUREUSAGE_COLOR_TARGET); } impl_with!(bitwise_and_or TextureUsage); @@ -227,12 +224,14 @@ pub enum VertexInputRate { #[derive(Default, Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] pub struct BufferUsageFlags(pub sys::gpu::SDL_GPUBufferUsageFlags); impl BufferUsageFlags { - pub const VERTEX : Self = Self(sys::gpu::SDL_GPU_BUFFERUSAGE_VERTEX); - pub const INDEX : Self = Self(sys::gpu::SDL_GPU_BUFFERUSAGE_INDEX); - pub const INDIRECT : Self = Self(sys::gpu::SDL_GPU_BUFFERUSAGE_INDIRECT); - pub const GRAPHICS_STORAGE_READ : Self = Self(sys::gpu::SDL_GPU_BUFFERUSAGE_GRAPHICS_STORAGE_READ); - pub const COMPUTE_STORAGE_READ : Self = Self(sys::gpu::SDL_GPU_BUFFERUSAGE_COMPUTE_STORAGE_READ); - pub const COMPUTE_STORAGE_WRITE : Self = Self(sys::gpu::SDL_GPU_BUFFERUSAGE_COMPUTE_STORAGE_WRITE); + pub const VERTEX: Self = Self(sys::gpu::SDL_GPU_BUFFERUSAGE_VERTEX); + pub const INDEX: Self = Self(sys::gpu::SDL_GPU_BUFFERUSAGE_INDEX); + pub const INDIRECT: Self = Self(sys::gpu::SDL_GPU_BUFFERUSAGE_INDIRECT); + pub const GRAPHICS_STORAGE_READ: Self = + Self(sys::gpu::SDL_GPU_BUFFERUSAGE_GRAPHICS_STORAGE_READ); + pub const COMPUTE_STORAGE_READ: Self = Self(sys::gpu::SDL_GPU_BUFFERUSAGE_COMPUTE_STORAGE_READ); + pub const COMPUTE_STORAGE_WRITE: Self = + Self(sys::gpu::SDL_GPU_BUFFERUSAGE_COMPUTE_STORAGE_WRITE); } impl_with!(bitwise_and_or BufferUsageFlags); diff --git a/src/sdl3/gpu/info_struct.rs b/src/sdl3/gpu/info_struct.rs index a246ef65..db71986d 100644 --- a/src/sdl3/gpu/info_struct.rs +++ b/src/sdl3/gpu/info_struct.rs @@ -1,17 +1,31 @@ //! Types which hold data but don't own any GPU-resources. //! There are no calls to SDL here. -//! +//! use std::marker::PhantomData; use sys::gpu::{ - SDL_GPUBlendFactor, SDL_GPUBlendOp, SDL_GPUBufferBinding, SDL_GPUBufferLocation, SDL_GPUBufferRegion, SDL_GPUColorTargetBlendState, SDL_GPUColorTargetDescription, SDL_GPUColorTargetInfo, SDL_GPUCompareOp, SDL_GPUCullMode, SDL_GPUDepthStencilState, SDL_GPUDepthStencilTargetInfo, SDL_GPUFillMode, SDL_GPUFilter, SDL_GPUFrontFace, SDL_GPUGraphicsPipelineTargetInfo, SDL_GPUIndirectDispatchCommand, SDL_GPURasterizerState, SDL_GPUSampleCount, SDL_GPUSamplerAddressMode, SDL_GPUSamplerCreateInfo, SDL_GPUSamplerMipmapMode, SDL_GPUStencilOp, SDL_GPUStencilOpState, SDL_GPUStorageBufferReadWriteBinding, SDL_GPUStorageTextureReadWriteBinding, SDL_GPUTextureCreateInfo, SDL_GPUTextureLocation, SDL_GPUTextureRegion, SDL_GPUTextureSamplerBinding, SDL_GPUTextureTransferInfo, SDL_GPUTextureType, SDL_GPUTransferBufferLocation, SDL_GPUVertexAttribute, SDL_GPUVertexBufferDescription, SDL_GPUVertexInputRate, SDL_GPUVertexInputState + SDL_GPUBlendFactor, SDL_GPUBlendOp, SDL_GPUBufferBinding, SDL_GPUBufferLocation, + SDL_GPUBufferRegion, SDL_GPUColorTargetBlendState, SDL_GPUColorTargetDescription, + SDL_GPUColorTargetInfo, SDL_GPUCompareOp, SDL_GPUCullMode, SDL_GPUDepthStencilState, + SDL_GPUDepthStencilTargetInfo, SDL_GPUFillMode, SDL_GPUFilter, SDL_GPUFrontFace, + SDL_GPUGraphicsPipelineTargetInfo, SDL_GPUIndirectDispatchCommand, SDL_GPURasterizerState, + SDL_GPUSampleCount, SDL_GPUSamplerAddressMode, SDL_GPUSamplerCreateInfo, + SDL_GPUSamplerMipmapMode, SDL_GPUStencilOp, SDL_GPUStencilOpState, + SDL_GPUStorageBufferReadWriteBinding, SDL_GPUStorageTextureReadWriteBinding, + SDL_GPUTextureCreateInfo, SDL_GPUTextureLocation, SDL_GPUTextureRegion, + SDL_GPUTextureSamplerBinding, SDL_GPUTextureTransferInfo, SDL_GPUTextureType, + SDL_GPUTransferBufferLocation, SDL_GPUVertexAttribute, SDL_GPUVertexBufferDescription, + SDL_GPUVertexInputRate, SDL_GPUVertexInputState, }; use crate::pixels::Color; use super::{ - BlendFactor, BlendOp, Buffer, ColorComponentFlags, CompareOp, CullMode, FillMode, Filter, FrontFace, LoadOp, SampleCount, Sampler, SamplerAddressMode, SamplerMipmapMode, StencilOp, StoreOp, Texture, TextureFormat, TextureType, TextureUsage, TransferBuffer, VertexElementFormat, VertexInputRate + BlendFactor, BlendOp, Buffer, ColorComponentFlags, CompareOp, CullMode, FillMode, Filter, + FrontFace, LoadOp, SampleCount, Sampler, SamplerAddressMode, SamplerMipmapMode, StencilOp, + StoreOp, Texture, TextureFormat, TextureType, TextureUsage, TransferBuffer, + VertexElementFormat, VertexInputRate, }; #[repr(transparent)] @@ -101,7 +115,6 @@ impl<'a> ColorTargetInfo<'a> { } } - #[repr(C)] #[derive(Default)] pub struct TextureCreateInfo { @@ -161,7 +174,6 @@ impl TextureCreateInfo { } } - #[repr(C)] #[derive(Default)] pub struct SamplerCreateInfo { @@ -353,7 +365,6 @@ impl<'a> TextureTransferInfo<'a> { } } - #[repr(C)] #[derive(Default)] pub struct BufferBinding<'a> { @@ -428,13 +439,11 @@ impl VertexBufferDescription { } } - - #[repr(C)] #[derive(Default)] pub struct VertexInputState<'a> { pub(super) inner: SDL_GPUVertexInputState, - _marker: PhantomData<(&'a [VertexBufferDescription],&'a [VertexAttribute])>, + _marker: PhantomData<(&'a [VertexBufferDescription], &'a [VertexAttribute])>, } impl<'a> VertexInputState<'a> { pub fn new() -> Self { @@ -455,7 +464,6 @@ impl<'a> VertexInputState<'a> { } } - #[repr(C)] #[derive(Default)] pub struct RasterizerState { @@ -609,7 +617,6 @@ impl DepthStencilState { } } - #[repr(C)] #[derive(Default)] pub struct GraphicsPipelineTargetInfo<'a> { @@ -642,7 +649,6 @@ impl<'a> GraphicsPipelineTargetInfo<'a> { } } - #[repr(C)] #[derive(Clone, Default)] pub struct VertexAttribute { @@ -678,7 +684,6 @@ impl VertexAttribute { } } - #[repr(C)] #[derive(Default)] pub struct ColorTargetBlendState { @@ -745,7 +750,7 @@ impl ColorTargetBlendState { } #[repr(C)] -#[derive(Default,Copy,Clone)] +#[derive(Default, Copy, Clone)] pub struct ColorTargetDescription { inner: SDL_GPUColorTargetDescription, } @@ -767,7 +772,6 @@ impl ColorTargetDescription { } } - #[repr(C)] #[derive(Default)] pub struct TextureSamplerBinding<'a> { @@ -792,7 +796,6 @@ impl<'a> TextureSamplerBinding<'a> { // } } - #[repr(C)] #[derive(Default)] pub struct StorageTextureReadWriteBinding<'a> { @@ -847,10 +850,9 @@ impl<'a> StorageBufferReadWriteBinding<'a> { // } } - pub type IndirectDispatchCommand = SDL_GPUIndirectDispatchCommand; pub struct TextureLocation<'a> { pub(crate) inner: SDL_GPUTextureLocation, pub(crate) _marker: PhantomData<&'a Texture>, -} \ No newline at end of file +} diff --git a/src/sdl3/gpu/mod.rs b/src/sdl3/gpu/mod.rs index cb48a9fb..195166f6 100644 --- a/src/sdl3/gpu/mod.rs +++ b/src/sdl3/gpu/mod.rs @@ -1,4 +1,3 @@ - use std::cell::UnsafeCell; use std::marker::{PhantomData, PhantomPinned}; @@ -10,29 +9,16 @@ pub use abstraction::Ref; mod resource; pub use resource::{ - Owned, - Buffer, - TransferBuffer, - GraphicsPipeline, - ComputePipeline, - Texture, - Sampler, - Shader, - OwnedDevice, Device, + Buffer, ComputePipeline, Device, GraphicsPipeline, Owned, OwnedDevice, Sampler, Shader, + Texture, TransferBuffer, }; pub use resource::{ - ComputePipelineBuilder, GraphicsPipelineBuilder, ShaderBuilder, BufferBuilder, + BufferBuilder, ComputePipelineBuilder, GraphicsPipelineBuilder, ShaderBuilder, TransferBufferBuilder, }; mod command_buffer; -pub use command_buffer::{ - CommandBuffer, - ComputePass, - RenderPass, - CopyPass, - Fence, -}; +pub use command_buffer::{CommandBuffer, ComputePass, CopyPass, Fence, RenderPass}; mod enums; pub use enums::{ @@ -44,17 +30,17 @@ pub use enums::{ mod info_struct; pub use info_struct::{ - BufferBinding, BufferRegion, ColorTargetInfo, DepthStencilTargetInfo, SamplerCreateInfo, - TextureCreateInfo, TextureRegion, TextureTransferInfo, TransferBufferLocation, - VertexBufferDescription, RasterizerState, - StencilOpState, VertexAttribute, VertexInputState, - ColorTargetBlendState, ColorTargetDescription, GraphicsPipelineTargetInfo, - DepthStencilState, TextureSamplerBinding, - StorageBufferReadWriteBinding, StorageTextureReadWriteBinding, + BufferBinding, BufferRegion, ColorTargetBlendState, ColorTargetDescription, ColorTargetInfo, + DepthStencilState, DepthStencilTargetInfo, GraphicsPipelineTargetInfo, RasterizerState, + SamplerCreateInfo, StencilOpState, StorageBufferReadWriteBinding, + StorageTextureReadWriteBinding, TextureCreateInfo, TextureRegion, TextureSamplerBinding, + TextureTransferInfo, TransferBufferLocation, VertexAttribute, VertexBufferDescription, + VertexInputState, }; - -use sys::gpu::{SDL_ClaimWindowForGPUDevice, SDL_GetGPUSwapchainTextureFormat, SDL_ReleaseWindowFromGPUDevice}; +use sys::gpu::{ + SDL_ClaimWindowForGPUDevice, SDL_GetGPUSwapchainTextureFormat, SDL_ReleaseWindowFromGPUDevice, +}; use crate::{get_error, Error}; @@ -79,7 +65,6 @@ impl Extern { } impl Device { - #[doc(alias = "SDL_ClaimWindowForGPUDevice")] pub fn claim_window(&self, w: &crate::video::Window) -> Result<(), Error> { let p = unsafe { SDL_ClaimWindowForGPUDevice(self.ll(), w.raw()) }; @@ -95,7 +80,6 @@ impl Device { unsafe { SDL_ReleaseWindowFromGPUDevice(self.ll(), w.raw()) }; } - #[doc(alias = "SDL_GetGPUSwapchainTextureFormat")] pub fn get_swapchain_texture_format(&self, w: &crate::video::Window) -> TextureFormat { unsafe { SDL_GetGPUSwapchainTextureFormat(self.ll(), w.raw()) } @@ -121,5 +105,4 @@ impl Device { sys::gpu::SDL_GDKResumeGPU(self.raw()); } } - } diff --git a/src/sdl3/gpu/resource/builders.rs b/src/sdl3/gpu/resource/builders.rs index 4389abaf..4621b676 100644 --- a/src/sdl3/gpu/resource/builders.rs +++ b/src/sdl3/gpu/resource/builders.rs @@ -1,20 +1,22 @@ //! Defines builders for various GPU-resources. -//! -//! +//! +//! use std::{ffi::CStr, marker::PhantomData}; use sys::gpu::{ - SDL_GPUBufferCreateInfo, SDL_GPUComputePipelineCreateInfo, - SDL_GPUFillMode, SDL_GPUGraphicsPipelineCreateInfo, - SDL_GPUPrimitiveType, SDL_GPUShaderCreateInfo, SDL_GPUTransferBufferCreateInfo + SDL_GPUBufferCreateInfo, SDL_GPUComputePipelineCreateInfo, SDL_GPUFillMode, + SDL_GPUGraphicsPipelineCreateInfo, SDL_GPUPrimitiveType, SDL_GPUShaderCreateInfo, + SDL_GPUTransferBufferCreateInfo, }; use crate::gpu::{SamplerCreateInfo, TextureCreateInfo}; use crate::Error; use super::super::{ - BufferUsageFlags, ComputePipeline, DepthStencilState, FillMode, GraphicsPipeline, GraphicsPipelineTargetInfo, PrimitiveType, RasterizerState, Shader, ShaderFormat, ShaderStage, TransferBuffer, TransferBufferUsage, VertexInputState + BufferUsageFlags, ComputePipeline, DepthStencilState, FillMode, GraphicsPipeline, + GraphicsPipelineTargetInfo, PrimitiveType, RasterizerState, Shader, ShaderFormat, ShaderStage, + TransferBuffer, TransferBufferUsage, VertexInputState, }; impl Device { @@ -34,17 +36,20 @@ impl Device { } #[doc(alias = "SDL_CreateGPUSampler")] - pub fn create_sampler<'gpu>(&'gpu self, create_info: SamplerCreateInfo) -> Result, Error> { + pub fn create_sampler<'gpu>( + &'gpu self, + create_info: SamplerCreateInfo, + ) -> Result, Error> { Owned::new(self, &create_info.inner, ()) } #[doc(alias = "SDL_CreateGPUGraphicsPipeline")] - pub fn create_graphics_pipeline<'gpu,'a>(&'gpu self) -> GraphicsPipelineBuilder<'gpu, 'a> { + pub fn create_graphics_pipeline<'gpu, 'a>(&'gpu self) -> GraphicsPipelineBuilder<'gpu, 'a> { GraphicsPipelineBuilder::new(self) } #[doc(alias = "SDL_CreateGPUComputePipeline")] - pub fn create_compute_pipeline<'gpu,'a>(&'gpu self) -> ComputePipelineBuilder<'gpu, 'a> { + pub fn create_compute_pipeline<'gpu, 'a>(&'gpu self) -> ComputePipelineBuilder<'gpu, 'a> { ComputePipelineBuilder::new(self) } @@ -53,12 +58,14 @@ impl Device { &'gpu self, create_info: &TextureCreateInfo, ) -> Result, Error> { - Owned::new(self, &create_info.inner, (create_info.inner.width, create_info.inner.height)) + Owned::new( + self, + &create_info.inner, + (create_info.inner.width, create_info.inner.height), + ) } - } - use super::{Buffer, Device, Owned, Sampler, Texture}; #[repr(C)] pub struct ComputePipelineBuilder<'gpu, 'builder> { @@ -159,7 +166,12 @@ impl<'gpu, 'builder> ShaderBuilder<'builder, 'gpu> { self } - pub fn with_code(mut self, fmt: ShaderFormat, code: &'builder [u8], stage: ShaderStage) -> Self { + pub fn with_code( + mut self, + fmt: ShaderFormat, + code: &'builder [u8], + stage: ShaderStage, + ) -> Self { self.inner.format = fmt.0; self.inner.code = code.as_ptr(); self.inner.code_size = code.len() as usize; @@ -175,7 +187,6 @@ impl<'gpu, 'builder> ShaderBuilder<'builder, 'gpu> { } } - pub struct TransferBufferBuilder<'gpu> { device: &'gpu Device, inner: SDL_GPUTransferBufferCreateInfo, @@ -205,7 +216,6 @@ impl<'gpu> TransferBufferBuilder<'gpu> { } } - pub struct BufferBuilder<'gpu> { device: &'gpu Device, inner: SDL_GPUBufferCreateInfo, @@ -233,15 +243,12 @@ impl<'gpu> BufferBuilder<'gpu> { } } -#[derive(Copy,Clone)] +#[derive(Copy, Clone)] #[repr(C)] pub struct GraphicsPipelineBuilder<'gpu, 'builder> { device: &'gpu Device, inner: SDL_GPUGraphicsPipelineCreateInfo, - _marker: PhantomData<( - &'builder Shader, - GraphicsPipelineTargetInfo<'builder>, - )>, + _marker: PhantomData<(&'builder Shader, GraphicsPipelineTargetInfo<'builder>)>, } impl<'gpu, 'builder> GraphicsPipelineBuilder<'gpu, 'builder> { @@ -300,4 +307,4 @@ impl<'gpu, 'builder> GraphicsPipelineBuilder<'gpu, 'builder> { pub fn build(&self) -> Result, Error> { Owned::new(self.device, &self.inner, ()) } -} \ No newline at end of file +} diff --git a/src/sdl3/gpu/resource/device.rs b/src/sdl3/gpu/resource/device.rs index 3ae4773b..5e36fd18 100644 --- a/src/sdl3/gpu/resource/device.rs +++ b/src/sdl3/gpu/resource/device.rs @@ -1,17 +1,13 @@ - - - use std::{ops::Deref, ptr::NonNull}; -use crate::{gpu::{util::nonnull_ext_or_get_error, Extern}, Error}; +use crate::{ + gpu::{util::nonnull_ext_or_get_error, Extern}, + Error, +}; use super::super::ShaderFormat; -use sys::gpu::{ - SDL_GPUDevice, - SDL_CreateGPUDevice, - SDL_DestroyGPUDevice -}; +use sys::gpu::{SDL_CreateGPUDevice, SDL_DestroyGPUDevice, SDL_GPUDevice}; pub type Device = Extern; @@ -24,7 +20,8 @@ impl OwnedDevice { pub fn new(flags: ShaderFormat, debug_mode: bool) -> Result { let raw = nonnull_ext_or_get_error(unsafe { SDL_CreateGPUDevice(flags.0, debug_mode, std::ptr::null()) - })?.cast(); + })? + .cast(); Ok(Self { raw }) } } @@ -43,4 +40,3 @@ impl Deref for OwnedDevice { unsafe { self.raw.as_ref() } } } - diff --git a/src/sdl3/gpu/resource/mod.rs b/src/sdl3/gpu/resource/mod.rs index c9266a7c..60e47b5d 100644 --- a/src/sdl3/gpu/resource/mod.rs +++ b/src/sdl3/gpu/resource/mod.rs @@ -1,33 +1,40 @@ //! GPU-resources -//! -//! +//! +//! mod builders; use std::{marker::PhantomData, ptr::NonNull}; pub use builders::{ - ComputePipelineBuilder, GraphicsPipelineBuilder, ShaderBuilder, BufferBuilder, + BufferBuilder, ComputePipelineBuilder, GraphicsPipelineBuilder, ShaderBuilder, TransferBufferBuilder, }; - mod device; -pub use device::OwnedDevice; pub use device::Device; +pub use device::OwnedDevice; -use sys::gpu::{SDL_GPUBufferRegion, SDL_GPUDevice, SDL_GPUStorageBufferReadWriteBinding, SDL_GPUStorageTextureReadWriteBinding, SDL_GPUTransferBufferLocation, SDL_MapGPUTransferBuffer, SDL_UnmapGPUTransferBuffer}; - +use sys::gpu::{ + SDL_GPUBufferRegion, SDL_GPUDevice, SDL_GPUStorageBufferReadWriteBinding, + SDL_GPUStorageTextureReadWriteBinding, SDL_GPUTransferBufferLocation, SDL_MapGPUTransferBuffer, + SDL_UnmapGPUTransferBuffer, +}; use crate::Error; use crate::{get_error, gpu::BufferRegion}; use super::util::Defer; use super::Extern; -use super::{StorageBufferReadWriteBinding, StorageTextureReadWriteBinding, TextureSamplerBinding, TransferBufferLocation}; - +use super::{ + StorageBufferReadWriteBinding, StorageTextureReadWriteBinding, TextureSamplerBinding, + TransferBufferLocation, +}; pub unsafe trait GpuCreate: GpuRelease { type CreateInfo; - const CREATE: unsafe extern "C" fn(*mut SDL_GPUDevice, *const Self::CreateInfo) -> *mut Self::SDLType; + const CREATE: unsafe extern "C" fn( + *mut SDL_GPUDevice, + *const Self::CreateInfo, + ) -> *mut Self::SDLType; } pub unsafe trait GpuRelease { @@ -38,24 +45,23 @@ pub unsafe trait GpuRelease { type ExtraState; } -pub struct Owned<'gpu, T: GpuRelease> -{ +pub struct Owned<'gpu, T: GpuRelease> { raw: NonNull, ctx: &'gpu Device, extra: T::ExtraState, } impl<'gpu, T: GpuCreate + GpuRelease> Owned<'gpu, T> { - pub(crate) fn new(ctx: &'gpu Device, info: &T::CreateInfo, extra: T::ExtraState) -> Result { + pub(crate) fn new( + ctx: &'gpu Device, + info: &T::CreateInfo, + extra: T::ExtraState, + ) -> Result { unsafe { let raw: *mut T::SDLType = T::CREATE(ctx.ll(), info); let raw: *mut T = raw.cast(); if let Some(raw) = NonNull::new(raw) { - Ok(Owned { - raw, - ctx, - extra, - }) + Ok(Owned { raw, ctx, extra }) } else { Err(get_error()) } @@ -81,27 +87,28 @@ impl<'gpu, T: GpuRelease> Drop for Owned<'gpu, T> { macro_rules! gpu_resource { ($rust_name:ident, $sdl_name:path, $info:path, $create:path, $release:path, $extra:ty) => { - const _: () = assert!(size_of::<$sdl_name>() == 0); - + pub type $rust_name = Extern<$sdl_name>; unsafe impl GpuCreate for $rust_name { type CreateInfo = $info; - - const CREATE: unsafe extern "C" fn(*mut SDL_GPUDevice, *const Self::CreateInfo) -> *mut Self::SDLType - = $create; + + const CREATE: unsafe extern "C" fn( + *mut SDL_GPUDevice, + *const Self::CreateInfo, + ) -> *mut Self::SDLType = $create; } unsafe impl GpuRelease for $rust_name { type SDLType = $sdl_name; type ExtraState = $extra; - - const RELEASE: unsafe extern "C" fn(*mut SDL_GPUDevice, *mut Self::SDLType) - = $release; + + const RELEASE: unsafe extern "C" fn(*mut SDL_GPUDevice, *mut Self::SDLType) = $release; } }; } -gpu_resource!(ComputePipeline, +gpu_resource!( + ComputePipeline, sys::gpu::SDL_GPUComputePipeline, sys::gpu::SDL_GPUComputePipelineCreateInfo, sys::gpu::SDL_CreateGPUComputePipeline, @@ -109,7 +116,8 @@ gpu_resource!(ComputePipeline, () ); -gpu_resource!(GraphicsPipeline, +gpu_resource!( + GraphicsPipeline, sys::gpu::SDL_GPUGraphicsPipeline, sys::gpu::SDL_GPUGraphicsPipelineCreateInfo, sys::gpu::SDL_CreateGPUGraphicsPipeline, @@ -117,8 +125,8 @@ gpu_resource!(GraphicsPipeline, () ); - -gpu_resource!(Sampler, +gpu_resource!( + Sampler, sys::gpu::SDL_GPUSampler, sys::gpu::SDL_GPUSamplerCreateInfo, sys::gpu::SDL_CreateGPUSampler, @@ -126,7 +134,8 @@ gpu_resource!(Sampler, () ); -gpu_resource!(Shader, +gpu_resource!( + Shader, sys::gpu::SDL_GPUShader, sys::gpu::SDL_GPUShaderCreateInfo, sys::gpu::SDL_CreateGPUShader, @@ -134,7 +143,8 @@ gpu_resource!(Shader, () ); -gpu_resource!(Texture, +gpu_resource!( + Texture, sys::gpu::SDL_GPUTexture, sys::gpu::SDL_GPUTextureCreateInfo, sys::gpu::SDL_CreateGPUTexture, @@ -142,7 +152,8 @@ gpu_resource!(Texture, (u32, u32) ); -gpu_resource!(TransferBuffer, +gpu_resource!( + TransferBuffer, sys::gpu::SDL_GPUTransferBuffer, sys::gpu::SDL_GPUTransferBufferCreateInfo, sys::gpu::SDL_CreateGPUTransferBuffer, @@ -150,7 +161,8 @@ gpu_resource!(TransferBuffer, u32 ); -gpu_resource!(Buffer, +gpu_resource!( + Buffer, sys::gpu::SDL_GPUBuffer, sys::gpu::SDL_GPUBufferCreateInfo, sys::gpu::SDL_CreateGPUBuffer, @@ -158,8 +170,6 @@ gpu_resource!(Buffer, u32 ); - - impl<'a> Owned<'a, Texture> { pub fn width(&self) -> u32 { self.extra.0 @@ -170,9 +180,7 @@ impl<'a> Owned<'a, Texture> { } } - impl<'gpu> Owned<'gpu, Buffer> { - /// The length of this buffer in bytes. pub fn len(&self) -> u32 { self.extra @@ -247,7 +255,6 @@ impl Texture { } } - impl TransferBuffer { pub fn get<'a>(&'a self, from: std::ops::RangeFrom) -> TransferBufferLocation<'a> { TransferBufferLocation { @@ -276,10 +283,8 @@ impl<'gpu> Owned<'gpu, TransferBuffer> { let bytes = std::slice::from_raw_parts_mut(raw as *mut u8, self.extra as usize); - let _defer = Defer::new(|| - SDL_UnmapGPUTransferBuffer(self.ctx.ll(), self.ll()) - ); - + let _defer = Defer::new(|| SDL_UnmapGPUTransferBuffer(self.ctx.ll(), self.ll())); + Ok(f(bytes)) } } diff --git a/src/sdl3/gpu/util.rs b/src/sdl3/gpu/util.rs index 2c652a7d..f3b818c9 100644 --- a/src/sdl3/gpu/util.rs +++ b/src/sdl3/gpu/util.rs @@ -4,7 +4,6 @@ use crate::{get_error, Error}; use super::Extern; - #[inline(always)] pub(super) fn nonnull_ext_or_get_error(ptr: *mut T) -> Result>, Error> { NonNull::new(ptr.cast()).ok_or_else(|| get_error()) @@ -26,4 +25,4 @@ impl Drop for Defer { f(); } } -} \ No newline at end of file +}