Merge pull request #4176 from ReinUsesLisp/compatible-formats
texture_cache: Check format compatibility before copying
This commit is contained in:
commit
a4f48efea4
|
@ -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
|
||||||
|
|
162
src/video_core/compatible_formats.cpp
Normal file
162
src/video_core/compatible_formats.cpp
Normal 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
|
32
src/video_core/compatible_formats.h
Normal file
32
src/video_core/compatible_formats.h
Normal 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
|
|
@ -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{};
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue