From 5fbd6954efbfe3dd95fcd496cd25664c092947fc Mon Sep 17 00:00:00 2001 From: Fernando Sahmkow Date: Sun, 6 Nov 2022 11:08:22 +0100 Subject: Fermi2D: Implement Bilinear software filtering and address feedback. --- src/video_core/engines/fermi_2d.cpp | 11 +- src/video_core/engines/sw_blitter/blitter.cpp | 97 +++++++++----- src/video_core/engines/sw_blitter/blitter.h | 2 +- src/video_core/engines/sw_blitter/converter.cpp | 171 ++++++++++++++---------- src/video_core/engines/sw_blitter/converter.h | 9 +- src/video_core/gpu.h | 4 +- src/video_core/surface.cpp | 2 + 7 files changed, 180 insertions(+), 116 deletions(-) diff --git a/src/video_core/engines/fermi_2d.cpp b/src/video_core/engines/fermi_2d.cpp index 2c722c778..c6478ae85 100644 --- a/src/video_core/engines/fermi_2d.cpp +++ b/src/video_core/engines/fermi_2d.cpp @@ -62,11 +62,15 @@ void Fermi2D::Blit() { const auto& args = regs.pixels_from_memory; constexpr s64 null_derivate = 1ULL << 32; + Surface src = regs.src; + const auto bytes_per_pixel = BytesPerBlock(PixelFormatFromRenderTargetFormat(src.format)); + const bool delegate_to_gpu = src.width > 512 && src.height > 512 && bytes_per_pixel <= 8 && + src.format != regs.dst.format; Config config{ .operation = regs.operation, .filter = args.sample_mode.filter, - .must_accelerate = args.du_dx != null_derivate || args.dv_dy != null_derivate || - args.sample_mode.filter == Filter::Bilinear, + .must_accelerate = + args.du_dx != null_derivate || args.dv_dy != null_derivate || delegate_to_gpu, .dst_x0 = args.dst_x0, .dst_y0 = args.dst_y0, .dst_x1 = args.dst_x0 + args.dst_width, @@ -76,8 +80,7 @@ void Fermi2D::Blit() { .src_x1 = static_cast((args.du_dx * args.dst_width + args.src_x0) >> 32), .src_y1 = static_cast((args.dv_dy * args.dst_height + args.src_y0) >> 32), }; - Surface src = regs.src; - const auto bytes_per_pixel = BytesPerBlock(PixelFormatFromRenderTargetFormat(src.format)); + const auto need_align_to_pitch = src.linear == Tegra::Engines::Fermi2D::MemoryLayout::Pitch && static_cast(src.width) == config.src_x1 && diff --git a/src/video_core/engines/sw_blitter/blitter.cpp b/src/video_core/engines/sw_blitter/blitter.cpp index caf51cbe3..c923a80e9 100644 --- a/src/video_core/engines/sw_blitter/blitter.cpp +++ b/src/video_core/engines/sw_blitter/blitter.cpp @@ -1,6 +1,8 @@ // SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project // SPDX-License-Identifier: GPL-3.0-or-later +#include +#include #include #include "video_core/engines/sw_blitter/blitter.h" @@ -22,8 +24,10 @@ using namespace Texture; namespace { -void NeighrestNeighbor(std::span input, std::span output, u32 src_width, u32 src_height, - u32 dst_width, u32 dst_height, size_t bpp) { +constexpr size_t ir_components = 4; + +void NeighrestNeighbor(std::span input, std::span output, u32 src_width, + u32 src_height, u32 dst_width, u32 dst_height, size_t bpp) { const size_t dx_du = std::llround((static_cast(src_width) / dst_width) * (1ULL << 32)); const size_t dy_dv = std::llround((static_cast(src_height) / dst_height) * (1ULL << 32)); size_t src_y = 0; @@ -40,7 +44,7 @@ void NeighrestNeighbor(std::span input, std::span output, u32 src_width, } } -void NeighrestNeighborFast(std::span input, std::span output, u32 src_width, +void NeighrestNeighborFast(std::span input, std::span output, u32 src_width, u32 src_height, u32 dst_width, u32 dst_height) { const size_t dx_du = std::llround((static_cast(src_width) / dst_width) * (1ULL << 32)); const size_t dy_dv = std::llround((static_cast(src_height) / dst_height) * (1ULL << 32)); @@ -48,44 +52,62 @@ void NeighrestNeighborFast(std::span input, std::span output, u32 src_ for (u32 y = 0; y < dst_height; y++) { size_t src_x = 0; for (u32 x = 0; x < dst_width; x++) { - const size_t read_from = ((src_y * src_width + src_x) >> 32) * 4; - const size_t write_to = (y * dst_width + x) * 4; + const size_t read_from = ((src_y * src_width + src_x) >> 32) * ir_components; + const size_t write_to = (y * dst_width + x) * ir_components; - std::memcpy(&output[write_to], &input[read_from], sizeof(f32) * 4); + std::memcpy(&output[write_to], &input[read_from], sizeof(f32) * ir_components); src_x += dx_du; } src_y += dy_dv; } } -/* -void Bilinear(std::span input, std::span output, size_t src_width, - size_t src_height, size_t dst_width, size_t dst_height) { - const auto inv_lerp = [](u32 coord, u32 end) { return -static_cast(std::min(std::max(static_cast(coord), 0), end - 1)) / (end); }; - - +void Bilinear(std::span input, std::span output, size_t src_width, + size_t src_height, size_t dst_width, size_t dst_height) { + const auto bilinear_sample = [](std::span x0_y0, std::span x1_y0, + std::span x0_y1, std::span x1_y1, + f32 weight_x, f32 weight_y) { + std::array result{}; + for (size_t i = 0; i < ir_components; i++) { + const f32 a = std::lerp(x0_y0[i], x1_y0[i], weight_x); + const f32 b = std::lerp(x0_y1[i], x1_y1[i], weight_x); + result[i] = std::lerp(a, b, weight_y); + } + return result; + }; + const f32 dx_du = + dst_width > 1 ? static_cast(src_width - 1) / static_cast(dst_width - 1) : 0.f; + const f32 dy_dv = + dst_height > 1 ? static_cast(src_height - 1) / static_cast(dst_height - 1) : 0.f; for (u32 y = 0; y < dst_height; y++) { - const f32 ty_0 = inv_lerp(y, dst_extent_y); - const f32 ty_1 = inv_lerp(y + 1, dst_extent_y); for (u32 x = 0; x < dst_width; x++) { - const f32 tx_0 = inv_lerp(x, dst_extent_x); - const f32 tx_1 = inv_lerp(x + 1, dst_extent_x); - const std::array get_pixel = [&](f32 tx, f32 ty, u32 width, u32 height) { - std::array result{}; - - return (std::llround(width * tx) + std::llround(height * ty) * width) * 4; + const f32 x_low = std::floor(static_cast(x) * dx_du); + const f32 y_low = std::floor(static_cast(y) * dy_dv); + const f32 x_high = std::ceil(static_cast(x) * dx_du); + const f32 y_high = std::ceil(static_cast(y) * dy_dv); + const f32 weight_x = (static_cast(x) * dx_du) - x_low; + const f32 weight_y = (static_cast(y) * dy_dv) - y_low; + + const auto read_src = [&](f32 in_x, f32 in_y) { + const size_t read_from = + ((static_cast(in_x) * src_width + static_cast(in_y)) >> 32) * + ir_components; + return std::span(&input[read_from], ir_components); }; - std::array result{}; - const size_t read_from = get_pixel(src_width, src_height); - const size_t write_to = get_pixel(tx_0, ty_0, dst_width, dst_height); + auto x0_y0 = read_src(x_low, y_low); + auto x1_y0 = read_src(x_high, y_low); + auto x0_y1 = read_src(x_low, y_high); + auto x1_y1 = read_src(x_high, y_high); - std::memcpy(&output[write_to], &input[read_from], bpp); + const auto result = bilinear_sample(x0_y0, x1_y0, x0_y1, x1_y1, weight_x, weight_y); + + const size_t write_to = (y * dst_width + x) * ir_components; + + std::memcpy(&output[write_to], &result, sizeof(f32) * ir_components); } } } -*/ } // namespace @@ -107,8 +129,6 @@ SoftwareBlitEngine::~SoftwareBlitEngine() = default; bool SoftwareBlitEngine::Blit(Fermi2D::Surface& src, Fermi2D::Surface& dst, Fermi2D::Config& config) { - UNIMPLEMENTED_IF(config.filter == Fermi2D::Filter::Bilinear); - const auto get_surface_size = [](Fermi2D::Surface& surface, u32 bytes_per_pixel) { if (surface.linear == Fermi2D::MemoryLayout::BlockLinear) { return CalculateSize(true, bytes_per_pixel, surface.width, surface.height, @@ -116,9 +136,9 @@ bool SoftwareBlitEngine::Blit(Fermi2D::Surface& src, Fermi2D::Surface& dst, } return static_cast(surface.pitch * surface.height); }; - const auto process_pitch_linear = [](bool unpack, std::span input, std::span output, - u32 extent_x, u32 extent_y, u32 pitch, u32 x0, u32 y0, - size_t bpp) { + const auto process_pitch_linear = [](bool unpack, std::span input, + std::span output, u32 extent_x, u32 extent_y, + u32 pitch, u32 x0, u32 y0, size_t bpp) { const size_t base_offset = x0 * bpp; const size_t copy_size = extent_x * bpp; for (u32 y = y0; y < extent_y; y++) { @@ -157,12 +177,17 @@ bool SoftwareBlitEngine::Blit(Fermi2D::Surface& src, Fermi2D::Surface& dst, const auto convertion_phase_ir = [&]() { auto* input_converter = impl->converter_factory.GetFormatConverter(src.format); - impl->intermediate_src.resize((src_copy_size / src_bytes_per_pixel) * 4); - impl->intermediate_dst.resize((dst_copy_size / dst_bytes_per_pixel) * 4); + impl->intermediate_src.resize((src_copy_size / src_bytes_per_pixel) * ir_components); + impl->intermediate_dst.resize((dst_copy_size / dst_bytes_per_pixel) * ir_components); input_converter->ConvertTo(impl->src_buffer, impl->intermediate_src); - NeighrestNeighborFast(impl->intermediate_src, impl->intermediate_dst, src_extent_x, - src_extent_y, dst_extent_x, dst_extent_y); + if (config.filter != Fermi2D::Filter::Bilinear) { + NeighrestNeighborFast(impl->intermediate_src, impl->intermediate_dst, src_extent_x, + src_extent_y, dst_extent_x, dst_extent_y); + } else { + Bilinear(impl->intermediate_src, impl->intermediate_dst, src_extent_x, src_extent_y, + dst_extent_x, dst_extent_y); + } auto* output_converter = impl->converter_factory.GetFormatConverter(dst.format); output_converter->ConvertFrom(impl->intermediate_dst, impl->dst_buffer); @@ -183,7 +208,7 @@ bool SoftwareBlitEngine::Blit(Fermi2D::Surface& src, Fermi2D::Surface& dst, // Conversion Phase if (no_passthrough) { - if (src.format != dst.format) { + if (src.format != dst.format || config.filter == Fermi2D::Filter::Bilinear) { convertion_phase_ir(); } else { convertion_phase_same_format(); diff --git a/src/video_core/engines/sw_blitter/blitter.h b/src/video_core/engines/sw_blitter/blitter.h index 3edf40c3e..85b55c836 100644 --- a/src/video_core/engines/sw_blitter/blitter.h +++ b/src/video_core/engines/sw_blitter/blitter.h @@ -13,7 +13,7 @@ namespace Tegra::Engines::Blitter { class SoftwareBlitEngine { public: - SoftwareBlitEngine(MemoryManager& memory_manager_); + explicit SoftwareBlitEngine(MemoryManager& memory_manager_); ~SoftwareBlitEngine(); bool Blit(Fermi2D::Surface& src, Fermi2D::Surface& dst, Fermi2D::Config& copy_config); diff --git a/src/video_core/engines/sw_blitter/converter.cpp b/src/video_core/engines/sw_blitter/converter.cpp index 2e376f430..408d87944 100644 --- a/src/video_core/engines/sw_blitter/converter.cpp +++ b/src/video_core/engines/sw_blitter/converter.cpp @@ -139,7 +139,7 @@ struct R32B32G32A32_FLOATTraits { ComponentType::FLOAT, ComponentType::FLOAT, ComponentType::FLOAT, ComponentType::FLOAT}; static constexpr std::array component_sizes = {32, 32, 32, 32}; static constexpr std::array component_swizzle = { - Swizzle::A, Swizzle::G, Swizzle::B, Swizzle::R}; + Swizzle::R, Swizzle::B, Swizzle::G, Swizzle::A}; }; struct R32G32B32A32_SINTTraits { @@ -148,7 +148,7 @@ struct R32G32B32A32_SINTTraits { ComponentType::SINT, ComponentType::SINT, ComponentType::SINT, ComponentType::SINT}; static constexpr std::array component_sizes = {32, 32, 32, 32}; static constexpr std::array component_swizzle = { - Swizzle::A, Swizzle::B, Swizzle::G, Swizzle::R}; + Swizzle::R, Swizzle::G, Swizzle::B, Swizzle::A}; }; struct R32G32B32A32_UINTTraits { @@ -157,7 +157,7 @@ struct R32G32B32A32_UINTTraits { ComponentType::UINT, ComponentType::UINT, ComponentType::UINT, ComponentType::UINT}; static constexpr std::array component_sizes = {32, 32, 32, 32}; static constexpr std::array component_swizzle = { - Swizzle::A, Swizzle::B, Swizzle::G, Swizzle::R}; + Swizzle::R, Swizzle::G, Swizzle::B, Swizzle::A}; }; struct R16G16B16A16_UNORMTraits { @@ -166,7 +166,7 @@ struct R16G16B16A16_UNORMTraits { ComponentType::UNORM, ComponentType::UNORM, ComponentType::UNORM, ComponentType::UNORM}; static constexpr std::array component_sizes = {16, 16, 16, 16}; static constexpr std::array component_swizzle = { - Swizzle::A, Swizzle::B, Swizzle::G, Swizzle::R}; + Swizzle::R, Swizzle::G, Swizzle::B, Swizzle::A}; }; struct R16G16B16A16_SNORMTraits { @@ -175,7 +175,7 @@ struct R16G16B16A16_SNORMTraits { ComponentType::SNORM, ComponentType::SNORM, ComponentType::SNORM, ComponentType::SNORM}; static constexpr std::array component_sizes = {16, 16, 16, 16}; static constexpr std::array component_swizzle = { - Swizzle::A, Swizzle::B, Swizzle::G, Swizzle::R}; + Swizzle::R, Swizzle::G, Swizzle::B, Swizzle::A}; }; struct R16G16B16A16_SINTTraits { @@ -184,7 +184,7 @@ struct R16G16B16A16_SINTTraits { ComponentType::SINT, ComponentType::SINT, ComponentType::SINT, ComponentType::SINT}; static constexpr std::array component_sizes = {16, 16, 16, 16}; static constexpr std::array component_swizzle = { - Swizzle::A, Swizzle::B, Swizzle::G, Swizzle::R}; + Swizzle::R, Swizzle::G, Swizzle::B, Swizzle::A}; }; struct R16G16B16A16_UINTTraits { @@ -193,7 +193,7 @@ struct R16G16B16A16_UINTTraits { ComponentType::UINT, ComponentType::UINT, ComponentType::UINT, ComponentType::UINT}; static constexpr std::array component_sizes = {16, 16, 16, 16}; static constexpr std::array component_swizzle = { - Swizzle::A, Swizzle::B, Swizzle::G, Swizzle::R}; + Swizzle::R, Swizzle::G, Swizzle::B, Swizzle::A}; }; struct R16G16B16A16_FLOATTraits { @@ -202,7 +202,7 @@ struct R16G16B16A16_FLOATTraits { ComponentType::FLOAT, ComponentType::FLOAT, ComponentType::FLOAT, ComponentType::FLOAT}; static constexpr std::array component_sizes = {16, 16, 16, 16}; static constexpr std::array component_swizzle = { - Swizzle::A, Swizzle::B, Swizzle::G, Swizzle::R}; + Swizzle::R, Swizzle::G, Swizzle::B, Swizzle::A}; }; struct R32G32_FLOATTraits { @@ -210,8 +210,8 @@ struct R32G32_FLOATTraits { static constexpr std::array component_types = { ComponentType::FLOAT, ComponentType::FLOAT}; static constexpr std::array component_sizes = {32, 32}; - static constexpr std::array component_swizzle = {Swizzle::G, - Swizzle::R}; + static constexpr std::array component_swizzle = {Swizzle::R, + Swizzle::G}; }; struct R32G32_SINTTraits { @@ -219,8 +219,8 @@ struct R32G32_SINTTraits { static constexpr std::array component_types = { ComponentType::SINT, ComponentType::SINT}; static constexpr std::array component_sizes = {32, 32}; - static constexpr std::array component_swizzle = {Swizzle::G, - Swizzle::R}; + static constexpr std::array component_swizzle = {Swizzle::R, + Swizzle::G}; }; struct R32G32_UINTTraits { @@ -228,8 +228,8 @@ struct R32G32_UINTTraits { static constexpr std::array component_types = { ComponentType::UINT, ComponentType::UINT}; static constexpr std::array component_sizes = {32, 32}; - static constexpr std::array component_swizzle = {Swizzle::G, - Swizzle::R}; + static constexpr std::array component_swizzle = {Swizzle::R, + Swizzle::G}; }; struct R16G16B16X16_FLOATTraits { @@ -238,7 +238,7 @@ struct R16G16B16X16_FLOATTraits { ComponentType::FLOAT, ComponentType::FLOAT, ComponentType::FLOAT, ComponentType::FLOAT}; static constexpr std::array component_sizes = {16, 16, 16, 16}; static constexpr std::array component_swizzle = { - Swizzle::None, Swizzle::B, Swizzle::G, Swizzle::R}; + Swizzle::R, Swizzle::G, Swizzle::B, Swizzle::None}; }; struct A8R8G8B8_UNORMTraits { @@ -247,7 +247,7 @@ struct A8R8G8B8_UNORMTraits { ComponentType::UNORM, ComponentType::UNORM, ComponentType::UNORM, ComponentType::UNORM}; static constexpr std::array component_sizes = {8, 8, 8, 8}; static constexpr std::array component_swizzle = { - Swizzle::B, Swizzle::G, Swizzle::R, Swizzle::A}; + Swizzle::A, Swizzle::R, Swizzle::G, Swizzle::B}; }; struct A8R8G8B8_SRGBTraits { @@ -256,25 +256,25 @@ struct A8R8G8B8_SRGBTraits { ComponentType::SRGB, ComponentType::SRGB, ComponentType::SRGB, ComponentType::SRGB}; static constexpr std::array component_sizes = {8, 8, 8, 8}; static constexpr std::array component_swizzle = { - Swizzle::B, Swizzle::G, Swizzle::R, Swizzle::A}; + Swizzle::A, Swizzle::R, Swizzle::G, Swizzle::B}; }; struct A2B10G10R10_UNORMTraits { static constexpr size_t num_components = 4; static constexpr std::array component_types = { ComponentType::UNORM, ComponentType::UNORM, ComponentType::UNORM, ComponentType::UNORM}; - static constexpr std::array component_sizes = {10, 10, 10, 2}; + static constexpr std::array component_sizes = {2, 10, 10, 10}; static constexpr std::array component_swizzle = { - Swizzle::R, Swizzle::G, Swizzle::B, Swizzle::A}; + Swizzle::A, Swizzle::B, Swizzle::G, Swizzle::R}; }; struct A2B10G10R10_UINTTraits { static constexpr size_t num_components = 4; static constexpr std::array component_types = { ComponentType::UINT, ComponentType::UINT, ComponentType::UINT, ComponentType::UINT}; - static constexpr std::array component_sizes = {10, 10, 10, 2}; + static constexpr std::array component_sizes = {2, 10, 10, 10}; static constexpr std::array component_swizzle = { - Swizzle::R, Swizzle::G, Swizzle::B, Swizzle::A}; + Swizzle::A, Swizzle::B, Swizzle::G, Swizzle::R}; }; struct A8B8G8R8_UNORMTraits { @@ -283,7 +283,7 @@ struct A8B8G8R8_UNORMTraits { ComponentType::UNORM, ComponentType::UNORM, ComponentType::UNORM, ComponentType::UNORM}; static constexpr std::array component_sizes = {8, 8, 8, 8}; static constexpr std::array component_swizzle = { - Swizzle::R, Swizzle::G, Swizzle::B, Swizzle::A}; + Swizzle::A, Swizzle::B, Swizzle::G, Swizzle::R}; }; struct A8B8G8R8_SRGBTraits { @@ -292,7 +292,7 @@ struct A8B8G8R8_SRGBTraits { ComponentType::SRGB, ComponentType::SRGB, ComponentType::SRGB, ComponentType::SRGB}; static constexpr std::array component_sizes = {8, 8, 8, 8}; static constexpr std::array component_swizzle = { - Swizzle::R, Swizzle::G, Swizzle::B, Swizzle::A}; + Swizzle::A, Swizzle::B, Swizzle::G, Swizzle::R}; }; struct A8B8G8R8_SNORMTraits { @@ -301,7 +301,7 @@ struct A8B8G8R8_SNORMTraits { ComponentType::SNORM, ComponentType::SNORM, ComponentType::SNORM, ComponentType::SNORM}; static constexpr std::array component_sizes = {8, 8, 8, 8}; static constexpr std::array component_swizzle = { - Swizzle::R, Swizzle::G, Swizzle::B, Swizzle::A}; + Swizzle::A, Swizzle::B, Swizzle::G, Swizzle::R}; }; struct A8B8G8R8_SINTTraits { @@ -310,7 +310,7 @@ struct A8B8G8R8_SINTTraits { ComponentType::SINT, ComponentType::SINT, ComponentType::SINT, ComponentType::SINT}; static constexpr std::array component_sizes = {8, 8, 8, 8}; static constexpr std::array component_swizzle = { - Swizzle::R, Swizzle::G, Swizzle::B, Swizzle::A}; + Swizzle::A, Swizzle::B, Swizzle::G, Swizzle::R}; }; struct A8B8G8R8_UINTTraits { @@ -319,7 +319,7 @@ struct A8B8G8R8_UINTTraits { ComponentType::UINT, ComponentType::UINT, ComponentType::UINT, ComponentType::UINT}; static constexpr std::array component_sizes = {8, 8, 8, 8}; static constexpr std::array component_swizzle = { - Swizzle::R, Swizzle::G, Swizzle::B, Swizzle::A}; + Swizzle::A, Swizzle::B, Swizzle::G, Swizzle::R}; }; struct R16G16_UNORMTraits { @@ -327,8 +327,8 @@ struct R16G16_UNORMTraits { static constexpr std::array component_types = { ComponentType::UNORM, ComponentType::UNORM}; static constexpr std::array component_sizes = {16, 16}; - static constexpr std::array component_swizzle = {Swizzle::G, - Swizzle::R}; + static constexpr std::array component_swizzle = {Swizzle::R, + Swizzle::G}; }; struct R16G16_SNORMTraits { @@ -336,8 +336,8 @@ struct R16G16_SNORMTraits { static constexpr std::array component_types = { ComponentType::SNORM, ComponentType::SNORM}; static constexpr std::array component_sizes = {16, 16}; - static constexpr std::array component_swizzle = {Swizzle::G, - Swizzle::R}; + static constexpr std::array component_swizzle = {Swizzle::R, + Swizzle::G}; }; struct R16G16_SINTTraits { @@ -345,8 +345,8 @@ struct R16G16_SINTTraits { static constexpr std::array component_types = { ComponentType::SINT, ComponentType::SINT}; static constexpr std::array component_sizes = {16, 16}; - static constexpr std::array component_swizzle = {Swizzle::G, - Swizzle::R}; + static constexpr std::array component_swizzle = {Swizzle::R, + Swizzle::G}; }; struct R16G16_UINTTraits { @@ -354,8 +354,8 @@ struct R16G16_UINTTraits { static constexpr std::array component_types = { ComponentType::UINT, ComponentType::UINT}; static constexpr std::array component_sizes = {16, 16}; - static constexpr std::array component_swizzle = {Swizzle::G, - Swizzle::R}; + static constexpr std::array component_swizzle = {Swizzle::R, + Swizzle::G}; }; struct R16G16_FLOATTraits { @@ -363,17 +363,17 @@ struct R16G16_FLOATTraits { static constexpr std::array component_types = { ComponentType::FLOAT, ComponentType::FLOAT}; static constexpr std::array component_sizes = {16, 16}; - static constexpr std::array component_swizzle = {Swizzle::G, - Swizzle::R}; + static constexpr std::array component_swizzle = {Swizzle::R, + Swizzle::G}; }; struct B10G11R11_FLOATTraits { static constexpr size_t num_components = 3; static constexpr std::array component_types = { ComponentType::FLOAT, ComponentType::FLOAT, ComponentType::FLOAT}; - static constexpr std::array component_sizes = {11, 11, 10}; + static constexpr std::array component_sizes = {10, 11, 11}; static constexpr std::array component_swizzle = { - Swizzle::R, Swizzle::G, Swizzle::B}; + Swizzle::B, Swizzle::G, Swizzle::R}; }; struct R32_SINTTraits { @@ -400,22 +400,40 @@ struct R32_FLOATTraits { static constexpr std::array component_swizzle = {Swizzle::R}; }; +struct X8R8G8B8_UNORMTraits { + static constexpr size_t num_components = 4; + static constexpr std::array component_types = { + ComponentType::UNORM, ComponentType::UNORM, ComponentType::UNORM, ComponentType::UNORM}; + static constexpr std::array component_sizes = {8, 8, 8, 8}; + static constexpr std::array component_swizzle = { + Swizzle::None, Swizzle::R, Swizzle::G, Swizzle::B}; +}; + +struct X8R8G8B8_SRGBTraits { + static constexpr size_t num_components = 4; + static constexpr std::array component_types = { + ComponentType::SRGB, ComponentType::SRGB, ComponentType::SRGB, ComponentType::SRGB}; + static constexpr std::array component_sizes = {8, 8, 8, 8}; + static constexpr std::array component_swizzle = { + Swizzle::None, Swizzle::R, Swizzle::G, Swizzle::B}; +}; + struct R5G6B5_UNORMTraits { static constexpr size_t num_components = 3; static constexpr std::array component_types = { ComponentType::UNORM, ComponentType::UNORM, ComponentType::UNORM}; static constexpr std::array component_sizes = {5, 6, 5}; static constexpr std::array component_swizzle = { - Swizzle::B, Swizzle::G, Swizzle::R}; + Swizzle::R, Swizzle::G, Swizzle::B}; }; struct A1R5G5B5_UNORMTraits { static constexpr size_t num_components = 4; static constexpr std::array component_types = { ComponentType::UNORM, ComponentType::UNORM, ComponentType::UNORM, ComponentType::UNORM}; - static constexpr std::array component_sizes = {5, 5, 5, 1}; + static constexpr std::array component_sizes = {1, 5, 5, 5}; static constexpr std::array component_swizzle = { - Swizzle::B, Swizzle::G, Swizzle::R, Swizzle::A}; + Swizzle::A, Swizzle::R, Swizzle::G, Swizzle::B}; }; struct R8G8_UNORMTraits { @@ -423,8 +441,8 @@ struct R8G8_UNORMTraits { static constexpr std::array component_types = { ComponentType::UNORM, ComponentType::UNORM}; static constexpr std::array component_sizes = {8, 8}; - static constexpr std::array component_swizzle = {Swizzle::G, - Swizzle::R}; + static constexpr std::array component_swizzle = {Swizzle::R, + Swizzle::G}; }; struct R8G8_SNORMTraits { @@ -432,8 +450,8 @@ struct R8G8_SNORMTraits { static constexpr std::array component_types = { ComponentType::SNORM, ComponentType::SNORM}; static constexpr std::array component_sizes = {8, 8}; - static constexpr std::array component_swizzle = {Swizzle::G, - Swizzle::R}; + static constexpr std::array component_swizzle = {Swizzle::R, + Swizzle::G}; }; struct R8G8_SINTTraits { @@ -441,8 +459,8 @@ struct R8G8_SINTTraits { static constexpr std::array component_types = { ComponentType::SINT, ComponentType::SINT}; static constexpr std::array component_sizes = {8, 8}; - static constexpr std::array component_swizzle = {Swizzle::G, - Swizzle::R}; + static constexpr std::array component_swizzle = {Swizzle::R, + Swizzle::G}; }; struct R8G8_UINTTraits { @@ -450,8 +468,8 @@ struct R8G8_UINTTraits { static constexpr std::array component_types = { ComponentType::UINT, ComponentType::UINT}; static constexpr std::array component_sizes = {8, 8}; - static constexpr std::array component_swizzle = {Swizzle::G, - Swizzle::R}; + static constexpr std::array component_swizzle = {Swizzle::R, + Swizzle::G}; }; struct R16_UNORMTraits { @@ -611,7 +629,7 @@ private: constexpr size_t fp16_mantissa_bits = 10; constexpr size_t mantissa_mask = ~((1ULL << (fp32_mantissa_bits - fp16_mantissa_bits)) - 1ULL); - tmp = tmp & mantissa_mask; + tmp = tmp & static_cast(mantissa_mask); // TODO: force the exponent within the range of half float. Not needed in UNORM / SNORM return std::bit_cast(tmp); }; @@ -624,12 +642,13 @@ private: }; const auto calculate_snorm = [&]() { return static_cast( - static_cast(sign_extend(value, component_sizes[which_component])) / - ((1ULL << (component_sizes[which_component] - 1ULL)) - 1ULL)); + static_cast(sign_extend(value, component_sizes[which_component])) / + static_cast((1ULL << (component_sizes[which_component] - 1ULL)) - 1ULL)); }; const auto calculate_unorm = [&]() { - return static_cast(static_cast(value) / - ((1ULL << (component_sizes[which_component])) - 1ULL)); + return static_cast( + static_cast(value) / + static_cast((1ULL << (component_sizes[which_component])) - 1ULL)); }; if constexpr (component_types[which_component] == ComponentType::SNORM) { out_component = calculate_snorm(); @@ -688,14 +707,15 @@ private: return tmp_value >> shift_towards; }; const auto calculate_unorm = [&]() { - return static_cast(static_cast(in_component) * - ((1ULL << (component_sizes[which_component])) - 1ULL)); + return static_cast( + static_cast(in_component) * + static_cast((1ULL << (component_sizes[which_component])) - 1ULL)); }; if constexpr (component_types[which_component] == ComponentType::SNORM || component_types[which_component] == ComponentType::SNORM_FORCE_FP16) { - s32 tmp_word = - static_cast(static_cast(in_component) * - ((1ULL << (component_sizes[which_component] - 1ULL)) - 1ULL)); + s32 tmp_word = static_cast( + static_cast(in_component) * + static_cast((1ULL << (component_sizes[which_component] - 1ULL)) - 1ULL)); insert_to_word(tmp_word); } else if constexpr (component_types[which_component] == ComponentType::UNORM || @@ -714,11 +734,12 @@ private: insert_to_word(tmp_word); } else if constexpr (component_sizes[which_component] == 16) { static constexpr u32 sign_mask = 0x8000; - static constexpr u32 mantissa_mask = 0x8000; + static constexpr u32 mantissa_mask = 0x03ff; + static constexpr u32 exponent_mask = 0x7c00; const u32 tmp_word = std::bit_cast(in_component); const u32 half = ((tmp_word >> 16) & sign_mask) | - ((((tmp_word & 0x7f800000) - 0x38000000) >> 13) & 0x7c00) | - ((tmp_word >> 13) & 0x03ff); + ((((tmp_word & 0x7f800000) - 0x38000000) >> 13) & exponent_mask) | + ((tmp_word >> 13) & mantissa_mask); insert_to_word(half); } else { insert_to_word(to_fp_n(in_component, component_sizes[which_component], @@ -740,7 +761,7 @@ private: } public: - void ConvertTo(std::span input, std::span output) override { + void ConvertTo(std::span input, std::span output) override { const size_t num_pixels = output.size() / components_per_ir_rep; for (size_t pixel = 0; pixel < num_pixels; pixel++) { std::array words{}; @@ -790,11 +811,11 @@ public: } } - void ConvertFrom(std::span input, std::span output) override { + void ConvertFrom(std::span input, std::span output) override { const size_t num_pixels = output.size() / total_bytes_per_pixel; for (size_t pixel = 0; pixel < num_pixels; pixel++) { - std::span old_components(&input[pixel * components_per_ir_rep], - components_per_ir_rep); + std::span old_components(&input[pixel * components_per_ir_rep], + components_per_ir_rep); std::array words{}; if constexpr (component_swizzle[0] != Swizzle::None) { ConvertFromComponent<0>(words[bound_words[0]], @@ -827,7 +848,7 @@ public: } ConverterImpl() = default; - ~ConverterImpl() = default; + ~ConverterImpl() override = default; }; struct ConverterFactory::ConverterFactoryImpl { @@ -850,13 +871,15 @@ Converter* ConverterFactory::GetFormatConverter(RenderTargetFormat format) { class NullConverter : public Converter { public: - void ConvertTo([[maybe_unused]] std::span input, std::span output) override { + void ConvertTo([[maybe_unused]] std::span input, std::span output) override { std::fill(output.begin(), output.end(), 0.0f); } - void ConvertFrom([[maybe_unused]] std::span input, std::span output) override { + void ConvertFrom([[maybe_unused]] std::span input, std::span output) override { const u8 fill_value = 0U; std::fill(output.begin(), output.end(), fill_value); } + NullConverter() = default; + ~NullConverter() = default; }; Converter* ConverterFactory::BuildConverter(RenderTargetFormat format) { @@ -1011,6 +1034,16 @@ Converter* ConverterFactory::BuildConverter(RenderTargetFormat format) { .emplace(format, std::make_unique>()) .first->second.get(); break; + case RenderTargetFormat::X8R8G8B8_UNORM: + return impl->converters_cache + .emplace(format, std::make_unique>()) + .first->second.get(); + break; + case RenderTargetFormat::X8R8G8B8_SRGB: + return impl->converters_cache + .emplace(format, std::make_unique>()) + .first->second.get(); + break; case RenderTargetFormat::R5G6B5_UNORM: return impl->converters_cache .emplace(format, std::make_unique>()) diff --git a/src/video_core/engines/sw_blitter/converter.h b/src/video_core/engines/sw_blitter/converter.h index 03337e906..f9bdc516e 100644 --- a/src/video_core/engines/sw_blitter/converter.h +++ b/src/video_core/engines/sw_blitter/converter.h @@ -1,21 +1,22 @@ // SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project // SPDX-License-Identifier: GPL-3.0-or-later +#pragma once + #include #include #include "common/common_types.h" -#pragma once - #include "video_core/gpu.h" namespace Tegra::Engines::Blitter { class Converter { public: - virtual void ConvertTo(std::span input, std::span output) = 0; - virtual void ConvertFrom(std::span input, std::span output) = 0; + virtual void ConvertTo(std::span input, std::span output) = 0; + virtual void ConvertFrom(std::span input, std::span output) = 0; + virtual ~Converter() = default; }; class ConverterFactory { diff --git a/src/video_core/gpu.h b/src/video_core/gpu.h index d0709dc69..87ebf2054 100644 --- a/src/video_core/gpu.h +++ b/src/video_core/gpu.h @@ -61,8 +61,8 @@ enum class RenderTargetFormat : u32 { R32_SINT = 0xE3, R32_UINT = 0xE4, R32_FLOAT = 0xE5, - // X8R8G8B8_UNORM = 0xE6, - // X8R8G8B8_SRGB = 0xE7, + X8R8G8B8_UNORM = 0xE6, + X8R8G8B8_SRGB = 0xE7, R5G6B5_UNORM = 0xE8, A1R5G5B5_UNORM = 0xE9, R8G8_UNORM = 0xEA, diff --git a/src/video_core/surface.cpp b/src/video_core/surface.cpp index 6bd133d10..80a7d908f 100644 --- a/src/video_core/surface.cpp +++ b/src/video_core/surface.cpp @@ -118,8 +118,10 @@ PixelFormat PixelFormatFromRenderTargetFormat(Tegra::RenderTargetFormat format) case Tegra::RenderTargetFormat::R16G16B16X16_FLOAT: return PixelFormat::R16G16B16X16_FLOAT; case Tegra::RenderTargetFormat::A8R8G8B8_UNORM: + case Tegra::RenderTargetFormat::X8R8G8B8_UNORM: return PixelFormat::B8G8R8A8_UNORM; case Tegra::RenderTargetFormat::A8R8G8B8_SRGB: + case Tegra::RenderTargetFormat::X8R8G8B8_SRGB: return PixelFormat::B8G8R8A8_SRGB; case Tegra::RenderTargetFormat::A2B10G10R10_UNORM: return PixelFormat::A2B10G10R10_UNORM; -- cgit v1.2.3