Skip to content

Commit

Permalink
VideoCommon: refactor GetTexture into a separate function for creatio…
Browse files Browse the repository at this point in the history
…n, separating the custom texture data path from the game's texture data path
  • Loading branch information
iwubcode committed Mar 19, 2023
1 parent 49b495f commit 93d4fff
Show file tree
Hide file tree
Showing 2 changed files with 118 additions and 100 deletions.
199 changes: 99 additions & 100 deletions Source/Core/VideoCommon/TextureCacheBase.cpp
Expand Up @@ -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"
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -1587,69 +1582,88 @@ RcTcacheEntry TextureCacheBase::GetTexture(const int textureCacheSafetyColorSamp
InvalidateTexture(oldest_entry);
}

std::shared_ptr<HiresTexture> hires_tex;
VideoCommon::CustomTextureData* data = nullptr;
bool has_arbitrary_mipmaps = false;
if (g_ActiveConfig.bHiresTextures)
{
hires_tex = HiresTexture::Search(texture_info);

if (hires_tex)
auto 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;
}
else
{
const u32 texLevels = no_mips ? 1 : texture_info.GetLevelCount();
const u32 expanded_width = texture_info.GetExpandedWidth();
const u32 expanded_height = texture_info.GetExpandedHeight();

// Initialized to null because only software loading uses this buffer
u8* dst_buffer = nullptr;
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 (!hires_tex)
{
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;

Expand Down Expand Up @@ -1690,55 +1704,21 @@ 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);
if (!mip_level)
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 =
Expand All @@ -1755,19 +1735,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()));

Expand All @@ -1776,6 +1774,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;
}

Expand Down
19 changes: 19 additions & 0 deletions Source/Core/VideoCommon/TextureCacheBase.h
Expand Up @@ -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";

Expand Down Expand Up @@ -242,6 +247,14 @@ class TextureCacheBase
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();

Expand Down Expand Up @@ -328,6 +341,12 @@ class TextureCacheBase

void SetBackupConfig(const VideoConfig& config);

RcTcacheEntry 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);

RcTcacheEntry GetXFBFromCache(u32 address, u32 width, u32 height, u32 stride);

RcTcacheEntry ApplyPaletteToEntry(RcTcacheEntry& entry, const u8* palette, TLUTFormat tlutfmt);
Expand Down

0 comments on commit 93d4fff

Please sign in to comment.