2
1
Fork 0
mirror of https://github.com/yuzu-emu/yuzu.git synced 2024-07-04 23:31:19 +01:00

Merge pull request #4176 from ReinUsesLisp/compatible-formats

texture_cache: Check format compatibility before copying
This commit is contained in:
Fernando Sahmkow 2020-06-30 15:36:13 -04:00 committed by GitHub
commit a4f48efea4
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 216 additions and 5 deletions

View file

@ -3,6 +3,8 @@ add_library(video_core STATIC
buffer_cache/buffer_cache.h buffer_cache/buffer_cache.h
buffer_cache/map_interval.cpp buffer_cache/map_interval.cpp
buffer_cache/map_interval.h buffer_cache/map_interval.h
compatible_formats.cpp
compatible_formats.h
dirty_flags.cpp dirty_flags.cpp
dirty_flags.h dirty_flags.h
dma_pusher.cpp dma_pusher.cpp

View file

@ -0,0 +1,162 @@
// Copyright 2020 yuzu Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#include <array>
#include <bitset>
#include <cstddef>
#include "video_core/compatible_formats.h"
#include "video_core/surface.h"
namespace VideoCore::Surface {
namespace {
// Compatibility table taken from Table 3.X.2 in:
// https://www.khronos.org/registry/OpenGL/extensions/ARB/ARB_texture_view.txt
constexpr std::array VIEW_CLASS_128_BITS = {
PixelFormat::RGBA32F,
PixelFormat::RGBA32UI,
};
// Missing formats:
// PixelFormat::RGBA32I
constexpr std::array VIEW_CLASS_96_BITS = {
PixelFormat::RGB32F,
};
// Missing formats:
// PixelFormat::RGB32UI,
// PixelFormat::RGB32I,
constexpr std::array VIEW_CLASS_64_BITS = {
PixelFormat::RGBA16F, PixelFormat::RG32F, PixelFormat::RGBA16UI, PixelFormat::RG32UI,
PixelFormat::RGBA16U, PixelFormat::RGBA16F, PixelFormat::RGBA16S,
};
// Missing formats:
// PixelFormat::RGBA16I
// PixelFormat::RG32I
// TODO: How should we handle 48 bits?
constexpr std::array VIEW_CLASS_32_BITS = {
PixelFormat::RG16F, PixelFormat::R11FG11FB10F, PixelFormat::R32F,
PixelFormat::A2B10G10R10U, PixelFormat::RG16UI, PixelFormat::R32UI,
PixelFormat::RG16I, PixelFormat::R32I, PixelFormat::ABGR8U,
PixelFormat::RG16, PixelFormat::ABGR8S, PixelFormat::RG16S,
PixelFormat::RGBA8_SRGB, PixelFormat::E5B9G9R9F, PixelFormat::BGRA8,
PixelFormat::BGRA8_SRGB,
};
// Missing formats:
// PixelFormat::RGBA8UI
// PixelFormat::RGBA8I
// PixelFormat::RGB10_A2_UI
// TODO: How should we handle 24 bits?
constexpr std::array VIEW_CLASS_16_BITS = {
PixelFormat::R16F, PixelFormat::RG8UI, PixelFormat::R16UI, PixelFormat::R16I,
PixelFormat::RG8U, PixelFormat::R16U, PixelFormat::RG8S, PixelFormat::R16S,
};
// Missing formats:
// PixelFormat::RG8I
constexpr std::array VIEW_CLASS_8_BITS = {
PixelFormat::R8UI,
PixelFormat::R8U,
};
// Missing formats:
// PixelFormat::R8I
// PixelFormat::R8S
constexpr std::array VIEW_CLASS_RGTC1_RED = {
PixelFormat::DXN1,
};
// Missing formats:
// COMPRESSED_SIGNED_RED_RGTC1
constexpr std::array VIEW_CLASS_RGTC2_RG = {
PixelFormat::DXN2UNORM,
PixelFormat::DXN2SNORM,
};
constexpr std::array VIEW_CLASS_BPTC_UNORM = {
PixelFormat::BC7U,
PixelFormat::BC7U_SRGB,
};
constexpr std::array VIEW_CLASS_BPTC_FLOAT = {
PixelFormat::BC6H_SF16,
PixelFormat::BC6H_UF16,
};
// Compatibility table taken from Table 4.X.1 in:
// https://www.khronos.org/registry/OpenGL/extensions/ARB/ARB_copy_image.txt
constexpr std::array COPY_CLASS_128_BITS = {
PixelFormat::RGBA32UI, PixelFormat::RGBA32F, PixelFormat::DXT23,
PixelFormat::DXT23_SRGB, PixelFormat::DXT45, PixelFormat::DXT45_SRGB,
PixelFormat::DXN2SNORM, PixelFormat::BC7U, PixelFormat::BC7U_SRGB,
PixelFormat::BC6H_SF16, PixelFormat::BC6H_UF16,
};
// Missing formats:
// PixelFormat::RGBA32I
// COMPRESSED_RG_RGTC2
constexpr std::array COPY_CLASS_64_BITS = {
PixelFormat::RGBA16F, PixelFormat::RG32F, PixelFormat::RGBA16UI, PixelFormat::RG32UI,
PixelFormat::RGBA16U, PixelFormat::RGBA16S, PixelFormat::DXT1_SRGB, PixelFormat::DXT1,
};
// Missing formats:
// PixelFormat::RGBA16I
// PixelFormat::RG32I,
// COMPRESSED_RGB_S3TC_DXT1_EXT
// COMPRESSED_SRGB_S3TC_DXT1_EXT
// COMPRESSED_RGBA_S3TC_DXT1_EXT
// COMPRESSED_SIGNED_RED_RGTC1
void Enable(FormatCompatibility::Table& compatiblity, size_t format_a, size_t format_b) {
compatiblity[format_a][format_b] = true;
compatiblity[format_b][format_a] = true;
}
void Enable(FormatCompatibility::Table& compatibility, PixelFormat format_a, PixelFormat format_b) {
Enable(compatibility, static_cast<size_t>(format_a), static_cast<size_t>(format_b));
}
template <typename Range>
void EnableRange(FormatCompatibility::Table& compatibility, const Range& range) {
for (auto it_a = range.begin(); it_a != range.end(); ++it_a) {
for (auto it_b = it_a; it_b != range.end(); ++it_b) {
Enable(compatibility, *it_a, *it_b);
}
}
}
} // Anonymous namespace
FormatCompatibility::FormatCompatibility() {
for (size_t i = 0; i < MaxPixelFormat; ++i) {
// Identity is allowed
Enable(view, i, i);
}
EnableRange(view, VIEW_CLASS_128_BITS);
EnableRange(view, VIEW_CLASS_96_BITS);
EnableRange(view, VIEW_CLASS_64_BITS);
EnableRange(view, VIEW_CLASS_32_BITS);
EnableRange(view, VIEW_CLASS_16_BITS);
EnableRange(view, VIEW_CLASS_8_BITS);
EnableRange(view, VIEW_CLASS_RGTC1_RED);
EnableRange(view, VIEW_CLASS_RGTC2_RG);
EnableRange(view, VIEW_CLASS_BPTC_UNORM);
EnableRange(view, VIEW_CLASS_BPTC_FLOAT);
copy = view;
EnableRange(copy, COPY_CLASS_128_BITS);
EnableRange(copy, COPY_CLASS_64_BITS);
}
} // namespace VideoCore::Surface

View file

@ -0,0 +1,32 @@
// Copyright 2020 yuzu Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#include <array>
#include <bitset>
#include <cstddef>
#include "video_core/surface.h"
namespace VideoCore::Surface {
class FormatCompatibility {
public:
using Table = std::array<std::bitset<MaxPixelFormat>, MaxPixelFormat>;
explicit FormatCompatibility();
bool TestView(PixelFormat format_a, PixelFormat format_b) const noexcept {
return view[static_cast<size_t>(format_a)][static_cast<size_t>(format_b)];
}
bool TestCopy(PixelFormat format_a, PixelFormat format_b) const noexcept {
return copy[static_cast<size_t>(format_a)][static_cast<size_t>(format_b)];
}
private:
Table view;
Table copy;
};
} // namespace VideoCore::Surface

View file

@ -24,6 +24,7 @@
#include "core/core.h" #include "core/core.h"
#include "core/memory.h" #include "core/memory.h"
#include "core/settings.h" #include "core/settings.h"
#include "video_core/compatible_formats.h"
#include "video_core/dirty_flags.h" #include "video_core/dirty_flags.h"
#include "video_core/engines/fermi_2d.h" #include "video_core/engines/fermi_2d.h"
#include "video_core/engines/maxwell_3d.h" #include "video_core/engines/maxwell_3d.h"
@ -47,8 +48,8 @@ class RasterizerInterface;
namespace VideoCommon { namespace VideoCommon {
using VideoCore::Surface::FormatCompatibility;
using VideoCore::Surface::PixelFormat; using VideoCore::Surface::PixelFormat;
using VideoCore::Surface::SurfaceTarget; using VideoCore::Surface::SurfaceTarget;
using RenderTargetConfig = Tegra::Engines::Maxwell3D::Regs::RenderTargetConfig; using RenderTargetConfig = Tegra::Engines::Maxwell3D::Regs::RenderTargetConfig;
@ -595,7 +596,7 @@ private:
} else { } else {
new_surface = GetUncachedSurface(gpu_addr, params); new_surface = GetUncachedSurface(gpu_addr, params);
} }
const auto& final_params = new_surface->GetSurfaceParams(); const SurfaceParams& final_params = new_surface->GetSurfaceParams();
if (cr_params.type != final_params.type) { if (cr_params.type != final_params.type) {
if (Settings::IsGPULevelExtreme()) { if (Settings::IsGPULevelExtreme()) {
BufferCopy(current_surface, new_surface); BufferCopy(current_surface, new_surface);
@ -603,7 +604,7 @@ private:
} else { } else {
std::vector<CopyParams> bricks = current_surface->BreakDown(final_params); std::vector<CopyParams> bricks = current_surface->BreakDown(final_params);
for (auto& brick : bricks) { for (auto& brick : bricks) {
ImageCopy(current_surface, new_surface, brick); TryCopyImage(current_surface, new_surface, brick);
} }
} }
Unregister(current_surface); Unregister(current_surface);
@ -694,7 +695,7 @@ private:
} }
const CopyParams copy_params(0, 0, 0, 0, 0, base_layer, 0, mipmap, width, height, const CopyParams copy_params(0, 0, 0, 0, 0, base_layer, 0, mipmap, width, height,
src_params.depth); src_params.depth);
ImageCopy(surface, new_surface, copy_params); TryCopyImage(surface, new_surface, copy_params);
} }
} }
if (passed_tests == 0) { if (passed_tests == 0) {
@ -791,7 +792,7 @@ private:
const u32 width = params.width; const u32 width = params.width;
const u32 height = params.height; const u32 height = params.height;
const CopyParams copy_params(0, 0, 0, 0, 0, slice, 0, 0, width, height, 1); const CopyParams copy_params(0, 0, 0, 0, 0, slice, 0, 0, width, height, 1);
ImageCopy(surface, new_surface, copy_params); TryCopyImage(surface, new_surface, copy_params);
} }
for (const auto& surface : overlaps) { for (const auto& surface : overlaps) {
Unregister(surface); Unregister(surface);
@ -1192,6 +1193,19 @@ private:
return {}; return {};
} }
/// Try to do an image copy logging when formats are incompatible.
void TryCopyImage(TSurface& src, TSurface& dst, const CopyParams& copy) {
const SurfaceParams& src_params = src->GetSurfaceParams();
const SurfaceParams& dst_params = dst->GetSurfaceParams();
if (!format_compatibility.TestCopy(src_params.pixel_format, dst_params.pixel_format)) {
LOG_ERROR(HW_GPU, "Illegal copy between formats={{{}, {}}}",
static_cast<int>(dst_params.pixel_format),
static_cast<int>(src_params.pixel_format));
return;
}
ImageCopy(src, dst, copy);
}
constexpr PixelFormat GetSiblingFormat(PixelFormat format) const { constexpr PixelFormat GetSiblingFormat(PixelFormat format) const {
return siblings_table[static_cast<std::size_t>(format)]; return siblings_table[static_cast<std::size_t>(format)];
} }
@ -1241,6 +1255,7 @@ private:
VideoCore::RasterizerInterface& rasterizer; VideoCore::RasterizerInterface& rasterizer;
FormatLookupTable format_lookup_table; FormatLookupTable format_lookup_table;
FormatCompatibility format_compatibility;
u64 ticks{}; u64 ticks{};