wgpu: Refactor surface command target to its own file

This commit is contained in:
Nathan Adams 2022-12-27 21:03:06 +01:00
parent a657feadae
commit 0272eda121
4 changed files with 398 additions and 388 deletions

View File

@ -2,256 +2,19 @@ use crate::blend::TrivialBlend;
use crate::blend::{BlendType, ComplexBlend};
use crate::buffer_pool::{PoolEntry, TexturePool};
use crate::mesh::{BitmapBinds, DrawType, Mesh};
use crate::surface::{BlendBuffer, DepthBuffer, FrameBuffer, ResolveBuffer, Surface};
use crate::utils::create_buffer_with_data;
use crate::surface::target::CommandTarget;
use crate::surface::Surface;
use crate::{
as_texture, ColorAdjustments, Descriptors, Globals, MaskState, Pipelines, Transforms,
UniformBuffer,
as_texture, ColorAdjustments, Descriptors, MaskState, Pipelines, Transforms, UniformBuffer,
};
use once_cell::race::OnceBool;
use once_cell::sync::OnceCell;
use ruffle_render::backend::ShapeHandle;
use ruffle_render::bitmap::BitmapHandle;
use ruffle_render::commands::{Command, CommandList};
use ruffle_render::matrix::Matrix;
use ruffle_render::tessellator::GradientType;
use ruffle_render::transform::Transform;
use std::sync::Arc;
use swf::{BlendMode, Color, GradientSpread};
pub struct CommandTarget {
frame_buffer: FrameBuffer,
blend_buffer: OnceCell<BlendBuffer>,
resolve_buffer: Option<ResolveBuffer>,
depth: OnceCell<DepthBuffer>,
globals: Arc<Globals>,
size: wgpu::Extent3d,
format: wgpu::TextureFormat,
sample_count: u32,
whole_frame_bind_group: OnceCell<(wgpu::Buffer, wgpu::BindGroup)>,
color_needs_clear: OnceBool,
}
impl CommandTarget {
pub fn new(
descriptors: &Descriptors,
pool: &mut TexturePool,
size: wgpu::Extent3d,
format: wgpu::TextureFormat,
sample_count: u32,
) -> Self {
let frame_buffer = FrameBuffer::new(
&descriptors,
sample_count,
size,
format,
if sample_count > 1 {
wgpu::TextureUsages::RENDER_ATTACHMENT
} else {
wgpu::TextureUsages::RENDER_ATTACHMENT
| wgpu::TextureUsages::COPY_SRC
| wgpu::TextureUsages::TEXTURE_BINDING
},
pool,
);
let resolve_buffer = if sample_count > 1 {
Some(ResolveBuffer::new(
&descriptors,
size,
format,
wgpu::TextureUsages::COPY_SRC
| wgpu::TextureUsages::TEXTURE_BINDING
| wgpu::TextureUsages::RENDER_ATTACHMENT,
pool,
))
} else {
None
};
let globals = pool.get_globals(descriptors, size.width, size.height);
Self {
frame_buffer,
blend_buffer: OnceCell::new(),
resolve_buffer,
depth: OnceCell::new(),
globals,
size,
format,
sample_count,
whole_frame_bind_group: OnceCell::new(),
color_needs_clear: OnceBool::new(),
}
}
pub fn width(&self) -> u32 {
self.size.width
}
pub fn height(&self) -> u32 {
self.size.height
}
pub fn ensure_cleared(&self, encoder: &mut wgpu::CommandEncoder, clear_color: wgpu::Color) {
if self.color_needs_clear.get().is_some() {
return;
}
encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
label: create_debug_label!("Clearing command target").as_deref(),
color_attachments: &[self.color_attachments(clear_color)],
depth_stencil_attachment: None,
});
}
pub fn take_color_texture(self) -> PoolEntry<wgpu::Texture> {
self.resolve_buffer
.map(|b| b.take_texture())
.unwrap_or_else(|| self.frame_buffer.take_texture())
}
pub fn globals(&self) -> &Globals {
&self.globals
}
pub fn whole_frame_bind_group(&self, descriptors: &Descriptors) -> &wgpu::BindGroup {
&self
.whole_frame_bind_group
.get_or_init(|| {
let transform = Transforms {
world_matrix: [
[self.size.width as f32, 0.0, 0.0, 0.0],
[0.0, self.size.height as f32, 0.0, 0.0],
[0.0, 0.0, 1.0, 0.0],
[0.0, 0.0, 0.0, 1.0],
],
color_adjustments: ColorAdjustments {
mult_color: [1.0, 1.0, 1.0, 1.0],
add_color: [0.0, 0.0, 0.0, 0.0],
},
};
let transforms_buffer = create_buffer_with_data(
&descriptors.device,
bytemuck::cast_slice(&[transform]),
wgpu::BufferUsages::UNIFORM,
create_debug_label!("Whole-frame transforms buffer"),
);
let whole_frame_bind_group =
descriptors
.device
.create_bind_group(&wgpu::BindGroupDescriptor {
layout: &descriptors.bind_layouts.transforms,
entries: &[wgpu::BindGroupEntry {
binding: 0,
resource: wgpu::BindingResource::Buffer(wgpu::BufferBinding {
buffer: &transforms_buffer,
offset: 0,
size: wgpu::BufferSize::new(
std::mem::size_of::<Transforms>() as u64
),
}),
}],
label: create_debug_label!("Whole-frame transforms bind group")
.as_deref(),
});
(transforms_buffer, whole_frame_bind_group)
})
.1
}
pub fn color_attachments(
&self,
clear_color: wgpu::Color,
) -> Option<wgpu::RenderPassColorAttachment> {
Some(wgpu::RenderPassColorAttachment {
view: &self.frame_buffer.view(),
resolve_target: self.resolve_buffer.as_ref().map(|b| b.view()),
ops: wgpu::Operations {
load: if self.color_needs_clear.set(false).is_ok() {
wgpu::LoadOp::Clear(clear_color)
} else {
wgpu::LoadOp::Load
},
store: true,
},
})
}
pub fn depth_attachment(
&self,
descriptors: &Descriptors,
pool: &mut TexturePool,
) -> Option<wgpu::RenderPassDepthStencilAttachment> {
let new_buffer = self.depth.get().is_none();
let depth = self
.depth
.get_or_init(|| DepthBuffer::new(descriptors, self.sample_count, self.size, pool));
Some(wgpu::RenderPassDepthStencilAttachment {
view: depth.view(),
depth_ops: Some(wgpu::Operations {
load: if new_buffer {
wgpu::LoadOp::Clear(0.0)
} else {
wgpu::LoadOp::Load
},
store: true,
}),
stencil_ops: Some(wgpu::Operations {
load: if new_buffer {
wgpu::LoadOp::Clear(0)
} else {
wgpu::LoadOp::Load
},
store: true,
}),
})
}
pub fn update_blend_buffer(
&self,
descriptors: &Descriptors,
pool: &mut TexturePool,
encoder: &mut wgpu::CommandEncoder,
) -> &BlendBuffer {
let blend_buffer = self.blend_buffer.get_or_init(|| {
BlendBuffer::new(
&descriptors,
self.size,
self.format,
wgpu::TextureUsages::TEXTURE_BINDING | wgpu::TextureUsages::COPY_DST,
pool,
)
});
encoder.copy_texture_to_texture(
wgpu::ImageCopyTextureBase {
texture: self
.resolve_buffer
.as_ref()
.map(|b| b.texture())
.unwrap_or_else(|| self.frame_buffer.texture()),
mip_level: 0,
origin: Default::default(),
aspect: Default::default(),
},
wgpu::ImageCopyTextureBase {
texture: blend_buffer.texture(),
mip_level: 0,
origin: Default::default(),
aspect: Default::default(),
},
self.frame_buffer.size(),
);
blend_buffer
}
pub fn color_view(&self) -> &wgpu::TextureView {
self.resolve_buffer
.as_ref()
.map(|b| b.view())
.unwrap_or_else(|| self.frame_buffer.view())
}
}
pub struct CommandRenderer<'pass, 'frame: 'pass, 'global: 'frame> {
pipelines: &'frame Pipelines,
meshes: &'global Vec<Mesh>,
@ -313,9 +76,9 @@ impl<'pass, 'frame: 'pass, 'global: 'frame> CommandRenderer<'pass, 'frame, 'glob
uniform_encoder,
draw_encoder,
meshes,
target.sample_count,
target.size.width,
target.size.height,
target.sample_count(),
target.width(),
target.height(),
nearest_layer,
texture_pool,
);
@ -341,7 +104,7 @@ impl<'pass, 'frame: 'pass, 'global: 'frame> CommandRenderer<'pass, 'frame, 'glob
None
},
});
render_pass.set_bind_group(0, target.globals.bind_group(), &[]);
render_pass.set_bind_group(0, target.globals().bind_group(), &[]);
let mut renderer = CommandRenderer::new(
&pipelines,
&meshes,
@ -471,7 +234,7 @@ impl<'pass, 'frame: 'pass, 'global: 'frame> CommandRenderer<'pass, 'frame, 'glob
None
},
});
render_pass.set_bind_group(0, target.globals.bind_group(), &[]);
render_pass.set_bind_group(0, target.globals().bind_group(), &[]);
if needs_depth {
match mask_state {

View File

@ -1,6 +1,5 @@
use crate::bitmaps::BitmapSamplers;
use crate::descriptors::Quad;
use crate::globals::Globals;
use crate::mesh::BitmapBinds;
use crate::pipelines::Pipelines;
use crate::target::{RenderTarget, SwapChainTarget};

View File

@ -1,151 +1,14 @@
use crate::buffer_pool::{PoolEntry, TexturePool};
use crate::commands::{CommandRenderer, CommandTarget};
pub mod target;
use crate::buffer_pool::TexturePool;
use crate::commands::CommandRenderer;
use crate::mesh::Mesh;
use crate::uniform_buffer::BufferStorage;
use crate::utils::remove_srgb;
use crate::{Descriptors, Pipelines, TextureTransforms, Transforms, UniformBuffer};
use ruffle_render::commands::CommandList;
use std::sync::Arc;
#[derive(Debug)]
pub struct ResolveBuffer {
texture: PoolEntry<wgpu::Texture>,
view: wgpu::TextureView,
}
impl ResolveBuffer {
pub fn new(
descriptors: &Descriptors,
size: wgpu::Extent3d,
format: wgpu::TextureFormat,
usage: wgpu::TextureUsages,
pool: &mut TexturePool,
) -> Self {
let texture = pool.get_texture(descriptors, size, usage, format, 1);
let view = texture.create_view(&Default::default());
Self { texture, view }
}
pub fn view(&self) -> &wgpu::TextureView {
&self.view
}
pub fn texture(&self) -> &wgpu::Texture {
&self.texture
}
pub fn take_texture(self) -> PoolEntry<wgpu::Texture> {
self.texture
}
}
#[derive(Debug)]
pub struct FrameBuffer {
texture: PoolEntry<wgpu::Texture>,
view: wgpu::TextureView,
size: wgpu::Extent3d,
}
impl FrameBuffer {
pub fn new(
descriptors: &Descriptors,
sample_count: u32,
size: wgpu::Extent3d,
format: wgpu::TextureFormat,
usage: wgpu::TextureUsages,
pool: &mut TexturePool,
) -> Self {
let texture = pool.get_texture(descriptors, size, usage, format, sample_count);
let view = texture.create_view(&Default::default());
Self {
texture,
view,
size,
}
}
pub fn view(&self) -> &wgpu::TextureView {
&self.view
}
pub fn texture(&self) -> &wgpu::Texture {
&self.texture
}
pub fn take_texture(self) -> PoolEntry<wgpu::Texture> {
self.texture
}
pub fn size(&self) -> wgpu::Extent3d {
self.size
}
}
#[derive(Debug)]
pub struct BlendBuffer {
texture: PoolEntry<wgpu::Texture>,
view: wgpu::TextureView,
}
impl BlendBuffer {
pub fn new(
descriptors: &Descriptors,
size: wgpu::Extent3d,
format: wgpu::TextureFormat,
usage: wgpu::TextureUsages,
pool: &mut TexturePool,
) -> Self {
let texture = pool.get_texture(descriptors, size, usage, format, 1);
let view = texture.create_view(&Default::default());
Self { texture, view }
}
pub fn view(&self) -> &wgpu::TextureView {
&self.view
}
pub fn texture(&self) -> &wgpu::Texture {
&self.texture
}
}
#[derive(Debug)]
pub struct DepthBuffer {
_texture: PoolEntry<wgpu::Texture>,
view: wgpu::TextureView,
}
impl DepthBuffer {
pub fn new(
descriptors: &Descriptors,
msaa_sample_count: u32,
size: wgpu::Extent3d,
pool: &mut TexturePool,
) -> Self {
let texture = pool.get_texture(
descriptors,
size,
wgpu::TextureUsages::RENDER_ATTACHMENT,
wgpu::TextureFormat::Depth24PlusStencil8,
msaa_sample_count,
);
let view = texture.create_view(&Default::default());
Self {
_texture: texture,
view,
}
}
pub fn view(&self) -> &wgpu::TextureView {
&self.view
}
}
use target::CommandTarget;
#[derive(Debug)]
pub struct Surface {

View File

@ -0,0 +1,385 @@
use crate::buffer_pool::{PoolEntry, TexturePool};
use crate::descriptors::Descriptors;
use crate::globals::Globals;
use crate::utils::create_buffer_with_data;
use crate::{ColorAdjustments, Transforms};
use once_cell::race::OnceBool;
use once_cell::sync::OnceCell;
use std::sync::Arc;
#[derive(Debug)]
pub struct ResolveBuffer {
texture: PoolEntry<wgpu::Texture>,
view: wgpu::TextureView,
}
impl ResolveBuffer {
pub fn new(
descriptors: &Descriptors,
size: wgpu::Extent3d,
format: wgpu::TextureFormat,
usage: wgpu::TextureUsages,
pool: &mut TexturePool,
) -> Self {
let texture = pool.get_texture(descriptors, size, usage, format, 1);
let view = texture.create_view(&Default::default());
Self { texture, view }
}
pub fn view(&self) -> &wgpu::TextureView {
&self.view
}
pub fn texture(&self) -> &wgpu::Texture {
&self.texture
}
pub fn take_texture(self) -> PoolEntry<wgpu::Texture> {
self.texture
}
}
#[derive(Debug)]
pub struct FrameBuffer {
texture: PoolEntry<wgpu::Texture>,
view: wgpu::TextureView,
size: wgpu::Extent3d,
}
impl FrameBuffer {
pub fn new(
descriptors: &Descriptors,
sample_count: u32,
size: wgpu::Extent3d,
format: wgpu::TextureFormat,
usage: wgpu::TextureUsages,
pool: &mut TexturePool,
) -> Self {
let texture = pool.get_texture(descriptors, size, usage, format, sample_count);
let view = texture.create_view(&Default::default());
Self {
texture,
view,
size,
}
}
pub fn view(&self) -> &wgpu::TextureView {
&self.view
}
pub fn texture(&self) -> &wgpu::Texture {
&self.texture
}
pub fn take_texture(self) -> PoolEntry<wgpu::Texture> {
self.texture
}
pub fn size(&self) -> wgpu::Extent3d {
self.size
}
}
#[derive(Debug)]
pub struct BlendBuffer {
texture: PoolEntry<wgpu::Texture>,
view: wgpu::TextureView,
}
impl BlendBuffer {
pub fn new(
descriptors: &Descriptors,
size: wgpu::Extent3d,
format: wgpu::TextureFormat,
usage: wgpu::TextureUsages,
pool: &mut TexturePool,
) -> Self {
let texture = pool.get_texture(descriptors, size, usage, format, 1);
let view = texture.create_view(&Default::default());
Self { texture, view }
}
pub fn view(&self) -> &wgpu::TextureView {
&self.view
}
pub fn texture(&self) -> &wgpu::Texture {
&self.texture
}
}
#[derive(Debug)]
pub struct DepthBuffer {
_texture: PoolEntry<wgpu::Texture>,
view: wgpu::TextureView,
}
impl DepthBuffer {
pub fn new(
descriptors: &Descriptors,
msaa_sample_count: u32,
size: wgpu::Extent3d,
pool: &mut TexturePool,
) -> Self {
let texture = pool.get_texture(
descriptors,
size,
wgpu::TextureUsages::RENDER_ATTACHMENT,
wgpu::TextureFormat::Depth24PlusStencil8,
msaa_sample_count,
);
let view = texture.create_view(&Default::default());
Self {
_texture: texture,
view,
}
}
pub fn view(&self) -> &wgpu::TextureView {
&self.view
}
}
pub struct CommandTarget {
frame_buffer: FrameBuffer,
blend_buffer: OnceCell<BlendBuffer>,
resolve_buffer: Option<ResolveBuffer>,
depth: OnceCell<DepthBuffer>,
globals: Arc<Globals>,
size: wgpu::Extent3d,
format: wgpu::TextureFormat,
sample_count: u32,
whole_frame_bind_group: OnceCell<(wgpu::Buffer, wgpu::BindGroup)>,
color_needs_clear: OnceBool,
}
impl CommandTarget {
pub fn new(
descriptors: &Descriptors,
pool: &mut TexturePool,
size: wgpu::Extent3d,
format: wgpu::TextureFormat,
sample_count: u32,
) -> Self {
let frame_buffer = FrameBuffer::new(
&descriptors,
sample_count,
size,
format,
if sample_count > 1 {
wgpu::TextureUsages::RENDER_ATTACHMENT
} else {
wgpu::TextureUsages::RENDER_ATTACHMENT
| wgpu::TextureUsages::COPY_SRC
| wgpu::TextureUsages::TEXTURE_BINDING
},
pool,
);
let resolve_buffer = if sample_count > 1 {
Some(ResolveBuffer::new(
&descriptors,
size,
format,
wgpu::TextureUsages::COPY_SRC
| wgpu::TextureUsages::TEXTURE_BINDING
| wgpu::TextureUsages::RENDER_ATTACHMENT,
pool,
))
} else {
None
};
let globals = pool.get_globals(descriptors, size.width, size.height);
Self {
frame_buffer,
blend_buffer: OnceCell::new(),
resolve_buffer,
depth: OnceCell::new(),
globals,
size,
format,
sample_count,
whole_frame_bind_group: OnceCell::new(),
color_needs_clear: OnceBool::new(),
}
}
pub fn width(&self) -> u32 {
self.size.width
}
pub fn height(&self) -> u32 {
self.size.height
}
pub fn sample_count(&self) -> u32 {
self.sample_count
}
pub fn ensure_cleared(&self, encoder: &mut wgpu::CommandEncoder, clear_color: wgpu::Color) {
if self.color_needs_clear.get().is_some() {
return;
}
encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
label: create_debug_label!("Clearing command target").as_deref(),
color_attachments: &[self.color_attachments(clear_color)],
depth_stencil_attachment: None,
});
}
pub fn take_color_texture(self) -> PoolEntry<wgpu::Texture> {
self.resolve_buffer
.map(|b| b.take_texture())
.unwrap_or_else(|| self.frame_buffer.take_texture())
}
pub fn globals(&self) -> &Globals {
&self.globals
}
pub fn whole_frame_bind_group(&self, descriptors: &Descriptors) -> &wgpu::BindGroup {
&self
.whole_frame_bind_group
.get_or_init(|| {
let transform = Transforms {
world_matrix: [
[self.size.width as f32, 0.0, 0.0, 0.0],
[0.0, self.size.height as f32, 0.0, 0.0],
[0.0, 0.0, 1.0, 0.0],
[0.0, 0.0, 0.0, 1.0],
],
color_adjustments: ColorAdjustments {
mult_color: [1.0, 1.0, 1.0, 1.0],
add_color: [0.0, 0.0, 0.0, 0.0],
},
};
let transforms_buffer = create_buffer_with_data(
&descriptors.device,
bytemuck::cast_slice(&[transform]),
wgpu::BufferUsages::UNIFORM,
create_debug_label!("Whole-frame transforms buffer"),
);
let whole_frame_bind_group =
descriptors
.device
.create_bind_group(&wgpu::BindGroupDescriptor {
layout: &descriptors.bind_layouts.transforms,
entries: &[wgpu::BindGroupEntry {
binding: 0,
resource: wgpu::BindingResource::Buffer(wgpu::BufferBinding {
buffer: &transforms_buffer,
offset: 0,
size: wgpu::BufferSize::new(
std::mem::size_of::<Transforms>() as u64
),
}),
}],
label: create_debug_label!("Whole-frame transforms bind group")
.as_deref(),
});
(transforms_buffer, whole_frame_bind_group)
})
.1
}
pub fn color_attachments(
&self,
clear_color: wgpu::Color,
) -> Option<wgpu::RenderPassColorAttachment> {
Some(wgpu::RenderPassColorAttachment {
view: &self.frame_buffer.view(),
resolve_target: self.resolve_buffer.as_ref().map(|b| b.view()),
ops: wgpu::Operations {
load: if self.color_needs_clear.set(false).is_ok() {
wgpu::LoadOp::Clear(clear_color)
} else {
wgpu::LoadOp::Load
},
store: true,
},
})
}
pub fn depth_attachment(
&self,
descriptors: &Descriptors,
pool: &mut TexturePool,
) -> Option<wgpu::RenderPassDepthStencilAttachment> {
let new_buffer = self.depth.get().is_none();
let depth = self
.depth
.get_or_init(|| DepthBuffer::new(descriptors, self.sample_count, self.size, pool));
Some(wgpu::RenderPassDepthStencilAttachment {
view: depth.view(),
depth_ops: Some(wgpu::Operations {
load: if new_buffer {
wgpu::LoadOp::Clear(0.0)
} else {
wgpu::LoadOp::Load
},
store: true,
}),
stencil_ops: Some(wgpu::Operations {
load: if new_buffer {
wgpu::LoadOp::Clear(0)
} else {
wgpu::LoadOp::Load
},
store: true,
}),
})
}
pub fn update_blend_buffer(
&self,
descriptors: &Descriptors,
pool: &mut TexturePool,
encoder: &mut wgpu::CommandEncoder,
) -> &BlendBuffer {
let blend_buffer = self.blend_buffer.get_or_init(|| {
BlendBuffer::new(
&descriptors,
self.size,
self.format,
wgpu::TextureUsages::TEXTURE_BINDING | wgpu::TextureUsages::COPY_DST,
pool,
)
});
encoder.copy_texture_to_texture(
wgpu::ImageCopyTextureBase {
texture: self
.resolve_buffer
.as_ref()
.map(|b| b.texture())
.unwrap_or_else(|| self.frame_buffer.texture()),
mip_level: 0,
origin: Default::default(),
aspect: Default::default(),
},
wgpu::ImageCopyTextureBase {
texture: blend_buffer.texture(),
mip_level: 0,
origin: Default::default(),
aspect: Default::default(),
},
self.frame_buffer.size(),
);
blend_buffer
}
pub fn color_view(&self) -> &wgpu::TextureView {
self.resolve_buffer
.as_ref()
.map(|b| b.view())
.unwrap_or_else(|| self.frame_buffer.view())
}
}