From cebe11ee381dc0a169f951084584a877efd451f5 Mon Sep 17 00:00:00 2001 From: Nathan Adams Date: Mon, 8 Aug 2022 14:54:34 +0200 Subject: [PATCH] wgpu: Avoid panics when attempting to create a texture larger than the device supports --- exporter/src/main.rs | 3 ++- render/wgpu/src/lib.rs | 27 ++++++++++++++++++++++++++- render/wgpu/src/target.rs | 19 ++++++++++++++++--- tests/tests/regression_tests.rs | 2 +- 4 files changed, 45 insertions(+), 6 deletions(-) diff --git a/exporter/src/main.rs b/exporter/src/main.rs index 47411c6c2..ad7d814b3 100644 --- a/exporter/src/main.rs +++ b/exporter/src/main.rs @@ -107,7 +107,8 @@ fn take_screenshot( .unwrap_or_else(|| movie.height().to_pixels()); let height = (height * size.scale).round() as u32; - let target = TextureTarget::new(&descriptors.device, (width, height)); + let target = TextureTarget::new(&descriptors.device, (width, height)) + .map_err(|e| anyhow!(e.to_string()))?; let player = PlayerBuilder::new() .with_renderer( WgpuRenderBackend::new(descriptors, target).map_err(|e| anyhow!(e.to_string()))?, diff --git a/render/wgpu/src/lib.rs b/render/wgpu/src/lib.rs index b58909586..b5595309a 100644 --- a/render/wgpu/src/lib.rs +++ b/render/wgpu/src/lib.rs @@ -395,7 +395,7 @@ impl WgpuRenderBackend { power_preference, trace_path, ))?; - let target = target::TextureTarget::new(&descriptors.device, size); + let target = target::TextureTarget::new(&descriptors.device, size)?; Self::new(Arc::new(descriptors), target) } @@ -406,6 +406,18 @@ impl WgpuRenderBackend { impl WgpuRenderBackend { pub fn new(descriptors: Arc, target: T) -> Result { + if target.width() > descriptors.limits.max_texture_dimension_2d + || target.height() > descriptors.limits.max_texture_dimension_2d + { + return Err(format!( + "Render target texture cannot be larger than {}px on either dimension (requested {} x {})", + descriptors.limits.max_texture_dimension_2d, + target.width(), + target.height() + ) + .into()); + } + let extent = wgpu::Extent3d { width: target.width(), height: target.height(), @@ -772,6 +784,7 @@ impl WgpuRenderBackend { impl RenderBackend for WgpuRenderBackend { fn set_viewport_dimensions(&mut self, width: u32, height: u32) { // Avoid panics from creating 0-sized framebuffers. + // TODO: find a way to bubble an error when the size is too large let width = std::cmp::max(width, 1); let height = std::cmp::max(height, 1); @@ -1370,6 +1383,18 @@ impl RenderBackend for WgpuRenderBackend { } fn register_bitmap(&mut self, bitmap: Bitmap) -> Result { + if bitmap.width() > self.descriptors.limits.max_texture_dimension_2d + || bitmap.height() > self.descriptors.limits.max_texture_dimension_2d + { + return Err(format!( + "Bitmap texture cannot be larger than {}px on either dimension (requested {} x {})", + self.descriptors.limits.max_texture_dimension_2d, + bitmap.width(), + bitmap.height() + ) + .into()); + } + let bitmap = bitmap.to_rgba(); let extent = wgpu::Extent3d { width: bitmap.width(), diff --git a/render/wgpu/src/target.rs b/render/wgpu/src/target.rs index deeda553f..f37d87261 100644 --- a/render/wgpu/src/target.rs +++ b/render/wgpu/src/target.rs @@ -1,5 +1,6 @@ #[cfg(not(target_family = "wasm"))] use crate::utils::BufferDimensions; +use crate::Error; use std::fmt::Debug; pub trait RenderTargetFrame: Debug { @@ -130,7 +131,18 @@ impl RenderTargetFrame for TextureTargetFrame { #[cfg(not(target_family = "wasm"))] impl TextureTarget { - pub fn new(device: &wgpu::Device, size: (u32, u32)) -> Self { + pub fn new(device: &wgpu::Device, size: (u32, u32)) -> Result { + if size.0 > device.limits().max_texture_dimension_2d + || size.1 > device.limits().max_texture_dimension_2d + { + return Err(format!( + "Texture target cannot be larger than {}px on either dimension (requested {} x {})", + device.limits().max_texture_dimension_2d, + size.0, + size.1 + ) + .into()); + } let buffer_dimensions = BufferDimensions::new(size.0 as usize, size.1 as usize); let size = wgpu::Extent3d { width: size.0, @@ -156,13 +168,13 @@ impl TextureTarget { usage: wgpu::BufferUsages::COPY_DST | wgpu::BufferUsages::MAP_READ, mapped_at_creation: false, }); - Self { + Ok(Self { size, texture, format, buffer, buffer_dimensions, - } + }) } pub fn capture(&self, device: &wgpu::Device) -> Option { @@ -204,6 +216,7 @@ impl RenderTarget for TextureTarget { type Frame = TextureTargetFrame; fn resize(&mut self, device: &wgpu::Device, width: u32, height: u32) { + // TODO: find a way to bubble an error when the size is too large self.size.width = width; self.size.height = height; diff --git a/tests/tests/regression_tests.rs b/tests/tests/regression_tests.rs index 24383f221..21589631e 100644 --- a/tests/tests/regression_tests.rs +++ b/tests/tests/regression_tests.rs @@ -1232,7 +1232,7 @@ fn run_swf( movie.width().to_pixels() as u32, movie.height().to_pixels() as u32, ), - ); + )?; builder = builder .with_renderer(WgpuRenderBackend::new(Arc::new(descriptors), target)?)