wgpu: Refactor surface command target to its own file
This commit is contained in:
parent
a657feadae
commit
0272eda121
|
@ -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 {
|
||||
|
|
|
@ -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};
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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())
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue