@@ -243,6 +243,101 @@ If you are running this program on native and not in a browser and wish to work
243
243
Adapter::downlevel_properties or Device::downlevel_properties to get a listing of the features the current \
244
244
platform supports.";
245
245
246
+ // #[cfg] attributes in exported macros are interesting!
247
+ //
248
+ // The #[cfg] conditions in a macro's expansion are evaluated using the
249
+ // configuration options (features, target architecture and os, etc.) in force
250
+ // where the macro is *used*, not where it is *defined*. That is, if crate A
251
+ // defines a macro like this:
252
+ //
253
+ // #[macro_export]
254
+ // macro_rules! if_bleep {
255
+ // { } => {
256
+ // #[cfg(feature = "bleep")]
257
+ // bleep();
258
+ // }
259
+ // }
260
+ //
261
+ // and then crate B uses it like this:
262
+ //
263
+ // fn f() {
264
+ // if_bleep! { }
265
+ // }
266
+ //
267
+ // then it is crate B's `"bleep"` feature, not crate A's, that determines
268
+ // whether the macro expands to a function call or an empty statement. The
269
+ // entire configuration predicate is evaluated in the use's context, not the
270
+ // definition's.
271
+ //
272
+ // Since `wgpu-core` selects back ends using features, we need to make sure the
273
+ // arms of the `gfx_select!` macro are pruned according to `wgpu-core`'s
274
+ // features, not those of whatever crate happens to be using `gfx_select!`. This
275
+ // means we can't use `#[cfg]` attributes in `gfx_select!`s definition itself.
276
+ // Instead, for each backend, `gfx_select!` must use a macro whose definition is
277
+ // selected by `#[cfg]` in `wgpu-core`. The configuration predicate is still
278
+ // evaluated when the macro is used; we've just moved the `#[cfg]` into a macro
279
+ // used by `wgpu-core` itself.
280
+
281
+ /// Define an exported macro named `$public` that expands to a call if the
282
+ /// configuration predicate `$condition` is true, or to a panic otherwise.
283
+ ///
284
+ /// Because of odd technical limitations on exporting macros expanded by other
285
+ /// macros, you must supply both a public-facing name for the macro and a
286
+ /// private name, which is never used outside this macro. For details:
287
+ /// <https://github.com/rust-lang/rust/pull/52234#issuecomment-976702997>
288
+ macro_rules! define_backend_caller {
289
+ { $public: ident, $private: ident if $condition: meta } => {
290
+ #[ cfg( $condition ) ]
291
+ #[ macro_export]
292
+ macro_rules! $private {
293
+ ( $backend: literal, $call: expr ) => ( $call )
294
+ }
295
+
296
+ #[ cfg( not( $condition ) ) ]
297
+ #[ macro_export]
298
+ macro_rules! $private {
299
+ ( $backend: literal, $call: expr ) => (
300
+ panic!( "Unexpected backend {:?}" , $backend)
301
+ )
302
+ }
303
+
304
+ // See note about rust-lang#52234 above.
305
+ #[ doc( hidden) ] pub use $private as $public;
306
+ }
307
+ }
308
+
309
+ define_backend_caller ! {
310
+ gfx_if_vulkan, gfx_if_vulkan_hidden
311
+ if any(
312
+ all( not( target_arch = "wasm32" ) , not( target_os = "ios" ) , not( target_os = "macos" ) ) ,
313
+ feature = "vulkan-portability"
314
+ )
315
+ }
316
+
317
+ define_backend_caller ! {
318
+ gfx_if_metal, gfx_if_metal_hidden
319
+ if all( not( target_arch = "wasm32" ) , any( target_os = "ios" , target_os = "macos" ) )
320
+ }
321
+
322
+ define_backend_caller ! {
323
+ gfx_if_dx12, gfx_if_dx12_hidden
324
+ if all( not( target_arch = "wasm32" ) , windows)
325
+ }
326
+
327
+ define_backend_caller ! {
328
+ gfx_if_dx11, gfx_if_dx11_hidden
329
+ if all( not( target_arch = "wasm32" ) , windows)
330
+ }
331
+
332
+ define_backend_caller ! {
333
+ gfx_if_gles, gfx_if_gles_hidden
334
+ if any(
335
+ all( unix, not( target_os = "macos" ) , not( target_os = "ios" ) ) ,
336
+ feature = "angle" ,
337
+ target_arch = "wasm32"
338
+ )
339
+ }
340
+
246
341
/// Dispatch on an [`Id`]'s backend to a backend-generic method.
247
342
///
248
343
/// Uses of this macro have the form:
@@ -291,29 +386,13 @@ platform supports.";
291
386
#[ macro_export]
292
387
macro_rules! gfx_select {
293
388
( $id: expr => $global: ident. $method: ident( $( $param: expr) ,* ) ) => {
294
- // Note: For some reason the cfg aliases defined in build.rs
295
- // don't succesfully apply in this macro so we must specify
296
- // their equivalents manually.
297
389
match $id. backend( ) {
298
- #[ cfg( any(
299
- all( not( target_arch = "wasm32" ) , not( target_os = "ios" ) , not( target_os = "macos" ) ) ,
300
- feature = "vulkan-portability"
301
- ) ) ]
302
- wgt:: Backend :: Vulkan => $global. $method:: <$crate:: api:: Vulkan >( $( $param) ,* ) ,
303
- #[ cfg( all( not( target_arch = "wasm32" ) , any( target_os = "ios" , target_os = "macos" ) ) ) ]
304
- wgt:: Backend :: Metal => $global. $method:: <$crate:: api:: Metal >( $( $param) ,* ) ,
305
- #[ cfg( all( not( target_arch = "wasm32" ) , windows) ) ]
306
- wgt:: Backend :: Dx12 => $global. $method:: <$crate:: api:: Dx12 >( $( $param) ,* ) ,
307
- #[ cfg( all( not( target_arch = "wasm32" ) , windows) ) ]
308
- wgt:: Backend :: Dx11 => $global. $method:: <$crate:: api:: Dx11 >( $( $param) ,* ) ,
309
- #[ cfg( any(
310
- all( unix, not( target_os = "macos" ) , not( target_os = "ios" ) ) ,
311
- feature = "angle" ,
312
- target_arch = "wasm32"
313
- ) ) ]
314
- wgt:: Backend :: Gl => $global. $method:: <$crate:: api:: Gles >( $( $param) ,+ ) ,
390
+ wgt:: Backend :: Vulkan => $crate:: gfx_if_vulkan!( "Vulkan" , $global. $method:: <$crate:: api:: Vulkan >( $( $param) ,* ) ) ,
391
+ wgt:: Backend :: Metal => $crate:: gfx_if_metal!( "Metal" , $global. $method:: <$crate:: api:: Metal >( $( $param) ,* ) ) ,
392
+ wgt:: Backend :: Dx12 => $crate:: gfx_if_dx12!( "Dx12" , $global. $method:: <$crate:: api:: Dx12 >( $( $param) ,* ) ) ,
393
+ wgt:: Backend :: Dx11 => $crate:: gfx_if_dx11!( "Dx11" , $global. $method:: <$crate:: api:: Dx11 >( $( $param) ,* ) ) ,
394
+ wgt:: Backend :: Gl => $crate:: gfx_if_gles!( "Gles" , $global. $method:: <$crate:: api:: Gles >( $( $param) ,+ ) ) ,
315
395
other => panic!( "Unexpected backend {:?}" , other) ,
316
-
317
396
}
318
397
} ;
319
398
}
0 commit comments