From 7e90304c3a123d37c7796ff891f31067cd95c96f Mon Sep 17 00:00:00 2001 From: Joe Cuffney Date: Fri, 18 Sep 2026 16:01:43 -0400 Subject: [PATCH] fix(native): gate wgpu-only items on the selected renderer `dioxus_renderer.rs` picks a renderer with a `cfg_if` chain - vello, vello-cpu-base, skia, vello-hybrid - and only the two wgpu arms define `InnerRendererOptions` or re-export `Features`/`Limits`. The items that use those types were gated on `any(feature = "vello", feature = "vello-hybrid")`, which asks whether a wgpu renderer is *enabled* rather than which one was *selected*. The two disagree whenever a CPU or Skia feature is on alongside a wgpu one - and since `vello-hybrid` is a default feature and `dioxus`'s `native` feature takes `dioxus-native` with its defaults, that is the only arrangement a consumer of `dioxus` can produce. The CPU and Skia arms were therefore unreachable downstream. Replace that predicate with one that mirrors the `cfg_if` chain. The `DeviceHandle` re-export keeps the original condition, because that pair is exactly what gates the optional `wgpu_context` dependency. Co-Authored-By: Claude Opus 5 --- packages/native/src/dioxus_renderer.rs | 15 ++++++- packages/native/src/lib.rs | 57 ++++++++++++++++++++++---- 2 files changed, 63 insertions(+), 9 deletions(-) diff --git a/packages/native/src/dioxus_renderer.rs b/packages/native/src/dioxus_renderer.rs index dce2ddd97b..f50c924152 100644 --- a/packages/native/src/dioxus_renderer.rs +++ b/packages/native/src/dioxus_renderer.rs @@ -42,7 +42,20 @@ impl DioxusNativeWindowRenderer { Self::with_inner_renderer(vello_renderer) } - #[cfg(any(feature = "vello-hybrid", feature = "vello"))] + // Gated on the renderer the `cfg_if` above actually selected, not on + // whichever renderer features happen to be enabled. `vello-hybrid` being + // enabled does not mean it is selected: it is last in the chain, and it is + // a default feature, so any downstream crate that also asks for + // `vello-cpu-*` or `skia` has both. `Features`, `Limits` and + // `InnerRendererOptions` only exist in the two wgpu arms. + #[cfg(any( + feature = "vello", + all( + feature = "vello-hybrid", + not(feature = "vello-cpu-base"), + not(feature = "skia") + ) + ))] pub fn with_features_and_limits(features: Option, limits: Option) -> Self { let mut options = InnerRendererOptions::default(); options.features = features; diff --git a/packages/native/src/lib.rs b/packages/native/src/lib.rs index e0c55ff820..20f0ffbfb6 100644 --- a/packages/native/src/lib.rs +++ b/packages/native/src/lib.rs @@ -49,11 +49,24 @@ pub fn current_android_app() -> android_activity::AndroidApp { #[cfg_attr(docsrs, doc(cfg(target_os = "android")))] pub use android_activity::AndroidApp; +// These two re-exports need different conditions, so they cannot share one +// `pub use`. `wgpu_context` is the optional dependency that `vello` and +// `vello-hybrid` both enable, so `DeviceHandle` exists whenever either feature +// is on. `Features`/`Limits` come from `dioxus_renderer`, which only defines +// them in the arm its `cfg_if` selected - and `vello-hybrid` is last in that +// chain as well as a default feature, so being enabled is not being selected. #[cfg(any(feature = "vello", feature = "vello-hybrid"))] -pub use { - dioxus_renderer::{Features, Limits}, - wgpu_context::DeviceHandle, -}; +pub use wgpu_context::DeviceHandle; + +#[cfg(any( + feature = "vello", + all( + feature = "vello-hybrid", + not(feature = "vello-cpu-base"), + not(feature = "skia") + ) +))] +pub use dioxus_renderer::{Features, Limits}; pub use blitz_dom::{FontContext, Widget, build_single_font_ctx}; pub use config::Config; @@ -124,12 +137,26 @@ pub fn launch_cfg_with_props( } // Read config values - #[cfg(any(feature = "vello", feature = "vello-hybrid"))] + #[cfg(any( + feature = "vello", + all( + feature = "vello-hybrid", + not(feature = "vello-cpu-base"), + not(feature = "skia") + ) + ))] let (mut features, mut limits) = (None, None); let mut window_attributes = None; let mut config = None; for mut cfg in configs { - #[cfg(any(feature = "vello", feature = "vello-hybrid"))] + #[cfg(any( + feature = "vello", + all( + feature = "vello-hybrid", + not(feature = "vello-cpu-base"), + not(feature = "skia") + ) + ))] { cfg = try_read_config!(cfg, features, Features); cfg = try_read_config!(cfg, limits, Limits); @@ -216,9 +243,23 @@ pub fn launch_cfg_with_props( ..Default::default() }, ); - #[cfg(any(feature = "vello", feature = "vello-hybrid"))] + #[cfg(any( + feature = "vello", + all( + feature = "vello-hybrid", + not(feature = "vello-cpu-base"), + not(feature = "skia") + ) + ))] let renderer = DioxusNativeWindowRenderer::with_features_and_limits(features, limits); - #[cfg(not(any(feature = "vello", feature = "vello-hybrid")))] + #[cfg(not(any( + feature = "vello", + all( + feature = "vello-hybrid", + not(feature = "vello-cpu-base"), + not(feature = "skia") + ) + )))] let renderer = DioxusNativeWindowRenderer::new(); let config = WindowConfig::with_attributes( Box::new(doc) as _,