wgpu: Fixed panic when rendering texture to itself, by always rendering to an intermediary

This commit is contained in:
Nathan Adams 2023-03-27 12:19:27 +02:00
parent 68343369a3
commit c85910b46d
3 changed files with 77 additions and 101 deletions

View File

@ -402,9 +402,7 @@ mod wrapper {
}
pub fn render(&self, smoothing: bool, context: &mut RenderContext<'_, 'gc>) {
// if try_write fails,
// this is caused by recursive render attempt. TODO: support this.
if let Ok(mut inner_bitmap_data) = self.0.try_write(context.gc_context) {
let mut inner_bitmap_data = self.0.write(context.gc_context);
if inner_bitmap_data.disposed() {
return;
}
@ -416,14 +414,9 @@ mod wrapper {
.bitmap_handle(context.renderer)
.expect("Missing bitmap handle");
context.commands.render_bitmap(
handle,
context.transform_stack.transform(),
smoothing,
);
} else {
//this is caused by recursive render attempt. TODO: support this.
}
context
.commands
.render_bitmap(handle, context.transform_stack.transform(), smoothing);
}
pub fn is_point_in_bounds(&self, x: i32, y: i32) -> bool {

View File

@ -111,7 +111,6 @@ impl Surface {
let mut buffers = vec![draw_encoder.finish()];
if let RenderTargetMode::FreshBuffer(_) = render_target_mode {
let mut copy_encoder =
descriptors
.device
@ -131,7 +130,6 @@ impl Surface {
&mut copy_encoder,
);
buffers.push(copy_encoder.finish());
}
buffers.insert(0, uniform_encoder.finish());
uniform_buffer.finish();

View File

@ -28,6 +28,7 @@ impl ResolveBuffer {
}
}
#[allow(dead_code)]
pub fn new_manual(texture: Arc<wgpu::Texture>) -> Self {
Self {
texture: PoolOrArcTexture::Manual((
@ -69,6 +70,7 @@ pub struct FrameBuffer {
/// (when doing an offscreen render to a BitmapData texture)
pub enum PoolOrArcTexture {
Pool(PoolEntry<(wgpu::Texture, wgpu::TextureView), AlwaysCompatible>),
#[allow(dead_code)]
Manual((Arc<wgpu::Texture>, wgpu::TextureView)),
}
@ -98,6 +100,7 @@ impl FrameBuffer {
}
}
#[allow(dead_code)]
pub fn new_manual(texture: Arc<wgpu::Texture>, size: wgpu::Extent3d) -> Self {
Self {
texture: PoolOrArcTexture::Manual((
@ -232,11 +235,6 @@ impl CommandTarget {
let whole_frame_bind_group = OnceCell::new();
let (frame_buffer, resolve_buffer) = match &render_target_mode {
// In `FreshBuffer` mode, get a new frame buffer (and resolve buffer, if necessary)
// from the pool. They will be cleared with the provided clear color
// in `color_attachments`
RenderTargetMode::FreshBuffer(_) => {
let frame_buffer = make_pooled_frame_buffer();
let resolve_buffer = if sample_count > 1 {
Some(ResolveBuffer::new(
@ -252,18 +250,9 @@ impl CommandTarget {
} else {
None
};
(frame_buffer, resolve_buffer)
}
// In `ExistingTexture` mode, we will use an existing texture
// as either the frame buffer or resolve buffer.
RenderTargetMode::ExistingTexture(texture) => {
if sample_count > 1 {
// The exising texture always has a sample count of 1,
// so we need to create a new texture for the multisampled frame
// buffer. Our existing texture will be used as the resolve buffer,
// which is downsampled from the frame buffer.
let frame_buffer = make_pooled_frame_buffer();
if let RenderTargetMode::ExistingTexture(texture) = &render_target_mode {
if sample_count > 1 {
// Both our frame buffer and resolve buffer need to start out
// in the same state, so copy our existing texture to the freshly
// allocated frame buffer. We cannot use `copy_texture_to_texture`,
@ -280,18 +269,14 @@ impl CommandTarget {
sample_count,
encoder,
);
(
frame_buffer,
Some(ResolveBuffer::new_manual(texture.clone())),
)
} else {
// If multisampling is disabled, we don't need a resolve buffer.
// We can just use our existing texture as the frame buffer.
(FrameBuffer::new_manual(texture.clone(), size), None)
encoder.copy_texture_to_texture(
texture.as_image_copy(),
frame_buffer.texture().as_image_copy(),
size,
);
}
}
};
Self {
frame_buffer,