use windows::Win32::Graphics::{
Direct2D::{D2D1CreateFactory, ID2D1Factory, D2D1_DEBUG_LEVEL_INFORMATION, D2D1_FACTORY_OPTIONS, D2D1_FACTORY_TYPE_SINGLE_THREADED},
Direct3D::{D3D_DRIVER_TYPE, D3D_DRIVER_TYPE_HARDWARE, D3D_DRIVER_TYPE_WARP},
Direct3D11::{D3D11CreateDevice, ID3D11Device, D3D11_CREATE_DEVICE_BGRA_SUPPORT, D3D11_CREATE_DEVICE_DEBUG, D3D11_SDK_VERSION},
DirectWrite::{DWriteCreateFactory, IDWriteFactory, DWRITE_FACTORY_TYPE_SHARED},
};
use crate::{device::DeviceContextBackend, error::GraphicsError};
#[derive(Clone, Debug)]
pub struct D2DDeviceContext {
pub device: ID3D11Device,
pub factory: ID2D1Factory,
pub dwrite_factory: IDWriteFactory,
}
impl DeviceContextBackend for D2DDeviceContext {
fn new() -> Result<Self, GraphicsError> {
let factory = Self::new_factory()?;
let device = Self::new_device()?;
let dwrite_factory = Self::new_dwrite_factory()?;
Ok(Self {
factory,
device,
dwrite_factory,
})
}
}
impl D2DDeviceContext {
fn new_factory() -> Result<ID2D1Factory, GraphicsError> {
let mut options = D2D1_FACTORY_OPTIONS::default();
if cfg!(debug_assertions) {
options.debugLevel = D2D1_DEBUG_LEVEL_INFORMATION;
}
unsafe { D2D1CreateFactory(D2D1_FACTORY_TYPE_SINGLE_THREADED, Some(&options)).map_err(|err| GraphicsError::CreationFailed(err.to_string())) }
}
fn new_device_with_type(device_type: D3D_DRIVER_TYPE) -> Result<ID3D11Device, GraphicsError> {
let mut flags = D3D11_CREATE_DEVICE_BGRA_SUPPORT;
if cfg!(debug_assertions) {
flags |= D3D11_CREATE_DEVICE_DEBUG;
}
let mut device = None;
unsafe {
D3D11CreateDevice(None, device_type, None, flags, None, D3D11_SDK_VERSION, Some(&mut device), None, None)
.map(|_| device.unwrap())
.map_err(|err| GraphicsError::CreationFailed(err.to_string()))
}
}
fn new_device() -> Result<ID3D11Device, GraphicsError> {
Self::new_device_with_type(D3D_DRIVER_TYPE_HARDWARE).or_else(|_| Self::new_device_with_type(D3D_DRIVER_TYPE_WARP))
}
fn new_dwrite_factory() -> Result<IDWriteFactory, GraphicsError> {
unsafe { DWriteCreateFactory(DWRITE_FACTORY_TYPE_SHARED).map_err(|err| GraphicsError::CreationFailed(err.to_string())) }
}
}