diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 99d9db7..3f33039 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -22,7 +22,7 @@ jobs: - name: Set up Rust toolchain id: setup-rust run: | - rustup toolchain install ${{ env.MSRV }} -c rustfmt,clippy -p minimal + rustup toolchain install ${{ env.MSRV }} -c rustfmt,clippy --profile minimal - name: caching uses: Swatinem/rust-cache@v2 @@ -39,4 +39,4 @@ jobs: - name: doc run: | - cargo +${{ env.MSRV }} doc --all-features + cargo +${{ env.MSRV }} doc --all-features --no-deps diff --git a/bors.toml b/bors.toml deleted file mode 100644 index fc646ce..0000000 --- a/bors.toml +++ /dev/null @@ -1,5 +0,0 @@ -status = [ - "continuous-integration/appveyor/branch" -] - -timeout_sec = 18000 # 5 hours diff --git a/src/com.rs b/src/com.rs index 8b0025a..10edee7 100644 --- a/src/com.rs +++ b/src/com.rs @@ -11,44 +11,90 @@ use winapi::{ctypes::c_void, um::unknwnbase::IUnknown, Interface}; pub struct ComPtr(*mut T); impl ComPtr { + /// Creates a null ComPtr. pub fn null() -> Self { ComPtr(ptr::null_mut()) } + /// Create a ComPtr from a raw pointer. This will call AddRef on the pointer. + /// + /// # Safety + /// + /// - if `raw` is not null, it must be a valid pointer to a COM object that implements T. pub unsafe fn from_raw(raw: *mut T) -> Self { if !raw.is_null() { - (&*(raw as *mut IUnknown)).AddRef(); + (*(raw as *mut IUnknown)).AddRef(); } ComPtr(raw) } + /// Returns true if the inner pointer is null. pub fn is_null(&self) -> bool { self.0.is_null() } + /// Returns the raw inner pointer. May be null. pub fn as_ptr(&self) -> *const T { self.0 } + /// Returns the raw inner pointer as mutable. May be null. pub fn as_mut_ptr(&self) -> *mut T { self.0 } - pub fn mut_void(&mut self) -> *mut *mut c_void { - &mut self.0 as *mut *mut _ as *mut *mut _ + /// Returns a mutable reference to the inner pointer casted as a pointer to c_void. + /// + /// This is useful when D3D functions initialize objects by filling in a pointer to pointer + /// by taking `void**` as an argument. + /// + /// # Safety + /// + /// - Any modifications done to this pointer must result in the pointer either: + /// - being set to null + /// - being set to a valid pointer to a COM object that implements T + pub unsafe fn mut_void(&mut self) -> &mut *mut c_void { + // SAFETY: We must first get a reference pointing to our internal pointer + // and only then cast it. As if we cast it, then take a reference, we would + // end up with a reference to a temporary. + let refer: &mut *mut T = &mut self.0; + let void: *mut *mut c_void = refer.cast(); + + // SAFETY: This reference is valid for the duration of the borrow due our mutable borrow of self. + &mut *void } - pub fn mut_self(&mut self) -> *mut *mut T { - &mut self.0 as *mut *mut _ + /// Returns a mutable reference to the inner pointer. + /// + /// This is useful when D3D functions initialize objects by filling in a pointer to pointer + /// by taking `T**` as an argument. + /// + /// # Safety + /// + /// - Any modifications done to this pointer must result in the pointer either: + /// - being set to null + /// - being set to a valid pointer to a COM object that implements T + pub fn mut_self(&mut self) -> &mut *mut T { + &mut self.0 } } impl ComPtr { + /// Returns a reference to the inner pointer casted as a pointer IUnknown. + /// + /// # Safety + /// + /// - This pointer must not be null. pub unsafe fn as_unknown(&self) -> &IUnknown { debug_assert!(!self.is_null()); &*(self.0 as *mut IUnknown) } + /// Casts the T to U using QueryInterface. + /// + /// # Safety + /// + /// - This pointer must not be null. pub unsafe fn cast(&self) -> D3DResult> where U: Interface, @@ -86,7 +132,7 @@ impl Drop for ComPtr { impl Deref for ComPtr { type Target = T; fn deref(&self) -> &T { - debug_assert!(!self.is_null()); + assert!(!self.is_null()); unsafe { &*self.0 } } } @@ -126,8 +172,8 @@ impl Hash for ComPtr { /// /// ```rust /// # pub use d3d12::weak_com_inheritance_chain; -/// # mod actual { -/// # pub struct ComObject; impl winapi::Interface for ComObject { fn uuidof() -> winapi::shared::guiddef::GUID { todo!() } } +/// # mod actual { +/// # pub struct ComObject; impl winapi::Interface for ComObject { fn uuidof() -> winapi::shared::guiddef::GUID { todo!() } } /// # pub struct ComObject1; impl winapi::Interface for ComObject1 { fn uuidof() -> winapi::shared::guiddef::GUID { todo!() } } /// # pub struct ComObject2; impl winapi::Interface for ComObject2 { fn uuidof() -> winapi::shared::guiddef::GUID { todo!() } } /// # } @@ -223,12 +269,16 @@ macro_rules! weak_com_inheritance_chain { $variant:ident($type:ty); $($next_variant:ident),*; ) => { - // Construct this enum from weak pointer to this interface. For best usability, always use the highest constructor you can. This doesn't try to upcast. + #[doc = concat!("Constructs this enum from a ComPtr to ", stringify!($variant), ". For best usability, always use the highest constructor you can. This doesn't try to upcast.")] + /// + /// # Safety + /// + #[doc = concat!(" - The value must be a valid pointer to a COM object that implements ", stringify!($variant))] $vis unsafe fn $from_name(value: $crate::ComPtr<$type>) -> Self { Self::$variant(value) } - // Returns Some if the value implements the interface otherwise returns None. + #[doc = concat!("Returns Some if the value implements ", stringify!($variant), ".")] $vis fn $as_name(&self) -> Option<&$crate::ComPtr<$type>> { match *self { $( @@ -237,14 +287,14 @@ macro_rules! weak_com_inheritance_chain { Self::$variant(ref v) => Some(v), $( Self::$next_variant(ref v) => { - // v is &ComPtr and se cast to &ComPtr + // v is &ComPtr and we cast to &ComPtr Some(unsafe { std::mem::transmute(v) }) } )* } } - // Returns the interface if the value implements it, otherwise panics. + #[doc = concat!("Returns a ", stringify!($variant), " if the value implements it, otherwise panics.")] #[track_caller] $vis fn $unwrap_name(&self) -> &$crate::ComPtr<$type> { match *self { diff --git a/src/command_list.rs b/src/command_list.rs index 015d578..168d935 100644 --- a/src/command_list.rs +++ b/src/command_list.rs @@ -19,7 +19,7 @@ pub enum CmdListType { // VideoProcess = d3d12::D3D12_COMMAND_LIST_TYPE_VIDEO_PROCESS, } -bitflags! { +bitflags::bitflags! { #[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)] pub struct ClearFlags: u32 { const DEPTH = d3d12::D3D12_CLEAR_FLAG_DEPTH; @@ -263,7 +263,7 @@ impl GraphicsCommandList { } } - pub fn set_pipeline_state(&self, pso:&PipelineState) { + pub fn set_pipeline_state(&self, pso: &PipelineState) { unsafe { self.SetPipelineState(pso.as_mut_ptr()); } diff --git a/src/descriptor.rs b/src/descriptor.rs index 5bb1b5b..e0b4e6a 100644 --- a/src/descriptor.rs +++ b/src/descriptor.rs @@ -20,7 +20,7 @@ pub enum DescriptorHeapType { Dsv = d3d12::D3D12_DESCRIPTOR_HEAP_TYPE_DSV, } -bitflags! { +bitflags::bitflags! { #[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)] pub struct DescriptorHeapFlags: u32 { const SHADER_VISIBLE = d3d12::D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE; @@ -253,7 +253,7 @@ pub enum RootSignatureVersion { V1_1 = d3d12::D3D_ROOT_SIGNATURE_VERSION_1_1, } -bitflags! { +bitflags::bitflags! { #[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)] pub struct RootSignatureFlags: u32 { const ALLOW_IA_INPUT_LAYOUT = d3d12::D3D12_ROOT_SIGNATURE_FLAG_ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT; @@ -297,12 +297,7 @@ impl crate::D3D12Lib { let mut error = Error::null(); let hr = unsafe { let func: libloading::Symbol = self.lib.get(b"D3D12SerializeRootSignature")?; - func( - &desc, - version as _, - blob.mut_void() as *mut *mut _, - error.mut_void() as *mut *mut _, - ) + func(&desc, version as _, blob.mut_self(), error.mut_self()) }; Ok(((blob, error), hr)) @@ -332,8 +327,8 @@ impl RootSignature { d3d12::D3D12SerializeRootSignature( &desc, version as _, - blob.mut_void() as *mut *mut _, - error.mut_void() as *mut *mut _, + blob.mut_self(), + error.mut_self(), ) }; diff --git a/src/device.rs b/src/device.rs index 517b858..475fa22 100644 --- a/src/device.rs +++ b/src/device.rs @@ -16,7 +16,7 @@ pub type Device = ComPtr; #[cfg(feature = "libloading")] impl crate::D3D12Lib { -pub fn create_device( + pub fn create_device( &self, adapter: &ComPtr, feature_level: crate::FeatureLevel, diff --git a/src/dxgi.rs b/src/dxgi.rs index 81e2aaa..7a67299 100644 --- a/src/dxgi.rs +++ b/src/dxgi.rs @@ -9,7 +9,7 @@ use winapi::{ Interface, }; -bitflags! { +bitflags::bitflags! { #[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)] pub struct FactoryCreationFlags: u32 { const DEBUG = dxgi1_3::DXGI_CREATE_FACTORY_DEBUG; @@ -211,7 +211,10 @@ impl SwapchainDesc { } impl Factory1 { - pub fn create_swapchain( + /// # Safety + /// + /// - `queue` must be a valid pointer to a D3D device. + pub unsafe fn create_swapchain( &self, queue: *mut IUnknown, hwnd: HWND, @@ -242,8 +245,7 @@ impl Factory1 { }; let mut swapchain = SwapChain::null(); - let hr = - unsafe { self.CreateSwapChain(queue, &mut desc, swapchain.mut_void() as *mut *mut _) }; + let hr = unsafe { self.CreateSwapChain(queue, &mut desc, swapchain.mut_self()) }; (swapchain, hr) } @@ -251,7 +253,10 @@ impl Factory1 { impl Factory2 { // TODO: interface not complete - pub fn create_swapchain_for_hwnd( + /// # Safety + /// + /// - `queue` must be a valid pointer to a D3D device. + pub unsafe fn create_swapchain_for_hwnd( &self, queue: *mut IUnknown, hwnd: HWND, @@ -265,14 +270,17 @@ impl Factory2 { &desc.to_desc1(), ptr::null(), ptr::null_mut(), - swap_chain.mut_void() as *mut *mut _, + swap_chain.mut_self(), ) }; (swap_chain, hr) } - pub fn create_swapchain_for_composition( + /// # Safety + /// + /// - `queue` must be a valid pointer to a D3D device. + pub unsafe fn create_swapchain_for_composition( &self, queue: *mut IUnknown, desc: &SwapchainDesc, @@ -283,7 +291,7 @@ impl Factory2 { queue, &desc.to_desc1(), ptr::null_mut(), - swap_chain.mut_void() as *mut *mut _, + swap_chain.mut_self(), ) }; @@ -308,14 +316,17 @@ impl Factory4 { pub fn enumerate_adapters(&self, id: u32) -> D3DResult { let mut adapter = Adapter1::null(); - let hr = unsafe { self.EnumAdapters1(id, adapter.mut_void() as *mut *mut _) }; + let hr = unsafe { self.EnumAdapters1(id, adapter.mut_self()) }; (adapter, hr) } } impl FactoryMedia { - pub fn create_swapchain_for_composition_surface_handle( + /// # Safety + /// + /// - `queue` must be a valid pointer to a D3D device. + pub unsafe fn create_swapchain_for_composition_surface_handle( &self, queue: *mut IUnknown, surface_handle: HANDLE, @@ -328,7 +339,7 @@ impl FactoryMedia { surface_handle, &desc.to_desc1(), ptr::null_mut(), - swap_chain.mut_void() as *mut *mut _, + swap_chain.mut_self(), ) }; @@ -336,7 +347,7 @@ impl FactoryMedia { } } -bitflags! { +bitflags::bitflags! { #[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)] pub struct SwapChainPresentFlags: u32 { const DXGI_PRESENT_DO_NOT_SEQUENCE = dxgi::DXGI_PRESENT_DO_NOT_SEQUENCE; diff --git a/src/heap.rs b/src/heap.rs index 8d081a2..074de56 100644 --- a/src/heap.rs +++ b/src/heap.rs @@ -29,7 +29,7 @@ pub enum MemoryPool { L1 = d3d12::D3D12_MEMORY_POOL_L1, } -bitflags! { +bitflags::bitflags! { #[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)] pub struct HeapFlags: u32 { const NONE = d3d12::D3D12_HEAP_FLAG_NONE; diff --git a/src/lib.rs b/src/lib.rs index 8a68475..db0aecd 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,5 +1,4 @@ -#[macro_use] -extern crate bitflags; +#![allow(clippy::too_many_arguments)] use std::{convert::TryFrom, ffi::CStr}; use winapi::{ @@ -100,10 +99,12 @@ pub type Blob = ComPtr; pub type Error = ComPtr; impl Error { - pub unsafe fn as_c_str(&self) -> &CStr { - debug_assert!(!self.is_null()); - let data = self.GetBufferPointer(); - CStr::from_ptr(data as *const _ as *const _) + pub fn as_c_str(&self) -> &CStr { + assert!(!self.is_null()); + unsafe { + let data = self.GetBufferPointer(); + CStr::from_ptr(data as *const _ as *const _) + } } } diff --git a/src/pso.rs b/src/pso.rs index 2c19bd4..72cc8bf 100644 --- a/src/pso.rs +++ b/src/pso.rs @@ -1,17 +1,22 @@ //! Pipeline state use crate::{com::ComPtr, Blob, D3DResult, Error}; -use std::{ffi::{self, c_void}, ops::Deref, ptr, marker::PhantomData}; +use std::{ + ffi::{self, c_void}, + marker::PhantomData, + ops::Deref, + ptr, +}; use winapi::um::{d3d12, d3dcompiler}; -bitflags! { +bitflags::bitflags! { #[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)] pub struct PipelineStateFlags: u32 { const TOOL_DEBUG = d3d12::D3D12_PIPELINE_STATE_FLAG_TOOL_DEBUG; } } -bitflags! { +bitflags::bitflags! { #[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)] pub struct ShaderCompileFlags: u32 { const DEBUG = d3dcompiler::D3DCOMPILE_DEBUG; @@ -28,25 +33,34 @@ bitflags! { pub struct Shader<'a>(d3d12::D3D12_SHADER_BYTECODE, PhantomData<&'a c_void>); impl<'a> Shader<'a> { pub fn null() -> Self { - Shader(d3d12::D3D12_SHADER_BYTECODE { - BytecodeLength: 0, - pShaderBytecode: ptr::null(), - }, PhantomData) + Shader( + d3d12::D3D12_SHADER_BYTECODE { + BytecodeLength: 0, + pShaderBytecode: ptr::null(), + }, + PhantomData, + ) } pub fn from_raw(data: &'a [u8]) -> Self { - Shader(d3d12::D3D12_SHADER_BYTECODE { - BytecodeLength: data.len() as _, - pShaderBytecode: data.as_ptr() as _, - }, PhantomData) + Shader( + d3d12::D3D12_SHADER_BYTECODE { + BytecodeLength: data.len() as _, + pShaderBytecode: data.as_ptr() as _, + }, + PhantomData, + ) } // `blob` may not be null. pub fn from_blob(blob: &'a Blob) -> Self { - Shader(d3d12::D3D12_SHADER_BYTECODE { - BytecodeLength: unsafe { blob.GetBufferSize() }, - pShaderBytecode: unsafe { blob.GetBufferPointer() }, - }, PhantomData) + Shader( + d3d12::D3D12_SHADER_BYTECODE { + BytecodeLength: unsafe { blob.GetBufferSize() }, + pShaderBytecode: unsafe { blob.GetBufferPointer() }, + }, + PhantomData, + ) } /// Compile a shader from raw HLSL. @@ -72,8 +86,8 @@ impl<'a> Shader<'a> { target.as_ptr() as *const _, flags.bits(), 0, - shader.mut_void() as *mut *mut _, - error.mut_void() as *mut *mut _, + shader.mut_self(), + error.mut_self(), ) }; @@ -92,18 +106,24 @@ impl<'a> Deref for Shader<'a> { pub struct CachedPSO<'a>(d3d12::D3D12_CACHED_PIPELINE_STATE, PhantomData<&'a c_void>); impl<'a> CachedPSO<'a> { pub fn null() -> Self { - CachedPSO(d3d12::D3D12_CACHED_PIPELINE_STATE { - CachedBlobSizeInBytes: 0, - pCachedBlob: ptr::null(), - }, PhantomData) + CachedPSO( + d3d12::D3D12_CACHED_PIPELINE_STATE { + CachedBlobSizeInBytes: 0, + pCachedBlob: ptr::null(), + }, + PhantomData, + ) } // `blob` may not be null. pub fn from_blob(blob: &'a Blob) -> Self { - CachedPSO(d3d12::D3D12_CACHED_PIPELINE_STATE { - CachedBlobSizeInBytes: unsafe { blob.GetBufferSize() }, - pCachedBlob: unsafe { blob.GetBufferPointer() }, - }, PhantomData) + CachedPSO( + d3d12::D3D12_CACHED_PIPELINE_STATE { + CachedBlobSizeInBytes: unsafe { blob.GetBufferSize() }, + pCachedBlob: unsafe { blob.GetBufferPointer() }, + }, + PhantomData, + ) } } diff --git a/src/queue.rs b/src/queue.rs index 944cb6f..a569344 100644 --- a/src/queue.rs +++ b/src/queue.rs @@ -8,7 +8,7 @@ pub enum Priority { GlobalRealtime = d3d12::D3D12_COMMAND_QUEUE_PRIORITY_GLOBAL_REALTIME, } -bitflags! { +bitflags::bitflags! { #[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)] pub struct CommandQueueFlags: u32 { const DISABLE_GPU_TIMEOUT = d3d12::D3D12_COMMAND_QUEUE_FLAG_DISABLE_GPU_TIMEOUT;