texture_cache: Test format compatibility before copying

Avoid illegal copies. This intercepts the last step of a copy to avoid
generating validation errors or corrupting the driver on some instances.

We can create views and emit copies accordingly in future commits and
remove this last-step validation.
This commit is contained in:
ReinUsesLisp 2020-06-26 19:25:49 -03:00
parent 1d6be9febf
commit bb2cbdf704
2 changed files with 21 additions and 6 deletions

View File

@ -130,7 +130,7 @@ template <typename Range>
void EnableRange(FormatCompatibility::Table& compatibility, const Range& range) { void EnableRange(FormatCompatibility::Table& compatibility, const Range& range) {
for (auto it_a = range.begin(); it_a != range.end(); ++it_a) { for (auto it_a = range.begin(); it_a != range.end(); ++it_a) {
for (auto it_b = it_a; it_b != range.end(); ++it_b) { for (auto it_b = it_a; it_b != range.end(); ++it_b) {
Enable(*it_a, *it_b); Enable(compatibility, *it_a, *it_b);
} }
} }
} }

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{};