VideoCommon: refactor GetTexture into a separate function for creation, separating the custom texture data path from the game's texture data path

This commit is contained in:
iwubcode 2023-03-14 00:10:40 -05:00
parent aaedc2827d
commit e101f7f6ae
2 changed files with 119 additions and 101 deletions

View File

@ -38,6 +38,7 @@
#include "VideoCommon/AbstractStagingTexture.h"
#include "VideoCommon/BPMemory.h"
#include "VideoCommon/FramebufferManager.h"
#include "VideoCommon/GraphicsModSystem/Runtime/CustomTextureData.h"
#include "VideoCommon/GraphicsModSystem/Runtime/FBInfo.h"
#include "VideoCommon/GraphicsModSystem/Runtime/GraphicsModActionData.h"
#include "VideoCommon/GraphicsModSystem/Runtime/GraphicsModManager.h"
@ -1327,12 +1328,6 @@ TCacheEntry* TextureCacheBase::Load(const TextureInfo& texture_info)
RcTcacheEntry TextureCacheBase::GetTexture(const int textureCacheSafetyColorSampleSize,
const TextureInfo& texture_info)
{
u32 expanded_width = texture_info.GetExpandedWidth();
u32 expanded_height = texture_info.GetExpandedHeight();
u32 width = texture_info.GetRawWidth();
u32 height = texture_info.GetRawHeight();
// Hash assigned to texcache entry (also used to generate filenames used for texture dumping and
// custom texture lookup)
u64 base_hash = TEXHASH_INVALID;
@ -1587,69 +1582,89 @@ RcTcacheEntry TextureCacheBase::GetTexture(const int textureCacheSafetyColorSamp
InvalidateTexture(oldest_entry);
}
std::shared_ptr<HiresTexture> hires_tex;
VideoCommon::CustomTextureData* data = nullptr;
bool has_arbitrary_mipmaps = false;
std::shared_ptr<HiresTexture> hires_texture;
if (g_ActiveConfig.bHiresTextures)
{
hires_tex = HiresTexture::Search(texture_info);
if (hires_tex)
hires_texture = HiresTexture::Search(texture_info);
if (hires_texture)
{
const auto& level = hires_tex->GetData().m_levels[0];
if (level.width != width || level.height != height)
{
width = level.width;
height = level.height;
}
expanded_width = level.width;
expanded_height = level.height;
data = &hires_texture->GetData();
has_arbitrary_mipmaps = hires_texture->HasArbitraryMipmaps();
}
}
return CreateTextureEntry(
TextureCreationInfo{base_hash, full_hash, bytes_per_block, palette_size}, texture_info,
textureCacheSafetyColorSampleSize, data, has_arbitrary_mipmaps);
}
RcTcacheEntry TextureCacheBase::CreateTextureEntry(
const TextureCreationInfo& creation_info, const TextureInfo& texture_info,
const int safety_color_sample_size, VideoCommon::CustomTextureData* custom_texture_data,
const bool custom_arbitrary_mipmaps)
{
#ifdef __APPLE__
const bool no_mips = g_ActiveConfig.bNoMipmapping;
#else
const bool no_mips = false;
#endif
// how many levels the allocated texture shall have
const u32 texLevels = no_mips ? 1 :
hires_tex ? (u32)hires_tex->GetData().m_levels.size() :
texture_info.GetLevelCount();
// We can decode on the GPU if it is a supported format and the flag is enabled.
// Currently we don't decode RGBA8 textures from TMEM, as that would require copying from both
// banks, and if we're doing an copy we may as well just do the whole thing on the CPU, since
// there's no conversion between formats. In the future this could be extended with a separate
// shader, however.
const bool decode_on_gpu =
!hires_tex && g_ActiveConfig.UseGPUTextureDecoding() &&
!(texture_info.IsFromTmem() && texture_info.GetTextureFormat() == TextureFormat::RGBA8);
// create the entry/texture
const TextureConfig config(width, height, texLevels, 1, 1,
hires_tex ? hires_tex->GetFormat() : AbstractTextureFormat::RGBA8, 0);
RcTcacheEntry entry = AllocateCacheEntry(config);
if (!entry)
return entry;
ArbitraryMipmapDetector arbitrary_mip_detector;
if (hires_tex)
RcTcacheEntry entry;
if (custom_texture_data && custom_texture_data->m_levels.size() >= 1)
{
const auto& level = hires_tex->GetData().m_levels[0];
entry->texture->Load(0, level.width, level.height, level.row_length, level.data.data(),
level.data.size());
const u32 texLevels = no_mips ? 1 : (u32)custom_texture_data->m_levels.size();
const auto& first_level = custom_texture_data->m_levels[0];
const TextureConfig config(first_level.width, first_level.height, texLevels, 1, 1,
first_level.format, 0);
entry = AllocateCacheEntry(config);
if (!entry) [[unlikely]]
return entry;
for (u32 level_index = 0; level_index != texLevels; ++level_index)
{
const auto& level = custom_texture_data->m_levels[level_index];
entry->texture->Load(level_index, level.width, level.height, level.row_length,
level.data.data(), level.data.size());
}
entry->has_arbitrary_mips = custom_arbitrary_mipmaps;
entry->is_custom_tex = true;
}
// Initialized to null because only software loading uses this buffer
u8* dst_buffer = nullptr;
if (!hires_tex)
else
{
const u32 texLevels = no_mips ? 1 : texture_info.GetLevelCount();
const u32 expanded_width = texture_info.GetExpandedWidth();
const u32 expanded_height = texture_info.GetExpandedHeight();
const u32 width = texture_info.GetRawWidth();
const u32 height = texture_info.GetRawHeight();
const TextureConfig config(width, height, texLevels, 1, 1, AbstractTextureFormat::RGBA8, 0);
entry = AllocateCacheEntry(config);
if (!entry) [[unlikely]]
return entry;
// We can decode on the GPU if it is a supported format and the flag is enabled.
// Currently we don't decode RGBA8 textures from TMEM, as that would require copying from both
// banks, and if we're doing an copy we may as well just do the whole thing on the CPU, since
// there's no conversion between formats. In the future this could be extended with a separate
// shader, however.
const bool decode_on_gpu =
g_ActiveConfig.UseGPUTextureDecoding() &&
!(texture_info.IsFromTmem() && texture_info.GetTextureFormat() == TextureFormat::RGBA8);
ArbitraryMipmapDetector arbitrary_mip_detector;
// Initialized to null because only software loading uses this buffer
u8* dst_buffer = nullptr;
if (!decode_on_gpu ||
!DecodeTextureOnGPU(entry, 0, texture_info.GetData(), texture_info.GetTextureSize(),
texture_info.GetTextureFormat(), width, height, expanded_width,
expanded_height,
bytes_per_block * (expanded_width / texture_info.GetBlockWidth()),
texture_info.GetTlutAddress(), texture_info.GetTlutFormat()))
!DecodeTextureOnGPU(
entry, 0, texture_info.GetData(), texture_info.GetTextureSize(),
texture_info.GetTextureFormat(), width, height, expanded_width, expanded_height,
creation_info.bytes_per_block * (expanded_width / texture_info.GetBlockWidth()),
texture_info.GetTlutAddress(), texture_info.GetTlutFormat()))
{
size_t decoded_texture_size = expanded_width * sizeof(u32) * expanded_height;
@ -1690,42 +1705,7 @@ RcTcacheEntry TextureCacheBase::GetTexture(const int textureCacheSafetyColorSamp
dst_buffer += decoded_texture_size;
}
}
iter = textures_by_address.emplace(texture_info.GetRawAddress(), entry);
if (textureCacheSafetyColorSampleSize == 0 ||
std::max(texture_info.GetTextureSize(), palette_size) <=
(u32)textureCacheSafetyColorSampleSize * 8)
{
entry->textures_by_hash_iter = textures_by_hash.emplace(full_hash, entry);
}
entry->SetGeneralParameters(texture_info.GetRawAddress(), texture_info.GetTextureSize(),
full_format, false);
entry->SetDimensions(texture_info.GetRawWidth(), texture_info.GetRawHeight(),
texture_info.GetLevelCount());
entry->SetHashes(base_hash, full_hash);
entry->is_custom_tex = hires_tex != nullptr;
entry->memory_stride = entry->BytesPerRow();
entry->SetNotCopy();
std::string basename;
if (g_ActiveConfig.bDumpTextures && !hires_tex)
{
basename = HiresTexture::GenBaseName(texture_info, true);
}
if (hires_tex)
{
for (u32 level_index = 1; level_index != texLevels; ++level_index)
{
const auto& level = hires_tex->GetData().m_levels[level_index];
entry->texture->Load(level_index, level.width, level.height, level.row_length,
level.data.data(), level.data.size());
}
}
else
{
for (u32 level = 1; level != texLevels; ++level)
{
auto mip_level = texture_info.GetMipMapLevel(level - 1);
@ -1733,12 +1713,13 @@ RcTcacheEntry TextureCacheBase::GetTexture(const int textureCacheSafetyColorSamp
continue;
if (!decode_on_gpu ||
!DecodeTextureOnGPU(
entry, level, mip_level->GetData(), mip_level->GetTextureSize(),
texture_info.GetTextureFormat(), mip_level->GetRawWidth(), mip_level->GetRawHeight(),
mip_level->GetExpandedWidth(), mip_level->GetExpandedHeight(),
bytes_per_block * (mip_level->GetExpandedWidth() / texture_info.GetBlockWidth()),
texture_info.GetTlutAddress(), texture_info.GetTlutFormat()))
!DecodeTextureOnGPU(entry, level, mip_level->GetData(), mip_level->GetTextureSize(),
texture_info.GetTextureFormat(), mip_level->GetRawWidth(),
mip_level->GetRawHeight(), mip_level->GetExpandedWidth(),
mip_level->GetExpandedHeight(),
creation_info.bytes_per_block *
(mip_level->GetExpandedWidth() / texture_info.GetBlockWidth()),
texture_info.GetTlutAddress(), texture_info.GetTlutFormat()))
{
// No need to call CheckTempSize here, as the whole buffer is preallocated at the beginning
const u32 decoded_mip_size =
@ -1755,19 +1736,37 @@ RcTcacheEntry TextureCacheBase::GetTexture(const int textureCacheSafetyColorSamp
dst_buffer += decoded_mip_size;
}
}
}
entry->has_arbitrary_mips = hires_tex ? hires_tex->HasArbitraryMipmaps() :
arbitrary_mip_detector.HasArbitraryMipmaps(dst_buffer);
entry->has_arbitrary_mips = arbitrary_mip_detector.HasArbitraryMipmaps(dst_buffer);
if (g_ActiveConfig.bDumpTextures && !hires_tex)
{
for (u32 level = 0; level < texLevels; ++level)
if (g_ActiveConfig.bDumpTextures)
{
DumpTexture(entry, basename, level, entry->has_arbitrary_mips);
const std::string basename = HiresTexture::GenBaseName(texture_info, true);
for (u32 level = 0; level < texLevels; ++level)
{
DumpTexture(entry, basename, level, entry->has_arbitrary_mips);
}
}
}
const auto iter = textures_by_address.emplace(texture_info.GetRawAddress(), entry);
if (safety_color_sample_size == 0 ||
std::max(texture_info.GetTextureSize(), creation_info.palette_size) <=
(u32)safety_color_sample_size * 8)
{
entry->textures_by_hash_iter = textures_by_hash.emplace(creation_info.full_hash, entry);
}
const TextureAndTLUTFormat full_format(texture_info.GetTextureFormat(),
texture_info.GetTlutFormat());
entry->SetGeneralParameters(texture_info.GetRawAddress(), texture_info.GetTextureSize(),
full_format, false);
entry->SetDimensions(texture_info.GetRawWidth(), texture_info.GetRawHeight(),
texture_info.GetLevelCount());
entry->SetHashes(creation_info.base_hash, creation_info.full_hash);
entry->memory_stride = entry->BytesPerRow();
entry->SetNotCopy();
INCSTAT(g_stats.num_textures_uploaded);
SETSTAT(g_stats.num_textures_alive, static_cast<int>(textures_by_address.size()));
@ -1776,6 +1775,7 @@ RcTcacheEntry TextureCacheBase::GetTexture(const int textureCacheSafetyColorSamp
// This should only be needed if the texture was updated, or used GPU decoding.
entry->texture->FinishedRendering();
return entry;
}

View File

@ -32,6 +32,11 @@ class AbstractStagingTexture;
class PointerWrap;
struct VideoConfig;
namespace VideoCommon
{
class CustomTextureData;
}
constexpr std::string_view EFB_DUMP_PREFIX = "efb1";
constexpr std::string_view XFB_DUMP_PREFIX = "xfb1";
@ -242,6 +247,14 @@ public:
TexPoolEntry(std::unique_ptr<AbstractTexture> tex, std::unique_ptr<AbstractFramebuffer> fb);
};
struct TextureCreationInfo
{
u64 base_hash;
u64 full_hash;
u32 bytes_per_block;
u32 palette_size;
};
TextureCacheBase();
virtual ~TextureCacheBase();
@ -328,6 +341,11 @@ private:
void SetBackupConfig(const VideoConfig& config);
RcTcacheEntry CreateTextureEntry(const TextureCreationInfo& creation_info,
const TextureInfo& texture_info, int safety_color_sample_size,
VideoCommon::CustomTextureData* custom_texture_data,
bool custom_arbitrary_mipmaps);
RcTcacheEntry GetXFBFromCache(u32 address, u32 width, u32 height, u32 stride);
RcTcacheEntry ApplyPaletteToEntry(RcTcacheEntry& entry, const u8* palette, TLUTFormat tlutfmt);