pub struct GraphicsContextDescriptor {
pub backends: Backends,
pub power_preference: PowerPreference,
pub force_fallback_adapter: bool,
pub required_gpu_features: GpuFeatures,
pub requested_gpu_features: GpuFeatures,
pub additional_wgpu_features: Features,
pub limits: Limits,
pub label: Option<&'static str>,
}Expand description
Descriptor for configuring graphics context creation.
Fields§
§backends: BackendsGPU backends to use
power_preference: PowerPreferencePower preference for adapter selection
force_fallback_adapter: boolWhether to force fallback adapter
required_gpu_features: GpuFeaturesRequired GPU features (panics if not available).
Use this for features that your application cannot function without.
requested_gpu_features: GpuFeaturesRequested GPU features (best-effort, logs warning if unavailable).
Use this for features that would be nice to have but are not essential.
additional_wgpu_features: FeaturesAdditional raw wgpu features to enable (for features not covered by GpuFeatures).
limits: LimitsRequired device limits
label: Option<&'static str>Optional label for debugging
Implementations§
Source§impl GraphicsContextDescriptor
impl GraphicsContextDescriptor
Sourcepub fn new() -> Self
pub fn new() -> Self
Create a new descriptor with default settings.
Examples found in repository?
278fn main() {
279 logging::init();
280
281 run_app(|ctx| {
282 let tier_override = parse_tier();
283
284 // Use the capability API to configure GPU requirements.
285 // For auto-detect, request the best capability (graceful degradation).
286 // For a specific tier, require that tier's capability.
287 let descriptor = match tier_override {
288 None => GraphicsContextDescriptor::new().request_capability::<BestBatchCapability2D>(),
289 Some(RenderTier::Direct) => {
290 GraphicsContextDescriptor::new().require_capability::<DirectBatchCapability2D>()
291 }
292 Some(RenderTier::Indirect) => {
293 GraphicsContextDescriptor::new().require_capability::<IndirectBatchCapability2D>()
294 }
295 Some(RenderTier::Bindless) => {
296 GraphicsContextDescriptor::new().require_capability::<BindlessBatchCapability2D>()
297 }
298 };
299 let graphics_ctx =
300 pollster::block_on(GraphicsContext::new_owned_with_descriptor(descriptor))
301 .expect("Failed to create graphics context");
302
303 let window = ctx
304 .create_window(WindowDescriptor {
305 title: "Batched Renderer Example".to_string(),
306 size: Some(WinitPhysicalSize::new(800.0, 600.0)),
307 ..Default::default()
308 })
309 .expect("Failed to create window");
310
311 let surface_format = wgpu::TextureFormat::Bgra8UnormSrgb;
312
313 let renderable_window = RenderWindowBuilder::new()
314 .color_format(surface_format)
315 .with_depth_default()
316 .build(window, graphics_ctx.clone())
317 .expect("Failed to create render window");
318
319 let window_id = renderable_window.id();
320
321 let renderer =
322 create_batch_renderer_2d(graphics_ctx.clone(), surface_format, tier_override);
323
324 tracing::info!("Using render tier: {}", renderer.tier());
325
326 // Create initial depth buffer
327 let depth_texture = graphics_ctx
328 .device()
329 .create_texture(&wgpu::TextureDescriptor {
330 label: Some("example_depth"),
331 size: wgpu::Extent3d {
332 width: 1,
333 height: 1,
334 depth_or_array_layers: 1,
335 },
336 mip_level_count: 1,
337 sample_count: 1,
338 dimension: wgpu::TextureDimension::D2,
339 format: DEPTH_FORMAT,
340 usage: wgpu::TextureUsages::RENDER_ATTACHMENT,
341 view_formats: &[],
342 });
343 let depth_view = depth_texture.create_view(&wgpu::TextureViewDescriptor::default());
344
345 let mut windows = HashMap::new();
346 windows.insert(window_id, renderable_window);
347
348 Box::new(App {
349 context: graphics_ctx,
350 windows,
351 renderer,
352 depth_texture,
353 depth_view,
354 depth_width: 1,
355 depth_height: 1,
356 frame_count: 0,
357 })
358 });
359}More examples
40fn main() {
41 logging::init();
42 init_profiling(ProfilingBackend::PuffinHttp);
43
44 run_app(|ctx| {
45 profile_function!();
46
47 // Request TIMESTAMP_QUERY for GPU profiling (best-effort, won't fail if unavailable)
48 let graphics_ctx = pollster::block_on(GraphicsContext::new_owned_with_descriptor(
49 GraphicsContextDescriptor::new()
50 .request_capability::<astrelis_render::gpu_profiling::GpuFrameProfiler>(),
51 ))
52 .expect("Failed to create graphics context");
53
54 let window = ctx
55 .create_window(WindowDescriptor {
56 title: "Profiling Demo — CPU + GPU".to_string(),
57 size: Some(WinitPhysicalSize::new(800.0, 600.0)),
58 ..Default::default()
59 })
60 .expect("Failed to create window");
61
62 #[allow(unused_mut)]
63 let mut window = RenderWindowBuilder::new()
64 .color_format(wgpu::TextureFormat::Bgra8UnormSrgb)
65 .with_depth_default()
66 .build(window, graphics_ctx.clone())
67 .expect("Failed to create render window");
68
69 let window_id = window.id();
70
71 // Attach GPU profiler to the window — all frames will be automatically profiled
72 let has_gpu_profiling;
73 #[cfg(feature = "gpu-profiling")]
74 {
75 match astrelis_render::gpu_profiling::GpuFrameProfiler::new(&graphics_ctx) {
76 Ok(profiler) => {
77 let has_timestamps = profiler.has_timestamp_queries();
78 window.set_gpu_profiler(Arc::new(profiler));
79 has_gpu_profiling = true;
80 if has_timestamps {
81 println!(" GPU profiling: enabled with TIMESTAMP_QUERY (full timing)");
82 } else {
83 println!(" GPU profiling: enabled (debug groups only, no timing data)");
84 println!(" TIMESTAMP_QUERY not supported by this GPU");
85 }
86 }
87 Err(e) => {
88 has_gpu_profiling = false;
89 tracing::warn!("Failed to create GPU profiler: {e}. GPU profiling disabled.");
90 println!(" GPU profiling: failed to create profiler");
91 }
92 }
93 }
94 #[cfg(not(feature = "gpu-profiling"))]
95 {
96 has_gpu_profiling = false;
97 }
98
99 println!();
100 println!("═══════════════════════════════════════════════════");
101 println!(" PROFILING DEMO — CPU + GPU");
102 println!("═══════════════════════════════════════════════════");
103 println!();
104 println!(" CPU profiling: enabled (puffin)");
105 if !has_gpu_profiling {
106 #[cfg(not(feature = "gpu-profiling"))]
107 println!(" GPU profiling: disabled (compile with --features gpu-profiling)");
108 }
109 println!();
110 println!(" Open puffin_viewer at 127.0.0.1:8585 to see the flame graph.");
111 println!(" Install with: cargo install puffin_viewer");
112 println!("═══════════════════════════════════════════════════");
113 println!();
114
115 Box::new(ProfilingDemo {
116 context: graphics_ctx,
117 window,
118 window_id,
119 frame_count: 0,
120 })
121 });
122}Sourcepub fn require_features(self, features: GpuFeatures) -> Self
pub fn require_features(self, features: GpuFeatures) -> Self
Set required GPU features (panics if not available).
Sourcepub fn request_features(self, features: GpuFeatures) -> Self
pub fn request_features(self, features: GpuFeatures) -> Self
Set requested GPU features (best-effort, warns if unavailable).
Sourcepub fn with_required_features(self, features: GpuFeatures) -> Self
pub fn with_required_features(self, features: GpuFeatures) -> Self
Add additional required features.
Sourcepub fn with_requested_features(self, features: GpuFeatures) -> Self
pub fn with_requested_features(self, features: GpuFeatures) -> Self
Add additional requested features.
Sourcepub fn with_wgpu_features(self, features: Features) -> Self
pub fn with_wgpu_features(self, features: Features) -> Self
Set additional raw wgpu features (for features not covered by GpuFeatures).
Sourcepub fn power_preference(self, preference: PowerPreference) -> Self
pub fn power_preference(self, preference: PowerPreference) -> Self
Set the power preference.
Sourcepub fn require_capability<T: RenderCapability>(self) -> Self
pub fn require_capability<T: RenderCapability>(self) -> Self
Require a capability — its features become required, limits are merged.
If the adapter doesn’t support the capability’s required features,
device creation will fail with GraphicsError::MissingRequiredFeatures.
§Example
use astrelis_render::{GraphicsContextDescriptor, GpuProfiler};
let desc = GraphicsContextDescriptor::new()
.require_capability::<GpuProfiler>();Examples found in repository?
278fn main() {
279 logging::init();
280
281 run_app(|ctx| {
282 let tier_override = parse_tier();
283
284 // Use the capability API to configure GPU requirements.
285 // For auto-detect, request the best capability (graceful degradation).
286 // For a specific tier, require that tier's capability.
287 let descriptor = match tier_override {
288 None => GraphicsContextDescriptor::new().request_capability::<BestBatchCapability2D>(),
289 Some(RenderTier::Direct) => {
290 GraphicsContextDescriptor::new().require_capability::<DirectBatchCapability2D>()
291 }
292 Some(RenderTier::Indirect) => {
293 GraphicsContextDescriptor::new().require_capability::<IndirectBatchCapability2D>()
294 }
295 Some(RenderTier::Bindless) => {
296 GraphicsContextDescriptor::new().require_capability::<BindlessBatchCapability2D>()
297 }
298 };
299 let graphics_ctx =
300 pollster::block_on(GraphicsContext::new_owned_with_descriptor(descriptor))
301 .expect("Failed to create graphics context");
302
303 let window = ctx
304 .create_window(WindowDescriptor {
305 title: "Batched Renderer Example".to_string(),
306 size: Some(WinitPhysicalSize::new(800.0, 600.0)),
307 ..Default::default()
308 })
309 .expect("Failed to create window");
310
311 let surface_format = wgpu::TextureFormat::Bgra8UnormSrgb;
312
313 let renderable_window = RenderWindowBuilder::new()
314 .color_format(surface_format)
315 .with_depth_default()
316 .build(window, graphics_ctx.clone())
317 .expect("Failed to create render window");
318
319 let window_id = renderable_window.id();
320
321 let renderer =
322 create_batch_renderer_2d(graphics_ctx.clone(), surface_format, tier_override);
323
324 tracing::info!("Using render tier: {}", renderer.tier());
325
326 // Create initial depth buffer
327 let depth_texture = graphics_ctx
328 .device()
329 .create_texture(&wgpu::TextureDescriptor {
330 label: Some("example_depth"),
331 size: wgpu::Extent3d {
332 width: 1,
333 height: 1,
334 depth_or_array_layers: 1,
335 },
336 mip_level_count: 1,
337 sample_count: 1,
338 dimension: wgpu::TextureDimension::D2,
339 format: DEPTH_FORMAT,
340 usage: wgpu::TextureUsages::RENDER_ATTACHMENT,
341 view_formats: &[],
342 });
343 let depth_view = depth_texture.create_view(&wgpu::TextureViewDescriptor::default());
344
345 let mut windows = HashMap::new();
346 windows.insert(window_id, renderable_window);
347
348 Box::new(App {
349 context: graphics_ctx,
350 windows,
351 renderer,
352 depth_texture,
353 depth_view,
354 depth_width: 1,
355 depth_height: 1,
356 frame_count: 0,
357 })
358 });
359}Sourcepub fn request_capability<T: RenderCapability>(self) -> Self
pub fn request_capability<T: RenderCapability>(self) -> Self
Request a capability — required features stay required, requested features stay optional, limits are merged.
The capability’s required features are added as required, and its requested features are added as requested (best-effort). Limits are merged and clamped to adapter capabilities during device creation.
§Example
use astrelis_render::GraphicsContextDescriptor;
use astrelis_render::batched::BestBatchCapability;
let desc = GraphicsContextDescriptor::new()
.request_capability::<BestBatchCapability>();Examples found in repository?
278fn main() {
279 logging::init();
280
281 run_app(|ctx| {
282 let tier_override = parse_tier();
283
284 // Use the capability API to configure GPU requirements.
285 // For auto-detect, request the best capability (graceful degradation).
286 // For a specific tier, require that tier's capability.
287 let descriptor = match tier_override {
288 None => GraphicsContextDescriptor::new().request_capability::<BestBatchCapability2D>(),
289 Some(RenderTier::Direct) => {
290 GraphicsContextDescriptor::new().require_capability::<DirectBatchCapability2D>()
291 }
292 Some(RenderTier::Indirect) => {
293 GraphicsContextDescriptor::new().require_capability::<IndirectBatchCapability2D>()
294 }
295 Some(RenderTier::Bindless) => {
296 GraphicsContextDescriptor::new().require_capability::<BindlessBatchCapability2D>()
297 }
298 };
299 let graphics_ctx =
300 pollster::block_on(GraphicsContext::new_owned_with_descriptor(descriptor))
301 .expect("Failed to create graphics context");
302
303 let window = ctx
304 .create_window(WindowDescriptor {
305 title: "Batched Renderer Example".to_string(),
306 size: Some(WinitPhysicalSize::new(800.0, 600.0)),
307 ..Default::default()
308 })
309 .expect("Failed to create window");
310
311 let surface_format = wgpu::TextureFormat::Bgra8UnormSrgb;
312
313 let renderable_window = RenderWindowBuilder::new()
314 .color_format(surface_format)
315 .with_depth_default()
316 .build(window, graphics_ctx.clone())
317 .expect("Failed to create render window");
318
319 let window_id = renderable_window.id();
320
321 let renderer =
322 create_batch_renderer_2d(graphics_ctx.clone(), surface_format, tier_override);
323
324 tracing::info!("Using render tier: {}", renderer.tier());
325
326 // Create initial depth buffer
327 let depth_texture = graphics_ctx
328 .device()
329 .create_texture(&wgpu::TextureDescriptor {
330 label: Some("example_depth"),
331 size: wgpu::Extent3d {
332 width: 1,
333 height: 1,
334 depth_or_array_layers: 1,
335 },
336 mip_level_count: 1,
337 sample_count: 1,
338 dimension: wgpu::TextureDimension::D2,
339 format: DEPTH_FORMAT,
340 usage: wgpu::TextureUsages::RENDER_ATTACHMENT,
341 view_formats: &[],
342 });
343 let depth_view = depth_texture.create_view(&wgpu::TextureViewDescriptor::default());
344
345 let mut windows = HashMap::new();
346 windows.insert(window_id, renderable_window);
347
348 Box::new(App {
349 context: graphics_ctx,
350 windows,
351 renderer,
352 depth_texture,
353 depth_view,
354 depth_width: 1,
355 depth_height: 1,
356 frame_count: 0,
357 })
358 });
359}More examples
40fn main() {
41 logging::init();
42 init_profiling(ProfilingBackend::PuffinHttp);
43
44 run_app(|ctx| {
45 profile_function!();
46
47 // Request TIMESTAMP_QUERY for GPU profiling (best-effort, won't fail if unavailable)
48 let graphics_ctx = pollster::block_on(GraphicsContext::new_owned_with_descriptor(
49 GraphicsContextDescriptor::new()
50 .request_capability::<astrelis_render::gpu_profiling::GpuFrameProfiler>(),
51 ))
52 .expect("Failed to create graphics context");
53
54 let window = ctx
55 .create_window(WindowDescriptor {
56 title: "Profiling Demo — CPU + GPU".to_string(),
57 size: Some(WinitPhysicalSize::new(800.0, 600.0)),
58 ..Default::default()
59 })
60 .expect("Failed to create window");
61
62 #[allow(unused_mut)]
63 let mut window = RenderWindowBuilder::new()
64 .color_format(wgpu::TextureFormat::Bgra8UnormSrgb)
65 .with_depth_default()
66 .build(window, graphics_ctx.clone())
67 .expect("Failed to create render window");
68
69 let window_id = window.id();
70
71 // Attach GPU profiler to the window — all frames will be automatically profiled
72 let has_gpu_profiling;
73 #[cfg(feature = "gpu-profiling")]
74 {
75 match astrelis_render::gpu_profiling::GpuFrameProfiler::new(&graphics_ctx) {
76 Ok(profiler) => {
77 let has_timestamps = profiler.has_timestamp_queries();
78 window.set_gpu_profiler(Arc::new(profiler));
79 has_gpu_profiling = true;
80 if has_timestamps {
81 println!(" GPU profiling: enabled with TIMESTAMP_QUERY (full timing)");
82 } else {
83 println!(" GPU profiling: enabled (debug groups only, no timing data)");
84 println!(" TIMESTAMP_QUERY not supported by this GPU");
85 }
86 }
87 Err(e) => {
88 has_gpu_profiling = false;
89 tracing::warn!("Failed to create GPU profiler: {e}. GPU profiling disabled.");
90 println!(" GPU profiling: failed to create profiler");
91 }
92 }
93 }
94 #[cfg(not(feature = "gpu-profiling"))]
95 {
96 has_gpu_profiling = false;
97 }
98
99 println!();
100 println!("═══════════════════════════════════════════════════");
101 println!(" PROFILING DEMO — CPU + GPU");
102 println!("═══════════════════════════════════════════════════");
103 println!();
104 println!(" CPU profiling: enabled (puffin)");
105 if !has_gpu_profiling {
106 #[cfg(not(feature = "gpu-profiling"))]
107 println!(" GPU profiling: disabled (compile with --features gpu-profiling)");
108 }
109 println!();
110 println!(" Open puffin_viewer at 127.0.0.1:8585 to see the flame graph.");
111 println!(" Install with: cargo install puffin_viewer");
112 println!("═══════════════════════════════════════════════════");
113 println!();
114
115 Box::new(ProfilingDemo {
116 context: graphics_ctx,
117 window,
118 window_id,
119 frame_count: 0,
120 })
121 });
122}Trait Implementations§
Auto Trait Implementations§
impl Freeze for GraphicsContextDescriptor
impl RefUnwindSafe for GraphicsContextDescriptor
impl Send for GraphicsContextDescriptor
impl Sync for GraphicsContextDescriptor
impl Unpin for GraphicsContextDescriptor
impl UnsafeUnpin for GraphicsContextDescriptor
impl UnwindSafe for GraphicsContextDescriptor
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
Source§impl<T> Downcast for Twhere
T: Any,
impl<T> Downcast for Twhere
T: Any,
Source§fn into_any(self: Box<T>) -> Box<dyn Any>
fn into_any(self: Box<T>) -> Box<dyn Any>
Box<dyn Trait> (where Trait: Downcast) to Box<dyn Any>. Box<dyn Any> can
then be further downcast into Box<ConcreteType> where ConcreteType implements Trait.Source§fn into_any_rc(self: Rc<T>) -> Rc<dyn Any>
fn into_any_rc(self: Rc<T>) -> Rc<dyn Any>
Rc<Trait> (where Trait: Downcast) to Rc<Any>. Rc<Any> can then be
further downcast into Rc<ConcreteType> where ConcreteType implements Trait.Source§fn as_any(&self) -> &(dyn Any + 'static)
fn as_any(&self) -> &(dyn Any + 'static)
&Trait (where Trait: Downcast) to &Any. This is needed since Rust cannot
generate &Any’s vtable from &Trait’s.Source§fn as_any_mut(&mut self) -> &mut (dyn Any + 'static)
fn as_any_mut(&mut self) -> &mut (dyn Any + 'static)
&mut Trait (where Trait: Downcast) to &Any. This is needed since Rust cannot
generate &mut Any’s vtable from &mut Trait’s.Source§impl<T> DowncastSync for T
impl<T> DowncastSync for T
Source§impl<T> Instrument for T
impl<T> Instrument for T
Source§fn instrument(self, span: Span) -> Instrumented<Self>
fn instrument(self, span: Span) -> Instrumented<Self>
Source§fn in_current_span(self) -> Instrumented<Self>
fn in_current_span(self) -> Instrumented<Self>
Source§impl<T> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self>
fn into_either(self, into_left: bool) -> Either<Self, Self>
self into a Left variant of Either<Self, Self>
if into_left is true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
self into a Left variant of Either<Self, Self>
if into_left(&self) returns true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read more