wgpu: Store quality, not sample_count, and calculate the correct sample count per format

This commit is contained in:
Nathan Adams 2023-02-03 16:44:21 +01:00
parent b95983b492
commit 1cb3ea7bf9
9 changed files with 53 additions and 31 deletions

1
Cargo.lock generated
View File

@ -4241,6 +4241,7 @@ dependencies = [
"regex",
"ruffle_core",
"ruffle_input_format",
"ruffle_render",
"ruffle_render_wgpu",
"serde",
"toml",

View File

@ -114,7 +114,7 @@ fn take_screenshot(
.map_err(|e| anyhow!(e.to_string()))?;
let player = PlayerBuilder::new()
.with_renderer(
WgpuRenderBackend::new(descriptors, target, 4).map_err(|e| anyhow!(e.to_string()))?,
WgpuRenderBackend::new(descriptors, target).map_err(|e| anyhow!(e.to_string()))?,
)
.with_movie(movie)
.with_viewport_dimensions(width, height, size.scale)

View File

@ -47,10 +47,7 @@ pub struct WgpuRenderBackend<T: RenderTarget> {
impl WgpuRenderBackend<SwapChainTarget> {
#[cfg(target_family = "wasm")]
pub async fn for_canvas(
canvas: &web_sys::HtmlCanvasElement,
sample_count: u32,
) -> Result<Self, Error> {
pub async fn for_canvas(canvas: &web_sys::HtmlCanvasElement) -> Result<Self, Error> {
let instance = wgpu::Instance::new(wgpu::InstanceDescriptor {
backends: wgpu::Backends::BROWSER_WEBGPU | wgpu::Backends::GL,
dx12_shader_compiler: wgpu::Dx12Compiler::default(),
@ -67,7 +64,7 @@ impl WgpuRenderBackend<SwapChainTarget> {
let descriptors = Descriptors::new(adapter, device, queue);
let target =
SwapChainTarget::new(surface, &descriptors.adapter, (1, 1), &descriptors.device);
Self::new(Arc::new(descriptors), target, sample_count)
Self::new(Arc::new(descriptors), target)
}
#[cfg(not(target_family = "wasm"))]
@ -100,7 +97,7 @@ impl WgpuRenderBackend<SwapChainTarget> {
))?;
let descriptors = Descriptors::new(adapter, device, queue);
let target = SwapChainTarget::new(surface, &descriptors.adapter, size, &descriptors.device);
Self::new(Arc::new(descriptors), target, 4)
Self::new(Arc::new(descriptors), target)
}
}
@ -131,7 +128,7 @@ impl WgpuRenderBackend<crate::target::TextureTarget> {
))?;
let descriptors = Descriptors::new(adapter, device, queue);
let target = crate::target::TextureTarget::new(&descriptors.device, size)?;
Self::new(Arc::new(descriptors), target, 4)
Self::new(Arc::new(descriptors), target)
}
pub fn capture_frame(&self, premultiplied_alpha: bool) -> Option<image::RgbaImage> {
@ -152,11 +149,7 @@ impl WgpuRenderBackend<crate::target::TextureTarget> {
}
impl<T: RenderTarget> WgpuRenderBackend<T> {
pub fn new(
descriptors: Arc<Descriptors>,
target: T,
preferred_sample_count: u32,
) -> Result<Self, Error> {
pub fn new(descriptors: Arc<Descriptors>, target: T) -> Result<Self, Error> {
if target.width() > descriptors.limits.max_texture_dimension_2d
|| target.height() > descriptors.limits.max_texture_dimension_2d
{
@ -171,7 +164,7 @@ impl<T: RenderTarget> WgpuRenderBackend<T> {
let surface = Surface::new(
&descriptors,
preferred_sample_count,
StageQuality::Low,
target.width(),
target.height(),
target.format(),
@ -319,7 +312,7 @@ impl<T: RenderTarget + 'static> RenderBackend for WgpuRenderBackend<T> {
self.surface = Surface::new(
&self.descriptors,
self.surface.sample_count(),
self.surface.quality(),
width,
height,
self.target.format(),
@ -400,6 +393,7 @@ impl<T: RenderTarget + 'static> RenderBackend for WgpuRenderBackend<T> {
result.push(format!("Enabled features: {enabled_features:?}"));
result.push(format!("Available features: {available_features:?}"));
result.push(format!("Current limits: {current_limits:?}"));
result.push(format!("Surface quality: {}", self.surface.quality()));
result.push(format!("Surface samples: {}", self.surface.sample_count()));
result.push(format!("Surface size: {:?}", self.surface.size()));
@ -409,7 +403,7 @@ impl<T: RenderTarget + 'static> RenderBackend for WgpuRenderBackend<T> {
fn set_quality(&mut self, quality: StageQuality) {
self.surface = Surface::new(
&self.descriptors,
quality.sample_count(),
quality,
self.surface.size().width,
self.surface.size().height,
self.target.format(),
@ -630,7 +624,7 @@ impl<T: RenderTarget + 'static> RenderBackend for WgpuRenderBackend<T> {
let mut surface = Surface::new(
&self.descriptors,
self.surface.sample_count(),
self.surface.quality(),
width,
height,
wgpu::TextureFormat::Rgba8Unorm,
@ -701,7 +695,7 @@ impl<T: RenderTarget + 'static> RenderBackend for WgpuRenderBackend<T> {
.expect("TextureTargetFrame.get_next_texture is infallible");
let surface = Surface::new(
&self.descriptors,
self.preferred_sample_count,
self.surface.quality(),
dest_texture.width,
dest_texture.height,
wgpu::TextureFormat::Rgba8Unorm,

View File

@ -6,13 +6,14 @@ use crate::buffer_pool::TexturePool;
use crate::mesh::Mesh;
use crate::surface::commands::{chunk_blends, Chunk, CommandRenderer};
use crate::uniform_buffer::BufferStorage;
use crate::utils::remove_srgb;
use crate::utils::{remove_srgb, supported_sample_count};
use crate::{
ColorAdjustments, Descriptors, MaskState, Pipelines, PushConstants, Texture, TextureTransforms,
Transforms, UniformBuffer, DEFAULT_COLOR_ADJUSTMENTS,
};
use ruffle_render::commands::CommandList;
use ruffle_render::filters::{BlurFilter, ColorMatrixFilter, Filter};
use ruffle_render::quality::StageQuality;
use std::sync::Arc;
use target::CommandTarget;
use tracing::instrument;
@ -21,6 +22,7 @@ use wgpu::util::DeviceExt;
#[derive(Debug)]
pub struct Surface {
size: wgpu::Extent3d,
quality: StageQuality,
sample_count: u32,
pipelines: Arc<Pipelines>,
format: wgpu::TextureFormat,
@ -30,7 +32,7 @@ pub struct Surface {
impl Surface {
pub fn new(
descriptors: &Descriptors,
sample_count: u32,
quality: StageQuality,
width: u32,
height: u32,
surface_format: wgpu::TextureFormat,
@ -42,9 +44,11 @@ impl Surface {
};
let frame_buffer_format = remove_srgb(surface_format);
let sample_count = supported_sample_count(quality, frame_buffer_format);
let pipelines = descriptors.pipelines(sample_count, frame_buffer_format);
Self {
size,
quality,
sample_count,
pipelines,
format: frame_buffer_format,
@ -219,7 +223,7 @@ impl Surface {
uniform_encoder,
draw_encoder,
meshes,
target.sample_count(),
self.quality,
target.width(),
target.height(),
nearest_layer.unwrap_or(&target),
@ -395,6 +399,10 @@ impl Surface {
target
}
pub fn quality(&self) -> StageQuality {
self.quality
}
pub fn sample_count(&self) -> u32 {
self.sample_count
}

View File

@ -13,6 +13,7 @@ use ruffle_render::bitmap::BitmapHandle;
use ruffle_render::color_transform::ColorTransform;
use ruffle_render::commands::Command;
use ruffle_render::matrix::Matrix;
use ruffle_render::quality::StageQuality;
use ruffle_render::tessellator::GradientType;
use ruffle_render::transform::Transform;
use swf::{BlendMode, Color, Fixed8, GradientSpread};
@ -449,7 +450,7 @@ pub fn chunk_blends<'a>(
uniform_encoder: &mut wgpu::CommandEncoder,
draw_encoder: &mut wgpu::CommandEncoder,
meshes: &'a Vec<Mesh>,
sample_count: u32,
quality: StageQuality,
width: u32,
height: u32,
nearest_layer: &CommandTarget,
@ -465,7 +466,7 @@ pub fn chunk_blends<'a>(
Command::Blend(commands, blend_mode) => {
let mut surface = Surface::new(
&descriptors,
sample_count,
quality,
width,
height,
wgpu::TextureFormat::Rgba8Unorm,

View File

@ -206,10 +206,6 @@ impl CommandTarget {
self.size.height
}
pub fn sample_count(&self) -> u32 {
self.sample_count
}
pub fn ensure_cleared(&self, encoder: &mut wgpu::CommandEncoder) {
if self.color_needs_clear.get().is_some() {
return;

View File

@ -1,3 +1,4 @@
use ruffle_render::quality::StageQuality;
use ruffle_render::utils::unmultiply_alpha_rgba;
use std::borrow::Cow;
use std::mem::size_of;
@ -155,3 +156,16 @@ pub fn buffer_to_image(
buffer.unmap();
image
}
pub fn supported_sample_count(quality: StageQuality, format: wgpu::TextureFormat) -> u32 {
let mut sample_count = quality.sample_count();
let features = format.describe().guaranteed_format_features.flags;
// Keep halving the sample count until we get one that's supported - or 1 (no multisampling)
// It's not guaranteed that supporting 4x means supporting 2x, so there's no "max" option
// And it's probably safer to round down than up, given it's a performance setting.
while sample_count > 1 && !features.sample_count_supported(sample_count) {
sample_count /= 2;
}
sample_count
}

View File

@ -11,6 +11,7 @@ version.workspace = true
futures = "0.3.25"
ruffle_core = { path = "../core", features = ["deterministic", "timeline_debug", "avm_debug"] }
ruffle_render_wgpu = { path = "../render/wgpu" }
ruffle_render = { path = "../render" }
ruffle_input_format = { path = "input-format" }
image = { version = "0.24.5", default-features = false, features = ["png"] }
regex = "1.7.1"

View File

@ -4,6 +4,8 @@ use approx::assert_relative_eq;
use regex::Regex;
use ruffle_core::tag_utils::SwfMovie;
use ruffle_core::{PlayerBuilder, ViewportDimensions};
use ruffle_render::backend::RenderBackend;
use ruffle_render::quality::StageQuality;
use serde::Deserialize;
use std::fs;
use std::path::{Path, PathBuf};
@ -118,10 +120,15 @@ impl PlayerOptions {
let target = TextureTarget::new(&descriptors.device, (width, height))
.map_err(|e| anyhow!(e.to_string()))?;
player_builder = player_builder.with_renderer(
WgpuRenderBackend::new(descriptors, target, render_options.sample_count)
.map_err(|e| anyhow!(e.to_string()))?,
);
let mut backend = WgpuRenderBackend::new(descriptors, target)
.map_err(|e| anyhow!(e.to_string()))?;
backend.set_quality(match render_options.sample_count {
8 => StageQuality::High,
4 => StageQuality::High,
2 => StageQuality::Medium,
_ => StageQuality::Low,
});
player_builder = player_builder.with_renderer(backend);
}
}