Renderer: skip a frame the GPU won't stage instead of crashing (#1469) (#1579)

Thanks @DuBearte.
This commit is contained in:
DuBearte authored and GitHub committed 2026-10-16 00:27:33 -04:00
1 parent c419dec76c
commit 3fe929e91c
3 files changed
+23 -4

No files matched your search

+2
View File
@@ -147,6 +147,8 @@ SolidCraft changes:
- `src/lib.rs`: use 1x MSAA on the selected OpenGL adapter before creating pipelines,
exposing the effective sample count so host paint callbacks can match it.
- `src/winit.rs`: use that same effective count for depth and resolve attachments.
- `src/renderer.rs`: when the GPU refuses a staging buffer for a frame's meshes (device lost
or out of memory), log a warning and draw nothing that frame instead of panicking (#1469).
- Other backends retain requested MSAA, without another adapter or device probe.
- `src/lib.rs`: clamp MSAA to the largest sample count the device supports for the surface and
depth formats (`supported_msaa_samples`, `RenderState::msaa_supported`): a saved 8x on a
+19 -4
View File
@@ -254,6 +254,11 @@ pub struct Renderer {
options: RendererOptions,
/// The last `update_buffers` could not upload this frame's meshes (the GPU refused a
/// staging buffer: device lost or out of memory), so `render` draws nothing this frame
/// instead of panicking (SolidCraft #1469).
skip_frame: bool,
/// Storage for resources shared with all invocations of [`CallbackTrait`]'s methods.
///
/// See also [`CallbackTrait`].
@@ -453,6 +458,7 @@ impl Renderer {
slices: Vec::with_capacity(64),
capacity: INDEX_BUFFER_START_CAPACITY,
},
skip_frame: false,
uniform_buffer,
// Buffers on wgpu are zero initialized, so this is indeed its current state!
previous_uniform_buffer_content: UniformBuffer::zeroed(),
@@ -484,6 +490,10 @@ impl Renderer {
) {
profiling::function_scope!();
if self.skip_frame {
return;
}
let pixels_per_point = screen_descriptor.pixels_per_point;
let size_in_pixels = screen_descriptor.size_in_pixels;
@@ -922,6 +932,7 @@ impl Renderer {
) -> Vec<wgpu::CommandBuffer> {
profiling::function_scope!();
self.skip_frame = false;
let screen_size_in_points = screen_descriptor.screen_size_in_points();
let uniform_buffer_content = UniformBuffer {
@@ -981,11 +992,13 @@ impl Renderer {
);
let Some(mut index_buffer_staging) = index_buffer_staging else {
panic!(
"Failed to create staging buffer for index data. Index count: {index_count}. Required index buffer size: {required_index_buffer_size}. Actual size {} and capacity: {} (bytes)",
log::warn!(
"Failed to create staging buffer for index data; skipping this frame. Index count: {index_count}. Required index buffer size: {required_index_buffer_size}. Actual size {} and capacity: {} (bytes)",
self.index_buffer.buffer.size(),
self.index_buffer.capacity
);
self.skip_frame = true;
return Vec::new();
};
let mut index_offset = 0;
@@ -1027,11 +1040,13 @@ impl Renderer {
);
let Some(mut vertex_buffer_staging) = vertex_buffer_staging else {
panic!(
"Failed to create staging buffer for vertex data. Vertex count: {vertex_count}. Required vertex buffer size: {required_vertex_buffer_size}. Actual size {} and capacity: {} (bytes)",
log::warn!(
"Failed to create staging buffer for vertex data; skipping this frame. Vertex count: {vertex_count}. Required vertex buffer size: {required_vertex_buffer_size}. Actual size {} and capacity: {} (bytes)",
self.vertex_buffer.buffer.size(),
self.vertex_buffer.capacity
);
self.skip_frame = true;
return Vec::new();
};
let mut vertex_offset = 0;