wgpu: Avoid panics when attempting to create a texture larger than the device supports

This commit is contained in:
Nathan Adams 2022-08-08 14:54:34 +02:00 committed by Mike Welsh
parent ef4a955e65
commit cebe11ee38
4 changed files with 45 additions and 6 deletions

View File

@ -107,7 +107,8 @@ fn take_screenshot(
.unwrap_or_else(|| movie.height().to_pixels()); .unwrap_or_else(|| movie.height().to_pixels());
let height = (height * size.scale).round() as u32; 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() let player = PlayerBuilder::new()
.with_renderer( .with_renderer(
WgpuRenderBackend::new(descriptors, target).map_err(|e| anyhow!(e.to_string()))?, WgpuRenderBackend::new(descriptors, target).map_err(|e| anyhow!(e.to_string()))?,

View File

@ -395,7 +395,7 @@ impl WgpuRenderBackend<target::TextureTarget> {
power_preference, power_preference,
trace_path, trace_path,
))?; ))?;
let target = target::TextureTarget::new(&descriptors.device, size); let target = target::TextureTarget::new(&descriptors.device, size)?;
Self::new(Arc::new(descriptors), target) Self::new(Arc::new(descriptors), target)
} }
@ -406,6 +406,18 @@ impl WgpuRenderBackend<target::TextureTarget> {
impl<T: RenderTarget> WgpuRenderBackend<T> { impl<T: RenderTarget> WgpuRenderBackend<T> {
pub fn new(descriptors: Arc<Descriptors>, target: T) -> Result<Self, Error> { pub fn new(descriptors: Arc<Descriptors>, target: T) -> Result<Self, Error> {
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 { let extent = wgpu::Extent3d {
width: target.width(), width: target.width(),
height: target.height(), height: target.height(),
@ -772,6 +784,7 @@ impl<T: RenderTarget> WgpuRenderBackend<T> {
impl<T: RenderTarget + 'static> RenderBackend for WgpuRenderBackend<T> { impl<T: RenderTarget + 'static> RenderBackend for WgpuRenderBackend<T> {
fn set_viewport_dimensions(&mut self, width: u32, height: u32) { fn set_viewport_dimensions(&mut self, width: u32, height: u32) {
// Avoid panics from creating 0-sized framebuffers. // 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 width = std::cmp::max(width, 1);
let height = std::cmp::max(height, 1); let height = std::cmp::max(height, 1);
@ -1370,6 +1383,18 @@ impl<T: RenderTarget + 'static> RenderBackend for WgpuRenderBackend<T> {
} }
fn register_bitmap(&mut self, bitmap: Bitmap) -> Result<BitmapHandle, Error> { fn register_bitmap(&mut self, bitmap: Bitmap) -> Result<BitmapHandle, Error> {
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 bitmap = bitmap.to_rgba();
let extent = wgpu::Extent3d { let extent = wgpu::Extent3d {
width: bitmap.width(), width: bitmap.width(),

View File

@ -1,5 +1,6 @@
#[cfg(not(target_family = "wasm"))] #[cfg(not(target_family = "wasm"))]
use crate::utils::BufferDimensions; use crate::utils::BufferDimensions;
use crate::Error;
use std::fmt::Debug; use std::fmt::Debug;
pub trait RenderTargetFrame: Debug { pub trait RenderTargetFrame: Debug {
@ -130,7 +131,18 @@ impl RenderTargetFrame for TextureTargetFrame {
#[cfg(not(target_family = "wasm"))] #[cfg(not(target_family = "wasm"))]
impl TextureTarget { impl TextureTarget {
pub fn new(device: &wgpu::Device, size: (u32, u32)) -> Self { pub fn new(device: &wgpu::Device, size: (u32, u32)) -> Result<Self, Error> {
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 buffer_dimensions = BufferDimensions::new(size.0 as usize, size.1 as usize);
let size = wgpu::Extent3d { let size = wgpu::Extent3d {
width: size.0, width: size.0,
@ -156,13 +168,13 @@ impl TextureTarget {
usage: wgpu::BufferUsages::COPY_DST | wgpu::BufferUsages::MAP_READ, usage: wgpu::BufferUsages::COPY_DST | wgpu::BufferUsages::MAP_READ,
mapped_at_creation: false, mapped_at_creation: false,
}); });
Self { Ok(Self {
size, size,
texture, texture,
format, format,
buffer, buffer,
buffer_dimensions, buffer_dimensions,
} })
} }
pub fn capture(&self, device: &wgpu::Device) -> Option<image::RgbaImage> { pub fn capture(&self, device: &wgpu::Device) -> Option<image::RgbaImage> {
@ -204,6 +216,7 @@ impl RenderTarget for TextureTarget {
type Frame = TextureTargetFrame; type Frame = TextureTargetFrame;
fn resize(&mut self, device: &wgpu::Device, width: u32, height: u32) { 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.width = width;
self.size.height = height; self.size.height = height;

View File

@ -1232,7 +1232,7 @@ fn run_swf(
movie.width().to_pixels() as u32, movie.width().to_pixels() as u32,
movie.height().to_pixels() as u32, movie.height().to_pixels() as u32,
), ),
); )?;
builder = builder builder = builder
.with_renderer(WgpuRenderBackend::new(Arc::new(descriptors), target)?) .with_renderer(WgpuRenderBackend::new(Arc::new(descriptors), target)?)