2022-07-02 12:18:30 +00:00
|
|
|
use crate::bitmaps::BitmapSamplers;
|
|
|
|
use crate::globals::Globals;
|
2020-04-29 10:25:37 +00:00
|
|
|
use crate::pipelines::Pipelines;
|
2022-09-06 21:38:48 +00:00
|
|
|
use crate::target::TextureTarget;
|
2020-05-04 20:59:06 +00:00
|
|
|
use crate::target::{RenderTarget, RenderTargetFrame, SwapChainTarget};
|
2022-07-02 12:18:30 +00:00
|
|
|
use crate::uniform_buffer::UniformBuffer;
|
2022-09-06 21:38:48 +00:00
|
|
|
use crate::utils::{create_buffer_with_data, format_list, get_backend_names, BufferDimensions};
|
2022-05-27 19:16:33 +00:00
|
|
|
use bytemuck::{Pod, Zeroable};
|
2020-10-14 18:25:55 +00:00
|
|
|
use enum_map::Enum;
|
2022-06-29 22:16:43 +00:00
|
|
|
use fnv::FnvHashMap;
|
2022-08-04 05:50:18 +00:00
|
|
|
use ruffle_render::backend::{RenderBackend, ShapeHandle, ViewportDimensions};
|
2022-08-13 22:52:16 +00:00
|
|
|
use ruffle_render::bitmap::{Bitmap, BitmapHandle, BitmapSource};
|
2022-08-13 23:07:13 +00:00
|
|
|
use ruffle_render::color_transform::ColorTransform;
|
2022-08-18 23:34:35 +00:00
|
|
|
use ruffle_render::error::Error as BitmapError;
|
2022-08-13 23:05:38 +00:00
|
|
|
use ruffle_render::shape_utils::DistilledShape;
|
2022-08-13 23:27:27 +00:00
|
|
|
use ruffle_render::tessellator::{
|
2021-03-20 14:30:21 +00:00
|
|
|
DrawType as TessDrawType, Gradient as TessGradient, GradientType, ShapeTessellator,
|
|
|
|
Vertex as TessVertex,
|
|
|
|
};
|
2022-08-13 23:27:27 +00:00
|
|
|
use ruffle_render::transform::Transform;
|
2022-05-27 19:16:33 +00:00
|
|
|
use std::num::NonZeroU32;
|
2022-07-02 12:18:30 +00:00
|
|
|
use std::path::Path;
|
2022-08-08 00:14:25 +00:00
|
|
|
use std::sync::Arc;
|
2022-07-25 16:31:40 +00:00
|
|
|
use swf::{BlendMode, Color};
|
2022-07-02 12:18:30 +00:00
|
|
|
pub use wgpu;
|
2020-04-29 10:25:37 +00:00
|
|
|
|
2020-04-21 13:32:50 +00:00
|
|
|
type Error = Box<dyn std::error::Error>;
|
|
|
|
|
2020-04-28 14:10:45 +00:00
|
|
|
#[macro_use]
|
2020-04-29 10:25:37 +00:00
|
|
|
mod utils;
|
2020-04-28 14:10:45 +00:00
|
|
|
|
2020-10-15 22:55:19 +00:00
|
|
|
mod bitmaps;
|
2020-10-16 15:46:40 +00:00
|
|
|
mod globals;
|
2020-04-28 14:10:45 +00:00
|
|
|
mod pipelines;
|
2020-05-04 21:33:45 +00:00
|
|
|
pub mod target;
|
2021-09-07 20:25:56 +00:00
|
|
|
mod uniform_buffer;
|
2020-04-27 20:42:59 +00:00
|
|
|
|
2020-10-10 20:16:32 +00:00
|
|
|
#[cfg(feature = "clap")]
|
|
|
|
pub mod clap;
|
|
|
|
|
2022-09-06 21:38:48 +00:00
|
|
|
const DEFAULT_SAMPLE_COUNT: u32 = 4;
|
|
|
|
|
2020-10-15 23:23:36 +00:00
|
|
|
pub struct Descriptors {
|
|
|
|
pub device: wgpu::Device,
|
2022-09-06 21:38:48 +00:00
|
|
|
pub queue: wgpu::Queue,
|
2021-02-20 18:10:04 +00:00
|
|
|
pub info: wgpu::AdapterInfo,
|
2021-09-07 20:25:56 +00:00
|
|
|
pub limits: wgpu::Limits,
|
2022-08-07 23:54:11 +00:00
|
|
|
globals_layout: wgpu::BindGroupLayout,
|
2022-08-08 00:12:35 +00:00
|
|
|
uniform_buffers_layout: wgpu::BindGroupLayout,
|
2020-10-15 23:23:36 +00:00
|
|
|
bitmap_samplers: BitmapSamplers,
|
2022-09-06 21:38:48 +00:00
|
|
|
|
|
|
|
onscreen: DescriptorsTargetData,
|
|
|
|
offscreen: DescriptorsTargetData,
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Contains data specific to a `RenderTarget`.
|
|
|
|
/// We cannot re-use this data in `with_offscreen_backend`
|
|
|
|
pub struct DescriptorsTargetData {
|
|
|
|
// These fields are specific to our `RenderTarget`, and
|
|
|
|
// cannot be re-used
|
|
|
|
surface_format: wgpu::TextureFormat,
|
|
|
|
frame_buffer_format: wgpu::TextureFormat,
|
|
|
|
pipelines: Pipelines,
|
2020-10-15 23:23:36 +00:00
|
|
|
msaa_sample_count: u32,
|
|
|
|
}
|
|
|
|
|
2022-09-06 21:38:48 +00:00
|
|
|
impl DescriptorsTargetData {
|
|
|
|
fn new(
|
|
|
|
device: &wgpu::Device,
|
2021-09-08 01:55:26 +00:00
|
|
|
surface_format: wgpu::TextureFormat,
|
2022-09-06 21:38:48 +00:00
|
|
|
bitmap_samplers: &BitmapSamplers,
|
|
|
|
msaa_sample_count: u32,
|
|
|
|
globals_layout: &wgpu::BindGroupLayout,
|
|
|
|
uniform_buffers_layout: &wgpu::BindGroupLayout,
|
2022-08-18 23:48:01 +00:00
|
|
|
) -> Self {
|
2022-04-14 18:03:45 +00:00
|
|
|
// We want to render directly onto a linear render target to avoid any gamma correction.
|
|
|
|
// If our surface is sRGB, render to a linear texture and than copy over to the surface.
|
|
|
|
// Remove Srgb from texture format.
|
|
|
|
let frame_buffer_format = match surface_format {
|
|
|
|
wgpu::TextureFormat::Rgba8UnormSrgb => wgpu::TextureFormat::Rgba8Unorm,
|
|
|
|
wgpu::TextureFormat::Bgra8UnormSrgb => wgpu::TextureFormat::Bgra8Unorm,
|
|
|
|
wgpu::TextureFormat::Bc1RgbaUnormSrgb => wgpu::TextureFormat::Bc1RgbaUnorm,
|
|
|
|
wgpu::TextureFormat::Bc2RgbaUnormSrgb => wgpu::TextureFormat::Bc2RgbaUnorm,
|
|
|
|
wgpu::TextureFormat::Bc3RgbaUnormSrgb => wgpu::TextureFormat::Bc3RgbaUnorm,
|
|
|
|
wgpu::TextureFormat::Bc7RgbaUnormSrgb => wgpu::TextureFormat::Bc7RgbaUnorm,
|
|
|
|
wgpu::TextureFormat::Etc2Rgb8UnormSrgb => wgpu::TextureFormat::Etc2Rgb8Unorm,
|
|
|
|
wgpu::TextureFormat::Etc2Rgb8A1UnormSrgb => wgpu::TextureFormat::Etc2Rgb8A1Unorm,
|
|
|
|
wgpu::TextureFormat::Etc2Rgba8UnormSrgb => wgpu::TextureFormat::Etc2Rgba8Unorm,
|
2022-07-02 12:18:30 +00:00
|
|
|
wgpu::TextureFormat::Astc {
|
|
|
|
block,
|
|
|
|
channel: wgpu::AstcChannel::UnormSrgb,
|
|
|
|
} => wgpu::TextureFormat::Astc {
|
|
|
|
block,
|
|
|
|
channel: wgpu::AstcChannel::Unorm,
|
|
|
|
},
|
2022-04-14 18:03:45 +00:00
|
|
|
_ => surface_format,
|
|
|
|
};
|
|
|
|
|
2022-09-06 21:38:48 +00:00
|
|
|
let pipelines = Pipelines::new(
|
|
|
|
&device,
|
|
|
|
surface_format,
|
|
|
|
frame_buffer_format,
|
|
|
|
msaa_sample_count,
|
|
|
|
bitmap_samplers.layout(),
|
|
|
|
globals_layout,
|
|
|
|
uniform_buffers_layout,
|
|
|
|
);
|
|
|
|
|
|
|
|
DescriptorsTargetData {
|
|
|
|
surface_format,
|
|
|
|
frame_buffer_format,
|
|
|
|
pipelines,
|
|
|
|
msaa_sample_count,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Descriptors {
|
|
|
|
pub fn new(
|
|
|
|
device: wgpu::Device,
|
|
|
|
queue: wgpu::Queue,
|
|
|
|
info: wgpu::AdapterInfo,
|
|
|
|
surface_format: wgpu::TextureFormat,
|
|
|
|
msaa_sample_count: u32,
|
|
|
|
) -> Self {
|
|
|
|
let limits = device.limits();
|
|
|
|
let bitmap_samplers = BitmapSamplers::new(&device);
|
|
|
|
|
2022-08-07 23:54:11 +00:00
|
|
|
let globals_layout_label = create_debug_label!("Globals bind group layout");
|
|
|
|
let globals_layout = device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor {
|
|
|
|
label: globals_layout_label.as_deref(),
|
|
|
|
entries: &[wgpu::BindGroupLayoutEntry {
|
|
|
|
binding: 0,
|
|
|
|
visibility: wgpu::ShaderStages::VERTEX,
|
|
|
|
ty: wgpu::BindingType::Buffer {
|
|
|
|
ty: wgpu::BufferBindingType::Uniform,
|
|
|
|
has_dynamic_offset: false,
|
|
|
|
min_binding_size: None,
|
|
|
|
},
|
|
|
|
count: None,
|
|
|
|
}],
|
|
|
|
});
|
|
|
|
|
2022-09-06 21:38:48 +00:00
|
|
|
let uniform_buffer_layout_label = create_debug_label!("Uniform buffer bind group layout");
|
|
|
|
let uniform_buffers_layout =
|
|
|
|
device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor {
|
|
|
|
entries: &[wgpu::BindGroupLayoutEntry {
|
|
|
|
binding: 0,
|
|
|
|
visibility: wgpu::ShaderStages::VERTEX | wgpu::ShaderStages::FRAGMENT,
|
|
|
|
ty: wgpu::BindingType::Buffer {
|
|
|
|
ty: wgpu::BufferBindingType::Uniform,
|
|
|
|
has_dynamic_offset: true,
|
|
|
|
min_binding_size: None,
|
|
|
|
},
|
|
|
|
count: None,
|
|
|
|
}],
|
|
|
|
label: uniform_buffer_layout_label.as_deref(),
|
|
|
|
});
|
|
|
|
|
|
|
|
let onscreen = DescriptorsTargetData::new(
|
2020-10-16 15:46:40 +00:00
|
|
|
&device,
|
2021-09-08 01:55:26 +00:00
|
|
|
surface_format,
|
2022-09-06 21:38:48 +00:00
|
|
|
&bitmap_samplers,
|
2020-10-16 15:46:40 +00:00
|
|
|
msaa_sample_count,
|
2022-09-06 21:38:48 +00:00
|
|
|
&globals_layout,
|
|
|
|
&uniform_buffers_layout,
|
|
|
|
);
|
|
|
|
|
|
|
|
// FIXME - get MSAA working for `TextureTarget`
|
|
|
|
let offscreen = DescriptorsTargetData::new(
|
|
|
|
&device,
|
|
|
|
wgpu::TextureFormat::Rgba8Unorm,
|
|
|
|
&bitmap_samplers,
|
|
|
|
1,
|
2022-08-07 23:54:11 +00:00
|
|
|
&globals_layout,
|
2022-08-08 00:12:35 +00:00
|
|
|
&uniform_buffers_layout,
|
2022-08-18 23:46:53 +00:00
|
|
|
);
|
2020-10-15 23:23:36 +00:00
|
|
|
|
2022-08-18 23:48:01 +00:00
|
|
|
Self {
|
2020-10-15 23:23:36 +00:00
|
|
|
device,
|
2022-09-06 21:38:48 +00:00
|
|
|
queue,
|
2021-02-20 18:10:04 +00:00
|
|
|
info,
|
2021-09-07 20:25:56 +00:00
|
|
|
limits,
|
2022-09-06 21:38:48 +00:00
|
|
|
bitmap_samplers,
|
2022-08-07 23:54:11 +00:00
|
|
|
globals_layout,
|
2022-08-08 00:12:35 +00:00
|
|
|
uniform_buffers_layout,
|
2022-09-06 21:38:48 +00:00
|
|
|
onscreen,
|
|
|
|
offscreen,
|
2022-08-18 23:48:01 +00:00
|
|
|
}
|
2020-10-15 23:23:36 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-05-04 20:59:06 +00:00
|
|
|
pub struct WgpuRenderBackend<T: RenderTarget> {
|
2022-08-08 00:14:25 +00:00
|
|
|
descriptors: Arc<Descriptors>,
|
2022-08-07 23:54:11 +00:00
|
|
|
globals: Globals,
|
2022-08-08 00:12:35 +00:00
|
|
|
uniform_buffers: UniformBuffer<Transforms>,
|
2020-05-04 20:59:06 +00:00
|
|
|
target: T,
|
2022-04-14 21:53:12 +00:00
|
|
|
frame_buffer_view: Option<wgpu::TextureView>,
|
2020-04-21 13:32:50 +00:00
|
|
|
depth_texture_view: wgpu::TextureView,
|
2022-04-14 21:53:12 +00:00
|
|
|
copy_srgb_view: Option<wgpu::TextureView>,
|
|
|
|
copy_srgb_bind_group: Option<wgpu::BindGroup>,
|
2020-12-26 00:43:03 +00:00
|
|
|
current_frame: Option<Frame<'static, T>>,
|
2020-04-21 13:32:50 +00:00
|
|
|
meshes: Vec<Mesh>,
|
2020-10-14 18:25:55 +00:00
|
|
|
mask_state: MaskState,
|
2021-03-19 12:05:07 +00:00
|
|
|
shape_tessellator: ShapeTessellator,
|
2020-04-28 20:48:17 +00:00
|
|
|
num_masks: u32,
|
2020-04-29 10:06:02 +00:00
|
|
|
quad_vbo: wgpu::Buffer,
|
|
|
|
quad_ibo: wgpu::Buffer,
|
|
|
|
quad_tex_transforms: wgpu::Buffer,
|
2022-07-25 16:31:40 +00:00
|
|
|
blend_modes: Vec<BlendMode>,
|
2022-06-29 22:16:43 +00:00
|
|
|
bitmap_registry: FnvHashMap<BitmapHandle, RegistryData>,
|
|
|
|
next_bitmap_handle: BitmapHandle,
|
2022-08-04 05:50:18 +00:00
|
|
|
// This is currently unused - we just store it to report in
|
|
|
|
// `get_viewport_dimensions`
|
|
|
|
viewport_scale_factor: f64,
|
2022-09-06 21:38:48 +00:00
|
|
|
offscreen: bool,
|
2022-06-29 22:16:43 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
struct RegistryData {
|
|
|
|
bitmap: Bitmap,
|
|
|
|
texture_wrapper: Texture,
|
2020-04-21 13:32:50 +00:00
|
|
|
}
|
|
|
|
|
2020-12-26 00:43:03 +00:00
|
|
|
#[allow(dead_code)]
|
|
|
|
struct Frame<'a, T: RenderTarget> {
|
2021-09-07 20:25:56 +00:00
|
|
|
frame_data: Box<(wgpu::CommandEncoder, T::Frame, wgpu::CommandEncoder)>,
|
2020-12-26 00:43:03 +00:00
|
|
|
|
|
|
|
// TODO: This is a self-reference to the above, so we
|
|
|
|
// use some unsafe to cast the lifetime away. We know this
|
|
|
|
// is safe because the anpve data should live for the
|
|
|
|
// entire frame and is boxed to have a stable address.
|
|
|
|
// We could clean this up later by adjusting the
|
|
|
|
// RenderBackend interface to return a Frame object.
|
|
|
|
render_pass: wgpu::RenderPass<'a>,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<'a, T: RenderTarget> Frame<'static, T> {
|
|
|
|
// Get a reference to the render pass with the proper lifetime.
|
|
|
|
fn get(&mut self) -> &mut Frame<'a, T> {
|
|
|
|
unsafe { std::mem::transmute::<_, &mut Frame<'a, T>>(self) }
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-10-14 18:25:55 +00:00
|
|
|
#[derive(Debug, Clone, Copy, PartialEq, Eq, Enum)]
|
|
|
|
pub enum MaskState {
|
|
|
|
NoMask,
|
|
|
|
DrawMaskStencil,
|
|
|
|
DrawMaskedContent,
|
|
|
|
ClearMaskStencil,
|
|
|
|
}
|
|
|
|
|
2020-04-21 13:32:50 +00:00
|
|
|
#[repr(C)]
|
2021-02-17 04:34:12 +00:00
|
|
|
#[derive(Copy, Clone, Debug, Pod, Zeroable)]
|
2020-04-21 13:32:50 +00:00
|
|
|
struct Transforms {
|
|
|
|
world_matrix: [[f32; 4]; 4],
|
2021-09-07 20:25:56 +00:00
|
|
|
color_adjustments: ColorAdjustments,
|
2020-04-21 13:32:50 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
#[repr(C)]
|
2021-02-17 04:34:12 +00:00
|
|
|
#[derive(Copy, Clone, Debug, Pod, Zeroable)]
|
2020-04-21 13:32:50 +00:00
|
|
|
struct TextureTransforms {
|
|
|
|
u_matrix: [[f32; 4]; 4],
|
|
|
|
}
|
|
|
|
|
|
|
|
#[repr(C)]
|
2021-02-17 04:34:12 +00:00
|
|
|
#[derive(Copy, Clone, Debug, Pod, Zeroable)]
|
2020-04-21 13:32:50 +00:00
|
|
|
struct ColorAdjustments {
|
|
|
|
mult_color: [f32; 4],
|
|
|
|
add_color: [f32; 4],
|
|
|
|
}
|
|
|
|
|
2020-04-30 14:40:08 +00:00
|
|
|
impl From<ColorTransform> for ColorAdjustments {
|
|
|
|
fn from(transform: ColorTransform) -> Self {
|
|
|
|
Self {
|
2021-04-18 06:32:53 +00:00
|
|
|
mult_color: transform.mult_rgba_normalized(),
|
|
|
|
add_color: transform.add_rgba_normalized(),
|
2020-04-30 14:40:08 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-04-21 13:32:50 +00:00
|
|
|
#[repr(C)]
|
2021-02-17 04:34:12 +00:00
|
|
|
#[derive(Copy, Clone, Debug, Pod, Zeroable)]
|
2021-03-20 14:30:21 +00:00
|
|
|
struct Vertex {
|
2020-04-21 13:32:50 +00:00
|
|
|
position: [f32; 2],
|
|
|
|
color: [f32; 4],
|
|
|
|
}
|
|
|
|
|
2021-03-20 14:30:21 +00:00
|
|
|
impl From<TessVertex> for Vertex {
|
|
|
|
fn from(vertex: TessVertex) -> Self {
|
2021-03-19 12:05:07 +00:00
|
|
|
Self {
|
2021-03-20 14:12:39 +00:00
|
|
|
position: [vertex.x, vertex.y],
|
|
|
|
color: [
|
|
|
|
f32::from(vertex.color.r) / 255.0,
|
|
|
|
f32::from(vertex.color.g) / 255.0,
|
|
|
|
f32::from(vertex.color.b) / 255.0,
|
|
|
|
f32::from(vertex.color.a) / 255.0,
|
|
|
|
],
|
2020-12-25 21:42:14 +00:00
|
|
|
}
|
2020-04-21 13:32:50 +00:00
|
|
|
}
|
2021-03-20 14:12:39 +00:00
|
|
|
}
|
2020-04-21 13:32:50 +00:00
|
|
|
|
2021-03-20 14:12:39 +00:00
|
|
|
#[repr(C)]
|
|
|
|
#[derive(Copy, Clone, Debug, Pod, Zeroable)]
|
|
|
|
struct GradientUniforms {
|
2022-08-27 21:39:57 +00:00
|
|
|
colors: [[f32; 16]; 16],
|
|
|
|
ratios: [[f32; 4]; 16],
|
|
|
|
gradient_type: i32,
|
|
|
|
num_colors: u32,
|
|
|
|
repeat_mode: i32,
|
|
|
|
interpolation: i32,
|
|
|
|
focal_point: f32,
|
|
|
|
_padding: [f32; 3],
|
|
|
|
}
|
|
|
|
|
|
|
|
impl From<TessGradient> for GradientUniforms {
|
|
|
|
fn from(gradient: TessGradient) -> Self {
|
|
|
|
let mut ratios = [[0.0; 4]; 16];
|
|
|
|
let mut colors = [[0.0; 16]; 16];
|
|
|
|
|
|
|
|
for i in 0..gradient.num_colors {
|
|
|
|
ratios[i] = [gradient.ratios[i], 0.0, 0.0, 0.0];
|
|
|
|
colors[i][0..4].copy_from_slice(&gradient.colors[i]);
|
|
|
|
}
|
|
|
|
|
|
|
|
Self {
|
|
|
|
colors,
|
|
|
|
ratios,
|
|
|
|
gradient_type: match gradient.gradient_type {
|
|
|
|
GradientType::Linear => 0,
|
|
|
|
GradientType::Radial => 1,
|
|
|
|
GradientType::Focal => 2,
|
|
|
|
},
|
|
|
|
num_colors: gradient.num_colors as u32,
|
|
|
|
repeat_mode: match gradient.repeat_mode {
|
|
|
|
swf::GradientSpread::Pad => 0,
|
|
|
|
swf::GradientSpread::Repeat => 1,
|
|
|
|
swf::GradientSpread::Reflect => 2,
|
|
|
|
},
|
|
|
|
interpolation: (gradient.interpolation == swf::GradientInterpolation::LinearRgb) as i32,
|
|
|
|
focal_point: gradient.focal_point.to_f32(),
|
|
|
|
_padding: Default::default(),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[repr(C)]
|
|
|
|
#[derive(Copy, Clone, Debug, Pod, Zeroable)]
|
|
|
|
struct GradientStorage {
|
2021-03-20 14:12:39 +00:00
|
|
|
colors: [[f32; 4]; 16],
|
|
|
|
ratios: [f32; 16],
|
|
|
|
gradient_type: i32,
|
|
|
|
num_colors: u32,
|
|
|
|
repeat_mode: i32,
|
|
|
|
interpolation: i32,
|
|
|
|
focal_point: f32,
|
2022-01-19 18:21:28 +00:00
|
|
|
_padding: [f32; 3],
|
2021-03-20 14:12:39 +00:00
|
|
|
}
|
2020-04-21 13:32:50 +00:00
|
|
|
|
2022-08-27 21:39:57 +00:00
|
|
|
impl From<TessGradient> for GradientStorage {
|
2021-03-20 14:30:21 +00:00
|
|
|
fn from(gradient: TessGradient) -> Self {
|
2021-03-20 14:12:39 +00:00
|
|
|
let mut ratios = [0.0; 16];
|
|
|
|
let mut colors = [[0.0; 4]; 16];
|
|
|
|
ratios[..gradient.num_colors].copy_from_slice(&gradient.ratios[..gradient.num_colors]);
|
|
|
|
colors[..gradient.num_colors].copy_from_slice(&gradient.colors[..gradient.num_colors]);
|
2020-04-21 13:32:50 +00:00
|
|
|
|
2021-03-20 14:12:39 +00:00
|
|
|
Self {
|
|
|
|
colors,
|
|
|
|
ratios,
|
|
|
|
gradient_type: match gradient.gradient_type {
|
|
|
|
GradientType::Linear => 0,
|
|
|
|
GradientType::Radial => 1,
|
|
|
|
GradientType::Focal => 2,
|
|
|
|
},
|
|
|
|
num_colors: gradient.num_colors as u32,
|
|
|
|
repeat_mode: match gradient.repeat_mode {
|
2021-03-20 14:30:21 +00:00
|
|
|
swf::GradientSpread::Pad => 0,
|
|
|
|
swf::GradientSpread::Repeat => 1,
|
|
|
|
swf::GradientSpread::Reflect => 2,
|
2021-03-20 14:12:39 +00:00
|
|
|
},
|
2021-03-20 14:30:21 +00:00
|
|
|
interpolation: (gradient.interpolation == swf::GradientInterpolation::LinearRgb) as i32,
|
2021-05-30 20:30:06 +00:00
|
|
|
focal_point: gradient.focal_point.to_f32(),
|
2022-01-19 18:21:28 +00:00
|
|
|
_padding: Default::default(),
|
2020-04-21 13:32:50 +00:00
|
|
|
}
|
2021-03-20 14:12:39 +00:00
|
|
|
}
|
|
|
|
}
|
2020-04-21 13:32:50 +00:00
|
|
|
|
2021-03-20 14:12:39 +00:00
|
|
|
#[derive(Debug)]
|
|
|
|
struct Mesh {
|
|
|
|
draws: Vec<Draw>,
|
|
|
|
}
|
2020-04-21 13:32:50 +00:00
|
|
|
|
2021-03-20 14:12:39 +00:00
|
|
|
#[derive(Debug)]
|
|
|
|
struct Draw {
|
|
|
|
draw_type: DrawType,
|
|
|
|
vertex_buffer: wgpu::Buffer,
|
|
|
|
index_buffer: wgpu::Buffer,
|
2022-05-24 23:19:59 +00:00
|
|
|
num_indices: u32,
|
|
|
|
num_mask_indices: u32,
|
2021-03-20 14:12:39 +00:00
|
|
|
}
|
2020-04-21 13:32:50 +00:00
|
|
|
|
2021-09-12 04:25:41 +00:00
|
|
|
#[allow(dead_code)]
|
2021-03-20 14:12:39 +00:00
|
|
|
#[derive(Debug)]
|
|
|
|
enum DrawType {
|
|
|
|
Color,
|
|
|
|
Gradient {
|
|
|
|
texture_transforms: wgpu::Buffer,
|
|
|
|
gradient: wgpu::Buffer,
|
|
|
|
bind_group: wgpu::BindGroup,
|
|
|
|
},
|
|
|
|
Bitmap {
|
|
|
|
texture_transforms: wgpu::Buffer,
|
|
|
|
texture_view: wgpu::TextureView,
|
|
|
|
is_smoothed: bool,
|
|
|
|
is_repeating: bool,
|
|
|
|
bind_group: wgpu::BindGroup,
|
|
|
|
},
|
2021-03-19 12:05:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
impl WgpuRenderBackend<SwapChainTarget> {
|
2021-09-09 00:54:13 +00:00
|
|
|
#[cfg(target_family = "wasm")]
|
|
|
|
pub async fn for_canvas(canvas: &web_sys::HtmlCanvasElement) -> Result<Self, Error> {
|
2022-08-27 21:39:57 +00:00
|
|
|
let instance = wgpu::Instance::new(wgpu::Backends::BROWSER_WEBGPU | wgpu::Backends::GL);
|
2022-07-02 12:18:30 +00:00
|
|
|
let surface = instance.create_surface_from_canvas(canvas);
|
2021-09-09 00:54:13 +00:00
|
|
|
let descriptors = Self::build_descriptors(
|
2022-08-27 21:39:57 +00:00
|
|
|
wgpu::Backends::BROWSER_WEBGPU | wgpu::Backends::GL,
|
2021-09-09 00:54:13 +00:00
|
|
|
instance,
|
|
|
|
Some(&surface),
|
|
|
|
wgpu::PowerPreference::HighPerformance,
|
|
|
|
None,
|
|
|
|
)
|
|
|
|
.await?;
|
|
|
|
let target = SwapChainTarget::new(
|
|
|
|
surface,
|
2022-09-06 21:38:48 +00:00
|
|
|
descriptors.onscreen.surface_format,
|
2021-09-09 00:54:13 +00:00
|
|
|
(1, 1),
|
|
|
|
&descriptors.device,
|
|
|
|
);
|
2022-08-08 00:14:25 +00:00
|
|
|
Self::new(Arc::new(descriptors), target)
|
2021-09-09 00:54:13 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
#[cfg(not(target_family = "wasm"))]
|
|
|
|
pub fn for_window<W: raw_window_handle::HasRawWindowHandle>(
|
2021-03-19 12:05:07 +00:00
|
|
|
window: &W,
|
|
|
|
size: (u32, u32),
|
2021-09-08 07:20:11 +00:00
|
|
|
backend: wgpu::Backends,
|
2021-03-19 12:05:07 +00:00
|
|
|
power_preference: wgpu::PowerPreference,
|
|
|
|
trace_path: Option<&Path>,
|
|
|
|
) -> Result<Self, Error> {
|
2021-09-08 07:20:11 +00:00
|
|
|
if wgpu::Backends::SECONDARY.contains(backend) {
|
2021-03-19 12:05:07 +00:00
|
|
|
log::warn!(
|
|
|
|
"{} graphics backend support may not be fully supported.",
|
|
|
|
format_list(&get_backend_names(backend), "and")
|
|
|
|
);
|
|
|
|
}
|
|
|
|
let instance = wgpu::Instance::new(backend);
|
|
|
|
let surface = unsafe { instance.create_surface(window) };
|
2021-09-09 00:54:13 +00:00
|
|
|
let descriptors = futures::executor::block_on(Self::build_descriptors(
|
2021-03-19 12:05:07 +00:00
|
|
|
backend,
|
|
|
|
instance,
|
|
|
|
Some(&surface),
|
|
|
|
power_preference,
|
|
|
|
trace_path,
|
2021-09-08 23:40:51 +00:00
|
|
|
))?;
|
2021-09-08 01:55:26 +00:00
|
|
|
let target = SwapChainTarget::new(
|
|
|
|
surface,
|
2022-09-06 21:38:48 +00:00
|
|
|
descriptors.onscreen.surface_format,
|
2021-09-08 01:55:26 +00:00
|
|
|
size,
|
|
|
|
&descriptors.device,
|
|
|
|
);
|
2022-08-08 00:14:25 +00:00
|
|
|
Self::new(Arc::new(descriptors), target)
|
2021-03-19 12:05:07 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-09-09 00:54:13 +00:00
|
|
|
#[cfg(not(target_family = "wasm"))]
|
|
|
|
impl WgpuRenderBackend<target::TextureTarget> {
|
2021-03-19 12:05:07 +00:00
|
|
|
pub fn for_offscreen(
|
|
|
|
size: (u32, u32),
|
2021-09-08 07:20:11 +00:00
|
|
|
backend: wgpu::Backends,
|
2021-03-19 12:05:07 +00:00
|
|
|
power_preference: wgpu::PowerPreference,
|
|
|
|
trace_path: Option<&Path>,
|
|
|
|
) -> Result<Self, Error> {
|
2021-09-08 07:20:11 +00:00
|
|
|
if wgpu::Backends::SECONDARY.contains(backend) {
|
2021-03-19 12:05:07 +00:00
|
|
|
log::warn!(
|
|
|
|
"{} graphics backend support may not be fully supported.",
|
|
|
|
format_list(&get_backend_names(backend), "and")
|
|
|
|
);
|
|
|
|
}
|
|
|
|
let instance = wgpu::Instance::new(backend);
|
2021-09-09 00:54:13 +00:00
|
|
|
let descriptors = futures::executor::block_on(Self::build_descriptors(
|
2021-09-08 23:40:51 +00:00
|
|
|
backend,
|
|
|
|
instance,
|
|
|
|
None,
|
|
|
|
power_preference,
|
|
|
|
trace_path,
|
|
|
|
))?;
|
2022-08-08 12:54:34 +00:00
|
|
|
let target = target::TextureTarget::new(&descriptors.device, size)?;
|
2022-08-08 00:14:25 +00:00
|
|
|
Self::new(Arc::new(descriptors), target)
|
2021-03-19 12:05:07 +00:00
|
|
|
}
|
2022-07-02 19:50:36 +00:00
|
|
|
|
2022-09-09 17:52:58 +00:00
|
|
|
pub fn capture_frame(&self, premultiplied_alpha: bool) -> Option<image::RgbaImage> {
|
|
|
|
self.target
|
|
|
|
.capture(&self.descriptors.device, premultiplied_alpha)
|
2022-07-02 19:50:36 +00:00
|
|
|
}
|
2021-03-19 12:05:07 +00:00
|
|
|
}
|
|
|
|
|
2022-09-06 21:38:48 +00:00
|
|
|
macro_rules! target_data {
|
|
|
|
($this:expr) => {{
|
|
|
|
if $this.offscreen {
|
|
|
|
&$this.descriptors.offscreen
|
|
|
|
} else {
|
|
|
|
&$this.descriptors.onscreen
|
|
|
|
}
|
|
|
|
}};
|
|
|
|
}
|
|
|
|
|
2021-03-19 12:05:07 +00:00
|
|
|
impl<T: RenderTarget> WgpuRenderBackend<T> {
|
2022-08-08 00:14:25 +00:00
|
|
|
pub fn new(descriptors: Arc<Descriptors>, target: T) -> Result<Self, Error> {
|
2022-08-08 12:54:34 +00:00
|
|
|
if target.width() > descriptors.limits.max_texture_dimension_2d
|
|
|
|
|| target.height() > descriptors.limits.max_texture_dimension_2d
|
|
|
|
{
|
|
|
|
return Err(format!(
|
|
|
|
"Render target texture cannot be larger than {}px on either dimension (requested {} x {})",
|
|
|
|
descriptors.limits.max_texture_dimension_2d,
|
|
|
|
target.width(),
|
|
|
|
target.height()
|
|
|
|
)
|
|
|
|
.into());
|
|
|
|
}
|
|
|
|
|
2021-03-19 12:05:07 +00:00
|
|
|
let extent = wgpu::Extent3d {
|
|
|
|
width: target.width(),
|
|
|
|
height: target.height(),
|
2021-04-16 20:55:31 +00:00
|
|
|
depth_or_array_layers: 1,
|
2021-03-19 12:05:07 +00:00
|
|
|
};
|
|
|
|
|
2022-09-06 21:38:48 +00:00
|
|
|
let frame_buffer_view = if descriptors.onscreen.msaa_sample_count > 1 {
|
2022-04-14 21:53:12 +00:00
|
|
|
let frame_buffer = descriptors.device.create_texture(&wgpu::TextureDescriptor {
|
|
|
|
label: create_debug_label!("Framebuffer texture").as_deref(),
|
|
|
|
size: extent,
|
|
|
|
mip_level_count: 1,
|
2022-09-06 21:38:48 +00:00
|
|
|
sample_count: descriptors.onscreen.msaa_sample_count,
|
2022-04-14 21:53:12 +00:00
|
|
|
dimension: wgpu::TextureDimension::D2,
|
2022-09-06 21:38:48 +00:00
|
|
|
format: descriptors.onscreen.frame_buffer_format,
|
2022-04-14 21:53:12 +00:00
|
|
|
usage: wgpu::TextureUsages::RENDER_ATTACHMENT,
|
|
|
|
});
|
|
|
|
Some(frame_buffer.create_view(&Default::default()))
|
|
|
|
} else {
|
|
|
|
None
|
|
|
|
};
|
2021-03-19 12:05:07 +00:00
|
|
|
|
|
|
|
let depth_texture = descriptors.device.create_texture(&wgpu::TextureDescriptor {
|
2022-04-14 21:53:12 +00:00
|
|
|
label: create_debug_label!("Depth texture").as_deref(),
|
2021-03-19 12:05:07 +00:00
|
|
|
size: extent,
|
|
|
|
mip_level_count: 1,
|
2022-09-06 21:38:48 +00:00
|
|
|
sample_count: descriptors.onscreen.msaa_sample_count,
|
2021-03-19 12:05:07 +00:00
|
|
|
dimension: wgpu::TextureDimension::D2,
|
|
|
|
format: wgpu::TextureFormat::Depth24PlusStencil8,
|
2021-09-08 07:20:11 +00:00
|
|
|
usage: wgpu::TextureUsages::RENDER_ATTACHMENT,
|
2021-03-19 12:05:07 +00:00
|
|
|
});
|
|
|
|
let depth_texture_view = depth_texture.create_view(&Default::default());
|
|
|
|
|
|
|
|
let (quad_vbo, quad_ibo, quad_tex_transforms) = create_quad_buffers(&descriptors.device);
|
|
|
|
|
2022-09-06 21:38:48 +00:00
|
|
|
let (copy_srgb_view, copy_srgb_bind_group) = if descriptors.onscreen.frame_buffer_format
|
|
|
|
!= descriptors.offscreen.surface_format
|
2022-04-14 21:53:12 +00:00
|
|
|
{
|
|
|
|
let copy_srgb_buffer = descriptors.device.create_texture(&wgpu::TextureDescriptor {
|
|
|
|
label: create_debug_label!("Copy sRGB framebuffer texture").as_deref(),
|
|
|
|
size: extent,
|
|
|
|
mip_level_count: 1,
|
|
|
|
sample_count: 1,
|
|
|
|
dimension: wgpu::TextureDimension::D2,
|
2022-09-06 21:38:48 +00:00
|
|
|
format: descriptors.onscreen.frame_buffer_format,
|
2022-04-14 21:53:12 +00:00
|
|
|
usage: wgpu::TextureUsages::RENDER_ATTACHMENT
|
|
|
|
| wgpu::TextureUsages::TEXTURE_BINDING,
|
|
|
|
});
|
|
|
|
let copy_srgb_view = copy_srgb_buffer.create_view(&Default::default());
|
|
|
|
let copy_srgb_bind_group =
|
|
|
|
descriptors
|
|
|
|
.device
|
|
|
|
.create_bind_group(&wgpu::BindGroupDescriptor {
|
2022-09-06 21:38:48 +00:00
|
|
|
layout: &descriptors.onscreen.pipelines.bitmap_layout,
|
2022-04-14 21:53:12 +00:00
|
|
|
entries: &[
|
|
|
|
wgpu::BindGroupEntry {
|
|
|
|
binding: 0,
|
|
|
|
resource: wgpu::BindingResource::Buffer(wgpu::BufferBinding {
|
|
|
|
buffer: &quad_tex_transforms,
|
|
|
|
offset: 0,
|
|
|
|
size: wgpu::BufferSize::new(
|
|
|
|
std::mem::size_of::<TextureTransforms>() as u64,
|
|
|
|
),
|
|
|
|
}),
|
|
|
|
},
|
|
|
|
wgpu::BindGroupEntry {
|
|
|
|
binding: 1,
|
|
|
|
resource: wgpu::BindingResource::TextureView(©_srgb_view),
|
|
|
|
},
|
|
|
|
],
|
|
|
|
label: create_debug_label!("Copy sRGB bind group").as_deref(),
|
|
|
|
});
|
|
|
|
(Some(copy_srgb_view), Some(copy_srgb_bind_group))
|
|
|
|
} else {
|
|
|
|
(None, None)
|
|
|
|
};
|
2022-04-14 18:03:45 +00:00
|
|
|
|
2022-08-07 23:54:11 +00:00
|
|
|
let mut globals = Globals::new(&descriptors.device, &descriptors.globals_layout);
|
|
|
|
globals.set_resolution(target.width(), target.height());
|
2021-03-19 12:05:07 +00:00
|
|
|
|
2022-08-08 00:12:35 +00:00
|
|
|
let uniform_buffers =
|
|
|
|
UniformBuffer::new(descriptors.limits.min_uniform_buffer_offset_alignment);
|
|
|
|
|
2021-03-19 12:05:07 +00:00
|
|
|
Ok(Self {
|
|
|
|
descriptors,
|
2022-08-07 23:54:11 +00:00
|
|
|
globals,
|
2022-08-08 00:12:35 +00:00
|
|
|
uniform_buffers,
|
2021-03-19 12:05:07 +00:00
|
|
|
target,
|
|
|
|
frame_buffer_view,
|
|
|
|
depth_texture_view,
|
2022-04-14 18:03:45 +00:00
|
|
|
copy_srgb_view,
|
|
|
|
copy_srgb_bind_group,
|
2021-03-19 12:05:07 +00:00
|
|
|
current_frame: None,
|
|
|
|
meshes: Vec::new(),
|
|
|
|
shape_tessellator: ShapeTessellator::new(),
|
|
|
|
|
|
|
|
num_masks: 0,
|
|
|
|
mask_state: MaskState::NoMask,
|
|
|
|
|
|
|
|
quad_vbo,
|
|
|
|
quad_ibo,
|
|
|
|
quad_tex_transforms,
|
2022-07-25 16:31:40 +00:00
|
|
|
blend_modes: vec![BlendMode::Normal],
|
2022-06-29 22:16:43 +00:00
|
|
|
bitmap_registry: Default::default(),
|
|
|
|
next_bitmap_handle: BitmapHandle(0),
|
2022-08-04 05:50:18 +00:00
|
|
|
viewport_scale_factor: 1.0,
|
2022-09-06 21:38:48 +00:00
|
|
|
offscreen: false,
|
2021-03-19 12:05:07 +00:00
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2021-09-08 23:40:51 +00:00
|
|
|
pub async fn build_descriptors(
|
2021-09-08 07:20:11 +00:00
|
|
|
backend: wgpu::Backends,
|
2021-03-19 12:05:07 +00:00
|
|
|
instance: wgpu::Instance,
|
|
|
|
surface: Option<&wgpu::Surface>,
|
|
|
|
power_preference: wgpu::PowerPreference,
|
|
|
|
trace_path: Option<&Path>,
|
|
|
|
) -> Result<Descriptors, Error> {
|
2021-09-08 23:40:51 +00:00
|
|
|
let adapter = instance.request_adapter(&wgpu::RequestAdapterOptions {
|
2021-03-19 12:05:07 +00:00
|
|
|
power_preference,
|
|
|
|
compatible_surface: surface,
|
2021-09-08 07:20:11 +00:00
|
|
|
force_fallback_adapter: false,
|
2021-09-08 23:40:51 +00:00
|
|
|
}).await
|
2021-03-19 12:05:07 +00:00
|
|
|
.ok_or_else(|| {
|
|
|
|
let names = get_backend_names(backend);
|
|
|
|
if names.is_empty() {
|
|
|
|
"Ruffle requires hardware acceleration, but no compatible graphics device was found (no backend provided?)".to_string()
|
2021-10-24 21:44:16 +00:00
|
|
|
} else if cfg!(any(windows, target_os = "macos")) {
|
|
|
|
format!("Ruffle does not support OpenGL on {}.", if cfg!(windows) { "Windows" } else { "macOS" })
|
2021-03-19 12:05:07 +00:00
|
|
|
} else {
|
|
|
|
format!("Ruffle requires hardware acceleration, but no compatible graphics device was found supporting {}", format_list(&names, "or"))
|
|
|
|
}
|
|
|
|
})?;
|
|
|
|
|
2022-08-27 21:39:57 +00:00
|
|
|
let (device, queue) = request_device(&adapter, trace_path).await?;
|
2021-09-08 01:55:26 +00:00
|
|
|
let info = adapter.get_info();
|
2022-07-02 18:55:25 +00:00
|
|
|
// Ideally we want to use an RGBA non-sRGB surface format, because Flash colors and
|
|
|
|
// blending are done in sRGB space -- we don't want the GPU to adjust the colors.
|
|
|
|
// Some platforms may only support an sRGB surface, in which case we will draw to an
|
|
|
|
// intermediate linear buffer and then copy to the sRGB surface.
|
2022-02-14 20:43:26 +00:00
|
|
|
let surface_format = surface
|
2022-07-02 18:55:25 +00:00
|
|
|
.and_then(|surface| {
|
|
|
|
let formats = surface.get_supported_formats(&adapter);
|
|
|
|
formats
|
|
|
|
.iter()
|
|
|
|
.find(|format| {
|
|
|
|
matches!(
|
|
|
|
format,
|
|
|
|
wgpu::TextureFormat::Rgba8Unorm | wgpu::TextureFormat::Bgra8Unorm
|
|
|
|
)
|
|
|
|
})
|
|
|
|
.or_else(|| formats.first())
|
|
|
|
.cloned()
|
|
|
|
})
|
|
|
|
// No surface (rendering to texture), default to linear RBGA.
|
2022-02-14 20:43:26 +00:00
|
|
|
.unwrap_or(wgpu::TextureFormat::Rgba8Unorm);
|
2022-09-06 21:38:48 +00:00
|
|
|
// TODO: Allow the sample count to be set from command line/settings file.
|
|
|
|
Ok(Descriptors::new(
|
|
|
|
device,
|
|
|
|
queue,
|
|
|
|
info,
|
|
|
|
surface_format,
|
|
|
|
DEFAULT_SAMPLE_COUNT,
|
|
|
|
))
|
2021-03-19 12:05:07 +00:00
|
|
|
}
|
|
|
|
|
2021-03-19 11:48:52 +00:00
|
|
|
fn register_shape_internal(
|
|
|
|
&mut self,
|
|
|
|
shape: DistilledShape,
|
2021-06-13 21:44:16 +00:00
|
|
|
bitmap_source: &dyn BitmapSource,
|
2021-03-19 11:48:52 +00:00
|
|
|
) -> Mesh {
|
|
|
|
let shape_id = shape.id; // TODO: remove?
|
2021-06-13 21:44:16 +00:00
|
|
|
let lyon_mesh = self
|
|
|
|
.shape_tessellator
|
|
|
|
.tessellate_shape(shape, bitmap_source);
|
2021-03-19 11:48:52 +00:00
|
|
|
|
2021-03-20 14:12:39 +00:00
|
|
|
let mut draws = Vec::with_capacity(lyon_mesh.len());
|
|
|
|
for draw in lyon_mesh {
|
2021-03-20 14:30:21 +00:00
|
|
|
let vertices: Vec<_> = draw.vertices.into_iter().map(Vertex::from).collect();
|
2021-03-19 11:48:52 +00:00
|
|
|
let vertex_buffer = create_buffer_with_data(
|
2021-03-20 14:19:51 +00:00
|
|
|
&self.descriptors.device,
|
2021-03-20 14:12:39 +00:00
|
|
|
bytemuck::cast_slice(&vertices),
|
2021-09-08 07:20:11 +00:00
|
|
|
wgpu::BufferUsages::VERTEX,
|
2021-03-20 14:12:39 +00:00
|
|
|
create_debug_label!("Shape {} ({}) vbo", shape_id, draw.draw_type.name()),
|
2021-03-19 11:48:52 +00:00
|
|
|
);
|
|
|
|
|
|
|
|
let index_buffer = create_buffer_with_data(
|
2021-03-20 14:19:51 +00:00
|
|
|
&self.descriptors.device,
|
2021-03-20 14:12:39 +00:00
|
|
|
bytemuck::cast_slice(&draw.indices),
|
2021-09-08 07:20:11 +00:00
|
|
|
wgpu::BufferUsages::INDEX,
|
2021-03-20 14:12:39 +00:00
|
|
|
create_debug_label!("Shape {} ({}) ibo", shape_id, draw.draw_type.name()),
|
2021-03-19 11:48:52 +00:00
|
|
|
);
|
|
|
|
|
2021-03-20 14:12:39 +00:00
|
|
|
let index_count = draw.indices.len() as u32;
|
2021-03-19 11:48:52 +00:00
|
|
|
let draw_id = draws.len();
|
|
|
|
|
2021-03-20 14:12:39 +00:00
|
|
|
draws.push(match draw.draw_type {
|
|
|
|
TessDrawType::Color => Draw {
|
2021-03-19 11:48:52 +00:00
|
|
|
draw_type: DrawType::Color,
|
|
|
|
vertex_buffer,
|
|
|
|
index_buffer,
|
2022-05-24 23:19:59 +00:00
|
|
|
num_indices: index_count,
|
|
|
|
num_mask_indices: draw.mask_index_count,
|
2021-03-19 11:48:52 +00:00
|
|
|
},
|
2021-03-20 14:12:39 +00:00
|
|
|
TessDrawType::Gradient(gradient) => {
|
|
|
|
// TODO: Extract to function?
|
|
|
|
let mut texture_transform = [[0.0; 4]; 4];
|
|
|
|
texture_transform[0][..3].copy_from_slice(&gradient.matrix[0]);
|
|
|
|
texture_transform[1][..3].copy_from_slice(&gradient.matrix[1]);
|
|
|
|
texture_transform[2][..3].copy_from_slice(&gradient.matrix[2]);
|
|
|
|
|
2021-03-19 11:48:52 +00:00
|
|
|
let tex_transforms_ubo = create_buffer_with_data(
|
2021-03-20 14:19:51 +00:00
|
|
|
&self.descriptors.device,
|
2021-03-19 11:48:52 +00:00
|
|
|
bytemuck::cast_slice(&[texture_transform]),
|
2021-09-08 07:20:11 +00:00
|
|
|
wgpu::BufferUsages::UNIFORM,
|
2021-03-19 11:48:52 +00:00
|
|
|
create_debug_label!(
|
|
|
|
"Shape {} draw {} textransforms ubo transfer buffer",
|
|
|
|
shape_id,
|
|
|
|
draw_id
|
|
|
|
),
|
|
|
|
);
|
|
|
|
|
2022-08-27 21:39:57 +00:00
|
|
|
let (gradient_ubo, buffer_size) = if self
|
|
|
|
.descriptors
|
|
|
|
.limits
|
|
|
|
.max_storage_buffers_per_shader_stage
|
|
|
|
> 0
|
|
|
|
{
|
|
|
|
(
|
|
|
|
create_buffer_with_data(
|
|
|
|
&self.descriptors.device,
|
|
|
|
bytemuck::cast_slice(&[GradientStorage::from(gradient)]),
|
|
|
|
wgpu::BufferUsages::STORAGE,
|
|
|
|
create_debug_label!(
|
|
|
|
"Shape {} draw {} gradient ubo transfer buffer",
|
|
|
|
shape_id,
|
|
|
|
draw_id
|
|
|
|
),
|
|
|
|
),
|
|
|
|
wgpu::BufferSize::new(std::mem::size_of::<GradientStorage>() as u64),
|
|
|
|
)
|
|
|
|
} else {
|
|
|
|
(
|
|
|
|
create_buffer_with_data(
|
|
|
|
&self.descriptors.device,
|
|
|
|
bytemuck::cast_slice(&[GradientUniforms::from(gradient)]),
|
|
|
|
wgpu::BufferUsages::UNIFORM,
|
|
|
|
create_debug_label!(
|
|
|
|
"Shape {} draw {} gradient ubo transfer buffer",
|
|
|
|
shape_id,
|
|
|
|
draw_id
|
|
|
|
),
|
|
|
|
),
|
|
|
|
wgpu::BufferSize::new(std::mem::size_of::<GradientUniforms>() as u64),
|
|
|
|
)
|
|
|
|
};
|
2021-03-19 11:48:52 +00:00
|
|
|
|
2021-03-20 14:12:39 +00:00
|
|
|
let bind_group_label = create_debug_label!(
|
|
|
|
"Shape {} (gradient) draw {} bindgroup",
|
|
|
|
shape_id,
|
|
|
|
draw_id
|
|
|
|
);
|
2021-03-20 14:30:21 +00:00
|
|
|
let bind_group =
|
|
|
|
self.descriptors
|
|
|
|
.device
|
|
|
|
.create_bind_group(&wgpu::BindGroupDescriptor {
|
2022-09-06 21:38:48 +00:00
|
|
|
layout: &target_data!(self).pipelines.gradient_layout,
|
2021-03-20 14:30:21 +00:00
|
|
|
entries: &[
|
|
|
|
wgpu::BindGroupEntry {
|
|
|
|
binding: 0,
|
2021-04-29 20:42:12 +00:00
|
|
|
resource: wgpu::BindingResource::Buffer(
|
|
|
|
wgpu::BufferBinding {
|
|
|
|
buffer: &tex_transforms_ubo,
|
|
|
|
offset: 0,
|
|
|
|
size: wgpu::BufferSize::new(std::mem::size_of::<
|
|
|
|
TextureTransforms,
|
|
|
|
>(
|
|
|
|
)
|
|
|
|
as u64),
|
|
|
|
},
|
|
|
|
),
|
2021-03-20 14:30:21 +00:00
|
|
|
},
|
|
|
|
wgpu::BindGroupEntry {
|
|
|
|
binding: 1,
|
2021-04-29 20:42:12 +00:00
|
|
|
resource: wgpu::BindingResource::Buffer(
|
|
|
|
wgpu::BufferBinding {
|
|
|
|
buffer: &gradient_ubo,
|
|
|
|
offset: 0,
|
2022-08-27 21:39:57 +00:00
|
|
|
size: buffer_size,
|
2021-04-29 20:42:12 +00:00
|
|
|
},
|
|
|
|
),
|
2021-03-20 14:30:21 +00:00
|
|
|
},
|
|
|
|
],
|
|
|
|
label: bind_group_label.as_deref(),
|
|
|
|
});
|
2021-03-19 11:48:52 +00:00
|
|
|
|
|
|
|
Draw {
|
|
|
|
draw_type: DrawType::Gradient {
|
|
|
|
texture_transforms: tex_transforms_ubo,
|
|
|
|
gradient: gradient_ubo,
|
|
|
|
bind_group,
|
|
|
|
},
|
|
|
|
vertex_buffer,
|
|
|
|
index_buffer,
|
2022-05-24 23:19:59 +00:00
|
|
|
num_indices: index_count,
|
|
|
|
num_mask_indices: draw.mask_index_count,
|
2021-03-19 11:48:52 +00:00
|
|
|
}
|
|
|
|
}
|
2021-03-20 14:12:39 +00:00
|
|
|
TessDrawType::Bitmap(bitmap) => {
|
2022-06-29 22:16:43 +00:00
|
|
|
let entry = self.bitmap_registry.get(&bitmap.bitmap).unwrap();
|
|
|
|
let texture_view = entry
|
|
|
|
.texture_wrapper
|
|
|
|
.texture
|
|
|
|
.create_view(&Default::default());
|
2021-03-19 11:48:52 +00:00
|
|
|
|
2021-03-20 14:12:39 +00:00
|
|
|
// TODO: Extract to function?
|
|
|
|
let mut texture_transform = [[0.0; 4]; 4];
|
|
|
|
texture_transform[0][..3].copy_from_slice(&bitmap.matrix[0]);
|
|
|
|
texture_transform[1][..3].copy_from_slice(&bitmap.matrix[1]);
|
|
|
|
texture_transform[2][..3].copy_from_slice(&bitmap.matrix[2]);
|
|
|
|
|
2021-03-19 11:48:52 +00:00
|
|
|
let tex_transforms_ubo = create_buffer_with_data(
|
2021-03-20 14:19:51 +00:00
|
|
|
&self.descriptors.device,
|
2021-03-19 11:48:52 +00:00
|
|
|
bytemuck::cast_slice(&[texture_transform]),
|
2021-09-08 07:20:11 +00:00
|
|
|
wgpu::BufferUsages::UNIFORM,
|
2021-03-19 11:48:52 +00:00
|
|
|
create_debug_label!(
|
|
|
|
"Shape {} draw {} textransforms ubo transfer buffer",
|
|
|
|
shape_id,
|
|
|
|
draw_id
|
|
|
|
),
|
|
|
|
);
|
|
|
|
|
2021-03-20 14:12:39 +00:00
|
|
|
let bind_group_label = create_debug_label!(
|
|
|
|
"Shape {} (bitmap) draw {} bindgroup",
|
|
|
|
shape_id,
|
|
|
|
draw_id
|
|
|
|
);
|
2021-03-20 14:30:21 +00:00
|
|
|
let bind_group =
|
|
|
|
self.descriptors
|
|
|
|
.device
|
|
|
|
.create_bind_group(&wgpu::BindGroupDescriptor {
|
2022-09-06 21:38:48 +00:00
|
|
|
layout: &target_data!(self).pipelines.bitmap_layout,
|
2021-03-20 14:30:21 +00:00
|
|
|
entries: &[
|
|
|
|
wgpu::BindGroupEntry {
|
|
|
|
binding: 0,
|
2021-04-29 20:42:12 +00:00
|
|
|
resource: wgpu::BindingResource::Buffer(
|
|
|
|
wgpu::BufferBinding {
|
|
|
|
buffer: &tex_transforms_ubo,
|
|
|
|
offset: 0,
|
|
|
|
size: wgpu::BufferSize::new(std::mem::size_of::<
|
|
|
|
TextureTransforms,
|
|
|
|
>(
|
|
|
|
)
|
|
|
|
as u64),
|
|
|
|
},
|
|
|
|
),
|
2021-03-20 14:30:21 +00:00
|
|
|
},
|
|
|
|
wgpu::BindGroupEntry {
|
|
|
|
binding: 1,
|
|
|
|
resource: wgpu::BindingResource::TextureView(&texture_view),
|
|
|
|
},
|
|
|
|
],
|
|
|
|
label: bind_group_label.as_deref(),
|
|
|
|
});
|
2021-03-19 11:48:52 +00:00
|
|
|
|
|
|
|
Draw {
|
|
|
|
draw_type: DrawType::Bitmap {
|
|
|
|
texture_transforms: tex_transforms_ubo,
|
|
|
|
texture_view,
|
2021-03-20 14:12:39 +00:00
|
|
|
is_smoothed: bitmap.is_smoothed,
|
|
|
|
is_repeating: bitmap.is_repeating,
|
2021-03-19 11:48:52 +00:00
|
|
|
bind_group,
|
|
|
|
},
|
|
|
|
vertex_buffer,
|
|
|
|
index_buffer,
|
2022-05-24 23:19:59 +00:00
|
|
|
num_indices: index_count,
|
|
|
|
num_mask_indices: draw.mask_index_count,
|
2021-03-19 11:48:52 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2021-03-19 14:06:36 +00:00
|
|
|
Mesh { draws }
|
2020-04-21 13:32:50 +00:00
|
|
|
}
|
2022-07-25 16:31:40 +00:00
|
|
|
|
|
|
|
fn blend_mode(&self) -> BlendMode {
|
|
|
|
*self.blend_modes.last().unwrap()
|
|
|
|
}
|
2022-08-23 20:44:57 +00:00
|
|
|
|
|
|
|
pub fn descriptors(&self) -> &Arc<Descriptors> {
|
|
|
|
&self.descriptors
|
|
|
|
}
|
2022-09-06 21:38:48 +00:00
|
|
|
|
|
|
|
pub fn target(&self) -> &T {
|
|
|
|
&self.target
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn device(&self) -> &wgpu::Device {
|
|
|
|
&self.descriptors.device
|
|
|
|
}
|
|
|
|
|
|
|
|
fn render_offscreen_internal(
|
|
|
|
mut self,
|
|
|
|
handle: BitmapHandle,
|
|
|
|
width: u32,
|
|
|
|
height: u32,
|
|
|
|
f: &mut dyn FnMut(&mut dyn RenderBackend) -> Result<(), ruffle_render::error::Error>,
|
|
|
|
) -> Result<(Self, ruffle_render::bitmap::Bitmap), ruffle_render::error::Error> {
|
|
|
|
// We need ownership of `Texture` to access the non-`Clone`
|
|
|
|
// `wgpu` fields. At the end of this method, we re-insert
|
|
|
|
// `texture` into the map.
|
|
|
|
//
|
|
|
|
// This means that the target texture will be inaccessible
|
|
|
|
// while the callback `f` is a problem. This would only be
|
|
|
|
// an issue if a caller tried to render the target texture
|
|
|
|
// to itself, which probably isn't supported by Flash. If it
|
|
|
|
// is, then we could change `TextureTarget` to use an `Rc<wgpu::Texture>`
|
|
|
|
let mut texture = self.bitmap_registry.remove(&handle).unwrap();
|
|
|
|
|
|
|
|
let extent = wgpu::Extent3d {
|
|
|
|
width,
|
|
|
|
height,
|
|
|
|
depth_or_array_layers: 1,
|
|
|
|
};
|
|
|
|
|
|
|
|
if self.offscreen {
|
|
|
|
panic!("Nested render_onto_bitmap is not supported!")
|
|
|
|
}
|
|
|
|
|
|
|
|
let descriptors = self.descriptors.clone();
|
|
|
|
|
|
|
|
// We will (presumably) never render to the majority of textures, so
|
|
|
|
// we lazily create the buffer and depth texture.
|
|
|
|
// Once created, we never destroy this data, under the assumption
|
|
|
|
// that the SWF will try to render to this more than once.
|
|
|
|
//
|
|
|
|
// If we end up hitting wgpu device limits due to having too
|
|
|
|
// many buffers / depth textures rendered at once, we could
|
|
|
|
// try storing this data in an LRU cache, evicting entries
|
|
|
|
// as needed.
|
|
|
|
let mut texture_offscreen =
|
|
|
|
texture
|
|
|
|
.texture_wrapper
|
|
|
|
.texture_offscreen
|
|
|
|
.unwrap_or_else(|| {
|
|
|
|
let depth_texture_view =
|
|
|
|
create_depth_texture_view(&descriptors, &descriptors.offscreen, extent);
|
|
|
|
let buffer_dimensions = BufferDimensions::new(width as usize, height as usize);
|
|
|
|
let buffer_label = create_debug_label!("Render target buffer");
|
|
|
|
let buffer = descriptors.device.create_buffer(&wgpu::BufferDescriptor {
|
|
|
|
label: buffer_label.as_deref(),
|
|
|
|
size: (buffer_dimensions.padded_bytes_per_row.get() as u64
|
|
|
|
* buffer_dimensions.height as u64),
|
|
|
|
usage: wgpu::BufferUsages::COPY_DST | wgpu::BufferUsages::MAP_READ,
|
|
|
|
mapped_at_creation: false,
|
|
|
|
});
|
|
|
|
TextureOffscreen {
|
|
|
|
depth_texture_view,
|
|
|
|
buffer,
|
|
|
|
buffer_dimensions,
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
|
|
|
let target = TextureTarget {
|
|
|
|
size: extent,
|
|
|
|
texture: texture.texture_wrapper.texture,
|
|
|
|
format: wgpu::TextureFormat::Rgba8Unorm,
|
|
|
|
buffer: texture_offscreen.buffer,
|
|
|
|
buffer_dimensions: texture_offscreen.buffer_dimensions,
|
|
|
|
};
|
|
|
|
|
|
|
|
let (old_width, old_height) = self.globals.resolution();
|
|
|
|
|
|
|
|
// Is it worth caching this?
|
|
|
|
self.globals.set_resolution(width, height);
|
|
|
|
|
|
|
|
let mut texture_backend = WgpuRenderBackend {
|
|
|
|
descriptors,
|
|
|
|
target,
|
|
|
|
// FIXME - Enable MSAA for textures
|
|
|
|
frame_buffer_view: None,
|
|
|
|
depth_texture_view: texture_offscreen.depth_texture_view,
|
|
|
|
// We explicitly request a non-SRGB format for textures
|
|
|
|
copy_srgb_view: None,
|
|
|
|
copy_srgb_bind_group: None,
|
|
|
|
current_frame: None,
|
|
|
|
meshes: self.meshes,
|
|
|
|
mask_state: MaskState::NoMask,
|
|
|
|
shape_tessellator: self.shape_tessellator,
|
|
|
|
num_masks: 0,
|
|
|
|
quad_vbo: self.quad_vbo,
|
|
|
|
quad_ibo: self.quad_ibo,
|
|
|
|
quad_tex_transforms: self.quad_tex_transforms,
|
|
|
|
bitmap_registry: self.bitmap_registry,
|
|
|
|
offscreen: true,
|
|
|
|
next_bitmap_handle: self.next_bitmap_handle,
|
|
|
|
globals: self.globals,
|
|
|
|
uniform_buffers: self.uniform_buffers,
|
|
|
|
viewport_scale_factor: self.viewport_scale_factor,
|
|
|
|
blend_modes: vec![BlendMode::Normal],
|
|
|
|
};
|
|
|
|
|
|
|
|
let f_res = f(&mut texture_backend);
|
2022-09-09 17:52:58 +00:00
|
|
|
// Capture with premultiplied alpha, which is what we use for all textures
|
2022-09-06 21:38:48 +00:00
|
|
|
let image = texture_backend
|
|
|
|
.target
|
2022-09-09 17:52:58 +00:00
|
|
|
.capture(&texture_backend.descriptors.device, true);
|
2022-09-06 21:38:48 +00:00
|
|
|
|
|
|
|
let image = image.map(|image| {
|
|
|
|
ruffle_render::bitmap::Bitmap::new(
|
|
|
|
image.dimensions().0,
|
|
|
|
image.dimensions().1,
|
|
|
|
ruffle_render::bitmap::BitmapFormat::Rgba,
|
|
|
|
image.into_raw(),
|
|
|
|
)
|
|
|
|
});
|
|
|
|
|
|
|
|
self.offscreen = false;
|
|
|
|
self.meshes = texture_backend.meshes;
|
|
|
|
self.shape_tessellator = texture_backend.shape_tessellator;
|
|
|
|
self.bitmap_registry = texture_backend.bitmap_registry;
|
|
|
|
self.quad_tex_transforms = texture_backend.quad_tex_transforms;
|
|
|
|
self.quad_ibo = texture_backend.quad_ibo;
|
|
|
|
self.quad_vbo = texture_backend.quad_vbo;
|
|
|
|
self.globals = texture_backend.globals;
|
|
|
|
self.uniform_buffers = texture_backend.uniform_buffers;
|
|
|
|
self.next_bitmap_handle = texture_backend.next_bitmap_handle;
|
|
|
|
self.globals.set_resolution(old_width, old_height);
|
|
|
|
|
|
|
|
texture_offscreen.buffer = texture_backend.target.buffer;
|
|
|
|
texture_offscreen.buffer_dimensions = texture_backend.target.buffer_dimensions;
|
|
|
|
texture_offscreen.depth_texture_view = texture_backend.depth_texture_view;
|
|
|
|
texture.texture_wrapper.texture_offscreen = Some(texture_offscreen);
|
|
|
|
texture.texture_wrapper.texture = texture_backend.target.texture;
|
|
|
|
self.bitmap_registry.insert(handle, texture);
|
|
|
|
|
|
|
|
// Check result after restoring the backend fields
|
|
|
|
f_res?;
|
|
|
|
|
|
|
|
Ok((self, image.unwrap()))
|
|
|
|
}
|
2020-04-21 13:32:50 +00:00
|
|
|
}
|
|
|
|
|
2020-05-05 13:27:10 +00:00
|
|
|
impl<T: RenderTarget + 'static> RenderBackend for WgpuRenderBackend<T> {
|
2022-08-04 05:50:18 +00:00
|
|
|
fn set_viewport_dimensions(&mut self, dimensions: ViewportDimensions) {
|
2020-05-02 15:44:15 +00:00
|
|
|
// Avoid panics from creating 0-sized framebuffers.
|
2022-08-08 12:54:34 +00:00
|
|
|
// TODO: find a way to bubble an error when the size is too large
|
2022-08-27 21:39:57 +00:00
|
|
|
let width = std::cmp::max(
|
|
|
|
std::cmp::min(
|
|
|
|
dimensions.width,
|
|
|
|
self.descriptors.limits.max_texture_dimension_2d,
|
|
|
|
),
|
|
|
|
1,
|
|
|
|
);
|
|
|
|
let height = std::cmp::max(
|
|
|
|
std::cmp::min(
|
|
|
|
dimensions.height,
|
|
|
|
self.descriptors.limits.max_texture_dimension_2d,
|
|
|
|
),
|
|
|
|
1,
|
|
|
|
);
|
2020-10-15 23:23:36 +00:00
|
|
|
self.target.resize(&self.descriptors.device, width, height);
|
2020-04-21 13:32:50 +00:00
|
|
|
|
2022-04-14 18:03:45 +00:00
|
|
|
let size = wgpu::Extent3d {
|
|
|
|
width,
|
|
|
|
height,
|
|
|
|
depth_or_array_layers: 1,
|
|
|
|
};
|
|
|
|
|
2022-09-06 21:38:48 +00:00
|
|
|
self.frame_buffer_view = if target_data!(self).msaa_sample_count > 1 {
|
2022-04-14 21:53:12 +00:00
|
|
|
let frame_buffer = self
|
|
|
|
.descriptors
|
|
|
|
.device
|
|
|
|
.create_texture(&wgpu::TextureDescriptor {
|
|
|
|
label: create_debug_label!("Framebuffer texture").as_deref(),
|
|
|
|
size,
|
|
|
|
mip_level_count: 1,
|
2022-09-06 21:38:48 +00:00
|
|
|
sample_count: target_data!(self).msaa_sample_count,
|
2022-04-14 21:53:12 +00:00
|
|
|
dimension: wgpu::TextureDimension::D2,
|
2022-09-06 21:38:48 +00:00
|
|
|
format: target_data!(self).frame_buffer_format,
|
2022-04-14 21:53:12 +00:00
|
|
|
usage: wgpu::TextureUsages::RENDER_ATTACHMENT,
|
|
|
|
});
|
|
|
|
Some(frame_buffer.create_view(&Default::default()))
|
|
|
|
} else {
|
|
|
|
None
|
|
|
|
};
|
2020-05-01 02:56:07 +00:00
|
|
|
|
2020-10-15 23:23:36 +00:00
|
|
|
let depth_texture = self
|
|
|
|
.descriptors
|
|
|
|
.device
|
|
|
|
.create_texture(&wgpu::TextureDescriptor {
|
2022-04-14 21:53:12 +00:00
|
|
|
label: create_debug_label!("Depth texture").as_deref(),
|
2022-04-14 18:03:45 +00:00
|
|
|
size,
|
2020-10-15 23:23:36 +00:00
|
|
|
mip_level_count: 1,
|
2022-09-06 21:38:48 +00:00
|
|
|
sample_count: target_data!(self).msaa_sample_count,
|
2020-10-15 23:23:36 +00:00
|
|
|
dimension: wgpu::TextureDimension::D2,
|
|
|
|
format: wgpu::TextureFormat::Depth24PlusStencil8,
|
2021-09-08 07:20:11 +00:00
|
|
|
usage: wgpu::TextureUsages::RENDER_ATTACHMENT,
|
2020-10-15 23:23:36 +00:00
|
|
|
});
|
2020-08-27 10:32:41 +00:00
|
|
|
self.depth_texture_view = depth_texture.create_view(&Default::default());
|
2022-04-14 18:03:45 +00:00
|
|
|
|
2022-09-06 21:38:48 +00:00
|
|
|
(self.copy_srgb_view, self.copy_srgb_bind_group) = if target_data!(self).frame_buffer_format
|
|
|
|
!= target_data!(self).surface_format
|
2022-04-14 21:53:12 +00:00
|
|
|
{
|
|
|
|
let copy_srgb_buffer =
|
|
|
|
self.descriptors
|
|
|
|
.device
|
|
|
|
.create_texture(&wgpu::TextureDescriptor {
|
|
|
|
label: create_debug_label!("Copy sRGB framebuffer texture").as_deref(),
|
|
|
|
size,
|
|
|
|
mip_level_count: 1,
|
|
|
|
sample_count: 1,
|
|
|
|
dimension: wgpu::TextureDimension::D2,
|
2022-09-06 21:38:48 +00:00
|
|
|
format: target_data!(self).frame_buffer_format,
|
2022-04-14 21:53:12 +00:00
|
|
|
usage: wgpu::TextureUsages::RENDER_ATTACHMENT
|
|
|
|
| wgpu::TextureUsages::TEXTURE_BINDING,
|
|
|
|
});
|
|
|
|
let copy_srgb_view = copy_srgb_buffer.create_view(&Default::default());
|
|
|
|
let copy_srgb_bind_group =
|
|
|
|
self.descriptors
|
|
|
|
.device
|
|
|
|
.create_bind_group(&wgpu::BindGroupDescriptor {
|
2022-09-06 21:38:48 +00:00
|
|
|
layout: &target_data!(self).pipelines.bitmap_layout,
|
2022-04-14 21:53:12 +00:00
|
|
|
entries: &[
|
|
|
|
wgpu::BindGroupEntry {
|
|
|
|
binding: 0,
|
|
|
|
resource: wgpu::BindingResource::Buffer(wgpu::BufferBinding {
|
|
|
|
buffer: &self.quad_tex_transforms,
|
|
|
|
offset: 0,
|
|
|
|
size: wgpu::BufferSize::new(
|
|
|
|
std::mem::size_of::<TextureTransforms>() as u64,
|
|
|
|
),
|
|
|
|
}),
|
|
|
|
},
|
|
|
|
wgpu::BindGroupEntry {
|
|
|
|
binding: 1,
|
|
|
|
resource: wgpu::BindingResource::TextureView(©_srgb_view),
|
|
|
|
},
|
|
|
|
],
|
|
|
|
label: create_debug_label!("Copy sRGB bind group").as_deref(),
|
|
|
|
});
|
|
|
|
(Some(copy_srgb_view), Some(copy_srgb_bind_group))
|
|
|
|
} else {
|
|
|
|
(None, None)
|
|
|
|
};
|
2022-04-14 18:03:45 +00:00
|
|
|
|
2022-08-07 23:54:11 +00:00
|
|
|
self.globals.set_resolution(width, height);
|
2022-08-04 05:50:18 +00:00
|
|
|
self.viewport_scale_factor = dimensions.scale_factor;
|
|
|
|
}
|
|
|
|
|
|
|
|
fn viewport_dimensions(&self) -> ViewportDimensions {
|
|
|
|
ViewportDimensions {
|
|
|
|
width: self.target.width(),
|
|
|
|
height: self.target.height(),
|
|
|
|
scale_factor: self.viewport_scale_factor,
|
|
|
|
}
|
2020-04-21 13:32:50 +00:00
|
|
|
}
|
|
|
|
|
2020-12-30 23:35:43 +00:00
|
|
|
fn register_shape(
|
|
|
|
&mut self,
|
|
|
|
shape: DistilledShape,
|
2021-06-13 21:44:16 +00:00
|
|
|
bitmap_source: &dyn BitmapSource,
|
2020-12-30 23:35:43 +00:00
|
|
|
) -> ShapeHandle {
|
2020-05-19 11:03:23 +00:00
|
|
|
let handle = ShapeHandle(self.meshes.len());
|
2021-06-13 21:44:16 +00:00
|
|
|
let mesh = self.register_shape_internal(shape, bitmap_source);
|
2020-05-19 11:03:23 +00:00
|
|
|
self.meshes.push(mesh);
|
|
|
|
handle
|
|
|
|
}
|
|
|
|
|
2020-12-30 23:35:43 +00:00
|
|
|
fn replace_shape(
|
|
|
|
&mut self,
|
|
|
|
shape: DistilledShape,
|
2021-06-13 21:44:16 +00:00
|
|
|
bitmap_source: &dyn BitmapSource,
|
2020-12-30 23:35:43 +00:00
|
|
|
handle: ShapeHandle,
|
|
|
|
) {
|
2021-06-13 21:44:16 +00:00
|
|
|
let mesh = self.register_shape_internal(shape, bitmap_source);
|
2020-05-19 11:03:23 +00:00
|
|
|
self.meshes[handle.0] = mesh;
|
2020-04-21 13:32:50 +00:00
|
|
|
}
|
|
|
|
|
2021-03-20 14:30:21 +00:00
|
|
|
fn register_glyph_shape(&mut self, glyph: &swf::Glyph) -> ShapeHandle {
|
2022-08-13 23:05:38 +00:00
|
|
|
let shape = ruffle_render::shape_utils::swf_glyph_to_shape(glyph);
|
2020-05-19 11:03:23 +00:00
|
|
|
let handle = ShapeHandle(self.meshes.len());
|
2021-06-13 21:44:16 +00:00
|
|
|
let mesh = self.register_shape_internal(
|
|
|
|
(&shape).into(),
|
2022-08-13 23:16:17 +00:00
|
|
|
&ruffle_render::backend::null::NullBitmapSource,
|
2021-06-13 21:44:16 +00:00
|
|
|
);
|
2020-05-19 11:03:23 +00:00
|
|
|
self.meshes.push(mesh);
|
|
|
|
handle
|
2020-04-21 13:32:50 +00:00
|
|
|
}
|
|
|
|
|
2020-05-01 12:13:48 +00:00
|
|
|
fn begin_frame(&mut self, clear: Color) {
|
2020-12-26 00:43:03 +00:00
|
|
|
self.mask_state = MaskState::NoMask;
|
|
|
|
self.num_masks = 0;
|
2022-08-08 00:12:35 +00:00
|
|
|
self.uniform_buffers.reset();
|
2020-12-26 00:43:03 +00:00
|
|
|
|
|
|
|
let frame_output = match self.target.get_next_texture() {
|
|
|
|
Ok(frame) => frame,
|
2020-08-27 10:32:41 +00:00
|
|
|
Err(e) => {
|
|
|
|
log::warn!("Couldn't begin new render frame: {}", e);
|
2020-12-28 23:17:37 +00:00
|
|
|
// Attemp to recreate the swap chain in this case.
|
|
|
|
self.target.resize(
|
|
|
|
&self.descriptors.device,
|
|
|
|
self.target.width(),
|
|
|
|
self.target.height(),
|
|
|
|
);
|
|
|
|
return;
|
2020-04-21 13:32:50 +00:00
|
|
|
}
|
|
|
|
};
|
2020-10-14 18:25:55 +00:00
|
|
|
|
2020-12-26 00:43:03 +00:00
|
|
|
let label = create_debug_label!("Draw encoder");
|
|
|
|
let draw_encoder =
|
|
|
|
self.descriptors
|
|
|
|
.device
|
|
|
|
.create_command_encoder(&wgpu::CommandEncoderDescriptor {
|
|
|
|
label: label.as_deref(),
|
|
|
|
});
|
2021-09-07 20:25:56 +00:00
|
|
|
let uniform_encoder_label = create_debug_label!("Uniform upload command encoder");
|
|
|
|
let uniform_encoder =
|
|
|
|
self.descriptors
|
|
|
|
.device
|
|
|
|
.create_command_encoder(&wgpu::CommandEncoderDescriptor {
|
|
|
|
label: uniform_encoder_label.as_deref(),
|
|
|
|
});
|
|
|
|
let mut frame_data = Box::new((draw_encoder, frame_output, uniform_encoder));
|
2020-04-21 13:32:50 +00:00
|
|
|
|
2022-08-07 23:54:11 +00:00
|
|
|
self.globals
|
2020-12-26 00:43:03 +00:00
|
|
|
.update_uniform(&self.descriptors.device, &mut frame_data.0);
|
|
|
|
|
2022-04-14 18:03:45 +00:00
|
|
|
// Use intermediate render targets when resolving MSAA or copying from linear-to-sRGB texture.
|
2022-04-14 21:53:12 +00:00
|
|
|
let (color_view, resolve_target) = match (&self.frame_buffer_view, &self.copy_srgb_view) {
|
|
|
|
(None, None) => (frame_data.1.view(), None),
|
|
|
|
(None, Some(copy)) => (copy, None),
|
|
|
|
(Some(frame_buffer), None) => (frame_buffer, Some(frame_data.1.view())),
|
|
|
|
(Some(frame_buffer), Some(copy)) => (frame_buffer, Some(copy)),
|
2020-12-26 00:43:03 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
let render_pass = frame_data.0.begin_render_pass(&wgpu::RenderPassDescriptor {
|
2022-07-02 12:18:30 +00:00
|
|
|
color_attachments: &[Some(wgpu::RenderPassColorAttachment {
|
2021-04-16 20:55:31 +00:00
|
|
|
view: color_view,
|
2020-12-26 00:43:03 +00:00
|
|
|
ops: wgpu::Operations {
|
|
|
|
load: wgpu::LoadOp::Clear(wgpu::Color {
|
|
|
|
r: f64::from(clear.r) / 255.0,
|
|
|
|
g: f64::from(clear.g) / 255.0,
|
|
|
|
b: f64::from(clear.b) / 255.0,
|
|
|
|
a: f64::from(clear.a) / 255.0,
|
2020-08-27 10:32:41 +00:00
|
|
|
}),
|
2020-12-26 00:43:03 +00:00
|
|
|
store: true,
|
|
|
|
},
|
|
|
|
resolve_target,
|
2022-07-02 12:18:30 +00:00
|
|
|
})],
|
2021-04-16 20:55:31 +00:00
|
|
|
depth_stencil_attachment: Some(wgpu::RenderPassDepthStencilAttachment {
|
|
|
|
view: &self.depth_texture_view,
|
2020-12-26 00:43:03 +00:00
|
|
|
depth_ops: Some(wgpu::Operations {
|
|
|
|
load: wgpu::LoadOp::Clear(0.0),
|
2022-04-14 21:35:55 +00:00
|
|
|
store: false,
|
2020-04-21 13:32:50 +00:00
|
|
|
}),
|
2020-12-26 00:43:03 +00:00
|
|
|
stencil_ops: Some(wgpu::Operations {
|
|
|
|
load: wgpu::LoadOp::Clear(0),
|
|
|
|
store: true,
|
|
|
|
}),
|
|
|
|
}),
|
2020-12-27 06:33:38 +00:00
|
|
|
label: None,
|
2020-12-26 00:43:03 +00:00
|
|
|
});
|
|
|
|
|
|
|
|
// Since RenderPass holds a reference to the CommandEncoder, we cast the lifetime
|
|
|
|
// away to allow for the self-referencing struct. draw_encoder is boxed so its
|
|
|
|
// address should remain stable.
|
|
|
|
self.current_frame = Some(Frame {
|
|
|
|
render_pass: unsafe {
|
|
|
|
std::mem::transmute::<_, wgpu::RenderPass<'static>>(render_pass)
|
|
|
|
},
|
|
|
|
frame_data,
|
|
|
|
});
|
2020-04-21 13:32:50 +00:00
|
|
|
}
|
|
|
|
|
2022-09-06 21:38:48 +00:00
|
|
|
fn render_offscreen(
|
|
|
|
&mut self,
|
|
|
|
handle: BitmapHandle,
|
|
|
|
width: u32,
|
|
|
|
height: u32,
|
|
|
|
f: &mut dyn FnMut(&mut dyn RenderBackend) -> Result<(), ruffle_render::error::Error>,
|
|
|
|
) -> Result<Bitmap, ruffle_render::error::Error> {
|
|
|
|
// Rendering to a texture backend requires us to use non-`Clone`
|
|
|
|
// wgpu resources (e.g. `wgpu::Device`, `wgpu::Queue`.
|
|
|
|
//
|
|
|
|
// We expect that in the majority of SWFs, we will spend most
|
|
|
|
// of our time performing 'normal' (non-offscreen) renders.
|
|
|
|
// Therefore, we want to avoid penalizing this case by adding
|
|
|
|
// in a check for 'normal' or 'offscreen' mode in the main
|
|
|
|
// rendering code.
|
|
|
|
//
|
|
|
|
// To accomplish this, we use `take_mut` to temporarily
|
|
|
|
// move out of `self`. This allows us to construct a new
|
|
|
|
// `WgpuRenderBackend` with a `TextureTarget` corresponding to
|
|
|
|
// `handle`. This allows us to re-use many of the fields from
|
|
|
|
// our normal `WgpuRenderBackend` without wrapping in an `Rc`
|
|
|
|
// or other indirection.
|
|
|
|
//
|
|
|
|
// Note that `take_mut` causes the process to abort if the
|
|
|
|
// `with_offscreen_render_backend_internal` panics, since
|
|
|
|
// the `&mut self` reference would be logically uninitialized.
|
|
|
|
// However, we normally compile Ruffle with `panic=abort`,
|
|
|
|
// so this shouldn't actually have an effect in practice.
|
|
|
|
// Even with `panic=unwind`, we would still get a backtrace
|
|
|
|
// printed, and there's not really much point in attempting
|
|
|
|
// to recover from a partially failed render operation, anyway.
|
|
|
|
Ok(take_mut(self, |this| {
|
|
|
|
this.render_offscreen_internal(handle, width, height, f)
|
|
|
|
.expect("Failed to render to offscreen backend")
|
|
|
|
}))
|
|
|
|
}
|
|
|
|
|
2020-12-15 03:18:27 +00:00
|
|
|
fn render_bitmap(&mut self, bitmap: BitmapHandle, transform: &Transform, smoothing: bool) {
|
2022-09-06 21:38:48 +00:00
|
|
|
let target_data = target_data!(self);
|
2022-06-29 22:16:43 +00:00
|
|
|
if let Some(entry) = self.bitmap_registry.get(&bitmap) {
|
|
|
|
let texture = &entry.texture_wrapper;
|
2022-07-25 16:31:40 +00:00
|
|
|
let blend_mode = self.blend_mode();
|
2020-12-26 00:43:03 +00:00
|
|
|
let frame = if let Some(frame) = &mut self.current_frame {
|
|
|
|
frame.get()
|
|
|
|
} else {
|
|
|
|
return;
|
|
|
|
};
|
2020-04-29 10:06:02 +00:00
|
|
|
|
|
|
|
let transform = Transform {
|
|
|
|
matrix: transform.matrix
|
2022-08-13 23:01:54 +00:00
|
|
|
* ruffle_render::matrix::Matrix {
|
2020-04-29 10:06:02 +00:00
|
|
|
a: texture.width as f32,
|
|
|
|
d: texture.height as f32,
|
|
|
|
..Default::default()
|
|
|
|
},
|
|
|
|
..*transform
|
|
|
|
};
|
|
|
|
|
|
|
|
let world_matrix = [
|
|
|
|
[transform.matrix.a, transform.matrix.b, 0.0, 0.0],
|
|
|
|
[transform.matrix.c, transform.matrix.d, 0.0, 0.0],
|
|
|
|
[0.0, 0.0, 1.0, 0.0],
|
|
|
|
[
|
|
|
|
transform.matrix.tx.to_pixels() as f32,
|
|
|
|
transform.matrix.ty.to_pixels() as f32,
|
|
|
|
0.0,
|
|
|
|
1.0,
|
|
|
|
],
|
|
|
|
];
|
|
|
|
|
2020-12-26 00:43:03 +00:00
|
|
|
frame.render_pass.set_pipeline(
|
2022-09-06 21:38:48 +00:00
|
|
|
target_data
|
2020-10-15 23:23:36 +00:00
|
|
|
.pipelines
|
2020-10-17 19:05:16 +00:00
|
|
|
.bitmap_pipelines
|
2022-09-02 20:26:12 +00:00
|
|
|
.pipeline_for(blend_mode.into(), self.mask_state),
|
2020-10-15 23:23:36 +00:00
|
|
|
);
|
2020-12-26 00:43:03 +00:00
|
|
|
frame
|
|
|
|
.render_pass
|
2022-08-07 23:54:11 +00:00
|
|
|
.set_bind_group(0, self.globals.bind_group(), &[]);
|
2021-09-07 20:25:56 +00:00
|
|
|
|
2022-08-08 00:12:35 +00:00
|
|
|
self.uniform_buffers.write_uniforms(
|
2021-09-07 20:25:56 +00:00
|
|
|
&self.descriptors.device,
|
2022-08-08 00:12:35 +00:00
|
|
|
&self.descriptors.uniform_buffers_layout,
|
2021-09-07 20:25:56 +00:00
|
|
|
&mut frame.frame_data.2,
|
|
|
|
&mut frame.render_pass,
|
|
|
|
1,
|
|
|
|
&Transforms {
|
|
|
|
world_matrix,
|
|
|
|
color_adjustments: ColorAdjustments::from(transform.color_transform),
|
|
|
|
},
|
|
|
|
);
|
|
|
|
|
2020-12-26 03:19:42 +00:00
|
|
|
frame
|
|
|
|
.render_pass
|
2021-09-07 20:25:56 +00:00
|
|
|
.set_bind_group(2, &texture.bind_group, &[]);
|
2020-12-26 00:43:03 +00:00
|
|
|
frame.render_pass.set_bind_group(
|
2021-09-07 20:25:56 +00:00
|
|
|
3,
|
2020-12-15 03:18:27 +00:00
|
|
|
self.descriptors
|
|
|
|
.bitmap_samplers
|
|
|
|
.get_bind_group(false, smoothing),
|
2020-10-15 23:23:36 +00:00
|
|
|
&[],
|
|
|
|
);
|
2020-12-26 00:43:03 +00:00
|
|
|
frame
|
|
|
|
.render_pass
|
|
|
|
.set_vertex_buffer(0, self.quad_vbo.slice(..));
|
2020-12-27 06:33:38 +00:00
|
|
|
frame
|
|
|
|
.render_pass
|
2021-01-04 23:45:40 +00:00
|
|
|
.set_index_buffer(self.quad_ibo.slice(..), wgpu::IndexFormat::Uint32);
|
2020-04-29 10:06:02 +00:00
|
|
|
|
2020-10-14 18:25:55 +00:00
|
|
|
match self.mask_state {
|
|
|
|
MaskState::NoMask => (),
|
|
|
|
MaskState::DrawMaskStencil => {
|
|
|
|
debug_assert!(self.num_masks > 0);
|
2020-12-26 00:43:03 +00:00
|
|
|
frame.render_pass.set_stencil_reference(self.num_masks - 1);
|
2020-10-14 18:25:55 +00:00
|
|
|
}
|
|
|
|
MaskState::DrawMaskedContent | MaskState::ClearMaskStencil => {
|
|
|
|
debug_assert!(self.num_masks > 0);
|
2020-12-26 00:43:03 +00:00
|
|
|
frame.render_pass.set_stencil_reference(self.num_masks);
|
2020-10-14 18:25:55 +00:00
|
|
|
}
|
|
|
|
};
|
2020-04-29 10:06:02 +00:00
|
|
|
|
2020-12-26 00:43:03 +00:00
|
|
|
frame.render_pass.draw_indexed(0..6, 0, 0..1);
|
2020-04-29 10:06:02 +00:00
|
|
|
}
|
|
|
|
}
|
2020-04-21 13:32:50 +00:00
|
|
|
|
|
|
|
fn render_shape(&mut self, shape: ShapeHandle, transform: &Transform) {
|
2022-07-25 16:31:40 +00:00
|
|
|
let blend_mode = self.blend_mode();
|
2020-12-26 00:43:03 +00:00
|
|
|
let frame = if let Some(frame) = &mut self.current_frame {
|
|
|
|
frame.get()
|
2020-05-04 20:59:06 +00:00
|
|
|
} else {
|
|
|
|
return;
|
|
|
|
};
|
2020-04-21 13:32:50 +00:00
|
|
|
|
2020-04-30 14:33:41 +00:00
|
|
|
let mesh = &mut self.meshes[shape.0];
|
2020-04-21 13:32:50 +00:00
|
|
|
|
|
|
|
let world_matrix = [
|
|
|
|
[transform.matrix.a, transform.matrix.b, 0.0, 0.0],
|
|
|
|
[transform.matrix.c, transform.matrix.d, 0.0, 0.0],
|
|
|
|
[0.0, 0.0, 1.0, 0.0],
|
|
|
|
[
|
|
|
|
transform.matrix.tx.to_pixels() as f32,
|
|
|
|
transform.matrix.ty.to_pixels() as f32,
|
|
|
|
0.0,
|
|
|
|
1.0,
|
|
|
|
],
|
|
|
|
];
|
|
|
|
|
2020-12-26 00:43:03 +00:00
|
|
|
frame
|
|
|
|
.render_pass
|
2022-08-07 23:54:11 +00:00
|
|
|
.set_bind_group(0, self.globals.bind_group(), &[]);
|
2020-10-17 21:39:24 +00:00
|
|
|
|
2022-08-08 00:12:35 +00:00
|
|
|
self.uniform_buffers.write_uniforms(
|
2021-09-07 20:25:56 +00:00
|
|
|
&self.descriptors.device,
|
2022-08-08 00:12:35 +00:00
|
|
|
&self.descriptors.uniform_buffers_layout,
|
2021-09-07 20:25:56 +00:00
|
|
|
&mut frame.frame_data.2,
|
|
|
|
&mut frame.render_pass,
|
|
|
|
1,
|
|
|
|
&Transforms {
|
|
|
|
world_matrix,
|
|
|
|
color_adjustments: ColorAdjustments::from(transform.color_transform),
|
|
|
|
},
|
|
|
|
);
|
|
|
|
|
2020-04-21 13:32:50 +00:00
|
|
|
for draw in &mesh.draws {
|
2022-05-24 23:19:59 +00:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2020-04-21 13:32:50 +00:00
|
|
|
match &draw.draw_type {
|
|
|
|
DrawType::Color => {
|
2020-12-26 00:43:03 +00:00
|
|
|
frame.render_pass.set_pipeline(
|
2022-09-06 21:38:48 +00:00
|
|
|
target_data!(self)
|
2020-10-15 23:23:36 +00:00
|
|
|
.pipelines
|
2020-10-17 19:05:16 +00:00
|
|
|
.color_pipelines
|
2022-09-02 20:26:12 +00:00
|
|
|
.pipeline_for(blend_mode.into(), self.mask_state),
|
2020-10-15 23:23:36 +00:00
|
|
|
);
|
2020-04-21 13:32:50 +00:00
|
|
|
}
|
2020-10-17 21:39:24 +00:00
|
|
|
DrawType::Gradient { bind_group, .. } => {
|
2020-12-26 00:43:03 +00:00
|
|
|
frame.render_pass.set_pipeline(
|
2022-09-06 21:38:48 +00:00
|
|
|
target_data!(self)
|
2020-10-15 23:23:36 +00:00
|
|
|
.pipelines
|
2020-10-17 19:05:16 +00:00
|
|
|
.gradient_pipelines
|
2022-09-02 20:26:12 +00:00
|
|
|
.pipeline_for(blend_mode.into(), self.mask_state),
|
2020-10-15 23:23:36 +00:00
|
|
|
);
|
2021-09-07 20:25:56 +00:00
|
|
|
frame.render_pass.set_bind_group(2, bind_group, &[]);
|
2020-04-21 13:32:50 +00:00
|
|
|
}
|
2020-10-15 22:55:19 +00:00
|
|
|
DrawType::Bitmap {
|
|
|
|
is_repeating,
|
|
|
|
is_smoothed,
|
2020-10-17 21:39:24 +00:00
|
|
|
bind_group,
|
2020-10-15 22:55:19 +00:00
|
|
|
..
|
|
|
|
} => {
|
2020-12-26 00:43:03 +00:00
|
|
|
frame.render_pass.set_pipeline(
|
2022-09-06 21:38:48 +00:00
|
|
|
target_data!(self)
|
2020-10-15 23:23:36 +00:00
|
|
|
.pipelines
|
2020-10-17 19:05:16 +00:00
|
|
|
.bitmap_pipelines
|
2022-09-02 20:26:12 +00:00
|
|
|
.pipeline_for(blend_mode.into(), self.mask_state),
|
2020-10-15 23:23:36 +00:00
|
|
|
);
|
2021-09-07 20:25:56 +00:00
|
|
|
frame.render_pass.set_bind_group(2, bind_group, &[]);
|
2020-12-26 00:43:03 +00:00
|
|
|
frame.render_pass.set_bind_group(
|
2021-09-07 20:25:56 +00:00
|
|
|
3,
|
2020-10-15 23:23:36 +00:00
|
|
|
self.descriptors
|
|
|
|
.bitmap_samplers
|
2020-10-15 22:55:19 +00:00
|
|
|
.get_bind_group(*is_repeating, *is_smoothed),
|
|
|
|
&[],
|
|
|
|
);
|
2020-04-21 13:32:50 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-12-26 00:43:03 +00:00
|
|
|
frame
|
|
|
|
.render_pass
|
|
|
|
.set_vertex_buffer(0, draw.vertex_buffer.slice(..));
|
|
|
|
frame
|
|
|
|
.render_pass
|
2021-01-04 23:45:40 +00:00
|
|
|
.set_index_buffer(draw.index_buffer.slice(..), wgpu::IndexFormat::Uint32);
|
2020-04-21 13:32:50 +00:00
|
|
|
|
2020-10-14 18:25:55 +00:00
|
|
|
match self.mask_state {
|
|
|
|
MaskState::NoMask => (),
|
|
|
|
MaskState::DrawMaskStencil => {
|
|
|
|
debug_assert!(self.num_masks > 0);
|
2020-12-26 00:43:03 +00:00
|
|
|
frame.render_pass.set_stencil_reference(self.num_masks - 1);
|
2020-10-14 18:25:55 +00:00
|
|
|
}
|
|
|
|
MaskState::DrawMaskedContent | MaskState::ClearMaskStencil => {
|
|
|
|
debug_assert!(self.num_masks > 0);
|
2020-12-26 00:43:03 +00:00
|
|
|
frame.render_pass.set_stencil_reference(self.num_masks);
|
2020-10-14 18:25:55 +00:00
|
|
|
}
|
|
|
|
};
|
2020-04-28 20:48:17 +00:00
|
|
|
|
2022-05-24 23:19:59 +00:00
|
|
|
frame.render_pass.draw_indexed(0..num_indices, 0, 0..1);
|
2020-04-21 13:32:50 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-08-13 23:01:54 +00:00
|
|
|
fn draw_rect(&mut self, color: Color, matrix: &ruffle_render::matrix::Matrix) {
|
2022-07-25 16:31:40 +00:00
|
|
|
let blend_mode = self.blend_mode();
|
2020-12-26 00:43:03 +00:00
|
|
|
let frame = if let Some(frame) = &mut self.current_frame {
|
|
|
|
frame.get()
|
2020-09-15 21:14:25 +00:00
|
|
|
} else {
|
|
|
|
return;
|
|
|
|
};
|
|
|
|
|
|
|
|
let world_matrix = [
|
|
|
|
[matrix.a, matrix.b, 0.0, 0.0],
|
|
|
|
[matrix.c, matrix.d, 0.0, 0.0],
|
|
|
|
[0.0, 0.0, 1.0, 0.0],
|
|
|
|
[
|
|
|
|
matrix.tx.to_pixels() as f32,
|
|
|
|
matrix.ty.to_pixels() as f32,
|
|
|
|
0.0,
|
|
|
|
1.0,
|
|
|
|
],
|
|
|
|
];
|
|
|
|
|
|
|
|
let 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,
|
|
|
|
];
|
|
|
|
|
|
|
|
let add_color = [0.0, 0.0, 0.0, 0.0];
|
2020-12-26 00:43:03 +00:00
|
|
|
frame.render_pass.set_pipeline(
|
2022-09-06 21:38:48 +00:00
|
|
|
target_data!(self)
|
2020-12-26 00:43:03 +00:00
|
|
|
.pipelines
|
|
|
|
.color_pipelines
|
2022-09-02 20:26:12 +00:00
|
|
|
.pipeline_for(blend_mode.into(), self.mask_state),
|
2020-12-26 00:43:03 +00:00
|
|
|
);
|
2020-09-15 21:14:25 +00:00
|
|
|
|
2020-12-26 00:43:03 +00:00
|
|
|
frame
|
|
|
|
.render_pass
|
2022-08-07 23:54:11 +00:00
|
|
|
.set_bind_group(0, self.globals.bind_group(), &[]);
|
2021-09-07 20:25:56 +00:00
|
|
|
|
2022-08-08 00:12:35 +00:00
|
|
|
self.uniform_buffers.write_uniforms(
|
2021-09-07 20:25:56 +00:00
|
|
|
&self.descriptors.device,
|
2022-08-08 00:12:35 +00:00
|
|
|
&self.descriptors.uniform_buffers_layout,
|
2021-09-07 20:25:56 +00:00
|
|
|
&mut frame.frame_data.2,
|
|
|
|
&mut frame.render_pass,
|
|
|
|
1,
|
|
|
|
&Transforms {
|
|
|
|
world_matrix,
|
|
|
|
color_adjustments: ColorAdjustments {
|
|
|
|
mult_color,
|
|
|
|
add_color,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
);
|
|
|
|
|
2020-12-26 00:43:03 +00:00
|
|
|
frame
|
|
|
|
.render_pass
|
|
|
|
.set_vertex_buffer(0, self.quad_vbo.slice(..));
|
2020-12-27 06:33:38 +00:00
|
|
|
frame
|
|
|
|
.render_pass
|
2021-01-04 23:45:40 +00:00
|
|
|
.set_index_buffer(self.quad_ibo.slice(..), wgpu::IndexFormat::Uint32);
|
2020-09-15 21:14:25 +00:00
|
|
|
|
2020-10-14 18:25:55 +00:00
|
|
|
match self.mask_state {
|
|
|
|
MaskState::NoMask => (),
|
|
|
|
MaskState::DrawMaskStencil => {
|
|
|
|
debug_assert!(self.num_masks > 0);
|
2020-12-26 00:43:03 +00:00
|
|
|
frame.render_pass.set_stencil_reference(self.num_masks - 1);
|
2020-10-14 18:25:55 +00:00
|
|
|
}
|
|
|
|
MaskState::DrawMaskedContent | MaskState::ClearMaskStencil => {
|
|
|
|
debug_assert!(self.num_masks > 0);
|
2020-12-26 00:43:03 +00:00
|
|
|
frame.render_pass.set_stencil_reference(self.num_masks);
|
2020-10-14 18:25:55 +00:00
|
|
|
}
|
|
|
|
};
|
2020-09-15 21:14:25 +00:00
|
|
|
|
2020-12-26 00:43:03 +00:00
|
|
|
frame.render_pass.draw_indexed(0..6, 0, 0..1);
|
2020-09-15 21:14:25 +00:00
|
|
|
}
|
|
|
|
|
2020-04-21 13:32:50 +00:00
|
|
|
fn end_frame(&mut self) {
|
2020-12-26 00:43:03 +00:00
|
|
|
if let Some(frame) = self.current_frame.take() {
|
2022-04-14 18:03:45 +00:00
|
|
|
let draw_encoder = frame.frame_data.0;
|
|
|
|
let mut uniform_encoder = frame.frame_data.2;
|
|
|
|
let render_pass = frame.render_pass;
|
2020-12-26 00:43:03 +00:00
|
|
|
// Finalize render pass.
|
2022-04-14 18:03:45 +00:00
|
|
|
drop(render_pass);
|
|
|
|
|
|
|
|
// If we have an sRGB surface, copy from our linear intermediate buffer to the sRGB surface.
|
2022-04-14 21:53:12 +00:00
|
|
|
let command_buffers = if let Some(copy_srgb_bind_group) = &self.copy_srgb_bind_group {
|
|
|
|
debug_assert!(self.copy_srgb_view.is_some());
|
2022-04-14 18:03:45 +00:00
|
|
|
let mut copy_encoder = self.descriptors.device.create_command_encoder(
|
|
|
|
&wgpu::CommandEncoderDescriptor {
|
|
|
|
label: create_debug_label!("Frame copy command encoder").as_deref(),
|
|
|
|
},
|
|
|
|
);
|
|
|
|
|
|
|
|
let mut render_pass = copy_encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
|
2022-07-02 12:18:30 +00:00
|
|
|
color_attachments: &[Some(wgpu::RenderPassColorAttachment {
|
2022-07-08 09:11:48 +00:00
|
|
|
view: frame.frame_data.1.view(),
|
2022-04-14 18:03:45 +00:00
|
|
|
ops: wgpu::Operations {
|
|
|
|
load: wgpu::LoadOp::Clear(wgpu::Color::TRANSPARENT),
|
|
|
|
store: true,
|
|
|
|
},
|
|
|
|
resolve_target: None,
|
2022-07-02 12:18:30 +00:00
|
|
|
})],
|
2022-04-14 18:03:45 +00:00
|
|
|
depth_stencil_attachment: None,
|
|
|
|
label: None,
|
|
|
|
});
|
|
|
|
|
2022-09-06 21:38:48 +00:00
|
|
|
render_pass.set_pipeline(&target_data!(self).pipelines.copy_srgb_pipeline);
|
2022-08-07 23:54:11 +00:00
|
|
|
render_pass.set_bind_group(0, self.globals.bind_group(), &[]);
|
2022-08-08 00:12:35 +00:00
|
|
|
self.uniform_buffers.write_uniforms(
|
2022-04-14 18:03:45 +00:00
|
|
|
&self.descriptors.device,
|
2022-08-08 00:12:35 +00:00
|
|
|
&self.descriptors.uniform_buffers_layout,
|
2022-04-14 18:03:45 +00:00
|
|
|
&mut uniform_encoder,
|
|
|
|
&mut render_pass,
|
|
|
|
1,
|
|
|
|
&Transforms {
|
|
|
|
world_matrix: [
|
|
|
|
[self.target.width() as f32, 0.0, 0.0, 0.0],
|
|
|
|
[0.0, self.target.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],
|
|
|
|
},
|
|
|
|
},
|
|
|
|
);
|
2022-04-14 21:53:12 +00:00
|
|
|
render_pass.set_bind_group(2, copy_srgb_bind_group, &[]);
|
2022-04-14 18:03:45 +00:00
|
|
|
render_pass.set_bind_group(
|
|
|
|
3,
|
|
|
|
self.descriptors
|
|
|
|
.bitmap_samplers
|
|
|
|
.get_bind_group(false, false),
|
|
|
|
&[],
|
|
|
|
);
|
|
|
|
render_pass.set_vertex_buffer(0, self.quad_vbo.slice(..));
|
|
|
|
render_pass.set_index_buffer(self.quad_ibo.slice(..), wgpu::IndexFormat::Uint32);
|
|
|
|
render_pass.draw_indexed(0..6, 0, 0..1);
|
|
|
|
drop(render_pass);
|
|
|
|
vec![
|
|
|
|
uniform_encoder.finish(),
|
|
|
|
draw_encoder.finish(),
|
|
|
|
copy_encoder.finish(),
|
|
|
|
]
|
|
|
|
} else {
|
|
|
|
vec![uniform_encoder.finish(), draw_encoder.finish()]
|
|
|
|
};
|
|
|
|
|
2022-08-08 00:12:35 +00:00
|
|
|
self.uniform_buffers.finish();
|
2020-10-15 23:23:36 +00:00
|
|
|
self.target.submit(
|
|
|
|
&self.descriptors.device,
|
|
|
|
&self.descriptors.queue,
|
2022-04-14 18:03:45 +00:00
|
|
|
command_buffers,
|
2021-09-08 07:20:11 +00:00
|
|
|
frame.frame_data.1,
|
2020-10-15 23:23:36 +00:00
|
|
|
);
|
2020-04-21 13:32:50 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-04-28 20:48:17 +00:00
|
|
|
fn push_mask(&mut self) {
|
2021-01-14 21:59:23 +00:00
|
|
|
debug_assert!(
|
2020-10-14 18:25:55 +00:00
|
|
|
self.mask_state == MaskState::NoMask || self.mask_state == MaskState::DrawMaskedContent
|
|
|
|
);
|
2020-04-28 20:48:17 +00:00
|
|
|
self.num_masks += 1;
|
2020-10-14 18:25:55 +00:00
|
|
|
self.mask_state = MaskState::DrawMaskStencil;
|
2020-04-28 20:48:17 +00:00
|
|
|
}
|
2020-04-21 13:32:50 +00:00
|
|
|
|
2020-04-28 20:48:17 +00:00
|
|
|
fn activate_mask(&mut self) {
|
2021-01-14 21:59:23 +00:00
|
|
|
debug_assert!(self.num_masks > 0 && self.mask_state == MaskState::DrawMaskStencil);
|
2020-10-14 18:25:55 +00:00
|
|
|
self.mask_state = MaskState::DrawMaskedContent;
|
|
|
|
}
|
|
|
|
|
|
|
|
fn deactivate_mask(&mut self) {
|
2021-01-14 21:59:23 +00:00
|
|
|
debug_assert!(self.num_masks > 0 && self.mask_state == MaskState::DrawMaskedContent);
|
2020-10-14 18:25:55 +00:00
|
|
|
self.mask_state = MaskState::ClearMaskStencil;
|
2020-04-28 20:48:17 +00:00
|
|
|
}
|
2020-04-21 13:32:50 +00:00
|
|
|
|
2020-04-28 20:48:17 +00:00
|
|
|
fn pop_mask(&mut self) {
|
2021-01-14 21:59:23 +00:00
|
|
|
debug_assert!(self.num_masks > 0 && self.mask_state == MaskState::ClearMaskStencil);
|
2020-10-14 18:25:55 +00:00
|
|
|
self.num_masks -= 1;
|
|
|
|
self.mask_state = if self.num_masks == 0 {
|
|
|
|
MaskState::NoMask
|
|
|
|
} else {
|
|
|
|
MaskState::DrawMaskedContent
|
|
|
|
};
|
2020-04-28 20:48:17 +00:00
|
|
|
}
|
2020-10-19 00:25:23 +00:00
|
|
|
|
2022-07-25 16:31:40 +00:00
|
|
|
fn push_blend_mode(&mut self, blend: BlendMode) {
|
|
|
|
self.blend_modes.push(blend);
|
|
|
|
}
|
|
|
|
|
|
|
|
fn pop_blend_mode(&mut self) {
|
|
|
|
self.blend_modes.pop();
|
|
|
|
}
|
|
|
|
|
2020-11-01 18:43:15 +00:00
|
|
|
fn get_bitmap_pixels(&mut self, bitmap: BitmapHandle) -> Option<Bitmap> {
|
2022-06-29 22:16:43 +00:00
|
|
|
self.bitmap_registry.get(&bitmap).map(|e| e.bitmap.clone())
|
2020-11-01 18:43:15 +00:00
|
|
|
}
|
|
|
|
|
2022-08-18 23:34:35 +00:00
|
|
|
fn register_bitmap(&mut self, bitmap: Bitmap) -> Result<BitmapHandle, BitmapError> {
|
2022-08-08 12:54:34 +00:00
|
|
|
if bitmap.width() > self.descriptors.limits.max_texture_dimension_2d
|
|
|
|
|| bitmap.height() > self.descriptors.limits.max_texture_dimension_2d
|
|
|
|
{
|
2022-08-18 23:34:35 +00:00
|
|
|
return Err(BitmapError::TooLarge);
|
2022-08-08 12:54:34 +00:00
|
|
|
}
|
|
|
|
|
2022-05-27 19:16:33 +00:00
|
|
|
let bitmap = bitmap.to_rgba();
|
|
|
|
let extent = wgpu::Extent3d {
|
|
|
|
width: bitmap.width(),
|
|
|
|
height: bitmap.height(),
|
|
|
|
depth_or_array_layers: 1,
|
|
|
|
};
|
|
|
|
|
|
|
|
let texture_label = create_debug_label!("Bitmap");
|
|
|
|
let texture = self
|
|
|
|
.descriptors
|
|
|
|
.device
|
|
|
|
.create_texture(&wgpu::TextureDescriptor {
|
|
|
|
label: texture_label.as_deref(),
|
|
|
|
size: extent,
|
|
|
|
mip_level_count: 1,
|
|
|
|
sample_count: 1,
|
|
|
|
dimension: wgpu::TextureDimension::D2,
|
|
|
|
format: wgpu::TextureFormat::Rgba8Unorm,
|
2022-09-06 21:38:48 +00:00
|
|
|
usage: wgpu::TextureUsages::TEXTURE_BINDING
|
|
|
|
| wgpu::TextureUsages::COPY_DST
|
|
|
|
| wgpu::TextureUsages::RENDER_ATTACHMENT
|
|
|
|
| wgpu::TextureUsages::COPY_SRC,
|
2022-05-27 19:16:33 +00:00
|
|
|
});
|
|
|
|
|
|
|
|
self.descriptors.queue.write_texture(
|
|
|
|
wgpu::ImageCopyTexture {
|
|
|
|
texture: &texture,
|
|
|
|
mip_level: 0,
|
|
|
|
origin: Default::default(),
|
|
|
|
aspect: wgpu::TextureAspect::All,
|
|
|
|
},
|
|
|
|
bitmap.data(),
|
|
|
|
wgpu::ImageDataLayout {
|
|
|
|
offset: 0,
|
|
|
|
bytes_per_row: NonZeroU32::new(4 * extent.width),
|
|
|
|
rows_per_image: None,
|
|
|
|
},
|
|
|
|
extent,
|
|
|
|
);
|
|
|
|
|
2022-06-29 22:16:43 +00:00
|
|
|
let handle = self.next_bitmap_handle;
|
|
|
|
self.next_bitmap_handle = BitmapHandle(self.next_bitmap_handle.0 + 1);
|
2022-05-27 19:16:33 +00:00
|
|
|
let width = bitmap.width();
|
|
|
|
let height = bitmap.height();
|
|
|
|
|
|
|
|
// Make bind group for bitmap quad.
|
|
|
|
let texture_view = texture.create_view(&Default::default());
|
|
|
|
let bind_group = self
|
|
|
|
.descriptors
|
|
|
|
.device
|
|
|
|
.create_bind_group(&wgpu::BindGroupDescriptor {
|
2022-09-06 21:38:48 +00:00
|
|
|
layout: &target_data!(self).pipelines.bitmap_layout,
|
2022-05-27 19:16:33 +00:00
|
|
|
entries: &[
|
|
|
|
wgpu::BindGroupEntry {
|
|
|
|
binding: 0,
|
|
|
|
resource: wgpu::BindingResource::Buffer(wgpu::BufferBinding {
|
|
|
|
buffer: &self.quad_tex_transforms,
|
|
|
|
offset: 0,
|
|
|
|
size: wgpu::BufferSize::new(
|
|
|
|
std::mem::size_of::<TextureTransforms>() as u64
|
|
|
|
),
|
|
|
|
}),
|
|
|
|
},
|
|
|
|
wgpu::BindGroupEntry {
|
|
|
|
binding: 1,
|
|
|
|
resource: wgpu::BindingResource::TextureView(&texture_view),
|
|
|
|
},
|
|
|
|
],
|
|
|
|
label: create_debug_label!("Bitmap {} bind group", handle.0).as_deref(),
|
|
|
|
});
|
|
|
|
|
2022-09-06 21:38:48 +00:00
|
|
|
if self
|
|
|
|
.bitmap_registry
|
|
|
|
.insert(
|
|
|
|
handle,
|
|
|
|
RegistryData {
|
|
|
|
bitmap,
|
|
|
|
texture_wrapper: Texture {
|
|
|
|
width,
|
|
|
|
height,
|
|
|
|
texture,
|
|
|
|
bind_group,
|
|
|
|
texture_offscreen: None,
|
|
|
|
},
|
2022-06-29 22:16:43 +00:00
|
|
|
},
|
2022-09-06 21:38:48 +00:00
|
|
|
)
|
|
|
|
.is_some()
|
|
|
|
{
|
|
|
|
panic!("Overwrote existing bitmap {:?}", handle);
|
|
|
|
}
|
2022-05-27 19:16:33 +00:00
|
|
|
|
|
|
|
Ok(handle)
|
2020-12-09 18:38:41 +00:00
|
|
|
}
|
|
|
|
|
2022-08-18 23:40:21 +00:00
|
|
|
fn unregister_bitmap(&mut self, handle: BitmapHandle) {
|
2022-06-29 22:16:43 +00:00
|
|
|
self.bitmap_registry.remove(&handle);
|
|
|
|
}
|
|
|
|
|
2020-12-09 18:38:41 +00:00
|
|
|
fn update_texture(
|
|
|
|
&mut self,
|
|
|
|
handle: BitmapHandle,
|
|
|
|
width: u32,
|
|
|
|
height: u32,
|
|
|
|
rgba: Vec<u8>,
|
2022-08-18 23:34:35 +00:00
|
|
|
) -> Result<BitmapHandle, BitmapError> {
|
2022-06-29 22:16:43 +00:00
|
|
|
let texture = if let Some(entry) = self.bitmap_registry.get(&handle) {
|
|
|
|
&entry.texture_wrapper.texture
|
2020-12-15 02:35:12 +00:00
|
|
|
} else {
|
2022-08-18 23:34:35 +00:00
|
|
|
log::warn!("Tried to replace nonexistent texture");
|
|
|
|
return Ok(handle);
|
2020-12-09 18:38:41 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
let extent = wgpu::Extent3d {
|
|
|
|
width,
|
|
|
|
height,
|
2021-04-16 20:55:31 +00:00
|
|
|
depth_or_array_layers: 1,
|
2020-12-09 18:38:41 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
self.descriptors.queue.write_texture(
|
2021-04-16 20:55:31 +00:00
|
|
|
wgpu::ImageCopyTexture {
|
2021-06-05 10:53:23 +00:00
|
|
|
texture,
|
2020-12-09 18:38:41 +00:00
|
|
|
mip_level: 0,
|
|
|
|
origin: Default::default(),
|
2021-09-08 07:20:11 +00:00
|
|
|
aspect: wgpu::TextureAspect::All,
|
2020-12-09 18:38:41 +00:00
|
|
|
},
|
|
|
|
&rgba,
|
2021-04-16 20:55:31 +00:00
|
|
|
wgpu::ImageDataLayout {
|
2020-12-09 18:38:41 +00:00
|
|
|
offset: 0,
|
2021-04-16 20:55:31 +00:00
|
|
|
bytes_per_row: NonZeroU32::new(4 * extent.width),
|
|
|
|
rows_per_image: None,
|
2020-11-01 21:07:27 +00:00
|
|
|
},
|
2020-12-09 18:38:41 +00:00
|
|
|
extent,
|
|
|
|
);
|
|
|
|
|
|
|
|
Ok(handle)
|
2020-10-19 00:25:23 +00:00
|
|
|
}
|
2020-04-21 13:32:50 +00:00
|
|
|
}
|
|
|
|
|
2022-09-06 21:38:48 +00:00
|
|
|
fn create_depth_texture_view(
|
|
|
|
descriptors: &Descriptors,
|
|
|
|
target_data: &DescriptorsTargetData,
|
|
|
|
extent: wgpu::Extent3d,
|
|
|
|
) -> wgpu::TextureView {
|
|
|
|
let depth_texture = descriptors.device.create_texture(&wgpu::TextureDescriptor {
|
|
|
|
label: create_debug_label!("Depth texture").as_deref(),
|
|
|
|
size: extent,
|
|
|
|
mip_level_count: 1,
|
|
|
|
sample_count: target_data.msaa_sample_count,
|
|
|
|
dimension: wgpu::TextureDimension::D2,
|
|
|
|
format: wgpu::TextureFormat::Depth24PlusStencil8,
|
|
|
|
usage: wgpu::TextureUsages::RENDER_ATTACHMENT,
|
|
|
|
});
|
|
|
|
depth_texture.create_view(&Default::default())
|
|
|
|
}
|
|
|
|
|
2020-04-29 10:06:02 +00:00
|
|
|
fn create_quad_buffers(device: &wgpu::Device) -> (wgpu::Buffer, wgpu::Buffer, wgpu::Buffer) {
|
|
|
|
let vertices = [
|
2021-03-20 14:30:21 +00:00
|
|
|
Vertex {
|
2020-04-29 10:06:02 +00:00
|
|
|
position: [0.0, 0.0],
|
|
|
|
color: [1.0, 1.0, 1.0, 1.0],
|
|
|
|
},
|
2021-03-20 14:30:21 +00:00
|
|
|
Vertex {
|
2020-04-29 10:06:02 +00:00
|
|
|
position: [1.0, 0.0],
|
|
|
|
color: [1.0, 1.0, 1.0, 1.0],
|
|
|
|
},
|
2021-03-20 14:30:21 +00:00
|
|
|
Vertex {
|
2020-04-29 10:06:02 +00:00
|
|
|
position: [1.0, 1.0],
|
|
|
|
color: [1.0, 1.0, 1.0, 1.0],
|
|
|
|
},
|
2021-03-20 14:30:21 +00:00
|
|
|
Vertex {
|
2020-04-29 10:06:02 +00:00
|
|
|
position: [0.0, 1.0],
|
|
|
|
color: [1.0, 1.0, 1.0, 1.0],
|
|
|
|
},
|
|
|
|
];
|
2021-01-04 23:45:40 +00:00
|
|
|
let indices: [u32; 6] = [0, 1, 2, 0, 2, 3];
|
2020-04-29 10:06:02 +00:00
|
|
|
|
|
|
|
let vbo = create_buffer_with_data(
|
|
|
|
device,
|
|
|
|
bytemuck::cast_slice(&vertices),
|
2021-09-08 07:20:11 +00:00
|
|
|
wgpu::BufferUsages::VERTEX,
|
2020-04-29 10:06:02 +00:00
|
|
|
create_debug_label!("Quad vbo"),
|
|
|
|
);
|
|
|
|
|
|
|
|
let ibo = create_buffer_with_data(
|
|
|
|
device,
|
|
|
|
bytemuck::cast_slice(&indices),
|
2021-09-08 07:20:11 +00:00
|
|
|
wgpu::BufferUsages::INDEX,
|
2020-04-29 10:06:02 +00:00
|
|
|
create_debug_label!("Quad ibo"),
|
|
|
|
);
|
|
|
|
|
|
|
|
let tex_transforms = create_buffer_with_data(
|
|
|
|
device,
|
|
|
|
bytemuck::cast_slice(&[TextureTransforms {
|
|
|
|
u_matrix: [
|
|
|
|
[1.0, 0.0, 0.0, 0.0],
|
|
|
|
[0.0, 1.0, 0.0, 0.0],
|
|
|
|
[0.0, 0.0, 1.0, 0.0],
|
|
|
|
[0.0, 0.0, 0.0, 1.0],
|
|
|
|
],
|
|
|
|
}]),
|
2021-09-08 07:20:11 +00:00
|
|
|
wgpu::BufferUsages::UNIFORM,
|
2020-04-29 10:06:02 +00:00
|
|
|
create_debug_label!("Quad tex transforms"),
|
|
|
|
);
|
|
|
|
|
|
|
|
(vbo, ibo, tex_transforms)
|
|
|
|
}
|
|
|
|
|
2020-04-21 13:32:50 +00:00
|
|
|
#[derive(Debug)]
|
|
|
|
struct Texture {
|
|
|
|
width: u32,
|
|
|
|
height: u32,
|
|
|
|
texture: wgpu::Texture,
|
2020-12-26 03:19:42 +00:00
|
|
|
bind_group: wgpu::BindGroup,
|
2022-09-06 21:38:48 +00:00
|
|
|
texture_offscreen: Option<TextureOffscreen>,
|
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Debug)]
|
|
|
|
struct TextureOffscreen {
|
|
|
|
depth_texture_view: wgpu::TextureView,
|
|
|
|
buffer: wgpu::Buffer,
|
|
|
|
buffer_dimensions: BufferDimensions,
|
|
|
|
}
|
|
|
|
|
|
|
|
// Based on https://github.com/Sgeo/take_mut
|
|
|
|
fn take_mut<T, R, F>(mut_ref: &mut T, closure: F) -> R
|
|
|
|
where
|
|
|
|
F: FnOnce(T) -> (T, R),
|
|
|
|
{
|
|
|
|
unsafe {
|
|
|
|
let old_t = std::ptr::read(mut_ref);
|
|
|
|
let (new_t, ret) =
|
|
|
|
std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| closure(old_t)))
|
|
|
|
.unwrap_or_else(|e| {
|
|
|
|
eprintln!("Caught panic: {:?}", e);
|
|
|
|
::std::process::abort()
|
|
|
|
});
|
|
|
|
std::ptr::write(mut_ref, new_t);
|
|
|
|
ret
|
|
|
|
}
|
2020-04-21 13:32:50 +00:00
|
|
|
}
|
2022-08-27 21:39:57 +00:00
|
|
|
|
|
|
|
// We try to request the highest limits we can get away with
|
|
|
|
async fn request_device(
|
|
|
|
adapter: &wgpu::Adapter,
|
|
|
|
trace_path: Option<&Path>,
|
|
|
|
) -> Result<(wgpu::Device, wgpu::Queue), wgpu::RequestDeviceError> {
|
2022-09-03 00:06:30 +00:00
|
|
|
// We start off with the lowest limits we actually need - basically GL-ES 3.0
|
|
|
|
let mut limits = wgpu::Limits::downlevel_webgl2_defaults();
|
|
|
|
// Then we increase parts of it to the maximum supported by the adapter, to take advantage of
|
|
|
|
// more powerful hardware or capabilities
|
|
|
|
limits = limits.using_resolution(adapter.limits());
|
|
|
|
limits = limits.using_alignment(adapter.limits());
|
|
|
|
|
|
|
|
limits.max_storage_buffers_per_shader_stage =
|
|
|
|
adapter.limits().max_storage_buffers_per_shader_stage;
|
|
|
|
limits.max_storage_buffer_binding_size = adapter.limits().max_storage_buffer_binding_size;
|
2022-08-27 21:39:57 +00:00
|
|
|
|
|
|
|
adapter
|
|
|
|
.request_device(
|
|
|
|
&wgpu::DeviceDescriptor {
|
|
|
|
label: None,
|
|
|
|
features: wgpu::Features::empty(),
|
|
|
|
limits,
|
|
|
|
},
|
|
|
|
trace_path,
|
|
|
|
)
|
|
|
|
.await
|
|
|
|
}
|