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?
275fn main() {
276 logging::init();
277
278 run_app(|ctx| {
279 let tier_override = parse_tier();
280
281 // Use the capability API to configure GPU requirements.
282 // For auto-detect, request the best capability (graceful degradation).
283 // For a specific tier, require that tier's capability.
284 let descriptor = match tier_override {
285 None => GraphicsContextDescriptor::new()
286 .request_capability::<BestBatchCapability2D>(),
287 Some(RenderTier::Direct) => GraphicsContextDescriptor::new()
288 .require_capability::<DirectBatchCapability2D>(),
289 Some(RenderTier::Indirect) => GraphicsContextDescriptor::new()
290 .require_capability::<IndirectBatchCapability2D>(),
291 Some(RenderTier::Bindless) => GraphicsContextDescriptor::new()
292 .require_capability::<BindlessBatchCapability2D>(),
293 };
294 let graphics_ctx =
295 pollster::block_on(GraphicsContext::new_owned_with_descriptor(descriptor))
296 .expect("Failed to create graphics context");
297
298 let window = ctx
299 .create_window(WindowDescriptor {
300 title: "Batched Renderer Example".to_string(),
301 size: Some(WinitPhysicalSize::new(800.0, 600.0)),
302 ..Default::default()
303 })
304 .expect("Failed to create window");
305
306 let surface_format = wgpu::TextureFormat::Bgra8UnormSrgb;
307
308 let renderable_window = RenderableWindow::new_with_descriptor(
309 window,
310 graphics_ctx.clone(),
311 WindowContextDescriptor {
312 format: Some(surface_format),
313 ..Default::default()
314 },
315 )
316 .expect("Failed to create renderable window");
317
318 let window_id = renderable_window.id();
319
320 let renderer = create_batch_renderer_2d(
321 graphics_ctx.clone(),
322 surface_format,
323 tier_override,
324 );
325
326 tracing::info!("Using render tier: {}", renderer.tier());
327
328 // Create initial depth buffer
329 let depth_texture = graphics_ctx
330 .device()
331 .create_texture(&wgpu::TextureDescriptor {
332 label: Some("example_depth"),
333 size: wgpu::Extent3d {
334 width: 1,
335 height: 1,
336 depth_or_array_layers: 1,
337 },
338 mip_level_count: 1,
339 sample_count: 1,
340 dimension: wgpu::TextureDimension::D2,
341 format: DEPTH_FORMAT,
342 usage: wgpu::TextureUsages::RENDER_ATTACHMENT,
343 view_formats: &[],
344 });
345 let depth_view = depth_texture.create_view(&wgpu::TextureViewDescriptor::default());
346
347 let mut windows = HashMap::new();
348 windows.insert(window_id, renderable_window);
349
350 Box::new(App {
351 context: graphics_ctx,
352 windows,
353 renderer,
354 depth_texture,
355 depth_view,
356 depth_width: 1,
357 depth_height: 1,
358 frame_count: 0,
359 })
360 });
361}More examples
39fn main() {
40 logging::init();
41 init_profiling(ProfilingBackend::PuffinHttp);
42
43 run_app(|ctx| {
44 profile_function!();
45
46 // Request TIMESTAMP_QUERY for GPU profiling (best-effort, won't fail if unavailable)
47 let graphics_ctx = pollster::block_on(GraphicsContext::new_owned_with_descriptor(
48 GraphicsContextDescriptor::new()
49 .request_capability::<astrelis_render::gpu_profiling::GpuFrameProfiler>(),
50 ))
51 .expect("Failed to create graphics context");
52
53 let window = ctx
54 .create_window(WindowDescriptor {
55 title: "Profiling Demo — CPU + GPU".to_string(),
56 size: Some(WinitPhysicalSize::new(800.0, 600.0)),
57 ..Default::default()
58 })
59 .expect("Failed to create window");
60
61 #[allow(unused_mut)]
62 let mut window = RenderableWindow::new_with_descriptor(
63 window,
64 graphics_ctx.clone(),
65 WindowContextDescriptor {
66 format: Some(wgpu::TextureFormat::Bgra8UnormSrgb),
67 ..Default::default()
68 },
69 )
70 .expect("Failed to create renderable window");
71
72 let window_id = window.id();
73
74 // Attach GPU profiler to the window — all frames will be automatically profiled
75 let has_gpu_profiling;
76 #[cfg(feature = "gpu-profiling")]
77 {
78 match astrelis_render::gpu_profiling::GpuFrameProfiler::new(&graphics_ctx) {
79 Ok(profiler) => {
80 let has_timestamps = profiler.has_timestamp_queries();
81 window.set_gpu_profiler(Arc::new(profiler));
82 has_gpu_profiling = true;
83 if has_timestamps {
84 println!(" GPU profiling: enabled with TIMESTAMP_QUERY (full timing)");
85 } else {
86 println!(" GPU profiling: enabled (debug groups only, no timing data)");
87 println!(" TIMESTAMP_QUERY not supported by this GPU");
88 }
89 }
90 Err(e) => {
91 has_gpu_profiling = false;
92 tracing::warn!("Failed to create GPU profiler: {e}. GPU profiling disabled.");
93 println!(" GPU profiling: failed to create profiler");
94 }
95 }
96 }
97 #[cfg(not(feature = "gpu-profiling"))]
98 {
99 has_gpu_profiling = false;
100 }
101
102 println!();
103 println!("═══════════════════════════════════════════════════");
104 println!(" PROFILING DEMO — CPU + GPU");
105 println!("═══════════════════════════════════════════════════");
106 println!();
107 println!(" CPU profiling: enabled (puffin)");
108 if !has_gpu_profiling {
109 #[cfg(not(feature = "gpu-profiling"))]
110 println!(" GPU profiling: disabled (compile with --features gpu-profiling)");
111 }
112 println!();
113 println!(" Open puffin_viewer at 127.0.0.1:8585 to see the flame graph.");
114 println!(" Install with: cargo install puffin_viewer");
115 println!("═══════════════════════════════════════════════════");
116 println!();
117
118 Box::new(ProfilingDemo {
119 context: graphics_ctx,
120 window,
121 window_id,
122 frame_count: 0,
123 })
124 });
125}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?
275fn main() {
276 logging::init();
277
278 run_app(|ctx| {
279 let tier_override = parse_tier();
280
281 // Use the capability API to configure GPU requirements.
282 // For auto-detect, request the best capability (graceful degradation).
283 // For a specific tier, require that tier's capability.
284 let descriptor = match tier_override {
285 None => GraphicsContextDescriptor::new()
286 .request_capability::<BestBatchCapability2D>(),
287 Some(RenderTier::Direct) => GraphicsContextDescriptor::new()
288 .require_capability::<DirectBatchCapability2D>(),
289 Some(RenderTier::Indirect) => GraphicsContextDescriptor::new()
290 .require_capability::<IndirectBatchCapability2D>(),
291 Some(RenderTier::Bindless) => GraphicsContextDescriptor::new()
292 .require_capability::<BindlessBatchCapability2D>(),
293 };
294 let graphics_ctx =
295 pollster::block_on(GraphicsContext::new_owned_with_descriptor(descriptor))
296 .expect("Failed to create graphics context");
297
298 let window = ctx
299 .create_window(WindowDescriptor {
300 title: "Batched Renderer Example".to_string(),
301 size: Some(WinitPhysicalSize::new(800.0, 600.0)),
302 ..Default::default()
303 })
304 .expect("Failed to create window");
305
306 let surface_format = wgpu::TextureFormat::Bgra8UnormSrgb;
307
308 let renderable_window = RenderableWindow::new_with_descriptor(
309 window,
310 graphics_ctx.clone(),
311 WindowContextDescriptor {
312 format: Some(surface_format),
313 ..Default::default()
314 },
315 )
316 .expect("Failed to create renderable window");
317
318 let window_id = renderable_window.id();
319
320 let renderer = create_batch_renderer_2d(
321 graphics_ctx.clone(),
322 surface_format,
323 tier_override,
324 );
325
326 tracing::info!("Using render tier: {}", renderer.tier());
327
328 // Create initial depth buffer
329 let depth_texture = graphics_ctx
330 .device()
331 .create_texture(&wgpu::TextureDescriptor {
332 label: Some("example_depth"),
333 size: wgpu::Extent3d {
334 width: 1,
335 height: 1,
336 depth_or_array_layers: 1,
337 },
338 mip_level_count: 1,
339 sample_count: 1,
340 dimension: wgpu::TextureDimension::D2,
341 format: DEPTH_FORMAT,
342 usage: wgpu::TextureUsages::RENDER_ATTACHMENT,
343 view_formats: &[],
344 });
345 let depth_view = depth_texture.create_view(&wgpu::TextureViewDescriptor::default());
346
347 let mut windows = HashMap::new();
348 windows.insert(window_id, renderable_window);
349
350 Box::new(App {
351 context: graphics_ctx,
352 windows,
353 renderer,
354 depth_texture,
355 depth_view,
356 depth_width: 1,
357 depth_height: 1,
358 frame_count: 0,
359 })
360 });
361}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?
275fn main() {
276 logging::init();
277
278 run_app(|ctx| {
279 let tier_override = parse_tier();
280
281 // Use the capability API to configure GPU requirements.
282 // For auto-detect, request the best capability (graceful degradation).
283 // For a specific tier, require that tier's capability.
284 let descriptor = match tier_override {
285 None => GraphicsContextDescriptor::new()
286 .request_capability::<BestBatchCapability2D>(),
287 Some(RenderTier::Direct) => GraphicsContextDescriptor::new()
288 .require_capability::<DirectBatchCapability2D>(),
289 Some(RenderTier::Indirect) => GraphicsContextDescriptor::new()
290 .require_capability::<IndirectBatchCapability2D>(),
291 Some(RenderTier::Bindless) => GraphicsContextDescriptor::new()
292 .require_capability::<BindlessBatchCapability2D>(),
293 };
294 let graphics_ctx =
295 pollster::block_on(GraphicsContext::new_owned_with_descriptor(descriptor))
296 .expect("Failed to create graphics context");
297
298 let window = ctx
299 .create_window(WindowDescriptor {
300 title: "Batched Renderer Example".to_string(),
301 size: Some(WinitPhysicalSize::new(800.0, 600.0)),
302 ..Default::default()
303 })
304 .expect("Failed to create window");
305
306 let surface_format = wgpu::TextureFormat::Bgra8UnormSrgb;
307
308 let renderable_window = RenderableWindow::new_with_descriptor(
309 window,
310 graphics_ctx.clone(),
311 WindowContextDescriptor {
312 format: Some(surface_format),
313 ..Default::default()
314 },
315 )
316 .expect("Failed to create renderable window");
317
318 let window_id = renderable_window.id();
319
320 let renderer = create_batch_renderer_2d(
321 graphics_ctx.clone(),
322 surface_format,
323 tier_override,
324 );
325
326 tracing::info!("Using render tier: {}", renderer.tier());
327
328 // Create initial depth buffer
329 let depth_texture = graphics_ctx
330 .device()
331 .create_texture(&wgpu::TextureDescriptor {
332 label: Some("example_depth"),
333 size: wgpu::Extent3d {
334 width: 1,
335 height: 1,
336 depth_or_array_layers: 1,
337 },
338 mip_level_count: 1,
339 sample_count: 1,
340 dimension: wgpu::TextureDimension::D2,
341 format: DEPTH_FORMAT,
342 usage: wgpu::TextureUsages::RENDER_ATTACHMENT,
343 view_formats: &[],
344 });
345 let depth_view = depth_texture.create_view(&wgpu::TextureViewDescriptor::default());
346
347 let mut windows = HashMap::new();
348 windows.insert(window_id, renderable_window);
349
350 Box::new(App {
351 context: graphics_ctx,
352 windows,
353 renderer,
354 depth_texture,
355 depth_view,
356 depth_width: 1,
357 depth_height: 1,
358 frame_count: 0,
359 })
360 });
361}More examples
39fn main() {
40 logging::init();
41 init_profiling(ProfilingBackend::PuffinHttp);
42
43 run_app(|ctx| {
44 profile_function!();
45
46 // Request TIMESTAMP_QUERY for GPU profiling (best-effort, won't fail if unavailable)
47 let graphics_ctx = pollster::block_on(GraphicsContext::new_owned_with_descriptor(
48 GraphicsContextDescriptor::new()
49 .request_capability::<astrelis_render::gpu_profiling::GpuFrameProfiler>(),
50 ))
51 .expect("Failed to create graphics context");
52
53 let window = ctx
54 .create_window(WindowDescriptor {
55 title: "Profiling Demo — CPU + GPU".to_string(),
56 size: Some(WinitPhysicalSize::new(800.0, 600.0)),
57 ..Default::default()
58 })
59 .expect("Failed to create window");
60
61 #[allow(unused_mut)]
62 let mut window = RenderableWindow::new_with_descriptor(
63 window,
64 graphics_ctx.clone(),
65 WindowContextDescriptor {
66 format: Some(wgpu::TextureFormat::Bgra8UnormSrgb),
67 ..Default::default()
68 },
69 )
70 .expect("Failed to create renderable window");
71
72 let window_id = window.id();
73
74 // Attach GPU profiler to the window — all frames will be automatically profiled
75 let has_gpu_profiling;
76 #[cfg(feature = "gpu-profiling")]
77 {
78 match astrelis_render::gpu_profiling::GpuFrameProfiler::new(&graphics_ctx) {
79 Ok(profiler) => {
80 let has_timestamps = profiler.has_timestamp_queries();
81 window.set_gpu_profiler(Arc::new(profiler));
82 has_gpu_profiling = true;
83 if has_timestamps {
84 println!(" GPU profiling: enabled with TIMESTAMP_QUERY (full timing)");
85 } else {
86 println!(" GPU profiling: enabled (debug groups only, no timing data)");
87 println!(" TIMESTAMP_QUERY not supported by this GPU");
88 }
89 }
90 Err(e) => {
91 has_gpu_profiling = false;
92 tracing::warn!("Failed to create GPU profiler: {e}. GPU profiling disabled.");
93 println!(" GPU profiling: failed to create profiler");
94 }
95 }
96 }
97 #[cfg(not(feature = "gpu-profiling"))]
98 {
99 has_gpu_profiling = false;
100 }
101
102 println!();
103 println!("═══════════════════════════════════════════════════");
104 println!(" PROFILING DEMO — CPU + GPU");
105 println!("═══════════════════════════════════════════════════");
106 println!();
107 println!(" CPU profiling: enabled (puffin)");
108 if !has_gpu_profiling {
109 #[cfg(not(feature = "gpu-profiling"))]
110 println!(" GPU profiling: disabled (compile with --features gpu-profiling)");
111 }
112 println!();
113 println!(" Open puffin_viewer at 127.0.0.1:8585 to see the flame graph.");
114 println!(" Install with: cargo install puffin_viewer");
115 println!("═══════════════════════════════════════════════════");
116 println!();
117
118 Box::new(ProfilingDemo {
119 context: graphics_ctx,
120 window,
121 window_id,
122 frame_count: 0,
123 })
124 });
125}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 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