Skip to content

Commit c0879ef

Browse files
committed
[update] render context to not panic.
1 parent 3b34c26 commit c0879ef

File tree

4 files changed

+86
-14
lines changed

4 files changed

+86
-14
lines changed

crates/lambda-rs/src/render/bind.rs

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -278,7 +278,15 @@ impl<'a> BindGroupBuilder<'a> {
278278

279279
for (binding, buffer, offset, size) in self.entries.into_iter() {
280280
if let Some(sz) = size {
281-
assert!(
281+
if sz.get() > max_binding {
282+
logging::error!(
283+
"Uniform binding at binding={} requests size={} > device limit {}",
284+
binding,
285+
sz.get(),
286+
max_binding
287+
);
288+
}
289+
debug_assert!(
282290
sz.get() <= max_binding,
283291
"Uniform binding at binding={} requests size={} > device limit {}",
284292
binding,

crates/lambda-rs/src/render/mod.rs

Lines changed: 61 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,8 @@ use self::{
8282
/// to that window.
8383
pub struct RenderContextBuilder {
8484
name: String,
85+
/// Reserved for future timeout handling during rendering (nanoseconds).
86+
/// Not currently enforced; kept for forward compatibility with runtime controls.
8587
_render_timeout: u64,
8688
}
8789

@@ -102,7 +104,13 @@ impl RenderContextBuilder {
102104

103105
/// Build a `RenderContext` for the provided `window` and configure the
104106
/// presentation surface.
105-
pub fn build(self, window: &window::Window) -> RenderContext {
107+
///
108+
/// Errors are returned instead of panicking to allow callers to surface
109+
/// actionable initialization failures.
110+
pub fn build(
111+
self,
112+
window: &window::Window,
113+
) -> Result<RenderContext, RenderContextError> {
106114
let RenderContextBuilder { name, .. } = self;
107115

108116
let instance = InstanceBuilder::new()
@@ -112,12 +120,22 @@ impl RenderContextBuilder {
112120
let mut surface = SurfaceBuilder::new()
113121
.with_label(&format!("{} Surface", name))
114122
.build(&instance, window.window_handle())
115-
.expect("Failed to create rendering surface");
123+
.map_err(|e| {
124+
RenderContextError::SurfaceCreate(format!(
125+
"Failed to create rendering surface: {:?}",
126+
e
127+
))
128+
})?;
116129

117130
let gpu = GpuBuilder::new()
118131
.with_label(&format!("{} Device", name))
119132
.build(&instance, Some(&surface))
120-
.expect("Failed to create GPU device");
133+
.map_err(|e| {
134+
RenderContextError::GpuCreate(format!(
135+
"Failed to create GPU device: {:?}",
136+
e
137+
))
138+
})?;
121139

122140
let size = window.dimensions();
123141
surface
@@ -127,16 +145,22 @@ impl RenderContextBuilder {
127145
lambda_platform::wgpu::PresentMode::Fifo,
128146
lambda_platform::wgpu::TextureUsages::RENDER_ATTACHMENT,
129147
)
130-
.expect("Failed to configure surface");
131-
132-
let config = surface
133-
.configuration()
134-
.cloned()
135-
.expect("Surface was not configured");
148+
.map_err(|e| {
149+
RenderContextError::SurfaceConfig(format!(
150+
"Failed to configure surface: {:?}",
151+
e
152+
))
153+
})?;
154+
155+
let config = surface.configuration().cloned().ok_or_else(|| {
156+
RenderContextError::SurfaceConfig(
157+
"Surface was not configured".to_string(),
158+
)
159+
})?;
136160
let present_mode = config.present_mode;
137161
let texture_usage = config.usage;
138162

139-
return RenderContext {
163+
return Ok(RenderContext {
140164
label: name,
141165
instance,
142166
surface,
@@ -150,7 +174,7 @@ impl RenderContextBuilder {
150174
bind_group_layouts: vec![],
151175
bind_groups: vec![],
152176
buffers: vec![],
153-
};
177+
});
154178
}
155179
}
156180

@@ -547,3 +571,29 @@ impl From<lambda_platform::wgpu::SurfaceError> for RenderError {
547571
return RenderError::Surface(error);
548572
}
549573
}
574+
575+
#[derive(Debug)]
576+
/// Errors encountered while creating a `RenderContext`.
577+
///
578+
/// Returned by `RenderContextBuilder::build` to avoid panics during
579+
/// initialization and provide actionable error messages to callers.
580+
pub enum RenderContextError {
581+
/// Failure creating the presentation surface for the provided window.
582+
SurfaceCreate(String),
583+
/// Failure creating the logical GPU device/queue.
584+
GpuCreate(String),
585+
/// Failure configuring or retrieving the surface configuration.
586+
SurfaceConfig(String),
587+
}
588+
589+
impl core::fmt::Display for RenderContextError {
590+
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
591+
match self {
592+
RenderContextError::SurfaceCreate(s) => write!(f, "{}", s),
593+
RenderContextError::GpuCreate(s) => write!(f, "{}", s),
594+
RenderContextError::SurfaceConfig(s) => write!(f, "{}", s),
595+
}
596+
}
597+
}
598+
599+
impl std::error::Error for RenderContextError {}

crates/lambda-rs/src/render/pipeline.rs

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -184,7 +184,14 @@ impl RenderPipelineBuilder {
184184

185185
// Bind group layouts limit check
186186
let max_bind_groups = render_context.limit_max_bind_groups() as usize;
187-
assert!(
187+
if self.bind_group_layouts.len() > max_bind_groups {
188+
logging::error!(
189+
"Pipeline declares {} bind group layouts, exceeds device max {}",
190+
self.bind_group_layouts.len(),
191+
max_bind_groups
192+
);
193+
}
194+
debug_assert!(
188195
self.bind_group_layouts.len() <= max_bind_groups,
189196
"Pipeline declares {} bind group layouts, exceeds device max {}",
190197
self.bind_group_layouts.len(),

crates/lambda-rs/src/runtimes/application.rs

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -149,7 +149,14 @@ impl Runtime<(), String> for ApplicationRuntime {
149149
let mut event_loop = LoopBuilder::new().build();
150150
let window = self.window_builder.build(&mut event_loop);
151151
let mut component_stack = self.component_stack;
152-
let mut render_context = self.render_context_builder.build(&window);
152+
let mut render_context = match self.render_context_builder.build(&window) {
153+
Ok(ctx) => ctx,
154+
Err(err) => {
155+
let msg = format!("Failed to initialize render context: {}", err);
156+
logging::error!("{}", msg);
157+
return Err(msg);
158+
}
159+
};
153160
let mut active_render_context = Some(render_context);
154161

155162
let publisher = event_loop.create_event_publisher();

0 commit comments

Comments
 (0)