From 25fac2bcd57a507b7de10c29fa29335df2995d7a Mon Sep 17 00:00:00 2001 From: Simon Hausmann Date: Tue, 3 Aug 2021 11:12:06 +0200 Subject: [PATCH] GL backend: Avoid run-time opengl errors with clipped zero width or height rectangles If a Rectangle has a border-radius and clipping, we use an FBO to render the children and then use femtovg's stencil clipping. If the Rectangle has a zero width or height, we would end up trying to create a texture with such dimensions, which produces run-time opengl errors. We can detect this situation and avoid it early on. The same might happen for shadows. Fixes #377 --- .../rendering_backends/gl/images.rs | 10 ++++++++-- sixtyfps_runtime/rendering_backends/gl/lib.rs | 18 ++++++++++++------ 2 files changed, 20 insertions(+), 8 deletions(-) diff --git a/sixtyfps_runtime/rendering_backends/gl/images.rs b/sixtyfps_runtime/rendering_backends/gl/images.rs index 471420a87..93ee1836d 100644 --- a/sixtyfps_runtime/rendering_backends/gl/images.rs +++ b/sixtyfps_runtime/rendering_backends/gl/images.rs @@ -139,7 +139,10 @@ impl CachedImage { Self(RefCell::new(Texture { id: image_id, canvas: canvas.clone() }.into())) } - pub fn new_empty_on_gpu(canvas: &CanvasRc, width: usize, height: usize) -> Self { + pub fn new_empty_on_gpu(canvas: &CanvasRc, width: usize, height: usize) -> Option { + if width == 0 || height == 0 { + return None; + } let image_id = canvas .borrow_mut() .create_image_empty( @@ -149,7 +152,7 @@ impl CachedImage { femtovg::ImageFlags::PREMULTIPLIED | femtovg::ImageFlags::FLIP_Y, ) .unwrap(); - Self::new_on_gpu(canvas, image_id) + Self::new_on_gpu(canvas, image_id).into() } #[cfg(feature = "svg")] @@ -352,6 +355,9 @@ impl CachedImage { &canvas, size.width.ceil() as usize, size.height.ceil() as usize, + ) + .expect( + "internal error: this can only fail if the filtered image was zero width or height", ); let filtered_image_id = match &*filtered_image.0.borrow() { diff --git a/sixtyfps_runtime/rendering_backends/gl/lib.rs b/sixtyfps_runtime/rendering_backends/gl/lib.rs index 8b93cacf0..be671184f 100644 --- a/sixtyfps_runtime/rendering_backends/gl/lib.rs +++ b/sixtyfps_runtime/rendering_backends/gl/lib.rs @@ -934,7 +934,7 @@ impl ItemRenderer for GLItemRenderer { return; } - let cache_entry = self + let cache_entry = match self .graphics_window .graphics_cache .borrow_mut() @@ -961,7 +961,7 @@ impl ItemRenderer for GLItemRenderer { &self.shared_data.canvas, shadow_image_width, shadow_image_height, - ); + )?; { let mut canvas = self.shared_data.canvas.borrow_mut(); @@ -1033,8 +1033,10 @@ impl ItemRenderer for GLItemRenderer { Rc::new(shadow_image) }) .into() - }) - .expect("internal error: creation of the cached shadow image must always succeed"); + }) { + Some(cached_shadow_image) => cached_shadow_image, + None => return, // Zero width or height shadow + }; let shadow_image = cache_entry.as_image(); @@ -1514,11 +1516,15 @@ impl GLItemRenderer { let layer_width = path_bounds.maxx - path_bounds.minx; let layer_height = path_bounds.maxy - path_bounds.miny; - let clip_buffer_img = CachedImage::new_empty_on_gpu( + let clip_buffer_img = match CachedImage::new_empty_on_gpu( &self.shared_data.canvas, layer_width as _, layer_height as _, - ); + ) { + Some(clip_buffer) => clip_buffer, + None => return, // Zero width or height clip path + }; + { let mut canvas = self.shared_data.canvas.borrow_mut();