Fix GPU out-of-memory crash by reusing overlay textures (#3614)

* Refactor TargetTexture into proper abstraction with ensure_size() method

* Remove redundant overlays_texture field, use view() directly

* Use if-let syntax in render_vello_scene_to_target_texture to avoid explicit unwrap

* Implement TargetTexture::new() constructor to avoid dummy textures

* fix compile error

* cleanup

* Avoid cloning texture view

---------

Co-authored-by: Timon <me@timon.zip>
Co-authored-by: Dennis Kobert <dennis@kobert.dev>
This commit is contained in:
Mohammed Afreed baig
2026-01-26 18:14:41 +05:30
committed by GitHub
parent a88342b8da
commit c07124332b
3 changed files with 94 additions and 61 deletions

View File

@@ -1,6 +1,7 @@
use crate::window::Window;
use std::borrow::Cow;
use crate::wrapper::{Color, WgpuContext, WgpuExecutor};
use crate::window::Window;
use crate::wrapper::{Color, TargetTexture, WgpuContext, WgpuExecutor};
#[derive(derivative::Derivative)]
#[derivative(Debug)]
@@ -17,7 +18,7 @@ pub(crate) struct RenderState {
viewport_scale: [f32; 2],
viewport_offset: [f32; 2],
viewport_texture: Option<wgpu::Texture>,
overlays_texture: Option<wgpu::Texture>,
overlays_texture: Option<TargetTexture>,
ui_texture: Option<wgpu::Texture>,
bind_group: Option<wgpu::BindGroup>,
#[derivative(Debug = "ignore")]
@@ -208,11 +209,6 @@ impl RenderState {
self.update_bindgroup();
}
pub(crate) fn bind_overlays_texture(&mut self, overlays_texture: wgpu::Texture) {
self.overlays_texture = Some(overlays_texture);
self.update_bindgroup();
}
pub(crate) fn bind_ui_texture(&mut self, bind_ui_texture: wgpu::Texture) {
self.ui_texture = Some(bind_ui_texture);
self.update_bindgroup();
@@ -236,12 +232,15 @@ impl RenderState {
return;
};
let size = glam::UVec2::new(viewport_texture.width(), viewport_texture.height());
let texture = futures::executor::block_on(self.executor.render_vello_scene_to_texture(&scene, size, &Default::default(), Color::TRANSPARENT));
let Ok(texture) = texture else {
tracing::error!("Error rendering overlays");
let result = futures::executor::block_on(
self.executor
.render_vello_scene_to_target_texture(&scene, size, &Default::default(), Color::TRANSPARENT, &mut self.overlays_texture),
);
if let Err(e) = result {
tracing::error!("Error rendering overlays: {:?}", e);
return;
};
self.bind_overlays_texture(texture);
}
self.update_bindgroup();
}
pub(crate) fn render(&mut self, window: &Window) -> Result<(), RenderError> {
@@ -312,7 +311,11 @@ impl RenderState {
fn update_bindgroup(&mut self) {
let viewport_texture_view = self.viewport_texture.as_ref().unwrap_or(&self.transparent_texture).create_view(&wgpu::TextureViewDescriptor::default());
let overlays_texture_view = self.overlays_texture.as_ref().unwrap_or(&self.transparent_texture).create_view(&wgpu::TextureViewDescriptor::default());
let overlays_texture_view = self
.overlays_texture
.as_ref()
.map(|target| Cow::Borrowed(target.view()))
.unwrap_or_else(|| Cow::Owned(self.transparent_texture.create_view(&wgpu::TextureViewDescriptor::default())));
let ui_texture_view = self.ui_texture.as_ref().unwrap_or(&self.transparent_texture).create_view(&wgpu::TextureViewDescriptor::default());
let bind_group = self.context.device.create_bind_group(&wgpu::BindGroupDescriptor {
@@ -324,7 +327,7 @@ impl RenderState {
},
wgpu::BindGroupEntry {
binding: 1,
resource: wgpu::BindingResource::TextureView(&overlays_texture_view),
resource: wgpu::BindingResource::TextureView(&overlays_texture_view.as_ref()),
},
wgpu::BindGroupEntry {
binding: 2,