diff options
Diffstat (limited to 'src/video_core/texture_cache')
-rw-r--r-- | src/video_core/texture_cache/format_lookup_table.cpp | 208 | ||||
-rw-r--r-- | src/video_core/texture_cache/format_lookup_table.h | 51 | ||||
-rw-r--r-- | src/video_core/texture_cache/surface_base.h | 11 | ||||
-rw-r--r-- | src/video_core/texture_cache/surface_params.cpp | 42 | ||||
-rw-r--r-- | src/video_core/texture_cache/surface_params.h | 17 | ||||
-rw-r--r-- | src/video_core/texture_cache/texture_cache.h | 131 |
6 files changed, 392 insertions, 68 deletions
diff --git a/src/video_core/texture_cache/format_lookup_table.cpp b/src/video_core/texture_cache/format_lookup_table.cpp new file mode 100644 index 000000000..271e67533 --- /dev/null +++ b/src/video_core/texture_cache/format_lookup_table.cpp @@ -0,0 +1,208 @@ +// Copyright 2019 yuzu Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include <array> +#include "common/common_types.h" +#include "common/logging/log.h" +#include "video_core/texture_cache/format_lookup_table.h" + +namespace VideoCommon { + +using Tegra::Texture::ComponentType; +using Tegra::Texture::TextureFormat; +using VideoCore::Surface::PixelFormat; + +namespace { + +constexpr auto SNORM = ComponentType::SNORM; +constexpr auto UNORM = ComponentType::UNORM; +constexpr auto SINT = ComponentType::SINT; +constexpr auto UINT = ComponentType::UINT; +constexpr auto SNORM_FORCE_FP16 = ComponentType::SNORM_FORCE_FP16; +constexpr auto UNORM_FORCE_FP16 = ComponentType::UNORM_FORCE_FP16; +constexpr auto FLOAT = ComponentType::FLOAT; +constexpr bool C = false; // Normal color +constexpr bool S = true; // Srgb + +struct Table { + constexpr Table(TextureFormat texture_format, bool is_srgb, ComponentType red_component, + ComponentType green_component, ComponentType blue_component, + ComponentType alpha_component, PixelFormat pixel_format) + : texture_format{texture_format}, pixel_format{pixel_format}, red_component{red_component}, + green_component{green_component}, blue_component{blue_component}, + alpha_component{alpha_component}, is_srgb{is_srgb} {} + + TextureFormat texture_format; + PixelFormat pixel_format; + ComponentType red_component; + ComponentType green_component; + ComponentType blue_component; + ComponentType alpha_component; + bool is_srgb; +}; +constexpr std::array<Table, 74> DefinitionTable = {{ + {TextureFormat::A8R8G8B8, C, UNORM, UNORM, UNORM, UNORM, PixelFormat::ABGR8U}, + {TextureFormat::A8R8G8B8, C, SNORM, SNORM, SNORM, SNORM, PixelFormat::ABGR8S}, + {TextureFormat::A8R8G8B8, C, UINT, UINT, UINT, UINT, PixelFormat::ABGR8UI}, + {TextureFormat::A8R8G8B8, S, UNORM, UNORM, UNORM, UNORM, PixelFormat::RGBA8_SRGB}, + + {TextureFormat::B5G6R5, C, UNORM, UNORM, UNORM, UNORM, PixelFormat::B5G6R5U}, + + {TextureFormat::A2B10G10R10, C, UNORM, UNORM, UNORM, UNORM, PixelFormat::A2B10G10R10U}, + + {TextureFormat::A1B5G5R5, C, UNORM, UNORM, UNORM, UNORM, PixelFormat::A1B5G5R5U}, + + {TextureFormat::A4B4G4R4, C, UNORM, UNORM, UNORM, UNORM, PixelFormat::R4G4B4A4U}, + + {TextureFormat::R8, C, UNORM, UNORM, UNORM, UNORM, PixelFormat::R8U}, + {TextureFormat::R8, C, UINT, UINT, UINT, UINT, PixelFormat::R8UI}, + + {TextureFormat::G8R8, C, UNORM, UNORM, UNORM, UNORM, PixelFormat::RG8U}, + {TextureFormat::G8R8, C, SNORM, SNORM, SNORM, SNORM, PixelFormat::RG8S}, + + {TextureFormat::R16_G16_B16_A16, C, UNORM, UNORM, UNORM, UNORM, PixelFormat::RGBA16U}, + {TextureFormat::R16_G16_B16_A16, C, FLOAT, FLOAT, FLOAT, FLOAT, PixelFormat::RGBA16F}, + {TextureFormat::R16_G16_B16_A16, C, UINT, UINT, UINT, UINT, PixelFormat::RGBA16UI}, + + {TextureFormat::R16_G16, C, FLOAT, FLOAT, FLOAT, FLOAT, PixelFormat::RG16F}, + {TextureFormat::R16_G16, C, UNORM, UNORM, UNORM, UNORM, PixelFormat::RG16}, + {TextureFormat::R16_G16, C, SNORM, SNORM, SNORM, SNORM, PixelFormat::RG16S}, + {TextureFormat::R16_G16, C, UINT, UINT, UINT, UINT, PixelFormat::RG16UI}, + {TextureFormat::R16_G16, C, SINT, SINT, SINT, SINT, PixelFormat::RG16I}, + + {TextureFormat::R16, C, FLOAT, FLOAT, FLOAT, FLOAT, PixelFormat::R16F}, + {TextureFormat::R16, C, UNORM, UNORM, UNORM, UNORM, PixelFormat::R16U}, + {TextureFormat::R16, C, SNORM, SNORM, SNORM, SNORM, PixelFormat::R16S}, + {TextureFormat::R16, C, UINT, UINT, UINT, UINT, PixelFormat::R16UI}, + {TextureFormat::R16, C, SINT, SINT, SINT, SINT, PixelFormat::R16I}, + + {TextureFormat::BF10GF11RF11, C, FLOAT, FLOAT, FLOAT, FLOAT, PixelFormat::R11FG11FB10F}, + + {TextureFormat::R32_G32_B32_A32, C, FLOAT, FLOAT, FLOAT, FLOAT, PixelFormat::RGBA32F}, + {TextureFormat::R32_G32_B32_A32, C, UINT, UINT, UINT, UINT, PixelFormat::RGBA32UI}, + + {TextureFormat::R32_G32_B32, C, FLOAT, FLOAT, FLOAT, FLOAT, PixelFormat::RGB32F}, + + {TextureFormat::R32_G32, C, FLOAT, FLOAT, FLOAT, FLOAT, PixelFormat::RG32F}, + {TextureFormat::R32_G32, C, UINT, UINT, UINT, UINT, PixelFormat::RG32UI}, + + {TextureFormat::R32, C, FLOAT, FLOAT, FLOAT, FLOAT, PixelFormat::R32F}, + {TextureFormat::R32, C, UINT, UINT, UINT, UINT, PixelFormat::R32UI}, + + {TextureFormat::E5B9G9R9_SHAREDEXP, C, FLOAT, FLOAT, FLOAT, FLOAT, PixelFormat::E5B9G9R9F}, + + {TextureFormat::ZF32, C, FLOAT, FLOAT, FLOAT, FLOAT, PixelFormat::Z32F}, + {TextureFormat::Z16, C, UNORM, UNORM, UNORM, UNORM, PixelFormat::Z16}, + {TextureFormat::S8Z24, C, UINT, UNORM, UNORM, UNORM, PixelFormat::S8Z24}, + {TextureFormat::ZF32_X24S8, C, UNORM, UNORM, UNORM, UNORM, PixelFormat::Z32FS8}, + + {TextureFormat::DXT1, C, UNORM, UNORM, UNORM, UNORM, PixelFormat::DXT1}, + {TextureFormat::DXT1, S, UNORM, UNORM, UNORM, UNORM, PixelFormat::DXT1_SRGB}, + + {TextureFormat::DXT23, C, UNORM, UNORM, UNORM, UNORM, PixelFormat::DXT23}, + {TextureFormat::DXT23, S, UNORM, UNORM, UNORM, UNORM, PixelFormat::DXT23_SRGB}, + + {TextureFormat::DXT45, C, UNORM, UNORM, UNORM, UNORM, PixelFormat::DXT45}, + {TextureFormat::DXT45, S, UNORM, UNORM, UNORM, UNORM, PixelFormat::DXT45_SRGB}, + + // TODO: Use a different pixel format for SNORM + {TextureFormat::DXN1, C, UNORM, UNORM, UNORM, UNORM, PixelFormat::DXN1}, + {TextureFormat::DXN1, C, SNORM, SNORM, SNORM, SNORM, PixelFormat::DXN1}, + + {TextureFormat::DXN2, C, UNORM, UNORM, UNORM, UNORM, PixelFormat::DXN2UNORM}, + {TextureFormat::DXN2, C, SNORM, SNORM, SNORM, SNORM, PixelFormat::DXN2SNORM}, + + {TextureFormat::BC7U, C, UNORM, UNORM, UNORM, UNORM, PixelFormat::BC7U}, + {TextureFormat::BC7U, S, UNORM, UNORM, UNORM, UNORM, PixelFormat::BC7U_SRGB}, + + {TextureFormat::BC6H_SF16, C, FLOAT, FLOAT, FLOAT, FLOAT, PixelFormat::BC6H_SF16}, + {TextureFormat::BC6H_UF16, C, FLOAT, FLOAT, FLOAT, FLOAT, PixelFormat::BC6H_UF16}, + + {TextureFormat::ASTC_2D_4X4, C, UNORM, UNORM, UNORM, UNORM, PixelFormat::ASTC_2D_4X4}, + {TextureFormat::ASTC_2D_4X4, S, UNORM, UNORM, UNORM, UNORM, PixelFormat::ASTC_2D_4X4_SRGB}, + + {TextureFormat::ASTC_2D_5X4, C, UNORM, UNORM, UNORM, UNORM, PixelFormat::ASTC_2D_5X4}, + {TextureFormat::ASTC_2D_5X4, S, UNORM, UNORM, UNORM, UNORM, PixelFormat::ASTC_2D_5X4_SRGB}, + + {TextureFormat::ASTC_2D_5X5, C, UNORM, UNORM, UNORM, UNORM, PixelFormat::ASTC_2D_5X5}, + {TextureFormat::ASTC_2D_5X5, S, UNORM, UNORM, UNORM, UNORM, PixelFormat::ASTC_2D_5X5_SRGB}, + + {TextureFormat::ASTC_2D_8X8, C, UNORM, UNORM, UNORM, UNORM, PixelFormat::ASTC_2D_8X8}, + {TextureFormat::ASTC_2D_8X8, S, UNORM, UNORM, UNORM, UNORM, PixelFormat::ASTC_2D_8X8_SRGB}, + + {TextureFormat::ASTC_2D_8X5, C, UNORM, UNORM, UNORM, UNORM, PixelFormat::ASTC_2D_8X5}, + {TextureFormat::ASTC_2D_8X5, S, UNORM, UNORM, UNORM, UNORM, PixelFormat::ASTC_2D_8X5_SRGB}, + + {TextureFormat::ASTC_2D_10X8, C, UNORM, UNORM, UNORM, UNORM, PixelFormat::ASTC_2D_10X8}, + {TextureFormat::ASTC_2D_10X8, S, UNORM, UNORM, UNORM, UNORM, PixelFormat::ASTC_2D_10X8_SRGB}, + + {TextureFormat::ASTC_2D_6X6, C, UNORM, UNORM, UNORM, UNORM, PixelFormat::ASTC_2D_6X6}, + {TextureFormat::ASTC_2D_6X6, S, UNORM, UNORM, UNORM, UNORM, PixelFormat::ASTC_2D_6X6_SRGB}, + + {TextureFormat::ASTC_2D_10X10, C, UNORM, UNORM, UNORM, UNORM, PixelFormat::ASTC_2D_10X10}, + {TextureFormat::ASTC_2D_10X10, S, UNORM, UNORM, UNORM, UNORM, PixelFormat::ASTC_2D_10X10_SRGB}, + + {TextureFormat::ASTC_2D_12X12, C, UNORM, UNORM, UNORM, UNORM, PixelFormat::ASTC_2D_12X12}, + {TextureFormat::ASTC_2D_12X12, S, UNORM, UNORM, UNORM, UNORM, PixelFormat::ASTC_2D_12X12_SRGB}, + + {TextureFormat::ASTC_2D_8X6, C, UNORM, UNORM, UNORM, UNORM, PixelFormat::ASTC_2D_8X6}, + {TextureFormat::ASTC_2D_8X6, S, UNORM, UNORM, UNORM, UNORM, PixelFormat::ASTC_2D_8X6_SRGB}, + + {TextureFormat::ASTC_2D_6X5, C, UNORM, UNORM, UNORM, UNORM, PixelFormat::ASTC_2D_6X5}, + {TextureFormat::ASTC_2D_6X5, S, UNORM, UNORM, UNORM, UNORM, PixelFormat::ASTC_2D_6X5_SRGB}, +}}; + +} // Anonymous namespace + +FormatLookupTable::FormatLookupTable() { + table.fill(static_cast<u8>(PixelFormat::Invalid)); + + for (const auto& entry : DefinitionTable) { + table[CalculateIndex(entry.texture_format, entry.is_srgb != 0, entry.red_component, + entry.green_component, entry.blue_component, entry.alpha_component)] = + static_cast<u8>(entry.pixel_format); + } +} + +PixelFormat FormatLookupTable::GetPixelFormat(TextureFormat format, bool is_srgb, + ComponentType red_component, + ComponentType green_component, + ComponentType blue_component, + ComponentType alpha_component) const noexcept { + const auto pixel_format = static_cast<PixelFormat>(table[CalculateIndex( + format, is_srgb, red_component, green_component, blue_component, alpha_component)]); + // [[likely]] + if (pixel_format != PixelFormat::Invalid) { + return pixel_format; + } + UNIMPLEMENTED_MSG("texture format={} srgb={} components={{{} {} {} {}}}", + static_cast<int>(format), is_srgb, static_cast<int>(red_component), + static_cast<int>(green_component), static_cast<int>(blue_component), + static_cast<int>(alpha_component)); + return PixelFormat::ABGR8U; +} + +void FormatLookupTable::Set(TextureFormat format, bool is_srgb, ComponentType red_component, + ComponentType green_component, ComponentType blue_component, + ComponentType alpha_component, PixelFormat pixel_format) {} + +std::size_t FormatLookupTable::CalculateIndex(TextureFormat format, bool is_srgb, + ComponentType red_component, + ComponentType green_component, + ComponentType blue_component, + ComponentType alpha_component) noexcept { + const auto format_index = static_cast<std::size_t>(format); + const auto red_index = static_cast<std::size_t>(red_component); + const auto green_index = static_cast<std::size_t>(red_component); + const auto blue_index = static_cast<std::size_t>(red_component); + const auto alpha_index = static_cast<std::size_t>(red_component); + const std::size_t srgb_index = is_srgb ? 1 : 0; + + return format_index * PerFormat + + srgb_index * PerComponent * PerComponent * PerComponent * PerComponent + + alpha_index * PerComponent * PerComponent * PerComponent + + blue_index * PerComponent * PerComponent + green_index * PerComponent + red_index; +} + +} // namespace VideoCommon diff --git a/src/video_core/texture_cache/format_lookup_table.h b/src/video_core/texture_cache/format_lookup_table.h new file mode 100644 index 000000000..aa77e0a5a --- /dev/null +++ b/src/video_core/texture_cache/format_lookup_table.h @@ -0,0 +1,51 @@ +// Copyright 2019 yuzu Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include <array> +#include <limits> +#include "video_core/surface.h" +#include "video_core/textures/texture.h" + +namespace VideoCommon { + +class FormatLookupTable { +public: + explicit FormatLookupTable(); + + VideoCore::Surface::PixelFormat GetPixelFormat( + Tegra::Texture::TextureFormat format, bool is_srgb, + Tegra::Texture::ComponentType red_component, Tegra::Texture::ComponentType green_component, + Tegra::Texture::ComponentType blue_component, + Tegra::Texture::ComponentType alpha_component) const noexcept; + +private: + static_assert(VideoCore::Surface::MaxPixelFormat <= std::numeric_limits<u8>::max()); + + static constexpr std::size_t NumTextureFormats = 128; + + static constexpr std::size_t PerComponent = 8; + static constexpr std::size_t PerComponents2 = PerComponent * PerComponent; + static constexpr std::size_t PerComponents3 = PerComponents2 * PerComponent; + static constexpr std::size_t PerComponents4 = PerComponents3 * PerComponent; + static constexpr std::size_t PerFormat = PerComponents4 * 2; + + static std::size_t CalculateIndex(Tegra::Texture::TextureFormat format, bool is_srgb, + Tegra::Texture::ComponentType red_component, + Tegra::Texture::ComponentType green_component, + Tegra::Texture::ComponentType blue_component, + Tegra::Texture::ComponentType alpha_component) noexcept; + + void Set(Tegra::Texture::TextureFormat format, bool is_srgb, + Tegra::Texture::ComponentType red_component, + Tegra::Texture::ComponentType green_component, + Tegra::Texture::ComponentType blue_component, + Tegra::Texture::ComponentType alpha_component, + VideoCore::Surface::PixelFormat pixel_format); + + std::array<u8, NumTextureFormats * PerFormat> table; +}; + +} // namespace VideoCommon diff --git a/src/video_core/texture_cache/surface_base.h b/src/video_core/texture_cache/surface_base.h index 1bed82898..5f79bb0aa 100644 --- a/src/video_core/texture_cache/surface_base.h +++ b/src/video_core/texture_cache/surface_base.h @@ -254,16 +254,14 @@ public: if (!layer_mipmap) { return {}; } - const u32 end_layer{layer_mipmap->first}; - const u32 end_mipmap{layer_mipmap->second}; + const auto [end_layer, end_mipmap] = *layer_mipmap; if (layer != end_layer) { if (mipmap == 0 && end_mipmap == 0) { - return GetView(ViewParams(view_params.target, layer, end_layer - layer + 1, 0, 1)); + return GetView(ViewParams(view_params.target, layer, end_layer - layer, 0, 1)); } return {}; } else { - return GetView( - ViewParams(view_params.target, layer, 1, mipmap, end_mipmap - mipmap + 1)); + return GetView(ViewParams(view_params.target, layer, 1, mipmap, end_mipmap - mipmap)); } } @@ -278,8 +276,7 @@ public: if (!layer_mipmap) { return {}; } - const u32 layer{layer_mipmap->first}; - const u32 mipmap{layer_mipmap->second}; + const auto [layer, mipmap] = *layer_mipmap; if (GetMipmapSize(mipmap) != candidate_size) { return EmplaceIrregularView(view_params, view_addr, candidate_size, mipmap, layer); } diff --git a/src/video_core/texture_cache/surface_params.cpp b/src/video_core/texture_cache/surface_params.cpp index 1e4d3fb79..a4f1edd9a 100644 --- a/src/video_core/texture_cache/surface_params.cpp +++ b/src/video_core/texture_cache/surface_params.cpp @@ -2,24 +2,23 @@ // Licensed under GPLv2 or any later version // Refer to the license.txt file included. -#include <map> +#include <algorithm> +#include <string> +#include <tuple> #include "common/alignment.h" #include "common/bit_util.h" #include "core/core.h" #include "video_core/engines/shader_bytecode.h" #include "video_core/surface.h" +#include "video_core/texture_cache/format_lookup_table.h" #include "video_core/texture_cache/surface_params.h" namespace VideoCommon { -using VideoCore::Surface::ComponentTypeFromDepthFormat; -using VideoCore::Surface::ComponentTypeFromRenderTarget; -using VideoCore::Surface::ComponentTypeFromTexture; using VideoCore::Surface::PixelFormat; using VideoCore::Surface::PixelFormatFromDepthFormat; using VideoCore::Surface::PixelFormatFromRenderTargetFormat; -using VideoCore::Surface::PixelFormatFromTextureFormat; using VideoCore::Surface::SurfaceTarget; using VideoCore::Surface::SurfaceTargetFromTextureType; using VideoCore::Surface::SurfaceType; @@ -69,7 +68,8 @@ constexpr u32 GetMipmapSize(bool uncompressed, u32 mip_size, u32 tile) { } // Anonymous namespace -SurfaceParams SurfaceParams::CreateForTexture(const Tegra::Texture::TICEntry& tic, +SurfaceParams SurfaceParams::CreateForTexture(const FormatLookupTable& lookup_table, + const Tegra::Texture::TICEntry& tic, const VideoCommon::Shader::Sampler& entry) { SurfaceParams params; params.is_tiled = tic.IsTiled(); @@ -78,8 +78,8 @@ SurfaceParams SurfaceParams::CreateForTexture(const Tegra::Texture::TICEntry& ti params.block_height = params.is_tiled ? tic.BlockHeight() : 0, params.block_depth = params.is_tiled ? tic.BlockDepth() : 0, params.tile_width_spacing = params.is_tiled ? (1 << tic.tile_width_spacing.Value()) : 1; - params.pixel_format = - PixelFormatFromTextureFormat(tic.format, tic.r_type.Value(), params.srgb_conversion); + params.pixel_format = lookup_table.GetPixelFormat( + tic.format, params.srgb_conversion, tic.r_type, tic.g_type, tic.b_type, tic.a_type); params.type = GetFormatType(params.pixel_format); if (entry.IsShadow() && params.type == SurfaceType::ColorTexture) { switch (params.pixel_format) { @@ -99,7 +99,6 @@ SurfaceParams SurfaceParams::CreateForTexture(const Tegra::Texture::TICEntry& ti } params.type = GetFormatType(params.pixel_format); } - params.component_type = ComponentTypeFromTexture(tic.r_type.Value()); params.type = GetFormatType(params.pixel_format); // TODO: on 1DBuffer we should use the tic info. if (tic.IsBuffer()) { @@ -128,7 +127,8 @@ SurfaceParams SurfaceParams::CreateForTexture(const Tegra::Texture::TICEntry& ti return params; } -SurfaceParams SurfaceParams::CreateForImage(const Tegra::Texture::TICEntry& tic, +SurfaceParams SurfaceParams::CreateForImage(const FormatLookupTable& lookup_table, + const Tegra::Texture::TICEntry& tic, const VideoCommon::Shader::Image& entry) { SurfaceParams params; params.is_tiled = tic.IsTiled(); @@ -137,10 +137,9 @@ SurfaceParams SurfaceParams::CreateForImage(const Tegra::Texture::TICEntry& tic, params.block_height = params.is_tiled ? tic.BlockHeight() : 0, params.block_depth = params.is_tiled ? tic.BlockDepth() : 0, params.tile_width_spacing = params.is_tiled ? (1 << tic.tile_width_spacing.Value()) : 1; - params.pixel_format = - PixelFormatFromTextureFormat(tic.format, tic.r_type.Value(), params.srgb_conversion); + params.pixel_format = lookup_table.GetPixelFormat( + tic.format, params.srgb_conversion, tic.r_type, tic.g_type, tic.b_type, tic.a_type); params.type = GetFormatType(params.pixel_format); - params.component_type = ComponentTypeFromTexture(tic.r_type.Value()); params.type = GetFormatType(params.pixel_format); params.target = ImageTypeToSurfaceTarget(entry.GetType()); // TODO: on 1DBuffer we should use the tic info. @@ -181,7 +180,6 @@ SurfaceParams SurfaceParams::CreateForDepthBuffer( params.block_depth = std::min(block_depth, 5U); params.tile_width_spacing = 1; params.pixel_format = PixelFormatFromDepthFormat(format); - params.component_type = ComponentTypeFromDepthFormat(format); params.type = GetFormatType(params.pixel_format); params.width = zeta_width; params.height = zeta_height; @@ -206,7 +204,6 @@ SurfaceParams SurfaceParams::CreateForFramebuffer(Core::System& system, std::siz params.block_depth = config.memory_layout.block_depth; params.tile_width_spacing = 1; params.pixel_format = PixelFormatFromRenderTargetFormat(config.format); - params.component_type = ComponentTypeFromRenderTarget(config.format); params.type = GetFormatType(params.pixel_format); if (params.is_tiled) { params.pitch = 0; @@ -236,7 +233,6 @@ SurfaceParams SurfaceParams::CreateForFermiCopySurface( params.block_depth = params.is_tiled ? std::min(config.BlockDepth(), 5U) : 0, params.tile_width_spacing = 1; params.pixel_format = PixelFormatFromRenderTargetFormat(config.format); - params.component_type = ComponentTypeFromRenderTarget(config.format); params.type = GetFormatType(params.pixel_format); params.width = config.width; params.height = config.height; @@ -250,6 +246,16 @@ SurfaceParams SurfaceParams::CreateForFermiCopySurface( return params; } +VideoCore::Surface::SurfaceTarget SurfaceParams::ExpectedTarget( + const VideoCommon::Shader::Sampler& entry) { + return TextureTypeToSurfaceTarget(entry.GetType(), entry.IsArray()); +} + +VideoCore::Surface::SurfaceTarget SurfaceParams::ExpectedTarget( + const VideoCommon::Shader::Image& entry) { + return ImageTypeToSurfaceTarget(entry.GetType()); +} + bool SurfaceParams::IsLayered() const { switch (target) { case SurfaceTarget::Texture1DArray: @@ -355,10 +361,10 @@ std::size_t SurfaceParams::GetInnerMipmapMemorySize(u32 level, bool as_host_size bool SurfaceParams::operator==(const SurfaceParams& rhs) const { return std::tie(is_tiled, block_width, block_height, block_depth, tile_width_spacing, width, - height, depth, pitch, num_levels, pixel_format, component_type, type, target) == + height, depth, pitch, num_levels, pixel_format, type, target) == std::tie(rhs.is_tiled, rhs.block_width, rhs.block_height, rhs.block_depth, rhs.tile_width_spacing, rhs.width, rhs.height, rhs.depth, rhs.pitch, - rhs.num_levels, rhs.pixel_format, rhs.component_type, rhs.type, rhs.target); + rhs.num_levels, rhs.pixel_format, rhs.type, rhs.target); } std::string SurfaceParams::TargetName() const { diff --git a/src/video_core/texture_cache/surface_params.h b/src/video_core/texture_cache/surface_params.h index c58e7f8a4..129817ad3 100644 --- a/src/video_core/texture_cache/surface_params.h +++ b/src/video_core/texture_cache/surface_params.h @@ -16,16 +16,20 @@ namespace VideoCommon { +class FormatLookupTable; + using VideoCore::Surface::SurfaceCompression; class SurfaceParams { public: /// Creates SurfaceCachedParams from a texture configuration. - static SurfaceParams CreateForTexture(const Tegra::Texture::TICEntry& tic, + static SurfaceParams CreateForTexture(const FormatLookupTable& lookup_table, + const Tegra::Texture::TICEntry& tic, const VideoCommon::Shader::Sampler& entry); /// Creates SurfaceCachedParams from an image configuration. - static SurfaceParams CreateForImage(const Tegra::Texture::TICEntry& tic, + static SurfaceParams CreateForImage(const FormatLookupTable& lookup_table, + const Tegra::Texture::TICEntry& tic, const VideoCommon::Shader::Image& entry); /// Creates SurfaceCachedParams for a depth buffer configuration. @@ -41,6 +45,14 @@ public: static SurfaceParams CreateForFermiCopySurface( const Tegra::Engines::Fermi2D::Regs::Surface& config); + /// Obtains the texture target from a shader's sampler entry. + static VideoCore::Surface::SurfaceTarget ExpectedTarget( + const VideoCommon::Shader::Sampler& entry); + + /// Obtains the texture target from a shader's sampler entry. + static VideoCore::Surface::SurfaceTarget ExpectedTarget( + const VideoCommon::Shader::Image& entry); + std::size_t Hash() const { return static_cast<std::size_t>( Common::CityHash64(reinterpret_cast<const char*>(this), sizeof(*this))); @@ -248,7 +260,6 @@ public: u32 num_levels; u32 emulated_levels; VideoCore::Surface::PixelFormat pixel_format; - VideoCore::Surface::ComponentType component_type; VideoCore::Surface::SurfaceType type; VideoCore::Surface::SurfaceTarget target; diff --git a/src/video_core/texture_cache/texture_cache.h b/src/video_core/texture_cache/texture_cache.h index 6a92b22d3..02d2e9136 100644 --- a/src/video_core/texture_cache/texture_cache.h +++ b/src/video_core/texture_cache/texture_cache.h @@ -29,6 +29,7 @@ #include "video_core/rasterizer_interface.h" #include "video_core/surface.h" #include "video_core/texture_cache/copy_params.h" +#include "video_core/texture_cache/format_lookup_table.h" #include "video_core/texture_cache/surface_base.h" #include "video_core/texture_cache/surface_params.h" #include "video_core/texture_cache/surface_view.h" @@ -94,10 +95,16 @@ public: std::lock_guard lock{mutex}; const auto gpu_addr{tic.Address()}; if (!gpu_addr) { - return {}; + return GetNullSurface(SurfaceParams::ExpectedTarget(entry)); + } + + const auto host_ptr{system.GPU().MemoryManager().GetPointer(gpu_addr)}; + const auto cache_addr{ToCacheAddr(host_ptr)}; + if (!cache_addr) { + return GetNullSurface(SurfaceParams::ExpectedTarget(entry)); } - const auto params{SurfaceParams::CreateForTexture(tic, entry)}; - const auto [surface, view] = GetSurface(gpu_addr, params, true, false); + const auto params{SurfaceParams::CreateForTexture(format_lookup_table, tic, entry)}; + const auto [surface, view] = GetSurface(gpu_addr, cache_addr, params, true, false); if (guard_samplers) { sampled_textures.push_back(surface); } @@ -109,10 +116,15 @@ public: std::lock_guard lock{mutex}; const auto gpu_addr{tic.Address()}; if (!gpu_addr) { - return {}; + return GetNullSurface(SurfaceParams::ExpectedTarget(entry)); + } + const auto host_ptr{system.GPU().MemoryManager().GetPointer(gpu_addr)}; + const auto cache_addr{ToCacheAddr(host_ptr)}; + if (!cache_addr) { + return GetNullSurface(SurfaceParams::ExpectedTarget(entry)); } - const auto params{SurfaceParams::CreateForImage(tic, entry)}; - const auto [surface, view] = GetSurface(gpu_addr, params, true, false); + const auto params{SurfaceParams::CreateForImage(format_lookup_table, tic, entry)}; + const auto [surface, view] = GetSurface(gpu_addr, cache_addr, params, true, false); if (guard_samplers) { sampled_textures.push_back(surface); } @@ -142,11 +154,17 @@ public: SetEmptyDepthBuffer(); return {}; } + const auto host_ptr{system.GPU().MemoryManager().GetPointer(gpu_addr)}; + const auto cache_addr{ToCacheAddr(host_ptr)}; + if (!cache_addr) { + SetEmptyDepthBuffer(); + return {}; + } const auto depth_params{SurfaceParams::CreateForDepthBuffer( system, regs.zeta_width, regs.zeta_height, regs.zeta.format, regs.zeta.memory_layout.block_width, regs.zeta.memory_layout.block_height, regs.zeta.memory_layout.block_depth, regs.zeta.memory_layout.type)}; - auto surface_view = GetSurface(gpu_addr, depth_params, preserve_contents, true); + auto surface_view = GetSurface(gpu_addr, cache_addr, depth_params, preserve_contents, true); if (depth_buffer.target) depth_buffer.target->MarkAsRenderTarget(false, NO_RT); depth_buffer.target = surface_view.first; @@ -179,8 +197,16 @@ public: return {}; } - auto surface_view = GetSurface(gpu_addr, SurfaceParams::CreateForFramebuffer(system, index), - preserve_contents, true); + const auto host_ptr{system.GPU().MemoryManager().GetPointer(gpu_addr)}; + const auto cache_addr{ToCacheAddr(host_ptr)}; + if (!cache_addr) { + SetEmptyColorBuffer(index); + return {}; + } + + auto surface_view = + GetSurface(gpu_addr, cache_addr, SurfaceParams::CreateForFramebuffer(system, index), + preserve_contents, true); if (render_targets[index].target) render_targets[index].target->MarkAsRenderTarget(false, NO_RT); render_targets[index].target = surface_view.first; @@ -229,8 +255,14 @@ public: const GPUVAddr src_gpu_addr = src_config.Address(); const GPUVAddr dst_gpu_addr = dst_config.Address(); DeduceBestBlit(src_params, dst_params, src_gpu_addr, dst_gpu_addr); - std::pair<TSurface, TView> dst_surface = GetSurface(dst_gpu_addr, dst_params, true, false); - std::pair<TSurface, TView> src_surface = GetSurface(src_gpu_addr, src_params, true, false); + const auto dst_host_ptr{system.GPU().MemoryManager().GetPointer(dst_gpu_addr)}; + const auto dst_cache_addr{ToCacheAddr(dst_host_ptr)}; + const auto src_host_ptr{system.GPU().MemoryManager().GetPointer(src_gpu_addr)}; + const auto src_cache_addr{ToCacheAddr(src_host_ptr)}; + std::pair<TSurface, TView> dst_surface = + GetSurface(dst_gpu_addr, dst_cache_addr, dst_params, true, false); + std::pair<TSurface, TView> src_surface = + GetSurface(src_gpu_addr, src_cache_addr, src_params, true, false); ImageBlit(src_surface.second, dst_surface.second, copy_config); dst_surface.first->MarkAsModified(true, Tick()); } @@ -346,13 +378,6 @@ protected: return new_surface; } - std::pair<TSurface, TView> GetFermiSurface( - const Tegra::Engines::Fermi2D::Regs::Surface& config) { - SurfaceParams params = SurfaceParams::CreateForFermiCopySurface(config); - const GPUVAddr gpu_addr = config.Address(); - return GetSurface(gpu_addr, params, true, false); - } - Core::System& system; private: @@ -485,15 +510,13 @@ private: GetSiblingFormat(cr_params.pixel_format) == params.pixel_format) { SurfaceParams new_params = params; new_params.pixel_format = cr_params.pixel_format; - new_params.component_type = cr_params.component_type; new_params.type = cr_params.type; new_surface = GetUncachedSurface(gpu_addr, new_params); } else { new_surface = GetUncachedSurface(gpu_addr, params); } const auto& final_params = new_surface->GetSurfaceParams(); - if (cr_params.type != final_params.type || - (cr_params.component_type != final_params.component_type)) { + if (cr_params.type != final_params.type) { BufferCopy(current_surface, new_surface); } else { std::vector<CopyParams> bricks = current_surface->BreakDown(final_params); @@ -615,22 +638,9 @@ private: * left blank. * @param is_render Whether or not the surface is a render target. **/ - std::pair<TSurface, TView> GetSurface(const GPUVAddr gpu_addr, const SurfaceParams& params, - bool preserve_contents, bool is_render) { - const auto host_ptr{system.GPU().MemoryManager().GetPointer(gpu_addr)}; - const auto cache_addr{ToCacheAddr(host_ptr)}; - - // Step 0: guarantee a valid surface - if (!cache_addr) { - // Return a null surface if it's invalid - SurfaceParams new_params = params; - new_params.width = 1; - new_params.height = 1; - new_params.depth = 1; - new_params.block_height = 0; - new_params.block_depth = 0; - return InitializeSurface(gpu_addr, new_params, false); - } + std::pair<TSurface, TView> GetSurface(const GPUVAddr gpu_addr, const CacheAddr cache_addr, + const SurfaceParams& params, bool preserve_contents, + bool is_render) { // Step 1 // Check Level 1 Cache for a fast structural match. If candidate surface @@ -795,6 +805,41 @@ private: } /** + * Gets a null surface based on a target texture. + * @param target The target of the null surface. + */ + TView GetNullSurface(SurfaceTarget target) { + const u32 i_target = static_cast<u32>(target); + if (const auto it = invalid_cache.find(i_target); it != invalid_cache.end()) { + return it->second->GetMainView(); + } + SurfaceParams params{}; + params.target = target; + params.is_tiled = false; + params.srgb_conversion = false; + params.is_layered = false; + params.block_width = 0; + params.block_height = 0; + params.block_depth = 0; + params.tile_width_spacing = 1; + params.width = 1; + params.height = 1; + params.depth = 1; + params.pitch = 4; + params.num_levels = 1; + params.emulated_levels = 1; + params.pixel_format = VideoCore::Surface::PixelFormat::RGBA16F; + params.type = VideoCore::Surface::SurfaceType::ColorTexture; + auto surface = CreateSurface(0ULL, params); + invalid_memory.clear(); + invalid_memory.resize(surface->GetHostSizeInBytes(), 0U); + surface->UploadTexture(invalid_memory); + surface->MarkAsModified(false, Tick()); + invalid_cache.emplace(i_target, surface); + return surface->GetMainView(); + } + + /** * Gets the a source and destination starting address and parameters, * and tries to deduce if they are supposed to be depth textures. If so, their * parameters are modified and fixed into so. @@ -835,12 +880,11 @@ private: } } - const auto inherit_format = ([](SurfaceParams& to, TSurface from) { + const auto inherit_format = [](SurfaceParams& to, TSurface from) { const SurfaceParams& params = from->GetSurfaceParams(); to.pixel_format = params.pixel_format; - to.component_type = params.component_type; to.type = params.type; - }); + }; // Now we got the cases where one or both is Depth and the other is not known if (!incomplete_src) { inherit_format(src_params, deduced_src.surface); @@ -956,6 +1000,8 @@ private: VideoCore::RasterizerInterface& rasterizer; + FormatLookupTable format_lookup_table; + u64 ticks{}; // Guards the cache for protection conflicts. @@ -991,6 +1037,11 @@ private: std::vector<TSurface> sampled_textures; + /// This cache stores null surfaces in order to be used as a placeholder + /// for invalid texture calls. + std::unordered_map<u32, TSurface> invalid_cache; + std::vector<u8> invalid_memory; + StagingCache staging_cache; std::recursive_mutex mutex; }; |