use crate::DecodeError;
use mediaway_common::NativeHandle;
use windows::Win32::Graphics::Direct3D12::{
D3D12_COMMAND_LIST_FLAG_NONE, D3D12_COMMAND_LIST_TYPE, D3D12_COMMAND_QUEUE_DESC,
D3D12_COMMAND_QUEUE_FLAG_NONE, D3D12_CPU_PAGE_PROPERTY_UNKNOWN, D3D12_HEAP_FLAG_NONE,
D3D12_HEAP_PROPERTIES, D3D12_HEAP_TYPE, D3D12_HEAP_TYPE_DEFAULT, D3D12_MEMORY_POOL_UNKNOWN,
D3D12_RESOURCE_DESC, D3D12_RESOURCE_DIMENSION_BUFFER, D3D12_RESOURCE_DIMENSION_TEXTURE2D,
D3D12_RESOURCE_FLAG_NONE, D3D12_RESOURCE_STATE_COMMON, D3D12_RESOURCE_STATES,
D3D12_TEXTURE_LAYOUT_ROW_MAJOR, D3D12_TEXTURE_LAYOUT_UNKNOWN, ID3D12CommandAllocator,
ID3D12CommandQueue, ID3D12Device, ID3D12Device4, ID3D12Resource,
};
use windows::Win32::Graphics::Dxgi::Common::{
DXGI_FORMAT, DXGI_FORMAT_NV12, DXGI_FORMAT_UNKNOWN, DXGI_RATIONAL, DXGI_SAMPLE_DESC,
};
use windows::Win32::Media::MediaFoundation::{
D3D12_BITSTREAM_ENCRYPTION_TYPE_NONE, D3D12_FEATURE_DATA_VIDEO_DECODE_SUPPORT,
D3D12_FEATURE_VIDEO_DECODE_SUPPORT, D3D12_VIDEO_DECODE_CONFIGURATION,
D3D12_VIDEO_DECODE_CONFIGURATION_FLAGS, D3D12_VIDEO_DECODE_SUPPORT_FLAG_SUPPORTED,
D3D12_VIDEO_DECODE_SUPPORT_FLAGS, D3D12_VIDEO_DECODE_TIER_NOT_SUPPORTED,
D3D12_VIDEO_DECODER_DESC, D3D12_VIDEO_DECODER_HEAP_DESC,
D3D12_VIDEO_FRAME_CODED_INTERLACE_TYPE_NONE, ID3D12VideoDecoder, ID3D12VideoDecoderHeap,
ID3D12VideoDevice,
};
use windows::core::{GUID, Interface};
use super::util::data_size;
pub(super) fn device_from_handle(device_handle: NativeHandle) -> Result<ID3D12Device, DecodeError> {
let raw = device_handle.get() as *mut core::ffi::c_void;
let borrowed =
unsafe { ID3D12Device::from_raw_borrowed(&raw) }.ok_or(DecodeError::InvalidInput)?;
Ok(borrowed.clone())
}
pub(super) fn check_decode_support(
video_device: &ID3D12VideoDevice,
profile: GUID,
width: u32,
height: u32,
format: DXGI_FORMAT,
) -> Result<D3D12_FEATURE_DATA_VIDEO_DECODE_SUPPORT, DecodeError> {
let mut support = D3D12_FEATURE_DATA_VIDEO_DECODE_SUPPORT {
NodeIndex: 0,
Configuration: D3D12_VIDEO_DECODE_CONFIGURATION {
DecodeProfile: profile,
BitstreamEncryption: D3D12_BITSTREAM_ENCRYPTION_TYPE_NONE,
InterlaceType: D3D12_VIDEO_FRAME_CODED_INTERLACE_TYPE_NONE,
},
Width: width,
Height: height,
DecodeFormat: format,
FrameRate: DXGI_RATIONAL {
Numerator: 30,
Denominator: 1,
},
BitRate: 0,
SupportFlags: D3D12_VIDEO_DECODE_SUPPORT_FLAGS::default(),
ConfigurationFlags: D3D12_VIDEO_DECODE_CONFIGURATION_FLAGS::default(),
DecodeTier: D3D12_VIDEO_DECODE_TIER_NOT_SUPPORTED,
};
unsafe {
video_device
.CheckFeatureSupport(
D3D12_FEATURE_VIDEO_DECODE_SUPPORT,
std::ptr::from_mut(&mut support).cast(),
data_size::<D3D12_FEATURE_DATA_VIDEO_DECODE_SUPPORT>(),
)
.map_err(|_err| DecodeError::Unsupported)?;
}
if !support
.SupportFlags
.contains(D3D12_VIDEO_DECODE_SUPPORT_FLAG_SUPPORTED)
{
return Err(DecodeError::Unsupported);
}
Ok(support)
}
pub(super) fn create_decoder(
video_device: &ID3D12VideoDevice,
profile: GUID,
width: u32,
height: u32,
format: DXGI_FORMAT,
max_dpb_slots: u32,
) -> Result<(ID3D12VideoDecoder, ID3D12VideoDecoderHeap), DecodeError> {
let configuration = D3D12_VIDEO_DECODE_CONFIGURATION {
DecodeProfile: profile,
BitstreamEncryption: D3D12_BITSTREAM_ENCRYPTION_TYPE_NONE,
InterlaceType: D3D12_VIDEO_FRAME_CODED_INTERLACE_TYPE_NONE,
};
let decoder_desc = D3D12_VIDEO_DECODER_DESC {
NodeMask: 0,
Configuration: configuration,
};
let decoder: ID3D12VideoDecoder =
unsafe { video_device.CreateVideoDecoder(&raw const decoder_desc) }
.map_err(|_err| DecodeError::Backend)?;
let heap_desc = D3D12_VIDEO_DECODER_HEAP_DESC {
NodeMask: 0,
Configuration: configuration,
DecodeWidth: width,
DecodeHeight: height,
Format: format,
FrameRate: DXGI_RATIONAL {
Numerator: 30,
Denominator: 1,
},
BitRate: 0,
MaxDecodePictureBufferCount: max_dpb_slots,
};
let decoder_heap: ID3D12VideoDecoderHeap =
unsafe { video_device.CreateVideoDecoderHeap(&raw const heap_desc) }
.map_err(|_err| DecodeError::Backend)?;
Ok((decoder, decoder_heap))
}
pub(super) fn create_command_objects<T: Interface>(
device: &ID3D12Device,
device4: &ID3D12Device4,
list_type: D3D12_COMMAND_LIST_TYPE,
) -> Result<(ID3D12CommandQueue, ID3D12CommandAllocator, T), DecodeError> {
let queue_desc = D3D12_COMMAND_QUEUE_DESC {
Type: list_type,
Priority: 0,
Flags: D3D12_COMMAND_QUEUE_FLAG_NONE,
NodeMask: 0,
};
let queue: ID3D12CommandQueue = unsafe { device.CreateCommandQueue(&raw const queue_desc) }
.map_err(|_err| DecodeError::Backend)?;
let allocator: ID3D12CommandAllocator =
unsafe { device.CreateCommandAllocator(list_type) }.map_err(|_err| DecodeError::Backend)?;
let list: T = unsafe { device4.CreateCommandList1(0, list_type, D3D12_COMMAND_LIST_FLAG_NONE) }
.map_err(|_err| DecodeError::Backend)?;
Ok((queue, allocator, list))
}
pub(super) fn create_dpb_texture_array(
device: &ID3D12Device,
width: u32,
height: u32,
num_slots: u32,
) -> Result<ID3D12Resource, DecodeError> {
let heap_props = D3D12_HEAP_PROPERTIES {
Type: D3D12_HEAP_TYPE_DEFAULT,
CPUPageProperty: D3D12_CPU_PAGE_PROPERTY_UNKNOWN,
MemoryPoolPreference: D3D12_MEMORY_POOL_UNKNOWN,
CreationNodeMask: 1,
VisibleNodeMask: 1,
};
let desc = D3D12_RESOURCE_DESC {
Dimension: D3D12_RESOURCE_DIMENSION_TEXTURE2D,
Alignment: 0,
Width: u64::from(width),
Height: height,
DepthOrArraySize: u16::try_from(num_slots).unwrap_or(u16::MAX),
MipLevels: 1,
Format: DXGI_FORMAT_NV12,
SampleDesc: DXGI_SAMPLE_DESC {
Count: 1,
Quality: 0,
},
Layout: D3D12_TEXTURE_LAYOUT_UNKNOWN,
Flags: D3D12_RESOURCE_FLAG_NONE,
};
let mut resource: Option<ID3D12Resource> = None;
unsafe {
device
.CreateCommittedResource(
&raw const heap_props,
D3D12_HEAP_FLAG_NONE,
&raw const desc,
D3D12_RESOURCE_STATE_COMMON,
None,
&raw mut resource,
)
.map_err(|_err| DecodeError::Backend)?;
}
resource.ok_or(DecodeError::Backend)
}
pub(super) fn create_linear_buffer(
device: &ID3D12Device,
heap_type: D3D12_HEAP_TYPE,
size: u64,
initial_state: D3D12_RESOURCE_STATES,
) -> Result<ID3D12Resource, DecodeError> {
let heap_props = unsafe { device.GetCustomHeapProperties(0, heap_type) };
let desc = D3D12_RESOURCE_DESC {
Dimension: D3D12_RESOURCE_DIMENSION_BUFFER,
Alignment: 0,
Width: size.max(1),
Height: 1,
DepthOrArraySize: 1,
MipLevels: 1,
Format: DXGI_FORMAT_UNKNOWN,
SampleDesc: DXGI_SAMPLE_DESC {
Count: 1,
Quality: 0,
},
Layout: D3D12_TEXTURE_LAYOUT_ROW_MAJOR,
Flags: D3D12_RESOURCE_FLAG_NONE,
};
let mut resource: Option<ID3D12Resource> = None;
unsafe {
device
.CreateCommittedResource(
&raw const heap_props,
D3D12_HEAP_FLAG_NONE,
&raw const desc,
initial_state,
None,
&raw mut resource,
)
.map_err(|_err| DecodeError::Backend)?;
}
resource.ok_or(DecodeError::Backend)
}