1use std::ptr::null_mut;
5
6pub use winapi::shared::dxgi::DXGI_MAP_READ;
8
9use winapi::Interface;
10use winapi::shared::dxgi::{IDXGIDevice, IDXGISurface};
11use winapi::shared::dxgiformat::DXGI_FORMAT_R8G8B8A8_UNORM;
12use winapi::shared::dxgitype::DXGI_SAMPLE_DESC;
13use winapi::shared::winerror::{HRESULT, SUCCEEDED};
14use winapi::um::d3d11::{
15 D3D11_BIND_FLAG, D3D11_BIND_RENDER_TARGET, D3D11_BIND_SHADER_RESOURCE, D3D11_CPU_ACCESS_FLAG,
16 D3D11_CPU_ACCESS_READ, D3D11_CREATE_DEVICE_BGRA_SUPPORT, D3D11_SDK_VERSION,
17 D3D11_TEXTURE2D_DESC, D3D11_USAGE, D3D11_USAGE_DEFAULT, D3D11_USAGE_STAGING, D3D11CreateDevice,
18 ID3D11Device, ID3D11DeviceContext, ID3D11Texture2D,
19};
20use winapi::um::d3dcommon::D3D_DRIVER_TYPE_HARDWARE;
21
22use wio::com::ComPtr;
23
24#[derive(Debug)]
25pub struct Error(HRESULT);
26
27pub struct D3D11Device(ComPtr<ID3D11Device>);
28pub struct D3D11DeviceContext(ComPtr<ID3D11DeviceContext>);
29pub struct D3D11Texture2D(ComPtr<ID3D11Texture2D>);
30pub struct DxgiDevice(ComPtr<IDXGIDevice>);
31
32unsafe impl Send for D3D11Device {}
38unsafe impl Sync for D3D11Device {}
39unsafe impl Send for D3D11DeviceContext {}
40
41pub enum TextureMode {
42 Target,
43 Read,
44}
45
46impl TextureMode {
47 pub fn usage(&self) -> D3D11_USAGE {
48 match self {
49 TextureMode::Target => D3D11_USAGE_DEFAULT,
50 TextureMode::Read => D3D11_USAGE_STAGING,
51 }
52 }
53
54 pub fn bind_flags(&self) -> D3D11_BIND_FLAG {
55 match self {
56 TextureMode::Target => D3D11_BIND_SHADER_RESOURCE | D3D11_BIND_RENDER_TARGET,
57 TextureMode::Read => 0,
58 }
59 }
60
61 pub fn cpu_access_flags(&self) -> D3D11_CPU_ACCESS_FLAG {
62 match self {
63 TextureMode::Target => 0,
64 TextureMode::Read => D3D11_CPU_ACCESS_READ,
65 }
66 }
67}
68
69unsafe fn wrap<T, U, F>(hr: HRESULT, ptr: *mut T, f: F) -> Result<U, Error>
70where
71 F: Fn(ComPtr<T>) -> U,
72 T: Interface,
73{
74 if SUCCEEDED(hr) {
75 Ok(f(unsafe { ComPtr::from_raw(ptr) }))
76 } else {
77 Err(Error(hr))
78 }
79}
80
81impl D3D11Device {
82 pub fn inner(&self) -> &ComPtr<ID3D11Device> {
83 &self.0
84 }
85
86 pub fn create() -> Result<(D3D11Device, D3D11DeviceContext), Error> {
88 unsafe {
89 let mut ptr = null_mut();
90 let mut ctx_ptr = null_mut();
91 let hr = D3D11CreateDevice(
92 null_mut(), D3D_DRIVER_TYPE_HARDWARE,
94 null_mut(), D3D11_CREATE_DEVICE_BGRA_SUPPORT,
96 null_mut(), 0,
98 D3D11_SDK_VERSION,
99 &mut ptr,
100 null_mut(), &mut ctx_ptr,
102 );
103 let device = wrap(hr, ptr, D3D11Device)?;
104 let device_ctx = wrap(hr, ctx_ptr, D3D11DeviceContext)?;
105 Ok((device, device_ctx))
106 }
107 }
108
109 pub fn as_dxgi(&self) -> Option<DxgiDevice> {
110 self.0.cast().ok().map(DxgiDevice)
111 }
112
113 pub fn create_texture(
114 &self,
115 width: u32,
116 height: u32,
117 mode: TextureMode,
118 ) -> Result<D3D11Texture2D, Error> {
119 unsafe {
120 let mut ptr = null_mut();
121 let desc = D3D11_TEXTURE2D_DESC {
122 Width: width,
123 Height: height,
124 MipLevels: 1,
125 ArraySize: 1,
126 Format: DXGI_FORMAT_R8G8B8A8_UNORM,
127 SampleDesc: DXGI_SAMPLE_DESC {
128 Count: 1,
129 Quality: 0,
130 },
131 Usage: mode.usage(),
132 BindFlags: mode.bind_flags(),
133 CPUAccessFlags: mode.cpu_access_flags(),
134 MiscFlags: 0,
135 };
136 let hr = self.0.CreateTexture2D(&desc, null_mut(), &mut ptr);
137 wrap(hr, ptr, D3D11Texture2D)
138 }
139 }
140}
141
142impl D3D11DeviceContext {
143 pub fn inner(&self) -> &ComPtr<ID3D11DeviceContext> {
144 &self.0
145 }
146}
147
148impl D3D11Texture2D {
149 pub fn as_dxgi(&self) -> ComPtr<IDXGISurface> {
150 self.0.cast().unwrap()
151 }
152
153 pub fn as_raw(&self) -> *mut ID3D11Texture2D {
154 self.0.as_raw()
155 }
156}
157
158impl DxgiDevice {
159 pub fn as_raw(&self) -> *mut IDXGIDevice {
160 self.0.as_raw()
161 }
162}
163
164impl std::fmt::Display for Error {
165 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
166 write!(f, "HRESULT error {}", self.0)
167 }
168}
169
170impl std::error::Error for Error {}