Skip to content

Commit 537f077

Browse files
authored
Evaluate gfx_select's #[cfg] conditions at the right time. (#3253)
See the comments in the code for details.
1 parent 6147c91 commit 537f077

File tree

2 files changed

+101
-21
lines changed

2 files changed

+101
-21
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,7 @@ Additionally `Surface::get_default_config` now returns an Option and returns Non
120120
- Fix an integer overflow in `queue_write_texture` by @nical in (#3146)[https://github.com/gfx-rs/wgpu/pull/3146]
121121
- Make `RenderPassCompatibilityError` and `CreateShaderModuleError` not so huge. By @jimblandy in (#3226)[https://github.com/gfx-rs/wgpu/pull/3226]
122122
- Check for invalid bitflag bits in wgpu-core and allow them to be captured/replayed by @nical in (#3229)[https://github.com/gfx-rs/wgpu/pull/3229]
123+
- Evaluate `gfx_select!`'s `#[cfg]` conditions at the right time. By @jimblandy in [#3253](https://github.com/gfx-rs/wgpu/pull/3253)
123124

124125
#### WebGPU
125126

wgpu-core/src/lib.rs

Lines changed: 100 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -243,6 +243,101 @@ If you are running this program on native and not in a browser and wish to work
243243
Adapter::downlevel_properties or Device::downlevel_properties to get a listing of the features the current \
244244
platform supports.";
245245

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+
246341
/// Dispatch on an [`Id`]'s backend to a backend-generic method.
247342
///
248343
/// Uses of this macro have the form:
@@ -291,29 +386,13 @@ platform supports.";
291386
#[macro_export]
292387
macro_rules! gfx_select {
293388
($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.
297389
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),+ )),
315395
other => panic!("Unexpected backend {:?}", other),
316-
317396
}
318397
};
319398
}

0 commit comments

Comments
 (0)