From 7cab1747ee9af95816a5ca4dcd6eabecf65bbdcc Mon Sep 17 00:00:00 2001 From: Ebbe Steenhoudt Date: Fri, 18 Apr 2025 15:17:53 +0200 Subject: [PATCH] Loosen Viewport validation requirements to match the new specs (#7564) --- CHANGELOG.md | 2 ++ tests/tests/wgpu-gpu/encoder.rs | 2 +- wgpu-core/src/command/draw.rs | 6 ++++-- wgpu-core/src/command/render.rs | 33 ++++++++++++++++++++++++++------- 4 files changed, 33 insertions(+), 10 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c2cc78b621..94afe7bc5f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -59,6 +59,8 @@ Naga now infers the correct binding layout when a resource appears only in an as ### Changes +- Loosen Viewport validation requirements to match the [new specs](https://github.com/gpuweb/gpuweb/pull/5025). By @ebbdrop in [#7564](https://github.com/gfx-rs/wgpu/pull/7564) + #### General - Removed `MaintainBase` in favor of using `PollType`. By @waywardmonkeys in [#7508](https://github.com/gfx-rs/wgpu/pull/7508). diff --git a/tests/tests/wgpu-gpu/encoder.rs b/tests/tests/wgpu-gpu/encoder.rs index c832edd973..82fd1eda12 100644 --- a/tests/tests/wgpu-gpu/encoder.rs +++ b/tests/tests/wgpu-gpu/encoder.rs @@ -68,7 +68,7 @@ static DROP_ENCODER_AFTER_ERROR: GpuTestConfiguration = GpuTestConfiguration::ne renderpass.set_viewport(0.0, 0.0, -1.0, -1.0, 0.0, 1.0); drop(renderpass); }, - Some("viewport has invalid rect"), + Some("less than zero"), ); // This is the actual interesting error condition. We've created diff --git a/wgpu-core/src/command/draw.rs b/wgpu-core/src/command/draw.rs index d2bdd19038..3b32b21e0e 100644 --- a/wgpu-core/src/command/draw.rs +++ b/wgpu-core/src/command/draw.rs @@ -81,8 +81,10 @@ pub enum RenderCommandError { MissingTextureUsage(#[from] MissingTextureUsageError), #[error(transparent)] PushConstants(#[from] PushConstantUploadError), - #[error("Viewport has invalid rect {0:?}; origin and/or size is less than or equal to 0, and/or is not contained in the render target {1:?}")] - InvalidViewportRect(Rect, wgt::Extent3d), + #[error("Viewport size {{ w: {w}, h: {h} }} greater than device's requested `max_texture_dimension_2d` limit {max}, or less than zero")] + InvalidViewportRectSize { w: f32, h: f32, max: u32 }, + #[error("Viewport has invalid rect {rect:?} for device's requested `max_texture_dimension_2d` limit; Origin less than -2 * `max_texture_dimension_2d` ({min}), or rect extends past 2 * `max_texture_dimension_2d` - 1 ({max})")] + InvalidViewportRectPosition { rect: Rect, min: f32, max: f32 }, #[error("Viewport minDepth {0} and/or maxDepth {1} are not in [0, 1]")] InvalidViewportDepth(f32, f32), #[error("Scissor {0:?} is not contained in the render target {1:?}")] diff --git a/wgpu-core/src/command/render.rs b/wgpu-core/src/command/render.rs index dcb2a465a3..46d84773c7 100644 --- a/wgpu-core/src/command/render.rs +++ b/wgpu-core/src/command/render.rs @@ -2347,14 +2347,33 @@ fn set_viewport( depth_max: f32, ) -> Result<(), RenderPassErrorInner> { api_log!("RenderPass::set_viewport {rect:?}"); - if rect.x < 0.0 - || rect.y < 0.0 - || rect.w <= 0.0 - || rect.h <= 0.0 - || rect.x + rect.w > state.info.extent.width as f32 - || rect.y + rect.h > state.info.extent.height as f32 + + if rect.w < 0.0 + || rect.h < 0.0 + || rect.w > state.device.limits.max_texture_dimension_2d as f32 + || rect.h > state.device.limits.max_texture_dimension_2d as f32 { - return Err(RenderCommandError::InvalidViewportRect(rect, state.info.extent).into()); + return Err(RenderCommandError::InvalidViewportRectSize { + w: rect.w, + h: rect.h, + max: state.device.limits.max_texture_dimension_2d, + } + .into()); + } + + let max_viewport_range = state.device.limits.max_texture_dimension_2d as f32 * 2.0; + + if rect.x < -max_viewport_range + || rect.y < -max_viewport_range + || rect.x + rect.w > max_viewport_range - 1.0 + || rect.y + rect.h > max_viewport_range - 1.0 + { + return Err(RenderCommandError::InvalidViewportRectPosition { + rect, + min: -max_viewport_range, + max: max_viewport_range - 1.0, + } + .into()); } if !(0.0..=1.0).contains(&depth_min) || !(0.0..=1.0).contains(&depth_max) { return Err(RenderCommandError::InvalidViewportDepth(depth_min, depth_max).into());