wgpu: Fixed panic when rendering texture to itself, by always rendering to an intermediary
This commit is contained in:
parent
68343369a3
commit
c85910b46d
|
@ -402,28 +402,21 @@ mod wrapper {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn render(&self, smoothing: bool, context: &mut RenderContext<'_, 'gc>) {
|
pub fn render(&self, smoothing: bool, context: &mut RenderContext<'_, 'gc>) {
|
||||||
// if try_write fails,
|
let mut inner_bitmap_data = self.0.write(context.gc_context);
|
||||||
// this is caused by recursive render attempt. TODO: support this.
|
if inner_bitmap_data.disposed() {
|
||||||
if let Ok(mut inner_bitmap_data) = self.0.try_write(context.gc_context) {
|
return;
|
||||||
if inner_bitmap_data.disposed() {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Note - we do a CPU -> GPU sync, but we do *not* do a GPU -> CPU sync
|
|
||||||
// (rendering is done on the GPU, so the CPU pixels don't need to be up-to-date).
|
|
||||||
inner_bitmap_data.update_dirty_texture(context.renderer);
|
|
||||||
let handle = inner_bitmap_data
|
|
||||||
.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.
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Note - we do a CPU -> GPU sync, but we do *not* do a GPU -> CPU sync
|
||||||
|
// (rendering is done on the GPU, so the CPU pixels don't need to be up-to-date).
|
||||||
|
inner_bitmap_data.update_dirty_texture(context.renderer);
|
||||||
|
let handle = inner_bitmap_data
|
||||||
|
.bitmap_handle(context.renderer)
|
||||||
|
.expect("Missing bitmap handle");
|
||||||
|
|
||||||
|
context
|
||||||
|
.commands
|
||||||
|
.render_bitmap(handle, context.transform_stack.transform(), smoothing);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn is_point_in_bounds(&self, x: i32, y: i32) -> bool {
|
pub fn is_point_in_bounds(&self, x: i32, y: i32) -> bool {
|
||||||
|
|
|
@ -111,27 +111,25 @@ impl Surface {
|
||||||
|
|
||||||
let mut buffers = vec![draw_encoder.finish()];
|
let mut buffers = vec![draw_encoder.finish()];
|
||||||
|
|
||||||
if let RenderTargetMode::FreshBuffer(_) = render_target_mode {
|
let mut copy_encoder =
|
||||||
let mut copy_encoder =
|
descriptors
|
||||||
descriptors
|
.device
|
||||||
.device
|
.create_command_encoder(&wgpu::CommandEncoderDescriptor {
|
||||||
.create_command_encoder(&wgpu::CommandEncoderDescriptor {
|
label: create_debug_label!("Frame copy command encoder").as_deref(),
|
||||||
label: create_debug_label!("Frame copy command encoder").as_deref(),
|
});
|
||||||
});
|
run_copy_pipeline(
|
||||||
run_copy_pipeline(
|
descriptors,
|
||||||
descriptors,
|
self.format,
|
||||||
self.format,
|
self.actual_surface_format,
|
||||||
self.actual_surface_format,
|
self.size,
|
||||||
self.size,
|
frame_view,
|
||||||
frame_view,
|
target.color_view(),
|
||||||
target.color_view(),
|
target.whole_frame_bind_group(descriptors),
|
||||||
target.whole_frame_bind_group(descriptors),
|
target.globals(),
|
||||||
target.globals(),
|
1,
|
||||||
1,
|
&mut copy_encoder,
|
||||||
&mut copy_encoder,
|
);
|
||||||
);
|
buffers.push(copy_encoder.finish());
|
||||||
buffers.push(copy_encoder.finish());
|
|
||||||
}
|
|
||||||
|
|
||||||
buffers.insert(0, uniform_encoder.finish());
|
buffers.insert(0, uniform_encoder.finish());
|
||||||
uniform_buffer.finish();
|
uniform_buffer.finish();
|
||||||
|
|
|
@ -28,6 +28,7 @@ impl ResolveBuffer {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[allow(dead_code)]
|
||||||
pub fn new_manual(texture: Arc<wgpu::Texture>) -> Self {
|
pub fn new_manual(texture: Arc<wgpu::Texture>) -> Self {
|
||||||
Self {
|
Self {
|
||||||
texture: PoolOrArcTexture::Manual((
|
texture: PoolOrArcTexture::Manual((
|
||||||
|
@ -69,6 +70,7 @@ pub struct FrameBuffer {
|
||||||
/// (when doing an offscreen render to a BitmapData texture)
|
/// (when doing an offscreen render to a BitmapData texture)
|
||||||
pub enum PoolOrArcTexture {
|
pub enum PoolOrArcTexture {
|
||||||
Pool(PoolEntry<(wgpu::Texture, wgpu::TextureView), AlwaysCompatible>),
|
Pool(PoolEntry<(wgpu::Texture, wgpu::TextureView), AlwaysCompatible>),
|
||||||
|
#[allow(dead_code)]
|
||||||
Manual((Arc<wgpu::Texture>, wgpu::TextureView)),
|
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 {
|
pub fn new_manual(texture: Arc<wgpu::Texture>, size: wgpu::Extent3d) -> Self {
|
||||||
Self {
|
Self {
|
||||||
texture: PoolOrArcTexture::Manual((
|
texture: PoolOrArcTexture::Manual((
|
||||||
|
@ -232,67 +235,49 @@ impl CommandTarget {
|
||||||
|
|
||||||
let whole_frame_bind_group = OnceCell::new();
|
let whole_frame_bind_group = OnceCell::new();
|
||||||
|
|
||||||
let (frame_buffer, resolve_buffer) = match &render_target_mode {
|
let frame_buffer = make_pooled_frame_buffer();
|
||||||
// In `FreshBuffer` mode, get a new frame buffer (and resolve buffer, if necessary)
|
let resolve_buffer = if sample_count > 1 {
|
||||||
// from the pool. They will be cleared with the provided clear color
|
Some(ResolveBuffer::new(
|
||||||
// in `color_attachments`
|
descriptors,
|
||||||
RenderTargetMode::FreshBuffer(_) => {
|
size,
|
||||||
let frame_buffer = make_pooled_frame_buffer();
|
format,
|
||||||
let resolve_buffer = if sample_count > 1 {
|
wgpu::TextureUsages::COPY_SRC
|
||||||
Some(ResolveBuffer::new(
|
| wgpu::TextureUsages::COPY_DST
|
||||||
descriptors,
|
| wgpu::TextureUsages::TEXTURE_BINDING
|
||||||
size,
|
| wgpu::TextureUsages::RENDER_ATTACHMENT,
|
||||||
format,
|
pool,
|
||||||
wgpu::TextureUsages::COPY_SRC
|
))
|
||||||
| wgpu::TextureUsages::COPY_DST
|
} else {
|
||||||
| wgpu::TextureUsages::TEXTURE_BINDING
|
None
|
||||||
| wgpu::TextureUsages::RENDER_ATTACHMENT,
|
|
||||||
pool,
|
|
||||||
))
|
|
||||||
} 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();
|
|
||||||
|
|
||||||
// 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`,
|
|
||||||
// since the sample counts are different.
|
|
||||||
run_copy_pipeline(
|
|
||||||
descriptors,
|
|
||||||
format,
|
|
||||||
format,
|
|
||||||
size,
|
|
||||||
frame_buffer.texture.view(),
|
|
||||||
&texture.create_view(&Default::default()),
|
|
||||||
get_whole_frame_bind_group(&whole_frame_bind_group, descriptors, size),
|
|
||||||
&globals,
|
|
||||||
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)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
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`,
|
||||||
|
// since the sample counts are different.
|
||||||
|
run_copy_pipeline(
|
||||||
|
descriptors,
|
||||||
|
format,
|
||||||
|
format,
|
||||||
|
size,
|
||||||
|
frame_buffer.texture.view(),
|
||||||
|
&texture.create_view(&Default::default()),
|
||||||
|
get_whole_frame_bind_group(&whole_frame_bind_group, descriptors, size),
|
||||||
|
&globals,
|
||||||
|
sample_count,
|
||||||
|
encoder,
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
encoder.copy_texture_to_texture(
|
||||||
|
texture.as_image_copy(),
|
||||||
|
frame_buffer.texture().as_image_copy(),
|
||||||
|
size,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
frame_buffer,
|
frame_buffer,
|
||||||
blend_buffer: OnceCell::new(),
|
blend_buffer: OnceCell::new(),
|
||||||
|
|
Loading…
Reference in New Issue