Skip to content

Commit 37e7304

Browse files
authored
deps(lambda-rs-platform): Update wgpu and naga to v29.0.0 (#199)
## Summary Upgrade `naga` and `wgpu` to `29.0.0` and update the `lambda-rs-platform` `wgpu` integration to compile and behave correctly with the new APIs. This includes wrapper changes required for instance creation, pipeline layout/depth state configuration, surface creation, and surface frame acquisition/error handling. ## Related Issues None. ## Changes - Bump `naga` and `wgpu` to `29.0.0` in `lambda-rs-platform` and refresh `Cargo.lock` - Update `wgpu::Instance` construction for the new `InstanceDescriptor` API - Adjust pipeline layout creation to pass optional bind group layout entries - Update depth/stencil pipeline state setup for `wgpu` 29 optional depth fields - Update unsafe surface creation to use the new raw display handle shape - Handle `CurrentSurfaceTexture` acquisition results from `wgpu` 29 - Add explicit `Occluded` and `Validation` surface error variants - Remove a now-useless `u64` conversion ## Type of Change - [x] Bug fix (non-breaking change that fixes an issue) - [ ] Feature (non-breaking change that adds functionality) - [x] Breaking change (fix or feature that would cause existing functionality to change) - [ ] Documentation (updates to docs, specs, tutorials, or comments) - [x] Refactor (code change that neither fixes a bug nor adds a feature) - [ ] Performance (change that improves performance) - [ ] Test (adding or updating tests) - [ ] Build/CI (changes to build process or CI configuration) ## Affected Crates - [x] `lambda-rs` - [x] `lambda-rs-platform` - [ ] `lambda-rs-args` - [ ] `lambda-rs-logging` - [ ] Other: ## Checklist - [x] Code follows the repository style guidelines (`cargo +nightly fmt --all`) - [ ] Code passes clippy (`cargo clippy --workspace --all-targets -- -D warnings`) - [ ] Tests pass (`cargo test --workspace`) - [x] New code includes appropriate documentation - [x] Public API changes are documented - [x] Breaking changes are noted in this PR description ## Testing **Commands run:** ```bash cargo +nightly fmt --all --check cargo clippy -p lambda-rs-platform --all-targets -- -D warnings cargo check --workspace --locked ``` ## Screenshots/Recordings Not applicable. ## Platform Testing - [x] macOS - [ ] Windows - [ ] Linux ## Additional Notes
2 parents f3c56aa + feea35a commit 37e7304

File tree

9 files changed

+231
-172
lines changed

9 files changed

+231
-172
lines changed

Cargo.lock

Lines changed: 145 additions & 133 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

crates/lambda-rs-platform/Cargo.toml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,14 +12,14 @@ path = "src/lib.rs"
1212

1313
[dependencies]
1414
winit = "=0.29.15"
15-
naga = { version = "=28.0.0", optional = true, default-features = false, features = [
15+
naga = { version = "=29.0.0", optional = true, default-features = false, features = [
1616
"spv-out",
1717
"glsl-in",
1818
"wgsl-in",
1919
] }
2020
rand = "=0.8.5"
2121
obj-rs = "=0.7.4"
22-
wgpu = { version = "=28.0.0", optional = true, features = ["wgsl", "spirv"] }
22+
wgpu = { version = "=29.0.0", optional = true, features = ["wgsl", "spirv"] }
2323
pollster = { version = "=0.4.0", optional = true }
2424
lambda-rs-logging = { path = "../lambda-rs-logging", version = "2023.1.30" }
2525
cpal = { version = "=0.17.2", optional = true }

crates/lambda-rs-platform/src/wgpu/gpu.rs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -246,8 +246,7 @@ impl Gpu {
246246
return GpuLimits {
247247
max_uniform_buffer_binding_size: self
248248
.limits
249-
.max_uniform_buffer_binding_size
250-
.into(),
249+
.max_uniform_buffer_binding_size,
251250
max_bind_groups: self.limits.max_bind_groups,
252251
max_vertex_buffers: self.limits.max_vertex_buffers,
253252
max_vertex_attributes: self.limits.max_vertex_attributes,

crates/lambda-rs-platform/src/wgpu/instance.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -167,11 +167,12 @@ impl InstanceBuilder {
167167
flags: self.flags.to_wgpu(),
168168
memory_budget_thresholds: self.memory_budget_thresholds,
169169
backend_options: self.backend_options,
170+
display: None,
170171
};
171172

172173
Instance {
173174
label: self.label,
174-
instance: wgpu::Instance::new(&descriptor),
175+
instance: wgpu::Instance::new(descriptor),
175176
}
176177
}
177178
}

crates/lambda-rs-platform/src/wgpu/pipeline.rs

Lines changed: 18 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -305,7 +305,7 @@ fn align_up_u32(value: u32, alignment: u32) -> u32 {
305305

306306
/// Validate immediate ranges and calculate the minimum allocation size.
307307
///
308-
/// wgpu v28 uses a single byte region of size `immediate_size`, addressed by
308+
/// wgpu uses a single byte region of size `immediate_size`, addressed by
309309
/// `set_immediates(offset, data)`. This function enforces that the provided
310310
/// ranges:
311311
/// - Start at byte offset 0 (as a union)
@@ -408,10 +408,13 @@ impl<'a> PipelineLayoutBuilder<'a> {
408408

409409
/// Build the layout.
410410
pub fn build(self, gpu: &Gpu) -> PipelineLayout {
411-
let layouts_raw: Vec<&wgpu::BindGroupLayout> =
412-
self.layouts.iter().map(|l| l.raw()).collect();
411+
let layouts_raw: Vec<Option<&wgpu::BindGroupLayout>> = self
412+
.layouts
413+
.iter()
414+
.map(|layout| Some(layout.raw()))
415+
.collect();
413416

414-
// wgpu v28 allocates a single immediate byte region sized by
417+
// wgpu allocates a single immediate byte region sized by
415418
// `PipelineLayoutDescriptor::immediate_size`. If callers provide multiple
416419
// ranges, they are treated as sub-ranges of the same contiguous allocation.
417420
//
@@ -442,7 +445,7 @@ impl<'a> PipelineLayoutBuilder<'a> {
442445
.device()
443446
.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor {
444447
label: self.label.as_deref(),
445-
bind_group_layouts: &layouts_raw,
448+
bind_group_layouts: layouts_raw.as_slice(),
446449
immediate_size,
447450
});
448451
if fallback_used {
@@ -625,8 +628,8 @@ impl<'a> RenderPipelineBuilder<'a> {
625628
pub fn with_depth_stencil(mut self, format: DepthFormat) -> Self {
626629
self.depth_stencil = Some(wgpu::DepthStencilState {
627630
format: format.to_wgpu(),
628-
depth_write_enabled: true,
629-
depth_compare: wgpu::CompareFunction::Less,
631+
depth_write_enabled: Some(true),
632+
depth_compare: Some(wgpu::CompareFunction::Less),
630633
stencil: wgpu::StencilState::default(),
631634
bias: wgpu::DepthBiasState::default(),
632635
});
@@ -637,34 +640,34 @@ impl<'a> RenderPipelineBuilder<'a> {
637640
pub fn with_depth_compare(mut self, compare: CompareFunction) -> Self {
638641
let ds = self.depth_stencil.get_or_insert(wgpu::DepthStencilState {
639642
format: wgpu::TextureFormat::Depth32Float,
640-
depth_write_enabled: true,
641-
depth_compare: wgpu::CompareFunction::Less,
643+
depth_write_enabled: Some(true),
644+
depth_compare: Some(wgpu::CompareFunction::Less),
642645
stencil: wgpu::StencilState::default(),
643646
bias: wgpu::DepthBiasState::default(),
644647
});
645-
ds.depth_compare = compare.to_wgpu();
648+
ds.depth_compare = Some(compare.to_wgpu());
646649
return self;
647650
}
648651

649652
/// Enable or disable depth writes. Requires depth-stencil enabled.
650653
pub fn with_depth_write_enabled(mut self, enabled: bool) -> Self {
651654
let ds = self.depth_stencil.get_or_insert(wgpu::DepthStencilState {
652655
format: wgpu::TextureFormat::Depth32Float,
653-
depth_write_enabled: true,
654-
depth_compare: wgpu::CompareFunction::Less,
656+
depth_write_enabled: Some(true),
657+
depth_compare: Some(wgpu::CompareFunction::Less),
655658
stencil: wgpu::StencilState::default(),
656659
bias: wgpu::DepthBiasState::default(),
657660
});
658-
ds.depth_write_enabled = enabled;
661+
ds.depth_write_enabled = Some(enabled);
659662
return self;
660663
}
661664

662665
/// Configure stencil state (front/back ops and masks). Requires depth-stencil enabled.
663666
pub fn with_stencil(mut self, stencil: StencilState) -> Self {
664667
let ds = self.depth_stencil.get_or_insert(wgpu::DepthStencilState {
665668
format: wgpu::TextureFormat::Depth24PlusStencil8,
666-
depth_write_enabled: true,
667-
depth_compare: wgpu::CompareFunction::Less,
669+
depth_write_enabled: Some(true),
670+
depth_compare: Some(wgpu::CompareFunction::Less),
668671
stencil: wgpu::StencilState::default(),
669672
bias: wgpu::DepthBiasState::default(),
670673
});

crates/lambda-rs-platform/src/wgpu/render_pass.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -431,7 +431,7 @@ impl<'a> RenderPass<'a> {
431431

432432
/// Set immediate data for subsequent draw calls.
433433
///
434-
/// This is the wgpu v28 replacement for push constants. The `offset` and
434+
/// This is the current wgpu replacement for push constants. The `offset` and
435435
/// `data` length MUST be multiples of 4 bytes (IMMEDIATE_DATA_ALIGNMENT).
436436
pub fn set_immediates(&mut self, offset: u32, data: &[u8]) {
437437
self.raw.set_immediates(offset, data);

crates/lambda-rs-platform/src/wgpu/surface.rs

Lines changed: 34 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -97,23 +97,14 @@ pub enum SurfaceError {
9797
OutOfMemory,
9898
/// Timed out waiting for a frame.
9999
Timeout,
100+
/// The window is occluded and cannot currently present.
101+
Occluded,
102+
/// Surface acquisition triggered a validation error.
103+
Validation,
100104
/// Other/unclassified error (opaque).
101105
Other(String),
102106
}
103107

104-
impl From<wgpu::SurfaceError> for SurfaceError {
105-
fn from(error: wgpu::SurfaceError) -> Self {
106-
use wgpu::SurfaceError as We;
107-
match error {
108-
We::Lost => return SurfaceError::Lost,
109-
We::Outdated => return SurfaceError::Outdated,
110-
We::OutOfMemory => return SurfaceError::OutOfMemory,
111-
We::Timeout => return SurfaceError::Timeout,
112-
_ => return SurfaceError::Other(format!("{:?}", error)),
113-
}
114-
}
115-
}
116-
117108
/// Builder for creating a `Surface` bound to a `winit` window.
118109
#[derive(Debug, Clone)]
119110
pub struct SurfaceBuilder {
@@ -160,7 +151,7 @@ impl SurfaceBuilder {
160151
instance
161152
.raw()
162153
.create_surface_unsafe(wgpu::SurfaceTargetUnsafe::RawHandle {
163-
raw_display_handle,
154+
raw_display_handle: Some(raw_display_handle),
164155
raw_window_handle,
165156
})
166157
.map_err(CreateSurfaceError::from)?
@@ -298,15 +289,34 @@ impl<'window> Surface<'window> {
298289

299290
/// Acquire the next swapchain texture and a default view.
300291
pub fn acquire_next_frame(&self) -> Result<Frame, SurfaceError> {
301-
let texture = match self.surface.get_current_texture() {
302-
Ok(t) => t,
303-
Err(e) => return Err(SurfaceError::from(e)),
292+
let (texture, suboptimal) = match self.surface.get_current_texture() {
293+
wgpu::CurrentSurfaceTexture::Success(texture) => (texture, false),
294+
wgpu::CurrentSurfaceTexture::Suboptimal(texture) => (texture, true),
295+
wgpu::CurrentSurfaceTexture::Timeout => {
296+
return Err(SurfaceError::Timeout);
297+
}
298+
wgpu::CurrentSurfaceTexture::Outdated => {
299+
return Err(SurfaceError::Outdated);
300+
}
301+
wgpu::CurrentSurfaceTexture::Lost => {
302+
return Err(SurfaceError::Lost);
303+
}
304+
wgpu::CurrentSurfaceTexture::Occluded => {
305+
return Err(SurfaceError::Occluded);
306+
}
307+
wgpu::CurrentSurfaceTexture::Validation => {
308+
return Err(SurfaceError::Validation);
309+
}
304310
};
305311
let view = texture
306312
.texture
307313
.create_view(&wgpu::TextureViewDescriptor::default());
308314

309-
return Ok(Frame { texture, view });
315+
return Ok(Frame {
316+
texture,
317+
view,
318+
suboptimal,
319+
});
310320
}
311321
}
312322

@@ -383,6 +393,7 @@ fn select_present_mode(
383393
pub struct Frame {
384394
texture: wgpu::SurfaceTexture,
385395
view: wgpu::TextureView,
396+
suboptimal: bool,
386397
}
387398

388399
/// Borrowed reference to a texture view used for render passes.
@@ -397,6 +408,11 @@ impl Frame {
397408
return TextureViewRef { raw: &self.view };
398409
}
399410

411+
/// Whether this frame was acquired in a suboptimal surface state.
412+
pub fn is_suboptimal(&self) -> bool {
413+
return self.suboptimal;
414+
}
415+
400416
/// Present the frame to the swapchain.
401417
pub fn present(self) {
402418
self.texture.present();

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

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -177,6 +177,10 @@ pub enum SurfaceError {
177177
OutOfMemory,
178178
/// Timed out waiting for a frame.
179179
Timeout,
180+
/// The window is occluded and cannot currently present.
181+
Occluded,
182+
/// Surface acquisition triggered a validation error.
183+
Validation,
180184
/// Other/unclassified error.
181185
Other(String),
182186
}
@@ -188,6 +192,8 @@ impl From<platform_surface::SurfaceError> for SurfaceError {
188192
platform_surface::SurfaceError::Outdated => SurfaceError::Outdated,
189193
platform_surface::SurfaceError::OutOfMemory => SurfaceError::OutOfMemory,
190194
platform_surface::SurfaceError::Timeout => SurfaceError::Timeout,
195+
platform_surface::SurfaceError::Occluded => SurfaceError::Occluded,
196+
platform_surface::SurfaceError::Validation => SurfaceError::Validation,
191197
platform_surface::SurfaceError::Other(msg) => SurfaceError::Other(msg),
192198
};
193199
}
@@ -236,6 +242,14 @@ mod tests {
236242
SurfaceError::from(platform_surface::SurfaceError::Timeout),
237243
SurfaceError::Timeout
238244
));
245+
assert!(matches!(
246+
SurfaceError::from(platform_surface::SurfaceError::Occluded),
247+
SurfaceError::Occluded
248+
));
249+
assert!(matches!(
250+
SurfaceError::from(platform_surface::SurfaceError::Validation),
251+
SurfaceError::Validation
252+
));
239253

240254
let other = SurfaceError::from(platform_surface::SurfaceError::Other(
241255
"opaque".to_string(),

crates/lambda-rs/src/render/targets/surface.rs

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -199,6 +199,10 @@ pub enum SurfaceError {
199199
OutOfMemory,
200200
/// Timed out waiting for a frame.
201201
Timeout,
202+
/// The window is occluded and cannot currently present.
203+
Occluded,
204+
/// Surface acquisition triggered a validation error.
205+
Validation,
202206
/// Other/unclassified error.
203207
Other(String),
204208
}
@@ -210,6 +214,8 @@ impl From<platform::surface::SurfaceError> for SurfaceError {
210214
platform::surface::SurfaceError::Outdated => SurfaceError::Outdated,
211215
platform::surface::SurfaceError::OutOfMemory => SurfaceError::OutOfMemory,
212216
platform::surface::SurfaceError::Timeout => SurfaceError::Timeout,
217+
platform::surface::SurfaceError::Occluded => SurfaceError::Occluded,
218+
platform::surface::SurfaceError::Validation => SurfaceError::Validation,
213219
platform::surface::SurfaceError::Other(msg) => SurfaceError::Other(msg),
214220
};
215221
}
@@ -415,6 +421,14 @@ mod tests {
415421
SurfaceError::from(platform::surface::SurfaceError::Timeout),
416422
SurfaceError::Timeout
417423
));
424+
assert!(matches!(
425+
SurfaceError::from(platform::surface::SurfaceError::Occluded),
426+
SurfaceError::Occluded
427+
));
428+
assert!(matches!(
429+
SurfaceError::from(platform::surface::SurfaceError::Validation),
430+
SurfaceError::Validation
431+
));
418432
let other = SurfaceError::from(platform::surface::SurfaceError::Other(
419433
"opaque".to_string(),
420434
));

0 commit comments

Comments
 (0)