mirror of
				https://git.suyu.dev/suyu/suyu
				synced 2025-11-03 16:39:01 -06:00 
			
		
		
		
	Merge pull request #4176 from ReinUsesLisp/compatible-formats
texture_cache: Check format compatibility before copying
This commit is contained in:
		@@ -3,6 +3,8 @@ add_library(video_core STATIC
 | 
			
		||||
    buffer_cache/buffer_cache.h
 | 
			
		||||
    buffer_cache/map_interval.cpp
 | 
			
		||||
    buffer_cache/map_interval.h
 | 
			
		||||
    compatible_formats.cpp
 | 
			
		||||
    compatible_formats.h
 | 
			
		||||
    dirty_flags.cpp
 | 
			
		||||
    dirty_flags.h
 | 
			
		||||
    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/memory.h"
 | 
			
		||||
#include "core/settings.h"
 | 
			
		||||
#include "video_core/compatible_formats.h"
 | 
			
		||||
#include "video_core/dirty_flags.h"
 | 
			
		||||
#include "video_core/engines/fermi_2d.h"
 | 
			
		||||
#include "video_core/engines/maxwell_3d.h"
 | 
			
		||||
@@ -47,8 +48,8 @@ class RasterizerInterface;
 | 
			
		||||
 | 
			
		||||
namespace VideoCommon {
 | 
			
		||||
 | 
			
		||||
using VideoCore::Surface::FormatCompatibility;
 | 
			
		||||
using VideoCore::Surface::PixelFormat;
 | 
			
		||||
 | 
			
		||||
using VideoCore::Surface::SurfaceTarget;
 | 
			
		||||
using RenderTargetConfig = Tegra::Engines::Maxwell3D::Regs::RenderTargetConfig;
 | 
			
		||||
 | 
			
		||||
@@ -595,7 +596,7 @@ private:
 | 
			
		||||
        } else {
 | 
			
		||||
            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 (Settings::IsGPULevelExtreme()) {
 | 
			
		||||
                BufferCopy(current_surface, new_surface);
 | 
			
		||||
@@ -603,7 +604,7 @@ private:
 | 
			
		||||
        } else {
 | 
			
		||||
            std::vector<CopyParams> bricks = current_surface->BreakDown(final_params);
 | 
			
		||||
            for (auto& brick : bricks) {
 | 
			
		||||
                ImageCopy(current_surface, new_surface, brick);
 | 
			
		||||
                TryCopyImage(current_surface, new_surface, brick);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        Unregister(current_surface);
 | 
			
		||||
@@ -694,7 +695,7 @@ private:
 | 
			
		||||
                }
 | 
			
		||||
                const CopyParams copy_params(0, 0, 0, 0, 0, base_layer, 0, mipmap, width, height,
 | 
			
		||||
                                             src_params.depth);
 | 
			
		||||
                ImageCopy(surface, new_surface, copy_params);
 | 
			
		||||
                TryCopyImage(surface, new_surface, copy_params);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        if (passed_tests == 0) {
 | 
			
		||||
@@ -791,7 +792,7 @@ private:
 | 
			
		||||
            const u32 width = params.width;
 | 
			
		||||
            const u32 height = params.height;
 | 
			
		||||
            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) {
 | 
			
		||||
            Unregister(surface);
 | 
			
		||||
@@ -1192,6 +1193,19 @@ private:
 | 
			
		||||
        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 {
 | 
			
		||||
        return siblings_table[static_cast<std::size_t>(format)];
 | 
			
		||||
    }
 | 
			
		||||
@@ -1241,6 +1255,7 @@ private:
 | 
			
		||||
    VideoCore::RasterizerInterface& rasterizer;
 | 
			
		||||
 | 
			
		||||
    FormatLookupTable format_lookup_table;
 | 
			
		||||
    FormatCompatibility format_compatibility;
 | 
			
		||||
 | 
			
		||||
    u64 ticks{};
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user