diff --git a/piet-gpu-hal/examples/dx12_toy.rs b/piet-gpu-hal/examples/dx12_toy.rs index da0ac20..bd769f5 100644 --- a/piet-gpu-hal/examples/dx12_toy.rs +++ b/piet-gpu-hal/examples/dx12_toy.rs @@ -2,15 +2,72 @@ //! This will probably go away when it's fully implemented and we can //! just use the hub. -use piet_gpu_hal::{dx12, Device, Error, MemFlags}; +use piet_gpu_hal::{dx12, CmdBuf, Device, Error, MemFlags}; + +const SHADER_CODE: &str = r#"RWByteAddressBuffer _53 : register(u0, space0); + +static uint3 gl_GlobalInvocationID; +struct SPIRV_Cross_Input +{ + uint3 gl_GlobalInvocationID : SV_DispatchThreadID; +}; + +uint collatz_iterations(inout uint n) +{ + uint i = 0u; + while (n != 1u) + { + if ((n & 1u) == 0u) + { + n /= 2u; + } + else + { + n = (3u * n) + 1u; + } + i++; + } + return i; +} + +void comp_main() +{ + uint index = gl_GlobalInvocationID.x; + uint param = _53.Load(index * 4 + 0); + uint _61 = collatz_iterations(param); + _53.Store(index * 4 + 0, _61); +} + +[numthreads(256, 1, 1)] +void main(SPIRV_Cross_Input stage_input) +{ + gl_GlobalInvocationID = stage_input.gl_GlobalInvocationID; + comp_main(); +} +"#; fn toy() -> Result<(), Error> { let instance = dx12::Dx12Instance::new()?; let device = instance.device()?; let buf = device.create_buffer(1024, MemFlags::host_coherent())?; - let data: Vec = (0..256).collect(); + let dev_buf = device.create_buffer(1024, MemFlags::device_local())?; + let data: Vec = (1..257).collect(); unsafe { device.write_buffer(&buf, &data)?; + let pipeline = device.create_simple_compute_pipeline(SHADER_CODE, 1, 0)?; + let ds = device.create_descriptor_set(&pipeline, &[&dev_buf], &[])?; + let mut cmd_buf = device.create_cmd_buf()?; + let fence = device.create_fence(false)?; + cmd_buf.begin(); + cmd_buf.copy_buffer(&buf, &dev_buf); + cmd_buf.memory_barrier(); + cmd_buf.dispatch(&pipeline, &ds, (1, 1, 1)); + cmd_buf.memory_barrier(); + cmd_buf.copy_buffer(&dev_buf, &buf); + cmd_buf.host_barrier(); + cmd_buf.finish(); + device.run_cmd_buf(&cmd_buf, &[], &[], Some(&fence))?; + device.wait_and_reset(&[fence])?; let mut readback: Vec = Vec::new(); device.read_buffer(&buf, &mut readback)?; println!("{:?}", readback); @@ -20,5 +77,4 @@ fn toy() -> Result<(), Error> { fn main() { toy().unwrap(); - println!("hello dx12"); } diff --git a/piet-gpu-hal/src/dx12.rs b/piet-gpu-hal/src/dx12.rs index 4e58a77..fff2519 100644 --- a/piet-gpu-hal/src/dx12.rs +++ b/piet-gpu-hal/src/dx12.rs @@ -3,7 +3,7 @@ mod error; mod wrappers; -use std::{cell::Cell, convert::TryInto}; +use std::{cell::Cell, convert::TryInto, mem, ptr}; use winapi::shared::dxgi1_3; use winapi::um::d3d12; @@ -11,7 +11,7 @@ use winapi::um::d3d12; use crate::Error; use self::wrappers::{ - CommandAllocator, CommandQueue, Device, Factory4, GraphicsCommandList, Resource, + CommandAllocator, CommandQueue, Device, Factory4, GraphicsCommandList, Resource, ShaderByteCode, }; pub struct Dx12Instance { @@ -24,6 +24,7 @@ pub struct Dx12Device { command_queue: CommandQueue, } +#[derive(Clone)] pub struct Buffer { resource: Resource, size: u64, @@ -44,9 +45,15 @@ pub enum MemFlags { pub struct CmdBuf(GraphicsCommandList); -pub struct Pipeline; +pub struct Pipeline { + pipeline_state: wrappers::PipelineState, + root_signature: wrappers::RootSignature, +} -pub struct DescriptorSet; +// Right now, each descriptor set gets its own heap, but we'll move +// to a more sophisticated allocation scheme, probably using the +// gpu-descriptor crate. +pub struct DescriptorSet(wrappers::DescriptorHeap); pub struct QueryPool; @@ -59,11 +66,18 @@ pub struct Fence { pub struct Semaphore; -// TODO -pub struct PipelineBuilder; +#[derive(Default)] +pub struct PipelineBuilder { + ranges: Vec, + n_uav: u32, + // TODO: add counters for other resource types +} // TODO -pub struct DescriptorSetBuilder; +#[derive(Default)] +pub struct DescriptorSetBuilder { + buffers: Vec, +} impl Dx12Instance { /// Create a new instance. @@ -72,6 +86,12 @@ impl Dx12Instance { /// TODO: can probably be a trait. pub fn new() -> Result { unsafe { + #[cfg(debug_assertions)] + if let Err(e) = wrappers::enable_debug_layer() { + // Maybe a better logging solution? + println!("{}", e); + } + #[cfg(debug_assertions)] let factory_flags = dxgi1_3::DXGI_CREATE_FACTORY_DEBUG; @@ -132,6 +152,9 @@ impl crate::Device for Dx12Device { type Sampler = (); + // Currently this is HLSL source, but we'll probably change it to IR. + type ShaderSource = str; + fn create_buffer(&self, size: u64, mem_flags: Self::MemFlags) -> Result { unsafe { let resource = match mem_flags { @@ -258,11 +281,11 @@ impl crate::Device for Dx12Device { } unsafe fn pipeline_builder(&self) -> Self::PipelineBuilder { - todo!() + PipelineBuilder::default() } unsafe fn descriptor_set_builder(&self) -> Self::DescriptorSetBuilder { - todo!() + DescriptorSetBuilder::default() } unsafe fn create_sampler(&self, params: crate::SamplerParams) -> Result { @@ -283,15 +306,29 @@ impl crate::CmdBuf for CmdBuf { descriptor_set: &DescriptorSet, size: (u32, u32, u32), ) { - todo!() + self.0.set_pipeline_state(&pipeline.pipeline_state); + self.0 + .set_compute_pipeline_root_signature(&pipeline.root_signature); + self.0.set_descriptor_heaps(&[&descriptor_set.0]); + self.0.set_compute_root_descriptor_table( + 0, + descriptor_set.0.get_gpu_descriptor_handle_at_offset(0), + ); + self.0.dispatch(size.0, size.1, size.2); } unsafe fn memory_barrier(&mut self) { - todo!() + // See comments in CommandBuffer::pipeline_barrier in gfx-hal dx12 backend. + // The "proper" way to do this would be to name the actual buffers participating + // in the barrier. But it seems like this is a reasonable way to create a + // global barrier. + let bar = wrappers::create_uav_resource_barrier(ptr::null_mut()); + self.0.resource_barrier(&[bar]); } unsafe fn host_barrier(&mut self) { - todo!() + // TODO: anything special here? + self.memory_barrier(); } unsafe fn image_barrier( @@ -308,7 +345,8 @@ impl crate::CmdBuf for CmdBuf { } unsafe fn copy_buffer(&self, src: &Buffer, dst: &Buffer) { - todo!() + let size = src.size.min(dst.size); + self.0.copy_buffer(&dst.resource, 0, &src.resource, 0, size); } unsafe fn copy_image_to_buffer(&self, src: &Image, dst: &Buffer) { @@ -344,36 +382,124 @@ impl crate::MemFlags for MemFlags { impl crate::PipelineBuilder for PipelineBuilder { fn add_buffers(&mut self, n_buffers: u32) { - todo!() + if n_buffers != 0 { + self.ranges.push(d3d12::D3D12_DESCRIPTOR_RANGE { + RangeType: d3d12::D3D12_DESCRIPTOR_RANGE_TYPE_UAV, + NumDescriptors: n_buffers, + BaseShaderRegister: self.n_uav, + RegisterSpace: 0, + OffsetInDescriptorsFromTableStart: d3d12::D3D12_DESCRIPTOR_RANGE_OFFSET_APPEND, + }); + self.n_uav += n_buffers; + } } fn add_images(&mut self, n_images: u32) { - todo!() + if n_images != 0 { + todo!() + } } fn add_textures(&mut self, max_textures: u32) { todo!() } - unsafe fn create_compute_pipeline(self, device: &Dx12Device, code: &[u8]) -> Result { - todo!() + unsafe fn create_compute_pipeline( + self, + device: &Dx12Device, + code: &str, + ) -> Result { + #[cfg(debug_assertions)] + let flags = winapi::um::d3dcompiler::D3DCOMPILE_DEBUG + | winapi::um::d3dcompiler::D3DCOMPILE_SKIP_OPTIMIZATION; + #[cfg(not(debug_assertions))] + let flags = 0; + let shader_blob = ShaderByteCode::compile(code, "cs_5_1", "main", flags)?; + let shader = ShaderByteCode::from_blob(shader_blob); + let mut root_parameter = d3d12::D3D12_ROOT_PARAMETER { + ParameterType: d3d12::D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE, + ShaderVisibility: d3d12::D3D12_SHADER_VISIBILITY_ALL, + ..mem::zeroed() + }; + *root_parameter.u.DescriptorTable_mut() = d3d12::D3D12_ROOT_DESCRIPTOR_TABLE { + NumDescriptorRanges: self.ranges.len().try_into()?, + pDescriptorRanges: self.ranges.as_ptr(), + }; + let root_signature_desc = d3d12::D3D12_ROOT_SIGNATURE_DESC { + NumParameters: 1, + pParameters: &root_parameter, + NumStaticSamplers: 0, + pStaticSamplers: ptr::null(), + Flags: d3d12::D3D12_ROOT_SIGNATURE_FLAG_NONE, + }; + let root_signature_blob = wrappers::RootSignature::serialize_description( + &root_signature_desc, + d3d12::D3D_ROOT_SIGNATURE_VERSION_1, + )?; + let root_signature = device + .device + .create_root_signature(0, root_signature_blob)?; + let desc = d3d12::D3D12_COMPUTE_PIPELINE_STATE_DESC { + pRootSignature: root_signature.0.as_raw(), + CS: shader.bytecode, + NodeMask: 0, + CachedPSO: d3d12::D3D12_CACHED_PIPELINE_STATE { + pCachedBlob: ptr::null(), + CachedBlobSizeInBytes: 0, + }, + Flags: d3d12::D3D12_PIPELINE_STATE_FLAG_NONE, + }; + let pipeline_state = device.device.create_compute_pipeline_state(&desc)?; + Ok(Pipeline { + pipeline_state, + root_signature, + }) } } impl crate::DescriptorSetBuilder for DescriptorSetBuilder { fn add_buffers(&mut self, buffers: &[&Buffer]) { - todo!() + // Note: we could get rid of the clone here (which is an AddRef) + // and store a raw pointer, as it's a safety precondition that + // the resources are kept alive til build. + self.buffers.extend(buffers.iter().copied().cloned()); } fn add_images(&mut self, images: &[&Image]) { - todo!() + if !images.is_empty() { + todo!() + } } fn add_textures(&mut self, images: &[&Image]) { todo!() } - unsafe fn build(self, device: &Dx12Device, pipeline: &Pipeline) -> Result { - todo!() + unsafe fn build( + self, + device: &Dx12Device, + _pipeline: &Pipeline, + ) -> Result { + let n_descriptors = self.buffers.len(); + let heap_desc = d3d12::D3D12_DESCRIPTOR_HEAP_DESC { + Type: d3d12::D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV, + NumDescriptors: n_descriptors.try_into()?, + Flags: d3d12::D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE, + NodeMask: 0, + }; + let heap = device.device.create_descriptor_heap(&heap_desc)?; + let mut ix = 0; + for buffer in self.buffers { + device + .device + .create_byte_addressed_buffer_unordered_access_view( + &buffer.resource, + heap.get_cpu_descriptor_handle_at_offset(ix), + 0, + (buffer.size / 4).try_into()?, + ); + ix += 1; + } + Ok(DescriptorSet(heap)) } } diff --git a/piet-gpu-hal/src/dx12/error.rs b/piet-gpu-hal/src/dx12/error.rs index 5af2da3..5a77a01 100644 --- a/piet-gpu-hal/src/dx12/error.rs +++ b/piet-gpu-hal/src/dx12/error.rs @@ -21,7 +21,7 @@ impl std::fmt::Debug for Error { match self { Error::Hresult(hr) => write!(f, "hresult {:x}", hr), Error::ExplainedHr(exp, hr) => { - write!(f, "{}: ", hr)?; + write!(f, "{}: ", exp)?; write_hr(f, *hr) } } diff --git a/piet-gpu-hal/src/dx12/wrappers.rs b/piet-gpu-hal/src/dx12/wrappers.rs index e19cce9..f60f42a 100644 --- a/piet-gpu-hal/src/dx12/wrappers.rs +++ b/piet-gpu-hal/src/dx12/wrappers.rs @@ -161,15 +161,24 @@ impl Drop for Resource { unsafe { let ptr = self.get(); if !ptr.is_null() { - // Should warn here if resource was created for buffer, but - // it will probably happen in normal operation for things like - // swapchain textures. (*ptr).Release(); } } } } +impl Clone for Resource { + fn clone(&self) -> Self { + unsafe { + let ptr = self.get_mut(); + (*ptr).AddRef(); + Resource { + ptr: AtomicPtr::new(ptr), + } + } + } +} + impl Factory4 { pub unsafe fn create(flags: minwindef::UINT) -> Result { let mut factory = ptr::null_mut(); @@ -236,7 +245,7 @@ impl CommandQueue { explain_error( self.0.GetTimestampFrequency(&mut result), "could not get timestamp frequency", - ); + )?; Ok(result) } @@ -310,7 +319,7 @@ impl SwapChain3 { } impl Blob { - pub unsafe fn print_to_console(blob: Blob) { + pub unsafe fn print_to_console(blob: &Blob) { println!("==SHADER COMPILE MESSAGES=="); let message = { let pointer = blob.0.GetBufferPointer(); @@ -457,7 +466,7 @@ impl Device { &mut pipeline_state as *mut _ as *mut _, ), "device could not create compute pipeline state", - ); + )?; Ok(PipelineState(ComPtr::from_raw(pipeline_state))) } @@ -468,14 +477,16 @@ impl Device { blob: Blob, ) -> Result { let mut signature = ptr::null_mut(); - explain_error(self.0.CreateRootSignature( - node_mask, - blob.0.GetBufferPointer(), - blob.0.GetBufferSize(), - &d3d12::ID3D12RootSignature::uuidof(), - &mut signature as *mut _ as *mut _, - ), - "device could not create root signature"); + explain_error( + self.0.CreateRootSignature( + node_mask, + blob.0.GetBufferPointer(), + blob.0.GetBufferSize(), + &d3d12::ID3D12RootSignature::uuidof(), + &mut signature as *mut _ as *mut _, + ), + "device could not create root signature", + )?; Ok(RootSignature(ComPtr::from_raw(signature))) } @@ -532,7 +543,7 @@ impl Device { pub unsafe fn create_byte_addressed_buffer_unordered_access_view( &self, - resource: Resource, + resource: &Resource, descriptor: CpuDescriptor, first_element: u64, num_elements: u32, @@ -558,7 +569,7 @@ impl Device { pub unsafe fn create_unordered_access_view( &self, - resource: Resource, + resource: &Resource, descriptor: CpuDescriptor, ) { self.0.CreateUnorderedAccessView( @@ -571,7 +582,7 @@ impl Device { pub unsafe fn create_constant_buffer_view( &self, - resource: Resource, + resource: &Resource, descriptor: CpuDescriptor, size_in_bytes: u32, ) { @@ -585,7 +596,7 @@ impl Device { pub unsafe fn create_byte_addressed_buffer_shader_resource_view( &self, - resource: Resource, + resource: &Resource, descriptor: CpuDescriptor, first_element: u64, num_elements: u32, @@ -611,7 +622,7 @@ impl Device { pub unsafe fn create_structured_buffer_shader_resource_view( &self, - resource: Resource, + resource: &Resource, descriptor: CpuDescriptor, first_element: u64, num_elements: u32, @@ -635,7 +646,7 @@ impl Device { pub unsafe fn create_texture2d_shader_resource_view( &self, - resource: Resource, + resource: &Resource, format: dxgiformat::DXGI_FORMAT, descriptor: CpuDescriptor, ) { @@ -657,7 +668,7 @@ impl Device { pub unsafe fn create_render_target_view( &self, - resource: Resource, + resource: &Resource, desc: *const d3d12::D3D12_RENDER_TARGET_VIEW_DESC, descriptor: CpuDescriptor, ) { @@ -1045,20 +1056,28 @@ impl RootSignature { pub unsafe fn serialize_description( desc: &d3d12::D3D12_ROOT_SIGNATURE_DESC, version: d3d12::D3D_ROOT_SIGNATURE_VERSION, - ) -> Blob { + ) -> Result { let mut blob = ptr::null_mut(); - //TODO: properly use error blob - let mut _error = ptr::null_mut(); + let mut error_blob_ptr = ptr::null_mut(); - error::error_if_failed_else_unit(d3d12::D3D12SerializeRootSignature( - desc as *const _, - version, - &mut blob as *mut _ as *mut _, - &mut _error as *mut _ as *mut _, - )) - .expect("could not serialize root signature description"); + let hresult = + d3d12::D3D12SerializeRootSignature(desc, version, &mut blob, &mut error_blob_ptr); - Blob(ComPtr::from_raw(blob)) + let error_blob = if error_blob_ptr.is_null() { + None + } else { + Some(Blob(ComPtr::from_raw(error_blob_ptr))) + }; + #[cfg(debug_assertions)] + { + if let Some(error_blob) = &error_blob { + Blob::print_to_console(error_blob); + } + } + + explain_error(hresult, "could not serialize root signature description")?; + + Ok(Blob(ComPtr::from_raw(blob))) } } @@ -1075,6 +1094,8 @@ impl ShaderByteCode { } // `blob` may not be null. + // TODO: this is not super elegant, maybe want to move the get + // operations closer to where they're used. pub unsafe fn from_blob(blob: Blob) -> ShaderByteCode { ShaderByteCode { bytecode: d3d12::D3D12_SHADER_BYTECODE { @@ -1089,11 +1110,11 @@ impl ShaderByteCode { /// /// * `target`: example format: `ps_5_1`. pub unsafe fn compile( - source: String, - target: String, - entry: String, + source: &str, + target: &str, + entry: &str, flags: minwindef::DWORD, - ) -> Blob { + ) -> Result { let mut shader_blob_ptr: *mut ID3DBlob = ptr::null_mut(); //TODO: use error blob properly let mut error_blob_ptr: *mut ID3DBlob = ptr::null_mut(); @@ -1109,37 +1130,42 @@ impl ShaderByteCode { ptr::null(), ptr::null(), d3dcompiler::D3D_COMPILE_STANDARD_FILE_INCLUDE, - entry.as_ptr() as *const _, - target.as_ptr() as *const _, + entry.as_ptr(), + target.as_ptr(), flags, 0, - &mut shader_blob_ptr as *mut _ as *mut _, - &mut error_blob_ptr as *mut _ as *mut _, + &mut shader_blob_ptr, + &mut error_blob_ptr, ); + let error_blob = if error_blob_ptr.is_null() { + None + } else { + Some(Blob(ComPtr::from_raw(error_blob_ptr))) + }; #[cfg(debug_assertions)] { - if !error_blob_ptr.is_null() { - let error_blob = Blob(ComPtr::from_raw(error_blob_ptr)); - Blob::print_to_console(error_blob.clone()); + if let Some(error_blob) = &error_blob { + Blob::print_to_console(error_blob); } } - error::error_if_failed_else_unit(hresult).expect("shader compilation failed"); + // TODO: we can put the shader compilation error into the returned error. + explain_error(hresult, "shader compilation failed")?; - Blob(ComPtr::from_raw(shader_blob_ptr)) + Ok(Blob(ComPtr::from_raw(shader_blob_ptr))) } pub unsafe fn compile_from_file( file_path: &Path, - target: String, - entry: String, + target: &str, + entry: &str, flags: minwindef::DWORD, - ) -> Blob { + ) -> Result { let file_open_error = format!("could not open shader source file for entry: {}", &entry); let source = std::fs::read_to_string(file_path).expect(&file_open_error); - ShaderByteCode::compile(source, target, entry, flags) + ShaderByteCode::compile(&source, target, entry, flags) } } @@ -1216,22 +1242,21 @@ impl GraphicsCommandList { .expect("could not reset command list"); } - pub unsafe fn set_compute_pipeline_root_signature(&self, signature: RootSignature) { + pub unsafe fn set_compute_pipeline_root_signature(&self, signature: &RootSignature) { self.0.SetComputeRootSignature(signature.0.as_raw()); } - pub unsafe fn set_graphics_pipeline_root_signature(&self, signature: RootSignature) { + pub unsafe fn set_graphics_pipeline_root_signature(&self, signature: &RootSignature) { self.0.SetGraphicsRootSignature(signature.0.as_raw()); } - pub unsafe fn set_resource_barrier( - &self, - resource_barriers: Vec, - ) { + pub unsafe fn resource_barrier(&self, resource_barriers: &[d3d12::D3D12_RESOURCE_BARRIER]) { self.0.ResourceBarrier( - u32::try_from(resource_barriers.len()) - .expect("could not safely convert resource_barriers.len() into u32"), - (&resource_barriers).as_ptr(), + resource_barriers + .len() + .try_into() + .expect("Waaaaaay too many barriers"), + resource_barriers.as_ptr(), ); } @@ -1258,7 +1283,7 @@ impl GraphicsCommandList { .DrawInstanced(num_vertices, num_instances, start_vertex, start_instance); } - pub unsafe fn set_pipeline_state(&self, pipeline_state: PipelineState) { + pub unsafe fn set_pipeline_state(&self, pipeline_state: &PipelineState) { self.0.SetPipelineState(pipeline_state.0.as_raw()); } @@ -1340,13 +1365,13 @@ impl GraphicsCommandList { .IASetVertexBuffers(start_slot, num_views, vertex_buffer_view as *const _); } - pub unsafe fn set_descriptor_heaps(&self, descriptor_heaps: Vec) { - let descriptor_heap_pointers: Vec<*mut d3d12::ID3D12DescriptorHeap> = + pub unsafe fn set_descriptor_heaps(&self, descriptor_heaps: &[&DescriptorHeap]) { + let mut descriptor_heap_pointers: Vec<_> = descriptor_heaps.iter().map(|dh| dh.heap.as_raw()).collect(); self.0.SetDescriptorHeaps( u32::try_from(descriptor_heap_pointers.len()) .expect("could not safely convert descriptor_heap_pointers.len() into u32"), - (&descriptor_heap_pointers).as_ptr() as *mut _, + descriptor_heap_pointers.as_mut_ptr(), ); } @@ -1399,6 +1424,23 @@ impl GraphicsCommandList { self.0 .CopyTextureRegion(&dst as *const _, 0, 0, 0, &src as *const _, ptr::null()); } + + pub unsafe fn copy_buffer( + &self, + dst_buf: &Resource, + dst_offset: u64, + src_buf: &Resource, + src_offset: u64, + size: u64, + ) { + self.0.CopyBufferRegion( + dst_buf.get_mut(), + dst_offset, + src_buf.get_mut(), + src_offset, + size, + ); + } } pub fn default_render_target_blend_desc() -> d3d12::D3D12_RENDER_TARGET_BLEND_DESC { @@ -1471,17 +1513,20 @@ pub unsafe fn create_transition_resource_barrier( resource_barrier } -pub unsafe fn enable_debug_layer() { +pub unsafe fn enable_debug_layer() -> Result<(), Error> { println!("enabling debug layer."); let mut debug_controller: *mut d3d12sdklayers::ID3D12Debug1 = ptr::null_mut(); - error::error_if_failed_else_unit(d3d12::D3D12GetDebugInterface( - &d3d12sdklayers::ID3D12Debug1::uuidof(), - &mut debug_controller as *mut _ as *mut _, - )) - .expect("could not create debug controller"); + explain_error( + d3d12::D3D12GetDebugInterface( + &d3d12sdklayers::ID3D12Debug1::uuidof(), + &mut debug_controller as *mut _ as *mut _, + ), + "could not create debug controller", + )?; - (*debug_controller).EnableDebugLayer(); + let debug_controller = ComPtr::from_raw(debug_controller); + debug_controller.EnableDebugLayer(); let mut queue = ptr::null_mut(); let hr = dxgi1_3::DXGIGetDebugInterface1( @@ -1490,13 +1535,10 @@ pub unsafe fn enable_debug_layer() { &mut queue as *mut _ as *mut _, ); - if winerror::SUCCEEDED(hr) { - (*debug_controller).SetEnableGPUBasedValidation(minwindef::TRUE); - } else { - println!("failed to enable debug layer!"); - } + explain_error(hr, "failed to enable debug layer")?; - (*debug_controller).Release(); + debug_controller.SetEnableGPUBasedValidation(minwindef::TRUE); + Ok(()) } pub struct InputElementDesc { diff --git a/piet-gpu-hal/src/lib.rs b/piet-gpu-hal/src/lib.rs index 0541748..1548838 100644 --- a/piet-gpu-hal/src/lib.rs +++ b/piet-gpu-hal/src/lib.rs @@ -67,6 +67,7 @@ pub trait Device: Sized { type PipelineBuilder: PipelineBuilder; type DescriptorSetBuilder: DescriptorSetBuilder; type Sampler; + type ShaderSource: ?Sized; /// Query the GPU info. /// @@ -118,7 +119,7 @@ pub trait Device: Sized { /// is subsumed by the builder. unsafe fn create_simple_compute_pipeline( &self, - code: &[u8], + code: &Self::ShaderSource, n_buffers: u32, n_images: u32, ) -> Result { @@ -259,7 +260,11 @@ pub trait PipelineBuilder { fn add_images(&mut self, n_images: u32); /// Add a binding with a variable-size array of textures. fn add_textures(&mut self, max_textures: u32); - unsafe fn create_compute_pipeline(self, device: &D, code: &[u8]) -> Result; + unsafe fn create_compute_pipeline( + self, + device: &D, + code: &D::ShaderSource, + ) -> Result; } /// A builder for descriptor sets with more complex layouts. diff --git a/piet-gpu-hal/src/vulkan.rs b/piet-gpu-hal/src/vulkan.rs index dd48dcf..3339bce 100644 --- a/piet-gpu-hal/src/vulkan.rs +++ b/piet-gpu-hal/src/vulkan.rs @@ -453,6 +453,7 @@ impl crate::Device for VkDevice { type PipelineBuilder = PipelineBuilder; type DescriptorSetBuilder = DescriptorSetBuilder; type Sampler = vk::Sampler; + type ShaderSource = [u8]; fn query_gpu_info(&self) -> GpuInfo { self.gpu_info.clone()