#![allow(unsafe_code)]
use mediaway_common::{
GpuBufferHandle, GpuDeviceHandle, NativeHandle, PixelFormat, VideoFrame, VideoFrameStorage,
};
use mediaway_decoder::windows::D3d11SharedDecodeBridge;
use windows_hal_interop::Win32::Graphics::Direct3D12::{ID3D12Device, ID3D12Resource};
use windows_hal_interop::core::Interface;
use crate::wgpu::error::WgpuInteropError;
pub const DECODE_BRIDGE_FORMAT: wgpu::TextureFormat = wgpu::TextureFormat::NV12;
pub struct WgpuDx12DecodeBridge {
bridge: D3d11SharedDecodeBridge,
texture: wgpu::Texture,
width: u32,
height: u32,
}
impl WgpuDx12DecodeBridge {
pub fn new(
device: &wgpu::Device,
d3d11_device: GpuDeviceHandle,
width: u32,
height: u32,
) -> Result<Self, WgpuInteropError> {
if width == 0 || height == 0 {
return Err(WgpuInteropError::InvalidInput);
}
let GpuDeviceHandle::DirectX11(d3d11_handle) = d3d11_device else {
return Err(WgpuInteropError::InvalidInput);
};
let native_device = unsafe { device.as_hal::<wgpu::hal::api::Dx12>() }
.ok_or(WgpuInteropError::HalUnavailable)?;
let raw_device: &ID3D12Device = native_device.raw_device();
let d3d12_handle = NativeHandle::new(Interface::as_raw(raw_device) as usize)
.ok_or(WgpuInteropError::InvalidInput)?;
drop(native_device);
let bridge = D3d11SharedDecodeBridge::open(d3d11_handle, d3d12_handle, width, height)?;
let texture = wrap_bridge_resource(device, &bridge, width, height)?;
Ok(Self {
bridge,
texture,
width,
height,
})
}
pub fn import_decoded_texture(
&self,
frame: &VideoFrame,
) -> Result<wgpu::Texture, WgpuInteropError> {
if frame.width != self.width
|| frame.height != self.height
|| frame.format != PixelFormat::Nv12
{
return Err(WgpuInteropError::InvalidInput);
}
let VideoFrameStorage::Gpu(GpuBufferHandle::DirectX11 {
texture,
subresource,
}) = &frame.storage
else {
return Err(WgpuInteropError::InvalidInput);
};
self.bridge.copy_from_decoded(*texture, *subresource)?;
Ok(self.texture.clone())
}
}
fn wrap_bridge_resource(
device: &wgpu::Device,
bridge: &D3d11SharedDecodeBridge,
width: u32,
height: u32,
) -> Result<wgpu::Texture, WgpuInteropError> {
let handle = bridge.d3d12_resource_handle()?;
let raw = handle.get() as *mut core::ffi::c_void;
let borrowed =
unsafe { ID3D12Resource::from_raw_borrowed(&raw) }.ok_or(WgpuInteropError::InvalidInput)?;
let resource: ID3D12Resource = borrowed.clone();
let size = wgpu::Extent3d {
width,
height,
depth_or_array_layers: 1,
};
let hal_texture = unsafe {
wgpu::hal::dx12::Device::texture_from_raw(
resource,
DECODE_BRIDGE_FORMAT,
wgpu::TextureDimension::D2,
size,
1,
1,
)
};
let texture_desc = wgpu::TextureDescriptor {
label: Some("mediaway-wgpu dx12 decode bridge dest"),
size,
mip_level_count: 1,
sample_count: 1,
dimension: wgpu::TextureDimension::D2,
format: DECODE_BRIDGE_FORMAT,
usage: wgpu::TextureUsages::TEXTURE_BINDING | wgpu::TextureUsages::COPY_SRC,
view_formats: &[],
};
let wgpu_texture = unsafe {
device.create_texture_from_hal::<wgpu::hal::api::Dx12>(hal_texture, &texture_desc)
};
Ok(wgpu_texture)
}