diff --git a/render/wgpu/src/commands.rs b/render/wgpu/src/commands.rs index 228d8c024..fb83a43d4 100644 --- a/render/wgpu/src/commands.rs +++ b/render/wgpu/src/commands.rs @@ -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, - resolve_buffer: Option, - depth: OnceCell, - globals: Arc, - 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 { - 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::() 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 { - 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 { - 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, @@ -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 { diff --git a/render/wgpu/src/lib.rs b/render/wgpu/src/lib.rs index 01a207dc6..3f13a39e2 100644 --- a/render/wgpu/src/lib.rs +++ b/render/wgpu/src/lib.rs @@ -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}; diff --git a/render/wgpu/src/surface.rs b/render/wgpu/src/surface.rs index 8eb30a3ae..02d4f9a26 100644 --- a/render/wgpu/src/surface.rs +++ b/render/wgpu/src/surface.rs @@ -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, - 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 { - self.texture - } -} - -#[derive(Debug)] -pub struct FrameBuffer { - texture: PoolEntry, - 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 { - self.texture - } - - pub fn size(&self) -> wgpu::Extent3d { - self.size - } -} - -#[derive(Debug)] -pub struct BlendBuffer { - texture: PoolEntry, - 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, - 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 { diff --git a/render/wgpu/src/surface/target.rs b/render/wgpu/src/surface/target.rs new file mode 100644 index 000000000..975c6386b --- /dev/null +++ b/render/wgpu/src/surface/target.rs @@ -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, + 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 { + self.texture + } +} + +#[derive(Debug)] +pub struct FrameBuffer { + texture: PoolEntry, + 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 { + self.texture + } + + pub fn size(&self) -> wgpu::Extent3d { + self.size + } +} + +#[derive(Debug)] +pub struct BlendBuffer { + texture: PoolEntry, + 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, + 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, + resolve_buffer: Option, + depth: OnceCell, + globals: Arc, + 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 { + 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::() 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 { + 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 { + 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()) + } +}