use std::mem::ManuallyDrop;
use crate::DecodeError;
use windows::Win32::Foundation::HANDLE;
use windows::Win32::Graphics::Direct3D12::{
D3D12_RESOURCE_BARRIER, D3D12_RESOURCE_BARRIER_0, D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES,
D3D12_RESOURCE_BARRIER_FLAG_NONE, D3D12_RESOURCE_BARRIER_TYPE_TRANSITION,
D3D12_RESOURCE_STATES, D3D12_RESOURCE_TRANSITION_BARRIER, ID3D12CommandQueue, ID3D12Fence,
ID3D12Resource,
};
use windows::Win32::System::Threading::{INFINITE, WaitForSingleObject};
pub(super) fn data_size<T>() -> u32 {
u32::try_from(std::mem::size_of::<T>()).unwrap_or(u32::MAX)
}
pub(super) const fn align_up_u32(value: u32, align: u32) -> u32 {
if align == 0 {
return value;
}
let rem = value % align;
if rem == 0 {
value
} else {
value + (align - rem)
}
}
pub(super) const fn align_up_u64(value: u64, align: u64) -> u64 {
if align == 0 {
return value;
}
let rem = value % align;
if rem == 0 {
value
} else {
value + (align - rem)
}
}
pub(super) fn nv12_size(width: u32, height: u32) -> Result<usize, DecodeError> {
let w = width as usize;
let h = height as usize;
w.checked_mul(h)
.and_then(|y| y.checked_add(y / 2))
.ok_or(DecodeError::InvalidInput)
}
pub(super) const fn transition_barrier(
resource: &ID3D12Resource,
subresource: u32,
before: D3D12_RESOURCE_STATES,
after: D3D12_RESOURCE_STATES,
) -> D3D12_RESOURCE_BARRIER {
D3D12_RESOURCE_BARRIER {
Type: D3D12_RESOURCE_BARRIER_TYPE_TRANSITION,
Flags: D3D12_RESOURCE_BARRIER_FLAG_NONE,
Anonymous: D3D12_RESOURCE_BARRIER_0 {
Transition: ManuallyDrop::new(D3D12_RESOURCE_TRANSITION_BARRIER {
pResource: borrow_resource(resource),
Subresource: subresource,
StateBefore: before,
StateAfter: after,
}),
},
}
}
pub(super) const fn transition_barrier_all(
resource: &ID3D12Resource,
before: D3D12_RESOURCE_STATES,
after: D3D12_RESOURCE_STATES,
) -> D3D12_RESOURCE_BARRIER {
transition_barrier(
resource,
D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES,
before,
after,
)
}
pub(super) const fn borrow_resource(
resource: &ID3D12Resource,
) -> ManuallyDrop<Option<ID3D12Resource>> {
unsafe { ManuallyDrop::new(Some(std::mem::transmute_copy(resource))) }
}
pub(super) fn signal_and_wait(
queue: &ID3D12CommandQueue,
fence: &ID3D12Fence,
fence_event: HANDLE,
fence_value: &mut u64,
) -> Result<(), DecodeError> {
*fence_value += 1;
unsafe { queue.Signal(fence, *fence_value) }.map_err(|_err| DecodeError::Backend)?;
if unsafe { fence.GetCompletedValue() } < *fence_value {
unsafe { fence.SetEventOnCompletion(*fence_value, fence_event) }
.map_err(|_err| DecodeError::Backend)?;
unsafe { WaitForSingleObject(fence_event, INFINITE) };
}
Ok(())
}