wgpu: Split off Frame into CommandRenderer and Frame - command renderer translates commands into draw calls on frame

This commit is contained in:
Nathan Adams 2022-09-07 11:33:12 +02:00
parent 22ba32b785
commit 91f3230a45
4 changed files with 228 additions and 176 deletions

View File

@ -1,3 +1,4 @@
use crate::commands::CommandRenderer;
use crate::descriptors::DescriptorsTargetData;
use crate::frame::Frame;
use crate::target::RenderTargetFrame;
@ -756,14 +757,16 @@ impl<T: RenderTarget + 'static> RenderBackend for WgpuRenderBackend<T> {
&self.descriptors.onscreen.pipelines,
&self.descriptors,
UniformBuffer::new(&mut self.uniform_buffers_storage),
self.quad_vbo.slice(..),
self.quad_ibo.slice(..),
&self.meshes,
render_pass,
&mut uniform_encoder,
&self.bitmap_registry,
);
commands.execute(&mut frame);
commands.execute(&mut CommandRenderer::new(
&mut frame,
&self.meshes,
&self.bitmap_registry,
self.quad_vbo.slice(..),
self.quad_ibo.slice(..),
));
// If we have an sRGB surface, copy from our linear intermediate buffer to the sRGB surface.
let copy_encoder = if let Some(copy_srgb_bind_group) = &self.copy_srgb_bind_group {
@ -774,6 +777,8 @@ impl<T: RenderTarget + 'static> RenderBackend for WgpuRenderBackend<T> {
copy_srgb_bind_group,
self.target.width() as f32,
self.target.height() as f32,
self.quad_vbo.slice(..),
self.quad_ibo.slice(..),
))
} else {
None
@ -1072,14 +1077,16 @@ impl<T: RenderTarget + 'static> RenderBackend for WgpuRenderBackend<T> {
&self.descriptors.offscreen.pipelines,
&self.descriptors,
UniformBuffer::new(&mut self.uniform_buffers_storage),
self.quad_vbo.slice(..),
self.quad_ibo.slice(..),
&self.meshes,
render_pass,
&mut uniform_encoder,
&self.bitmap_registry,
);
commands.execute(&mut frame);
commands.execute(&mut CommandRenderer::new(
&mut frame,
&self.meshes,
&self.bitmap_registry,
self.quad_vbo.slice(..),
self.quad_ibo.slice(..),
));
frame.finish();
target.submit(

189
render/wgpu/src/commands.rs Normal file
View File

@ -0,0 +1,189 @@
use crate::frame::Frame;
use crate::pipelines::BlendMode as ActualBlendMode;
use crate::{ColorAdjustments, DrawType, MaskState, Mesh, RegistryData};
use fnv::FnvHashMap;
use ruffle_render::backend::ShapeHandle;
use ruffle_render::bitmap::BitmapHandle;
use ruffle_render::commands::CommandHandler;
use ruffle_render::transform::Transform;
use swf::{BlendMode, Color};
pub struct CommandRenderer<'a, 'b> {
frame: &'b mut Frame<'a>,
bitmap_registry: &'a FnvHashMap<BitmapHandle, RegistryData>,
meshes: &'a Vec<Mesh>,
quad_vertices: wgpu::BufferSlice<'a>,
quad_indices: wgpu::BufferSlice<'a>,
blend_modes: Vec<BlendMode>,
}
impl<'a, 'b> CommandRenderer<'a, 'b> {
pub fn new(
frame: &'b mut Frame<'a>,
meshes: &'a Vec<Mesh>,
bitmap_registry: &'a FnvHashMap<BitmapHandle, RegistryData>,
quad_vertices: wgpu::BufferSlice<'a>,
quad_indices: wgpu::BufferSlice<'a>,
) -> Self {
Self {
frame,
bitmap_registry,
meshes,
quad_vertices,
quad_indices,
blend_modes: vec![BlendMode::Normal],
}
}
}
impl<'a, 'b> CommandHandler for CommandRenderer<'a, 'b> {
fn render_bitmap(&mut self, bitmap: BitmapHandle, transform: &Transform, smoothing: bool) {
if let Some(entry) = self.bitmap_registry.get(&bitmap) {
let texture = &entry.texture_wrapper;
self.frame.apply_transform(
&(transform.matrix
* ruffle_render::matrix::Matrix {
a: texture.width as f32,
d: texture.height as f32,
..Default::default()
}),
ColorAdjustments::from(transform.color_transform),
);
self.frame.draw_bitmap(
self.quad_vertices,
self.quad_indices,
6,
&texture.bind_group,
false,
smoothing,
);
}
}
fn render_shape(&mut self, shape: ShapeHandle, transform: &Transform) {
self.frame.apply_transform(
&transform.matrix,
ColorAdjustments::from(transform.color_transform),
);
let mesh = &self.meshes[shape.0];
let mask_state = self.frame.mask_state();
for draw in &mesh.draws {
let num_indices = if mask_state != MaskState::DrawMaskStencil
&& mask_state != MaskState::ClearMaskStencil
{
draw.num_indices
} else {
// Omit strokes when drawing a mask stencil.
draw.num_mask_indices
};
if num_indices == 0 {
continue;
}
match &draw.draw_type {
DrawType::Color => {
self.frame.draw_color(
draw.vertex_buffer.slice(..),
draw.index_buffer.slice(..),
num_indices,
);
}
DrawType::Gradient { bind_group, .. } => {
self.frame.draw_gradient(
draw.vertex_buffer.slice(..),
draw.index_buffer.slice(..),
num_indices,
bind_group,
);
}
DrawType::Bitmap {
is_repeating,
is_smoothed,
bind_group,
..
} => {
self.frame.draw_bitmap(
draw.vertex_buffer.slice(..),
draw.index_buffer.slice(..),
num_indices,
bind_group,
*is_repeating,
*is_smoothed,
);
}
}
}
}
fn draw_rect(&mut self, color: Color, matrix: &ruffle_render::matrix::Matrix) {
self.frame.apply_transform(
&matrix,
ColorAdjustments {
mult_color: [
f32::from(color.r) / 255.0,
f32::from(color.g) / 255.0,
f32::from(color.b) / 255.0,
f32::from(color.a) / 255.0,
],
add_color: [0.0, 0.0, 0.0, 0.0],
},
);
self.frame
.draw_color(self.quad_vertices, self.quad_indices, 6);
}
fn push_mask(&mut self) {
debug_assert!(
self.frame.mask_state() == MaskState::NoMask
|| self.frame.mask_state() == MaskState::DrawMaskedContent
);
self.frame.set_mask_state(MaskState::DrawMaskStencil);
self.frame.set_mask_count(self.frame.num_masks() + 1);
}
fn activate_mask(&mut self) {
debug_assert!(
self.frame.num_masks() > 0 && self.frame.mask_state() == MaskState::DrawMaskStencil
);
self.frame.set_mask_state(MaskState::DrawMaskedContent);
}
fn deactivate_mask(&mut self) {
debug_assert!(
self.frame.num_masks() > 0 && self.frame.mask_state() == MaskState::DrawMaskedContent
);
self.frame.set_mask_state(MaskState::ClearMaskStencil);
}
fn pop_mask(&mut self) {
debug_assert!(
self.frame.num_masks() > 0 && self.frame.mask_state() == MaskState::ClearMaskStencil
);
let num_masks = self.frame.num_masks() - 1;
self.frame.set_mask_count(num_masks);
if num_masks == 0 {
self.frame.set_mask_state(MaskState::NoMask);
} else {
self.frame.set_mask_state(MaskState::DrawMaskedContent);
};
}
fn push_blend_mode(&mut self, blend: BlendMode) {
self.blend_modes.push(blend);
self.frame.set_blend_mode(blend.into());
}
fn pop_blend_mode(&mut self) {
self.blend_modes.pop();
self.frame.set_blend_mode(
self.blend_modes
.last()
.map(|b| ActualBlendMode::from(*b))
.unwrap_or(ActualBlendMode::Normal),
);
}
}

View File

@ -1,16 +1,7 @@
use crate::pipelines::BlendMode as ActualBlendMode;
use crate::target::RenderTargetFrame;
use crate::Pipelines;
use crate::{
ColorAdjustments, Descriptors, DrawType, Globals, MaskState, Mesh, RegistryData, Transforms,
UniformBuffer,
};
use fnv::FnvHashMap;
use ruffle_render::backend::ShapeHandle;
use ruffle_render::bitmap::BitmapHandle;
use ruffle_render::commands::CommandHandler;
use ruffle_render::transform::Transform;
use swf::{BlendMode, Color};
use crate::{ColorAdjustments, Descriptors, Globals, MaskState, Transforms, UniformBuffer};
pub struct Frame<'a> {
pipelines: &'a Pipelines,
@ -20,26 +11,16 @@ pub struct Frame<'a> {
num_masks: u32,
uniform_encoder: &'a mut wgpu::CommandEncoder,
render_pass: wgpu::RenderPass<'a>,
blend_modes: Vec<BlendMode>,
blend_mode: ActualBlendMode,
bitmap_registry: &'a FnvHashMap<BitmapHandle, RegistryData>,
quad_vertices: wgpu::BufferSlice<'a>,
quad_indices: wgpu::BufferSlice<'a>,
meshes: &'a Vec<Mesh>,
}
impl<'a> Frame<'a> {
#[allow(clippy::too_many_arguments)]
pub fn new(
pipelines: &'a Pipelines,
descriptors: &'a Descriptors,
uniform_buffers: UniformBuffer<'a, Transforms>,
quad_vertices: wgpu::BufferSlice<'a>,
quad_indices: wgpu::BufferSlice<'a>,
meshes: &'a Vec<Mesh>,
render_pass: wgpu::RenderPass<'a>,
uniform_encoder: &'a mut wgpu::CommandEncoder,
bitmap_registry: &'a FnvHashMap<BitmapHandle, RegistryData>,
) -> Self {
Self {
pipelines,
@ -49,15 +30,11 @@ impl<'a> Frame<'a> {
num_masks: 0,
uniform_encoder,
render_pass,
blend_modes: vec![BlendMode::Normal],
blend_mode: ActualBlendMode::Normal,
bitmap_registry,
quad_vertices,
quad_indices,
meshes,
}
}
#[allow(clippy::too_many_arguments)]
pub fn swap_srgb<T: RenderTargetFrame>(
&mut self,
globals: &Globals,
@ -65,6 +42,8 @@ impl<'a> Frame<'a> {
copy_srgb_bind_group: &wgpu::BindGroup,
width: f32,
height: f32,
quad_vertices: wgpu::BufferSlice<'a>,
quad_indices: wgpu::BufferSlice<'a>,
) -> wgpu::CommandBuffer {
let mut copy_encoder =
self.descriptors
@ -115,8 +94,8 @@ impl<'a> Frame<'a> {
.get_bind_group(false, false),
&[],
);
render_pass.set_vertex_buffer(0, self.quad_vertices);
render_pass.set_index_buffer(self.quad_indices, wgpu::IndexFormat::Uint32);
render_pass.set_vertex_buffer(0, quad_vertices);
render_pass.set_index_buffer(quad_indices, wgpu::IndexFormat::Uint32);
render_pass.draw_indexed(0..6, 0, 0..1);
drop(render_pass);
@ -127,7 +106,7 @@ impl<'a> Frame<'a> {
self.uniform_buffers.finish()
}
fn draw_color(
pub fn draw_color(
&mut self,
vertices: wgpu::BufferSlice<'a>,
indices: wgpu::BufferSlice<'a>,
@ -146,7 +125,7 @@ impl<'a> Frame<'a> {
self.render_pass.draw_indexed(0..num_indices, 0, 0..1);
}
fn draw_gradient(
pub fn draw_gradient(
&mut self,
vertices: wgpu::BufferSlice<'a>,
indices: wgpu::BufferSlice<'a>,
@ -167,7 +146,7 @@ impl<'a> Frame<'a> {
self.render_pass.draw_indexed(0..num_indices, 0, 0..1);
}
fn draw_bitmap(
pub fn draw_bitmap(
&mut self,
vertices: wgpu::BufferSlice<'a>,
indices: wgpu::BufferSlice<'a>,
@ -197,7 +176,7 @@ impl<'a> Frame<'a> {
self.render_pass.draw_indexed(0..num_indices, 0, 0..1);
}
fn apply_transform(
pub fn apply_transform(
&mut self,
matrix: &ruffle_render::matrix::Matrix,
color_adjustments: ColorAdjustments,
@ -226,150 +205,26 @@ impl<'a> Frame<'a> {
},
);
}
}
impl<'a> CommandHandler for Frame<'a> {
fn render_bitmap(&mut self, bitmap: BitmapHandle, transform: &Transform, smoothing: bool) {
if let Some(entry) = self.bitmap_registry.get(&bitmap) {
let texture = &entry.texture_wrapper;
self.apply_transform(
&(transform.matrix
* ruffle_render::matrix::Matrix {
a: texture.width as f32,
d: texture.height as f32,
..Default::default()
}),
ColorAdjustments::from(transform.color_transform),
);
self.draw_bitmap(
self.quad_vertices,
self.quad_indices,
6,
&texture.bind_group,
false,
smoothing,
);
}
pub fn set_mask_state(&mut self, state: MaskState) {
self.mask_state = state;
}
fn render_shape(&mut self, shape: ShapeHandle, transform: &Transform) {
self.apply_transform(
&transform.matrix,
ColorAdjustments::from(transform.color_transform),
);
pub fn set_mask_count(&mut self, num: u32) {
self.num_masks = num;
let mesh = &self.meshes[shape.0];
for draw in &mesh.draws {
let num_indices = if self.mask_state != MaskState::DrawMaskStencil
&& self.mask_state != MaskState::ClearMaskStencil
{
draw.num_indices
} else {
// Omit strokes when drawing a mask stencil.
draw.num_mask_indices
};
if num_indices == 0 {
continue;
}
match &draw.draw_type {
DrawType::Color => {
self.draw_color(
draw.vertex_buffer.slice(..),
draw.index_buffer.slice(..),
num_indices,
);
}
DrawType::Gradient { bind_group, .. } => {
self.draw_gradient(
draw.vertex_buffer.slice(..),
draw.index_buffer.slice(..),
num_indices,
bind_group,
);
}
DrawType::Bitmap {
is_repeating,
is_smoothed,
bind_group,
..
} => {
self.draw_bitmap(
draw.vertex_buffer.slice(..),
draw.index_buffer.slice(..),
num_indices,
bind_group,
*is_repeating,
*is_smoothed,
);
}
}
}
}
fn draw_rect(&mut self, color: Color, matrix: &ruffle_render::matrix::Matrix) {
self.apply_transform(
&matrix,
ColorAdjustments {
mult_color: [
f32::from(color.r) / 255.0,
f32::from(color.g) / 255.0,
f32::from(color.b) / 255.0,
f32::from(color.a) / 255.0,
],
add_color: [0.0, 0.0, 0.0, 0.0],
},
);
self.draw_color(self.quad_vertices, self.quad_indices, 6);
}
fn push_mask(&mut self) {
debug_assert!(
self.mask_state == MaskState::NoMask || self.mask_state == MaskState::DrawMaskedContent
);
self.num_masks += 1;
self.mask_state = MaskState::DrawMaskStencil;
self.render_pass.set_stencil_reference(self.num_masks - 1);
}
fn activate_mask(&mut self) {
debug_assert!(self.num_masks > 0 && self.mask_state == MaskState::DrawMaskStencil);
self.mask_state = MaskState::DrawMaskedContent;
self.render_pass.set_stencil_reference(self.num_masks);
}
fn deactivate_mask(&mut self) {
debug_assert!(self.num_masks > 0 && self.mask_state == MaskState::DrawMaskedContent);
self.mask_state = MaskState::ClearMaskStencil;
self.render_pass.set_stencil_reference(self.num_masks);
pub fn set_blend_mode(&mut self, blend_mode: ActualBlendMode) {
self.blend_mode = blend_mode;
}
fn pop_mask(&mut self) {
debug_assert!(self.num_masks > 0 && self.mask_state == MaskState::ClearMaskStencil);
self.num_masks -= 1;
self.mask_state = if self.num_masks == 0 {
MaskState::NoMask
} else {
self.render_pass.set_stencil_reference(self.num_masks);
MaskState::DrawMaskedContent
};
pub fn mask_state(&self) -> MaskState {
self.mask_state
}
fn push_blend_mode(&mut self, blend: BlendMode) {
self.blend_modes.push(blend);
self.blend_mode = blend.into();
}
fn pop_blend_mode(&mut self) {
self.blend_modes.pop();
self.blend_mode = self
.blend_modes
.last()
.map(|b| ActualBlendMode::from(*b))
.unwrap_or(ActualBlendMode::Normal);
pub fn num_masks(&self) -> u32 {
self.num_masks
}
}

View File

@ -26,6 +26,7 @@ mod uniform_buffer;
pub mod backend;
#[cfg(feature = "clap")]
pub mod clap;
mod commands;
pub mod descriptors;
mod frame;
mod layouts;
@ -59,7 +60,7 @@ struct TextureTransforms {
#[repr(C)]
#[derive(Copy, Clone, Debug, Pod, Zeroable)]
struct ColorAdjustments {
pub struct ColorAdjustments {
mult_color: [f32; 4],
add_color: [f32; 4],
}