Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Evaluate gfx_select's #[cfg] conditions at the right time. #3253

Merged
merged 1 commit into from
Dec 5, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,7 @@ Additionally `Surface::get_default_config` now returns an Option and returns Non
- Fix an integer overflow in `queue_write_texture` by @nical in (#3146)[https://github.com/gfx-rs/wgpu/pull/3146]
- Make `RenderPassCompatibilityError` and `CreateShaderModuleError` not so huge. By @jimblandy in (#3226)[https://github.com/gfx-rs/wgpu/pull/3226]
- 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]
- Evaluate `gfx_select!`'s `#[cfg]` conditions at the right time. By @jimblandy in [#3253](https://github.com/gfx-rs/wgpu/pull/3253)

#### WebGPU

Expand Down
121 changes: 100 additions & 21 deletions wgpu-core/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -243,6 +243,101 @@ If you are running this program on native and not in a browser and wish to work
Adapter::downlevel_properties or Device::downlevel_properties to get a listing of the features the current \
platform supports.";

// #[cfg] attributes in exported macros are interesting!
//
// The #[cfg] conditions in a macro's expansion are evaluated using the
// configuration options (features, target architecture and os, etc.) in force
// where the macro is *used*, not where it is *defined*. That is, if crate A
// defines a macro like this:
//
// #[macro_export]
// macro_rules! if_bleep {
// { } => {
// #[cfg(feature = "bleep")]
// bleep();
// }
// }
//
// and then crate B uses it like this:
//
// fn f() {
// if_bleep! { }
// }
//
// then it is crate B's `"bleep"` feature, not crate A's, that determines
// whether the macro expands to a function call or an empty statement. The
// entire configuration predicate is evaluated in the use's context, not the
// definition's.
//
// Since `wgpu-core` selects back ends using features, we need to make sure the
// arms of the `gfx_select!` macro are pruned according to `wgpu-core`'s
// features, not those of whatever crate happens to be using `gfx_select!`. This
// means we can't use `#[cfg]` attributes in `gfx_select!`s definition itself.
// Instead, for each backend, `gfx_select!` must use a macro whose definition is
// selected by `#[cfg]` in `wgpu-core`. The configuration predicate is still
// evaluated when the macro is used; we've just moved the `#[cfg]` into a macro
// used by `wgpu-core` itself.

/// Define an exported macro named `$public` that expands to a call if the
/// configuration predicate `$condition` is true, or to a panic otherwise.
///
/// Because of odd technical limitations on exporting macros expanded by other
/// macros, you must supply both a public-facing name for the macro and a
/// private name, which is never used outside this macro. For details:
/// <https://github.com/rust-lang/rust/pull/52234#issuecomment-976702997>
macro_rules! define_backend_caller {
{ $public:ident, $private:ident if $condition:meta } => {
#[cfg( $condition )]
#[macro_export]
macro_rules! $private {
( $backend:literal, $call:expr ) => ( $call )
}

#[cfg(not( $condition ))]
#[macro_export]
macro_rules! $private {
( $backend:literal, $call:expr ) => (
panic!("Unexpected backend {:?}", $backend)
)
}

// See note about rust-lang#52234 above.
#[doc(hidden)] pub use $private as $public;
jimblandy marked this conversation as resolved.
Show resolved Hide resolved
}
}

define_backend_caller! {
gfx_if_vulkan, gfx_if_vulkan_hidden
if any(
all(not(target_arch = "wasm32"), not(target_os = "ios"), not(target_os = "macos")),
feature = "vulkan-portability"
)
}

define_backend_caller! {
gfx_if_metal, gfx_if_metal_hidden
if all(not(target_arch = "wasm32"), any(target_os = "ios", target_os = "macos"))
}

define_backend_caller! {
gfx_if_dx12, gfx_if_dx12_hidden
if all(not(target_arch = "wasm32"), windows)
}

define_backend_caller! {
gfx_if_dx11, gfx_if_dx11_hidden
if all(not(target_arch = "wasm32"), windows)
}

define_backend_caller! {
gfx_if_gles, gfx_if_gles_hidden
if any(
all(unix, not(target_os = "macos"), not(target_os = "ios")),
feature = "angle",
target_arch = "wasm32"
)
}

/// Dispatch on an [`Id`]'s backend to a backend-generic method.
///
/// Uses of this macro have the form:
Expand Down Expand Up @@ -291,29 +386,13 @@ platform supports.";
#[macro_export]
macro_rules! gfx_select {
($id:expr => $global:ident.$method:ident( $($param:expr),* )) => {
// Note: For some reason the cfg aliases defined in build.rs
// don't succesfully apply in this macro so we must specify
// their equivalents manually.
match $id.backend() {
#[cfg(any(
all(not(target_arch = "wasm32"), not(target_os = "ios"), not(target_os = "macos")),
feature = "vulkan-portability"
))]
wgt::Backend::Vulkan => $global.$method::<$crate::api::Vulkan>( $($param),* ),
#[cfg(all(not(target_arch = "wasm32"), any(target_os = "ios", target_os = "macos")))]
wgt::Backend::Metal => $global.$method::<$crate::api::Metal>( $($param),* ),
#[cfg(all(not(target_arch = "wasm32"), windows))]
wgt::Backend::Dx12 => $global.$method::<$crate::api::Dx12>( $($param),* ),
#[cfg(all(not(target_arch = "wasm32"), windows))]
wgt::Backend::Dx11 => $global.$method::<$crate::api::Dx11>( $($param),* ),
#[cfg(any(
all(unix, not(target_os = "macos"), not(target_os = "ios")),
feature = "angle",
target_arch = "wasm32"
))]
wgt::Backend::Gl => $global.$method::<$crate::api::Gles>( $($param),+ ),
wgt::Backend::Vulkan => $crate::gfx_if_vulkan!("Vulkan", $global.$method::<$crate::api::Vulkan>( $($param),* )),
wgt::Backend::Metal => $crate::gfx_if_metal!("Metal", $global.$method::<$crate::api::Metal>( $($param),* )),
wgt::Backend::Dx12 => $crate::gfx_if_dx12!("Dx12", $global.$method::<$crate::api::Dx12>( $($param),* )),
wgt::Backend::Dx11 => $crate::gfx_if_dx11!("Dx11", $global.$method::<$crate::api::Dx11>( $($param),* )),
wgt::Backend::Gl => $crate::gfx_if_gles!("Gles", $global.$method::<$crate::api::Gles>( $($param),+ )),
other => panic!("Unexpected backend {:?}", other),

}
};
}
Expand Down