direct_storage/
lib.rs

1//! Rust bindings for [DirectStorage](https://github.com/microsoft/DirectStorage).
2//!
3//! We try to provide the same abstraction level and coding style as [windows-rs](https://github.com/microsoft/windows-rs).
4//!
5//! For more documentation, please have a look at the header files of the official
6//! distribution. We can't simply copy those because of licensing issues.
7//!
8//! This crate will panic if it can't find the shared libraries of DirectStorage.
9//! Please refer to the README.md on how to install them.
10
11#![allow(non_snake_case)]
12#![allow(non_camel_case_types)]
13#![warn(unused_qualifications)]
14
15use std::mem::{transmute_copy, ManuallyDrop};
16
17use windows_core::Interface;
18
19mod bindings;
20#[cfg(feature = "loaded")]
21pub mod runtime_loaded;
22pub use bindings::Microsoft::Direct3D::DirectStorage::*;
23
24/// Create a temporary "owned" copy inside a [`ManuallyDrop`] without increasing the refcount or
25/// moving away the source variable.
26///
27/// This is a common pattern when needing to pass interface pointers ("borrows") into Windows
28/// structs.  Moving/cloning ownership is impossible/inconvenient because:
29///
30/// - The caller does _not_ assume ownership (and decrement the refcount at a later time);
31/// - Unnecessarily increasing and decrementing the refcount;
32/// - [`Drop`] destructors cannot run inside `union` structures (when the created structure is
33///   implicitly dropped after a calll).
34///
35/// See also <https://github.com/microsoft/windows-rs/pull/2361#discussion_r1150799401> and
36/// <https://github.com/microsoft/windows-rs/issues/2386>.
37///
38/// # Safety
39/// Performs a [`transmute_copy()`] on a refcounted [`Interface`] type.  The returned [`ManuallyDrop`] should _not_ be
40/// dropped.
41pub unsafe fn readonly_copy<Src: Interface, Dst>(src: &Src) -> ManuallyDrop<Option<Dst>> {
42    unsafe { transmute_copy(src) }
43}
44
45/// Since DirectStorage is compiled with MSVC, we have to use it's rules for C bitfields.
46/// MSVC will only pack fields of the same type in the same backing field.
47///
48/// ```cpp
49/// struct DSTORAGE_REQUEST_OPTIONS {
50///      DSTORAGE_COMPRESSION_FORMAT CompressionFormat : 8;     // uint8_t  -> saved into A
51///      DSTORAGE_REQUEST_SOURCE_TYPE SourceType : 1;           // uint64_t -> packed together into B
52///      DSTORAGE_REQUEST_DESTINATION_TYPE DestinationType : 7; // uint64_t -> packed together into B
53///      UINT64 Reserved : 48;                                  // uint64_t -> packed together into B
54/// };
55///
56/// // Resulting layout:
57/// struct Storage {
58///      uint8_t A;
59///      uint8_t PADDING[7];
60///      uint64_t B;
61/// }
62/// ```
63impl DSTORAGE_REQUEST_OPTIONS {
64    pub fn CompressionFormat(&self) -> DSTORAGE_COMPRESSION_FORMAT {
65        DSTORAGE_COMPRESSION_FORMAT(self._bitfield1)
66    }
67
68    pub fn set_CompressionFormat(&mut self, value: DSTORAGE_COMPRESSION_FORMAT) {
69        self._bitfield1 = value.0;
70    }
71
72    pub fn SourceType(&self) -> DSTORAGE_REQUEST_SOURCE_TYPE {
73        let size = u64::BITS;
74        DSTORAGE_REQUEST_SOURCE_TYPE(self._bitfield2 << (size - 1) >> (size - 1))
75    }
76
77    pub fn set_SourceType(&mut self, value: DSTORAGE_REQUEST_SOURCE_TYPE) {
78        let mask = ((1 << 1) - 1) << 0;
79        self._bitfield2 &= !mask;
80        self._bitfield2 |= value.0 & mask;
81    }
82
83    pub fn DestinationType(&self) -> DSTORAGE_REQUEST_DESTINATION_TYPE {
84        let size = u64::BITS;
85        DSTORAGE_REQUEST_DESTINATION_TYPE(self._bitfield2 << (size - 8) >> (size - 8 + 1))
86    }
87
88    pub fn set_DestinationType(&mut self, value: DSTORAGE_REQUEST_DESTINATION_TYPE) {
89        let mask = ((1 << (8 - 1)) - 1) << 1;
90        self._bitfield2 &= !mask;
91        self._bitfield2 |= (value.0 << 1) & mask;
92    }
93}
94
95#[cfg(test)]
96mod tests {
97    use std::mem::{align_of, size_of};
98
99    use super::*;
100
101    #[cfg(target_pointer_width = "32")]
102    #[test]
103    fn test_msvc_compat_32bit() {
104        assert_eq!(size_of::<DSTORAGE_PRIORITY>(), 1);
105        assert_eq!(align_of::<DSTORAGE_PRIORITY>(), 1);
106
107        assert_eq!(size_of::<DSTORAGE_REQUEST_SOURCE_TYPE>(), 8);
108        assert_eq!(align_of::<DSTORAGE_REQUEST_SOURCE_TYPE>(), 8);
109
110        assert_eq!(size_of::<DSTORAGE_REQUEST_DESTINATION_TYPE>(), 8);
111        assert_eq!(align_of::<DSTORAGE_REQUEST_DESTINATION_TYPE>(), 8);
112
113        assert_eq!(size_of::<DSTORAGE_QUEUE_DESC>(), 24);
114        assert_eq!(align_of::<DSTORAGE_QUEUE_DESC>(), 8);
115
116        assert_eq!(size_of::<DSTORAGE_QUEUE_INFO>(), 32);
117        assert_eq!(align_of::<DSTORAGE_QUEUE_INFO>(), 8);
118
119        assert_eq!(size_of::<DSTORAGE_COMPRESSION_FORMAT>(), 1);
120        assert_eq!(align_of::<DSTORAGE_COMPRESSION_FORMAT>(), 1);
121
122        assert_eq!(size_of::<DSTORAGE_REQUEST_OPTIONS>(), 16);
123        assert_eq!(align_of::<DSTORAGE_REQUEST_OPTIONS>(), 8);
124
125        assert_eq!(size_of::<DSTORAGE_DEBUG>(), 4);
126        assert_eq!(align_of::<DSTORAGE_DEBUG>(), 4);
127
128        assert_eq!(size_of::<DSTORAGE_SOURCE_FILE>(), 24);
129        assert_eq!(align_of::<DSTORAGE_SOURCE_FILE>(), 8);
130
131        assert_eq!(size_of::<DSTORAGE_SOURCE_MEMORY>(), 8);
132        assert_eq!(align_of::<DSTORAGE_SOURCE_MEMORY>(), 4);
133
134        assert_eq!(size_of::<DSTORAGE_DESTINATION_MEMORY>(), 8);
135        assert_eq!(align_of::<DSTORAGE_DESTINATION_MEMORY>(), 4);
136
137        assert_eq!(size_of::<DSTORAGE_DESTINATION_BUFFER>(), 24);
138        assert_eq!(align_of::<DSTORAGE_DESTINATION_BUFFER>(), 8);
139
140        assert_eq!(size_of::<DSTORAGE_DESTINATION_TEXTURE_REGION>(), 32);
141        assert_eq!(align_of::<DSTORAGE_DESTINATION_TEXTURE_REGION>(), 4);
142
143        assert_eq!(size_of::<DSTORAGE_DESTINATION_MULTIPLE_SUBRESOURCES>(), 8);
144        assert_eq!(align_of::<DSTORAGE_DESTINATION_MULTIPLE_SUBRESOURCES>(), 4);
145
146        assert_eq!(size_of::<DSTORAGE_DESTINATION_TILES>(), 36);
147        assert_eq!(align_of::<DSTORAGE_DESTINATION_TILES>(), 4);
148
149        assert_eq!(size_of::<DSTORAGE_SOURCE>(), 24);
150        assert_eq!(align_of::<DSTORAGE_SOURCE>(), 8);
151
152        assert_eq!(size_of::<DSTORAGE_DESTINATION>(), 40);
153        assert_eq!(align_of::<DSTORAGE_DESTINATION>(), 8);
154
155        assert_eq!(size_of::<DSTORAGE_REQUEST>(), 104);
156        assert_eq!(align_of::<DSTORAGE_REQUEST>(), 8);
157
158        assert_eq!(size_of::<DSTORAGE_COMMAND_TYPE>(), 4);
159        assert_eq!(align_of::<DSTORAGE_COMMAND_TYPE>(), 4);
160
161        assert_eq!(size_of::<DSTORAGE_ERROR_PARAMETERS_REQUEST>(), 688);
162        assert_eq!(align_of::<DSTORAGE_ERROR_PARAMETERS_REQUEST>(), 8);
163
164        assert_eq!(size_of::<DSTORAGE_ERROR_PARAMETERS_STATUS>(), 8);
165        assert_eq!(align_of::<DSTORAGE_ERROR_PARAMETERS_STATUS>(), 4);
166
167        assert_eq!(size_of::<DSTORAGE_ERROR_PARAMETERS_SIGNAL>(), 16);
168        assert_eq!(align_of::<DSTORAGE_ERROR_PARAMETERS_SIGNAL>(), 8);
169
170        assert_eq!(size_of::<DSTORAGE_ERROR_PARAMETERS_EVENT>(), 4);
171        assert_eq!(align_of::<DSTORAGE_ERROR_PARAMETERS_EVENT>(), 4);
172
173        assert_eq!(size_of::<DSTORAGE_ERROR_FIRST_FAILURE>(), 696);
174        assert_eq!(align_of::<DSTORAGE_ERROR_FIRST_FAILURE>(), 8);
175
176        assert_eq!(size_of::<DSTORAGE_ERROR_RECORD>(), 704);
177        assert_eq!(align_of::<DSTORAGE_ERROR_RECORD>(), 8);
178
179        assert_eq!(size_of::<DSTORAGE_STAGING_BUFFER_SIZE>(), 4);
180        assert_eq!(align_of::<DSTORAGE_STAGING_BUFFER_SIZE>(), 4);
181
182        assert_eq!(size_of::<DSTORAGE_GET_REQUEST_FLAGS>(), 4);
183        assert_eq!(align_of::<DSTORAGE_GET_REQUEST_FLAGS>(), 4);
184
185        assert_eq!(size_of::<DSTORAGE_CUSTOM_DECOMPRESSION_FLAGS>(), 4);
186        assert_eq!(align_of::<DSTORAGE_CUSTOM_DECOMPRESSION_FLAGS>(), 4);
187
188        assert_eq!(size_of::<DSTORAGE_CUSTOM_DECOMPRESSION_REQUEST>(), 48);
189        assert_eq!(align_of::<DSTORAGE_CUSTOM_DECOMPRESSION_REQUEST>(), 8);
190
191        assert_eq!(size_of::<DSTORAGE_CUSTOM_DECOMPRESSION_RESULT>(), 16);
192        assert_eq!(align_of::<DSTORAGE_CUSTOM_DECOMPRESSION_RESULT>(), 8);
193
194        assert_eq!(size_of::<DSTORAGE_CONFIGURATION>(), 28);
195        assert_eq!(align_of::<DSTORAGE_CONFIGURATION>(), 4);
196
197        assert_eq!(size_of::<DSTORAGE_COMPRESSION>(), 4);
198        assert_eq!(align_of::<DSTORAGE_COMPRESSION>(), 4);
199    }
200
201    #[cfg(target_pointer_width = "64")]
202    #[test]
203    fn test_msvc_compat_64bit() {
204        assert_eq!(size_of::<DSTORAGE_PRIORITY>(), 1);
205        assert_eq!(align_of::<DSTORAGE_PRIORITY>(), 1);
206
207        assert_eq!(size_of::<DSTORAGE_REQUEST_SOURCE_TYPE>(), 8);
208        assert_eq!(align_of::<DSTORAGE_REQUEST_SOURCE_TYPE>(), 8);
209
210        assert_eq!(size_of::<DSTORAGE_REQUEST_DESTINATION_TYPE>(), 8);
211        assert_eq!(align_of::<DSTORAGE_REQUEST_DESTINATION_TYPE>(), 8);
212
213        assert_eq!(size_of::<DSTORAGE_QUEUE_DESC>(), 32);
214        assert_eq!(align_of::<DSTORAGE_QUEUE_DESC>(), 8);
215
216        assert_eq!(size_of::<DSTORAGE_QUEUE_INFO>(), 40);
217        assert_eq!(align_of::<DSTORAGE_QUEUE_INFO>(), 8);
218
219        assert_eq!(size_of::<DSTORAGE_COMPRESSION_FORMAT>(), 1);
220        assert_eq!(align_of::<DSTORAGE_COMPRESSION_FORMAT>(), 1);
221
222        assert_eq!(size_of::<DSTORAGE_REQUEST_OPTIONS>(), 16);
223        assert_eq!(align_of::<DSTORAGE_REQUEST_OPTIONS>(), 8);
224
225        assert_eq!(size_of::<DSTORAGE_DEBUG>(), 4);
226        assert_eq!(align_of::<DSTORAGE_DEBUG>(), 4);
227
228        assert_eq!(size_of::<DSTORAGE_SOURCE_FILE>(), 24);
229        assert_eq!(align_of::<DSTORAGE_SOURCE_FILE>(), 8);
230
231        assert_eq!(size_of::<DSTORAGE_SOURCE_MEMORY>(), 16);
232        assert_eq!(align_of::<DSTORAGE_SOURCE_MEMORY>(), 8);
233
234        assert_eq!(size_of::<DSTORAGE_DESTINATION_MEMORY>(), 16);
235        assert_eq!(align_of::<DSTORAGE_DESTINATION_MEMORY>(), 8);
236
237        assert_eq!(size_of::<DSTORAGE_DESTINATION_BUFFER>(), 24);
238        assert_eq!(align_of::<DSTORAGE_DESTINATION_BUFFER>(), 8);
239
240        assert_eq!(size_of::<DSTORAGE_DESTINATION_TEXTURE_REGION>(), 40);
241        assert_eq!(align_of::<DSTORAGE_DESTINATION_TEXTURE_REGION>(), 8);
242
243        assert_eq!(size_of::<DSTORAGE_DESTINATION_MULTIPLE_SUBRESOURCES>(), 16);
244        assert_eq!(align_of::<DSTORAGE_DESTINATION_MULTIPLE_SUBRESOURCES>(), 8);
245
246        assert_eq!(size_of::<DSTORAGE_DESTINATION_TILES>(), 40);
247        assert_eq!(align_of::<DSTORAGE_DESTINATION_TILES>(), 8);
248
249        assert_eq!(size_of::<DSTORAGE_SOURCE>(), 24);
250        assert_eq!(align_of::<DSTORAGE_SOURCE>(), 8);
251
252        assert_eq!(size_of::<DSTORAGE_DESTINATION>(), 40);
253        assert_eq!(align_of::<DSTORAGE_DESTINATION>(), 8);
254
255        assert_eq!(size_of::<DSTORAGE_REQUEST>(), 104);
256        assert_eq!(align_of::<DSTORAGE_REQUEST>(), 8);
257
258        assert_eq!(size_of::<DSTORAGE_COMMAND_TYPE>(), 4);
259        assert_eq!(align_of::<DSTORAGE_COMMAND_TYPE>(), 4);
260
261        assert_eq!(size_of::<DSTORAGE_ERROR_PARAMETERS_REQUEST>(), 688);
262        assert_eq!(align_of::<DSTORAGE_ERROR_PARAMETERS_REQUEST>(), 8);
263
264        assert_eq!(size_of::<DSTORAGE_ERROR_PARAMETERS_STATUS>(), 16);
265        assert_eq!(align_of::<DSTORAGE_ERROR_PARAMETERS_STATUS>(), 8);
266
267        assert_eq!(size_of::<DSTORAGE_ERROR_PARAMETERS_SIGNAL>(), 16);
268        assert_eq!(align_of::<DSTORAGE_ERROR_PARAMETERS_SIGNAL>(), 8);
269
270        assert_eq!(size_of::<DSTORAGE_ERROR_PARAMETERS_EVENT>(), 8);
271        assert_eq!(align_of::<DSTORAGE_ERROR_PARAMETERS_EVENT>(), 8);
272
273        assert_eq!(size_of::<DSTORAGE_ERROR_FIRST_FAILURE>(), 696);
274        assert_eq!(align_of::<DSTORAGE_ERROR_FIRST_FAILURE>(), 8);
275
276        assert_eq!(size_of::<DSTORAGE_ERROR_RECORD>(), 704);
277        assert_eq!(align_of::<DSTORAGE_ERROR_RECORD>(), 8);
278
279        assert_eq!(size_of::<DSTORAGE_STAGING_BUFFER_SIZE>(), 4);
280        assert_eq!(align_of::<DSTORAGE_STAGING_BUFFER_SIZE>(), 4);
281
282        assert_eq!(size_of::<DSTORAGE_GET_REQUEST_FLAGS>(), 4);
283        assert_eq!(align_of::<DSTORAGE_GET_REQUEST_FLAGS>(), 4);
284
285        assert_eq!(size_of::<DSTORAGE_CUSTOM_DECOMPRESSION_FLAGS>(), 4);
286        assert_eq!(align_of::<DSTORAGE_CUSTOM_DECOMPRESSION_FLAGS>(), 4);
287
288        assert_eq!(size_of::<DSTORAGE_CUSTOM_DECOMPRESSION_REQUEST>(), 48);
289        assert_eq!(align_of::<DSTORAGE_CUSTOM_DECOMPRESSION_REQUEST>(), 8);
290
291        assert_eq!(size_of::<DSTORAGE_CUSTOM_DECOMPRESSION_RESULT>(), 16);
292        assert_eq!(align_of::<DSTORAGE_CUSTOM_DECOMPRESSION_RESULT>(), 8);
293
294        assert_eq!(size_of::<DSTORAGE_CONFIGURATION>(), 28);
295        assert_eq!(align_of::<DSTORAGE_CONFIGURATION>(), 4);
296
297        assert_eq!(size_of::<DSTORAGE_COMPRESSION>(), 4);
298        assert_eq!(align_of::<DSTORAGE_COMPRESSION>(), 4);
299    }
300
301    #[test]
302    fn test_bitfield() {
303        let mut options = DSTORAGE_REQUEST_OPTIONS::default();
304        options.set_CompressionFormat(DSTORAGE_COMPRESSION_FORMAT_GDEFLATE);
305        assert_eq!(
306            options.CompressionFormat(),
307            DSTORAGE_COMPRESSION_FORMAT_GDEFLATE
308        );
309
310        options.set_SourceType(DSTORAGE_REQUEST_SOURCE_MEMORY);
311        assert_eq!(options.SourceType(), DSTORAGE_REQUEST_SOURCE_MEMORY);
312
313        options.set_DestinationType(DSTORAGE_REQUEST_DESTINATION_TEXTURE_REGION);
314        assert_eq!(
315            options.DestinationType(),
316            DSTORAGE_REQUEST_DESTINATION_TEXTURE_REGION
317        );
318
319        options.set_CompressionFormat(DSTORAGE_COMPRESSION_FORMAT_NONE);
320        options.set_SourceType(DSTORAGE_REQUEST_SOURCE_FILE);
321        options.set_DestinationType(DSTORAGE_REQUEST_DESTINATION_MEMORY);
322
323        assert_eq!(options, DSTORAGE_REQUEST_OPTIONS::default());
324    }
325}