mirror of https://github.com/PCSX2/pcsx2.git
GS: Show VRAM usage in statistics
This commit is contained in:
parent
e76afee12d
commit
9d50d44c99
|
@ -180,9 +180,14 @@ void ImGuiManager::DrawPerformanceOverlay()
|
|||
|
||||
if (GSConfig.OsdShowGSStats)
|
||||
{
|
||||
std::string gs_stats;
|
||||
GSgetStats(gs_stats);
|
||||
DRAW_LINE(fixed_font, gs_stats.c_str(), IM_COL32(255, 255, 255, 255));
|
||||
text.clear();
|
||||
GSgetStats(text);
|
||||
DRAW_LINE(fixed_font, text.c_str(), IM_COL32(255, 255, 255, 255));
|
||||
|
||||
text.clear();
|
||||
GSgetMemoryStats(text);
|
||||
if (!text.empty())
|
||||
DRAW_LINE(fixed_font, text.c_str(), IM_COL32(255, 255, 255, 255));
|
||||
}
|
||||
|
||||
if (GSConfig.OsdShowResolution)
|
||||
|
|
|
@ -40,6 +40,8 @@
|
|||
#include "pcsx2/Frontend/InputManager.h"
|
||||
#include "pcsx2/GS.h"
|
||||
|
||||
#include "fmt/format.h"
|
||||
|
||||
#ifdef ENABLE_OPENGL
|
||||
#include "Renderers/OpenGL/GSDeviceOGL.h"
|
||||
#endif
|
||||
|
@ -588,14 +590,12 @@ void GSgetInternalResolution(int* width, int* height)
|
|||
void GSgetStats(std::string& info)
|
||||
{
|
||||
GSPerfMon& pm = g_perfmon;
|
||||
|
||||
const char* api_name = HostDisplay::RenderAPIToString(s_render_api);
|
||||
|
||||
if (GSConfig.Renderer == GSRendererType::SW)
|
||||
{
|
||||
const double fps = GetVerticalFrequency();
|
||||
const double fillrate = pm.Get(GSPerfMon::Fillrate);
|
||||
info = StringUtil::StdStringFromFormat("%s SW | %d S | %d P | %d D | %.2f U | %.2f D | %.2f mpps",
|
||||
fmt::format_to(std::back_inserter(info), "{} SW | {} S | {} P | {} D | {:.2f} U | {:.2f} D | {:.2f} mpps",
|
||||
api_name,
|
||||
(int)pm.Get(GSPerfMon::SyncPoint),
|
||||
(int)pm.Get(GSPerfMon::Prim),
|
||||
|
@ -606,35 +606,49 @@ void GSgetStats(std::string& info)
|
|||
}
|
||||
else if (GSConfig.Renderer == GSRendererType::Null)
|
||||
{
|
||||
info = StringUtil::StdStringFromFormat("%s Null", api_name);
|
||||
fmt::format_to(std::back_inserter(info), "{} Null", api_name);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (GSConfig.TexturePreloading == TexturePreloadingLevel::Full)
|
||||
{
|
||||
info = StringUtil::StdStringFromFormat("%s HW | HC: %d MB | %d P | %d D | %d DC | %d B | %d RB | %d TC | %d TU",
|
||||
api_name,
|
||||
(int)std::ceil(GSRendererHW::GetInstance()->GetTextureCache()->GetTotalHashCacheMemoryUsage() / 1048576.0f),
|
||||
(int)pm.Get(GSPerfMon::Prim),
|
||||
(int)pm.Get(GSPerfMon::Draw),
|
||||
(int)std::ceil(pm.Get(GSPerfMon::DrawCalls)),
|
||||
(int)std::ceil(pm.Get(GSPerfMon::Barriers)),
|
||||
(int)std::ceil(pm.Get(GSPerfMon::Readbacks)),
|
||||
(int)std::ceil(pm.Get(GSPerfMon::TextureCopies)),
|
||||
(int)std::ceil(pm.Get(GSPerfMon::TextureUploads)));
|
||||
}
|
||||
else
|
||||
{
|
||||
info = StringUtil::StdStringFromFormat("%s HW | %d P | %d D | %d DC | %d B | %d RB | %d TC | %d TU",
|
||||
api_name,
|
||||
(int)pm.Get(GSPerfMon::Prim),
|
||||
(int)pm.Get(GSPerfMon::Draw),
|
||||
(int)std::ceil(pm.Get(GSPerfMon::DrawCalls)),
|
||||
(int)std::ceil(pm.Get(GSPerfMon::Barriers)),
|
||||
(int)std::ceil(pm.Get(GSPerfMon::Readbacks)),
|
||||
(int)std::ceil(pm.Get(GSPerfMon::TextureCopies)),
|
||||
(int)std::ceil(pm.Get(GSPerfMon::TextureUploads)));
|
||||
}
|
||||
fmt::format_to(std::back_inserter(info), "{} HW | {} P | {} D | {} DC | {} B | {} RB | {} TC | {} TU",
|
||||
api_name,
|
||||
(int)pm.Get(GSPerfMon::Prim),
|
||||
(int)pm.Get(GSPerfMon::Draw),
|
||||
(int)std::ceil(pm.Get(GSPerfMon::DrawCalls)),
|
||||
(int)std::ceil(pm.Get(GSPerfMon::Barriers)),
|
||||
(int)std::ceil(pm.Get(GSPerfMon::Readbacks)),
|
||||
(int)std::ceil(pm.Get(GSPerfMon::TextureCopies)),
|
||||
(int)std::ceil(pm.Get(GSPerfMon::TextureUploads)));
|
||||
}
|
||||
}
|
||||
|
||||
void GSgetMemoryStats(std::string& info)
|
||||
{
|
||||
if (GSConfig.Renderer == GSRendererType::SW || GSConfig.Renderer == GSRendererType::Null)
|
||||
return;
|
||||
|
||||
const u64 targets = GSRendererHW::GetInstance()->GetTextureCache()->GetTargetMemoryUsage();
|
||||
const u64 sources = GSRendererHW::GetInstance()->GetTextureCache()->GetSourceMemoryUsage();
|
||||
const u64 hashcache = GSRendererHW::GetInstance()->GetTextureCache()->GetHashCacheMemoryUsage();
|
||||
const u64 pool = g_gs_device->GetPoolMemoryUsage();
|
||||
const u64 total = targets + sources + hashcache + pool;
|
||||
|
||||
if (GSConfig.TexturePreloading == TexturePreloadingLevel::Full)
|
||||
{
|
||||
fmt::format_to(std::back_inserter(info), "VRAM: {} MB | T: {} MB | S: {} MB | H: {} MB | P: {} MB",
|
||||
(int)std::ceil(total / 1048576.0f),
|
||||
(int)std::ceil(targets / 1048576.0f),
|
||||
(int)std::ceil(sources / 1048576.0f),
|
||||
(int)std::ceil(hashcache / 1048576.0f),
|
||||
(int)std::ceil(pool / 1048576.0f));
|
||||
}
|
||||
else
|
||||
{
|
||||
fmt::format_to(std::back_inserter(info), "VRAM: {} MB | T: {} MB | S: {} MB | P: {} MB",
|
||||
(int)std::ceil(total / 1048576.0f),
|
||||
(int)std::ceil(targets / 1048576.0f),
|
||||
(int)std::ceil(sources / 1048576.0f),
|
||||
(int)std::ceil(pool / 1048576.0f));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -81,6 +81,7 @@ void GSsetGameCRC(u32 crc);
|
|||
GSVideoMode GSgetDisplayMode();
|
||||
void GSgetInternalResolution(int* width, int* height);
|
||||
void GSgetStats(std::string& info);
|
||||
void GSgetMemoryStats(std::string& info);
|
||||
void GSgetTitleStats(std::string& info);
|
||||
|
||||
/// Converts window position to normalized display coordinates (0..1). A value less than 0 or greater than 1 is
|
||||
|
|
|
@ -126,6 +126,7 @@ GSTexture* GSDevice::FetchSurface(GSTexture::Type type, int width, int height, i
|
|||
{
|
||||
if (!prefer_new_texture || t->last_frame_used != m_frame)
|
||||
{
|
||||
m_pool_memory_usage -= t->GetMemUsage();
|
||||
m_pool.erase(i);
|
||||
break;
|
||||
}
|
||||
|
@ -143,6 +144,7 @@ GSTexture* GSDevice::FetchSurface(GSTexture::Type type, int width, int height, i
|
|||
if (m_pool.size() >= MAX_POOLED_TEXTURES && fallback != m_pool.end())
|
||||
{
|
||||
t = *fallback;
|
||||
m_pool_memory_usage -= t->GetMemUsage();
|
||||
m_pool.erase(fallback);
|
||||
}
|
||||
else
|
||||
|
@ -185,19 +187,6 @@ std::unique_ptr<GSDownloadTexture> GSDevice::CreateDownloadTexture(u32 width, u3
|
|||
return {};
|
||||
}
|
||||
|
||||
void GSDevice::PrintMemoryUsage()
|
||||
{
|
||||
#ifdef ENABLE_OGL_DEBUG
|
||||
u32 pool = 0;
|
||||
for (auto t : m_pool)
|
||||
{
|
||||
if (t)
|
||||
pool += t->GetMemUsage();
|
||||
}
|
||||
GL_PERF("MEM: Surface Pool %dMB", pool >> 20u);
|
||||
#endif
|
||||
}
|
||||
|
||||
void GSDevice::EndScene()
|
||||
{
|
||||
m_vertex.start += m_vertex.count;
|
||||
|
@ -208,20 +197,22 @@ void GSDevice::EndScene()
|
|||
|
||||
void GSDevice::Recycle(GSTexture* t)
|
||||
{
|
||||
if (t)
|
||||
if (!t)
|
||||
return;
|
||||
|
||||
t->last_frame_used = m_frame;
|
||||
|
||||
m_pool.push_front(t);
|
||||
m_pool_memory_usage += t->GetMemUsage();
|
||||
|
||||
//printf("%d\n",m_pool.size());
|
||||
|
||||
while (m_pool.size() > MAX_POOLED_TEXTURES)
|
||||
{
|
||||
t->last_frame_used = m_frame;
|
||||
m_pool_memory_usage -= m_pool.back()->GetMemUsage();
|
||||
delete m_pool.back();
|
||||
|
||||
m_pool.push_front(t);
|
||||
|
||||
//printf("%d\n",m_pool.size());
|
||||
|
||||
while (m_pool.size() > MAX_POOLED_TEXTURES)
|
||||
{
|
||||
delete m_pool.back();
|
||||
|
||||
m_pool.pop_back();
|
||||
}
|
||||
m_pool.pop_back();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -231,6 +222,7 @@ void GSDevice::AgePool()
|
|||
|
||||
while (m_pool.size() > 40 && m_frame - m_pool.back()->last_frame_used > 10)
|
||||
{
|
||||
m_pool_memory_usage -= m_pool.back()->GetMemUsage();
|
||||
delete m_pool.back();
|
||||
|
||||
m_pool.pop_back();
|
||||
|
@ -242,6 +234,7 @@ void GSDevice::PurgePool()
|
|||
for (auto t : m_pool)
|
||||
delete t;
|
||||
m_pool.clear();
|
||||
m_pool_memory_usage = 0;
|
||||
}
|
||||
|
||||
void GSDevice::ClearSamplerCache()
|
||||
|
|
|
@ -724,6 +724,7 @@ public:
|
|||
|
||||
private:
|
||||
FastList<GSTexture*> m_pool;
|
||||
u64 m_pool_memory_usage = 0;
|
||||
static const std::array<HWBlend, 3*3*3*3> m_blendMap;
|
||||
static const std::array<u8, 16> m_replaceDualSrcBlendMap;
|
||||
|
||||
|
@ -772,6 +773,7 @@ public:
|
|||
virtual ~GSDevice();
|
||||
|
||||
__fi unsigned int GetFrameNumber() const { return m_frame; }
|
||||
__fi u64 GetPoolMemoryUsage() const { return m_pool_memory_usage; }
|
||||
|
||||
void Recycle(GSTexture* t);
|
||||
|
||||
|
@ -855,8 +857,6 @@ public:
|
|||
|
||||
virtual void ClearSamplerCache();
|
||||
|
||||
virtual void PrintMemoryUsage();
|
||||
|
||||
__fi static constexpr bool IsDualSourceBlendFactor(u8 factor)
|
||||
{
|
||||
return (factor == SRC1_ALPHA || factor == INV_SRC1_ALPHA
|
||||
|
|
|
@ -222,9 +222,6 @@ void GSRendererHW::VSync(u32 field, bool registers_written)
|
|||
GSConfig.TexturePreloading = TexturePreloadingLevel::Partial;
|
||||
}
|
||||
|
||||
m_tc->PrintMemoryUsage();
|
||||
g_gs_device->PrintMemoryUsage();
|
||||
|
||||
m_skip = 0;
|
||||
m_skip_offset = 0;
|
||||
}
|
||||
|
|
|
@ -24,14 +24,14 @@
|
|||
#include "common/Align.h"
|
||||
#include "common/HashCombine.h"
|
||||
|
||||
u8* GSTextureCache::m_temp;
|
||||
static u8* s_unswizzle_buffer;
|
||||
|
||||
GSTextureCache::GSTextureCache()
|
||||
{
|
||||
// In theory 4MB is enough but 9MB is safer for overflow (8MB
|
||||
// isn't enough in custom resolution)
|
||||
// Test: onimusha 3 PAL 60Hz
|
||||
m_temp = (u8*)_aligned_malloc(9 * 1024 * 1024, 32);
|
||||
s_unswizzle_buffer = (u8*)_aligned_malloc(9 * 1024 * 1024, 32);
|
||||
|
||||
m_surface_offset_cache.reserve(S_SURFACE_OFFSET_CACHE_MAX_SIZE);
|
||||
}
|
||||
|
@ -44,7 +44,7 @@ GSTextureCache::~GSTextureCache()
|
|||
|
||||
m_surface_offset_cache.clear();
|
||||
|
||||
_aligned_free(m_temp);
|
||||
_aligned_free(s_unswizzle_buffer);
|
||||
}
|
||||
|
||||
void GSTextureCache::RemovePartial()
|
||||
|
@ -74,12 +74,16 @@ void GSTextureCache::RemoveAll()
|
|||
|
||||
for (auto it : m_hash_cache)
|
||||
g_gs_device->Recycle(it.second.texture);
|
||||
|
||||
m_hash_cache.clear();
|
||||
m_hash_cache_memory_usage = 0;
|
||||
m_hash_cache_replacement_memory_usage = 0;
|
||||
|
||||
m_palette_map.Clear();
|
||||
m_target_heights.clear();
|
||||
|
||||
m_source_memory_usage = 0;
|
||||
m_target_memory_usage = 0;
|
||||
}
|
||||
|
||||
void GSTextureCache::AddDirtyRectTarget(Target* target, GSVector4i rect, u32 psm, u32 bw)
|
||||
|
@ -589,6 +593,7 @@ GSTextureCache::Target* GSTextureCache::LookupTarget(const GIFRegTEX0& TEX0, con
|
|||
GSTexture* tex = type == RenderTarget ? g_gs_device->CreateRenderTarget(new_size.x, new_size.y, GSTexture::Format::Color, clear) :
|
||||
g_gs_device->CreateDepthStencil(new_size.x, new_size.y, GSTexture::Format::DepthStencil, clear);
|
||||
g_gs_device->StretchRect(dst->m_texture, sRect, tex, dRect, (type == RenderTarget) ? ShaderConvert::COPY : ShaderConvert::DEPTH_COPY, false);
|
||||
m_target_memory_usage = (m_target_memory_usage - dst->m_texture->GetMemUsage()) + tex->GetMemUsage();
|
||||
g_gs_device->Recycle(dst->m_texture);
|
||||
tex->SetScale(new_s);
|
||||
dst->m_texture = tex;
|
||||
|
@ -743,6 +748,7 @@ void GSTextureCache::ScaleTargetForDisplay(Target* t, const GIFRegTEX0& dispfb,
|
|||
|
||||
// Fill the new texture with the old data, and discard the old texture.
|
||||
g_gs_device->StretchRect(old_texture, new_texture, GSVector4(old_texture->GetSize()).zwxy(), ShaderConvert::COPY, false);
|
||||
m_target_memory_usage = (m_target_memory_usage - old_texture->GetMemUsage()) + new_texture->GetMemUsage();
|
||||
g_gs_device->Recycle(old_texture);
|
||||
t->m_texture = new_texture;
|
||||
|
||||
|
@ -1803,6 +1809,7 @@ GSTextureCache::Source* GSTextureCache::CreateSource(const GIFRegTEX0& TEX0, con
|
|||
GSTexture* dTex = outside_target ?
|
||||
g_gs_device->CreateRenderTarget(w, h, GSTexture::Format::Color, true) :
|
||||
g_gs_device->CreateTexture(w, h, tlevels, GSTexture::Format::Color, true);
|
||||
m_source_memory_usage += dTex->GetMemUsage();
|
||||
|
||||
// copy the rt in
|
||||
const GSVector4i area(GSVector4i(x, y, x + w, y + h).rintersect(GSVector4i(sTex->GetSize()).zwxy()));
|
||||
|
@ -2036,7 +2043,8 @@ GSTextureCache::Source* GSTextureCache::CreateSource(const GIFRegTEX0& TEX0, con
|
|||
GSTexture* dTex = use_texture ?
|
||||
g_gs_device->CreateTexture(w, h, 1, GSTexture::Format::Color, true) :
|
||||
g_gs_device->CreateRenderTarget(w, h, GSTexture::Format::Color, false);
|
||||
src->m_texture = dTex;
|
||||
dTex->SetScale(scale);
|
||||
m_source_memory_usage += dTex->GetMemUsage();
|
||||
|
||||
if (use_texture)
|
||||
{
|
||||
|
@ -2051,10 +2059,7 @@ GSTextureCache::Source* GSTextureCache::CreateSource(const GIFRegTEX0& TEX0, con
|
|||
g_gs_device->StretchRect(sTex, sRectF, dTex, GSVector4(destX, destY, w, h), shader, false);
|
||||
}
|
||||
|
||||
if (src->m_texture)
|
||||
src->m_texture->SetScale(scale);
|
||||
else
|
||||
ASSERT(0);
|
||||
src->m_texture = dTex;
|
||||
}
|
||||
|
||||
// GH: by default (m_paltex == 0) GS converts texture to the 32 bit format
|
||||
|
@ -2101,6 +2106,7 @@ GSTextureCache::Source* GSTextureCache::CreateSource(const GIFRegTEX0& TEX0, con
|
|||
else if (paltex)
|
||||
{
|
||||
src->m_texture = g_gs_device->CreateTexture(tw, th, tlevels, GSTexture::Format::UNorm8);
|
||||
m_source_memory_usage += src->m_texture->GetMemUsage();
|
||||
if (gpu_clut)
|
||||
AttachPaletteToSource(src, gpu_clut);
|
||||
else
|
||||
|
@ -2109,6 +2115,7 @@ GSTextureCache::Source* GSTextureCache::CreateSource(const GIFRegTEX0& TEX0, con
|
|||
else
|
||||
{
|
||||
src->m_texture = g_gs_device->CreateTexture(tw, th, tlevels, GSTexture::Format::Color);
|
||||
m_source_memory_usage += src->m_texture->GetMemUsage();
|
||||
if (gpu_clut)
|
||||
AttachPaletteToSource(src, gpu_clut);
|
||||
else if (psm.pal > 0)
|
||||
|
@ -2286,6 +2293,7 @@ GSTextureCache::Target* GSTextureCache::CreateTarget(const GIFRegTEX0& TEX0, int
|
|||
}
|
||||
|
||||
t->m_texture->SetScale(static_cast<GSRendererHW*>(g_gs_renderer.get())->GetTextureScaleFactor());
|
||||
m_target_memory_usage += t->m_texture->GetMemUsage();
|
||||
|
||||
m_dst[type].push_front(t);
|
||||
|
||||
|
@ -2486,38 +2494,6 @@ void GSTextureCache::Read(Source* t, const GSVector4i& r)
|
|||
}
|
||||
}
|
||||
|
||||
void GSTextureCache::PrintMemoryUsage()
|
||||
{
|
||||
#ifdef ENABLE_OGL_DEBUG
|
||||
u32 tex = 0;
|
||||
u32 tex_rt = 0;
|
||||
u32 rt = 0;
|
||||
u32 dss = 0;
|
||||
for (auto s : m_src.m_surfaces)
|
||||
{
|
||||
if (s && !s->m_shared_texture)
|
||||
{
|
||||
if (s->m_target)
|
||||
tex_rt += s->m_texture->GetMemUsage();
|
||||
else
|
||||
tex += s->m_texture->GetMemUsage();
|
||||
}
|
||||
}
|
||||
for (auto t : m_dst[RenderTarget])
|
||||
{
|
||||
if (t)
|
||||
rt += t->m_texture->GetMemUsage();
|
||||
}
|
||||
for (auto t : m_dst[DepthStencil])
|
||||
{
|
||||
if (t)
|
||||
dss += t->m_texture->GetMemUsage();
|
||||
}
|
||||
|
||||
GL_PERF("MEM: RO Tex %dMB. RW Tex %dMB. Target %dMB. Depth %dMB", tex >> 20u, tex_rt >> 20u, rt >> 20u, dss >> 20u);
|
||||
#endif
|
||||
}
|
||||
|
||||
// GSTextureCache::Surface
|
||||
|
||||
GSTextureCache::Surface::Surface()
|
||||
|
@ -2531,13 +2507,7 @@ GSTextureCache::Surface::Surface()
|
|||
m_TEX0.TBP0 = GSTextureCache::MAX_BP;
|
||||
}
|
||||
|
||||
GSTextureCache::Surface::~Surface()
|
||||
{
|
||||
// Shared textures are pointers copy. Therefore no allocation
|
||||
// to recycle.
|
||||
if (!m_shared_texture && !m_from_hash_cache && m_texture)
|
||||
g_gs_device->Recycle(m_texture);
|
||||
}
|
||||
GSTextureCache::Surface::~Surface() = default;
|
||||
|
||||
void GSTextureCache::Surface::UpdateAge()
|
||||
{
|
||||
|
@ -2560,62 +2530,6 @@ bool GSTextureCache::Surface::Overlaps(u32 bp, u32 bw, u32 psm, const GSVector4i
|
|||
return overlap;
|
||||
}
|
||||
|
||||
bool GSTextureCache::Surface::ResizeTexture(int new_width, int new_height, bool recycle_old)
|
||||
{
|
||||
return ResizeTexture(new_width, new_height, m_texture->GetScale(), recycle_old);
|
||||
}
|
||||
|
||||
bool GSTextureCache::Surface::ResizeTexture(int new_width, int new_height, GSVector2 new_scale, bool recycle_old)
|
||||
{
|
||||
const int width = m_texture->GetWidth();
|
||||
const int height = m_texture->GetHeight();
|
||||
if (width == new_width && height == new_height)
|
||||
return true;
|
||||
|
||||
// These exceptions *really* need to get lost. This gets called outside of draws, which just crashes
|
||||
// when it tries to propogate the exception back.
|
||||
const bool clear = (new_width > width || new_height > height);
|
||||
GSTexture* tex = nullptr;
|
||||
try
|
||||
{
|
||||
tex = m_texture->IsDepthStencil() ?
|
||||
g_gs_device->CreateDepthStencil(new_width, new_height, m_texture->GetFormat(), clear) :
|
||||
g_gs_device->CreateRenderTarget(new_width, new_height, m_texture->GetFormat(), clear);
|
||||
}
|
||||
catch (const std::bad_alloc&)
|
||||
{
|
||||
}
|
||||
|
||||
if (!tex)
|
||||
{
|
||||
Console.Error("(ResizeTexture) Failed to allocate %dx%d texture from %dx%d texture", new_width, new_height, width, height);
|
||||
return false;
|
||||
}
|
||||
|
||||
tex->SetScale(new_scale);
|
||||
|
||||
const GSVector4i rc(0, 0, std::min(width, new_width), std::min(height, new_height));
|
||||
if (tex->IsDepthStencil())
|
||||
{
|
||||
// Can't do partial copies in DirectX for depth textures, and it's probably not ideal in other
|
||||
// APIs either. So use a fullscreen quad setting depth instead.
|
||||
g_gs_device->StretchRect(m_texture, tex, GSVector4(rc), ShaderConvert::DEPTH_COPY, false);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Fast memcpy()-like path for color targets.
|
||||
g_gs_device->CopyRect(m_texture, tex, rc, 0, 0);
|
||||
}
|
||||
|
||||
if (recycle_old)
|
||||
g_gs_device->Recycle(m_texture);
|
||||
else
|
||||
delete m_texture;
|
||||
|
||||
m_texture = tex;
|
||||
return true;
|
||||
}
|
||||
|
||||
// GSTextureCache::Source
|
||||
|
||||
GSTextureCache::Source::Source(const GIFRegTEX0& TEX0, const GIFRegTEXA& TEXA, bool dummy_container)
|
||||
|
@ -2662,6 +2576,14 @@ GSTextureCache::Source::Source(const GIFRegTEX0& TEX0, const GIFRegTEXA& TEXA, b
|
|||
GSTextureCache::Source::~Source()
|
||||
{
|
||||
_aligned_free(m_write.rect);
|
||||
|
||||
// Shared textures are pointers copy. Therefore no allocation
|
||||
// to recycle.
|
||||
if (!m_shared_texture && !m_from_hash_cache && m_texture)
|
||||
{
|
||||
GSRendererHW::GetInstance()->GetTextureCache()->m_source_memory_usage -= m_texture->GetMemUsage();
|
||||
g_gs_device->Recycle(m_texture);
|
||||
}
|
||||
}
|
||||
|
||||
void GSTextureCache::Source::Update(const GSVector4i& rect, int level)
|
||||
|
@ -2838,7 +2760,7 @@ void GSTextureCache::Source::Flush(u32 count, int layer)
|
|||
rtx = psm.rtxP;
|
||||
}
|
||||
|
||||
u8* buff = m_temp;
|
||||
u8* buff = s_unswizzle_buffer;
|
||||
|
||||
for (u32 i = 0; i < count; i++)
|
||||
{
|
||||
|
@ -2916,6 +2838,17 @@ GSTextureCache::Target::Target(const GIFRegTEX0& TEX0, const bool depth_supporte
|
|||
m_dirty_alpha = GSLocalMemory::m_psm[TEX0.PSM].trbpp != 24;
|
||||
}
|
||||
|
||||
GSTextureCache::Target::~Target()
|
||||
{
|
||||
// Targets should never be shared.
|
||||
pxAssert(!m_shared_texture);
|
||||
if (m_texture)
|
||||
{
|
||||
GSRendererHW::GetInstance()->GetTextureCache()->m_target_memory_usage -= m_texture->GetMemUsage();
|
||||
g_gs_device->Recycle(m_texture);
|
||||
}
|
||||
}
|
||||
|
||||
void GSTextureCache::Target::Update(bool reset_age)
|
||||
{
|
||||
if(reset_age)
|
||||
|
@ -2982,9 +2915,9 @@ void GSTextureCache::Target::Update(bool reset_age)
|
|||
{
|
||||
int pitch = ((w + 3) & ~3) * 4;
|
||||
|
||||
g_gs_renderer->m_mem.ReadTexture(off, r, m_temp, pitch, TEXA);
|
||||
g_gs_renderer->m_mem.ReadTexture(off, r, s_unswizzle_buffer, pitch, TEXA);
|
||||
|
||||
t->Update(r.rsize(), m_temp, pitch);
|
||||
t->Update(r.rsize(), s_unswizzle_buffer, pitch);
|
||||
}
|
||||
|
||||
// m_renderer->m_perfmon.Put(GSPerfMon::Unswizzle, w * h * 4);
|
||||
|
@ -3042,6 +2975,66 @@ void GSTextureCache::Target::UpdateValidity(const GSVector4i& rect)
|
|||
// GL_CACHE("UpdateValidity (0x%x->0x%x) from R:%d,%d Valid: %d,%d", m_TEX0.TBP0, m_end_block, rect.z, rect.w, m_valid.z, m_valid.w);
|
||||
}
|
||||
|
||||
|
||||
bool GSTextureCache::Target::ResizeTexture(int new_width, int new_height, bool recycle_old)
|
||||
{
|
||||
return ResizeTexture(new_width, new_height, m_texture->GetScale(), recycle_old);
|
||||
}
|
||||
|
||||
bool GSTextureCache::Target::ResizeTexture(int new_width, int new_height, GSVector2 new_scale, bool recycle_old)
|
||||
{
|
||||
const int width = m_texture->GetWidth();
|
||||
const int height = m_texture->GetHeight();
|
||||
if (width == new_width && height == new_height)
|
||||
return true;
|
||||
|
||||
// These exceptions *really* need to get lost. This gets called outside of draws, which just crashes
|
||||
// when it tries to propogate the exception back.
|
||||
const bool clear = (new_width > width || new_height > height);
|
||||
GSTexture* tex = nullptr;
|
||||
try
|
||||
{
|
||||
tex = m_texture->IsDepthStencil() ?
|
||||
g_gs_device->CreateDepthStencil(new_width, new_height, m_texture->GetFormat(), clear) :
|
||||
g_gs_device->CreateRenderTarget(new_width, new_height, m_texture->GetFormat(), clear);
|
||||
}
|
||||
catch (const std::bad_alloc&)
|
||||
{
|
||||
}
|
||||
|
||||
if (!tex)
|
||||
{
|
||||
Console.Error("(ResizeTexture) Failed to allocate %dx%d texture from %dx%d texture", new_width, new_height, width, height);
|
||||
return false;
|
||||
}
|
||||
|
||||
tex->SetScale(new_scale);
|
||||
|
||||
const GSVector4i rc(0, 0, std::min(width, new_width), std::min(height, new_height));
|
||||
if (tex->IsDepthStencil())
|
||||
{
|
||||
// Can't do partial copies in DirectX for depth textures, and it's probably not ideal in other
|
||||
// APIs either. So use a fullscreen quad setting depth instead.
|
||||
g_gs_device->StretchRect(m_texture, tex, GSVector4(rc), ShaderConvert::DEPTH_COPY, false);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Fast memcpy()-like path for color targets.
|
||||
g_gs_device->CopyRect(m_texture, tex, rc, 0, 0);
|
||||
}
|
||||
|
||||
GSTextureCache* tc = GSRendererHW::GetInstance()->GetTextureCache();
|
||||
tc->m_target_memory_usage = (tc->m_target_memory_usage - m_texture->GetMemUsage()) + tex->GetMemUsage();
|
||||
|
||||
if (recycle_old)
|
||||
g_gs_device->Recycle(m_texture);
|
||||
else
|
||||
delete m_texture;
|
||||
|
||||
m_texture = tex;
|
||||
return true;
|
||||
}
|
||||
|
||||
// GSTextureCache::SourceMap
|
||||
|
||||
void GSTextureCache::SourceMap::Add(Source* s, const GIFRegTEX0& TEX0, const GSOffset& off)
|
||||
|
@ -3373,7 +3366,12 @@ GSTextureCache::Palette::Palette(u16 pal, bool need_gs_texture)
|
|||
|
||||
GSTextureCache::Palette::~Palette()
|
||||
{
|
||||
g_gs_device->Recycle(m_tex_palette);
|
||||
if (m_tex_palette)
|
||||
{
|
||||
GSRendererHW::GetInstance()->GetTextureCache()->m_source_memory_usage -= m_tex_palette->GetMemUsage();
|
||||
g_gs_device->Recycle(m_tex_palette);
|
||||
}
|
||||
|
||||
_aligned_free(m_clut);
|
||||
}
|
||||
|
||||
|
@ -3398,6 +3396,7 @@ void GSTextureCache::Palette::InitializeTexture()
|
|||
// and therefore will read texel 15/255 * texture size).
|
||||
m_tex_palette = g_gs_device->CreateTexture(m_pal, 1, 1, GSTexture::Format::Color);
|
||||
m_tex_palette->Update(GSVector4i(0, 0, m_pal, 1), m_clut, m_pal * sizeof(m_clut[0]));
|
||||
GSRendererHW::GetInstance()->GetTextureCache()->m_source_memory_usage += m_tex_palette->GetMemUsage();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -3638,7 +3637,7 @@ GSTextureCache::HashType GSTextureCache::HashTexture(const GIFRegTEX0& TEX0, con
|
|||
{
|
||||
BlockHashState hash_st;
|
||||
BlockHashReset(hash_st);
|
||||
HashTextureLevel(TEX0, TEXA, hash_st, m_temp);
|
||||
HashTextureLevel(TEX0, TEXA, hash_st, s_unswizzle_buffer);
|
||||
return FinishBlockHash(hash_st);
|
||||
}
|
||||
|
||||
|
@ -3675,7 +3674,7 @@ void GSTextureCache::PreloadTexture(const GIFRegTEX0& TEX0, const GIFRegTEXA& TE
|
|||
// Align pitch to 32 bytes for AVX2 if we're going through the temp buffer path.
|
||||
pitch = Common::AlignUpPow2(pitch, 32);
|
||||
|
||||
u8* buff = m_temp;
|
||||
u8* buff = s_unswizzle_buffer;
|
||||
rtx(mem, off, block_rect, buff, pitch, TEXA);
|
||||
tex->Update(rect, buff, pitch, level);
|
||||
}
|
||||
|
@ -3702,7 +3701,7 @@ GSTextureCache::HashCacheKey GSTextureCache::HashCacheKey::Create(const GIFRegTE
|
|||
BlockHashReset(hash_st);
|
||||
|
||||
// base level is always hashed
|
||||
HashTextureLevel(TEX0, TEXA, hash_st, m_temp);
|
||||
HashTextureLevel(TEX0, TEXA, hash_st, s_unswizzle_buffer);
|
||||
|
||||
if (lod)
|
||||
{
|
||||
|
@ -3712,7 +3711,7 @@ GSTextureCache::HashCacheKey GSTextureCache::HashCacheKey::Create(const GIFRegTE
|
|||
for (int i = 1; i < nmips; i++)
|
||||
{
|
||||
const GIFRegTEX0 MIP_TEX0{g_gs_renderer->GetTex0Layer(basemip + i)};
|
||||
HashTextureLevel(MIP_TEX0, TEXA, hash_st, m_temp);
|
||||
HashTextureLevel(MIP_TEX0, TEXA, hash_st, s_unswizzle_buffer);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -92,9 +92,6 @@ public:
|
|||
void UpdateAge();
|
||||
bool Inside(u32 bp, u32 bw, u32 psm, const GSVector4i& rect);
|
||||
bool Overlaps(u32 bp, u32 bw, u32 psm, const GSVector4i& rect);
|
||||
|
||||
bool ResizeTexture(int new_width, int new_height, bool recycle_old = true);
|
||||
bool ResizeTexture(int new_width, int new_height, GSVector2 new_scale, bool recycle_old = true);
|
||||
};
|
||||
|
||||
struct PaletteKey
|
||||
|
@ -200,6 +197,7 @@ public:
|
|||
|
||||
public:
|
||||
Target(const GIFRegTEX0& TEX0, const bool depth_supported, const int type);
|
||||
~Target();
|
||||
|
||||
void UpdateValidity(const GSVector4i& rect);
|
||||
|
||||
|
@ -207,6 +205,9 @@ public:
|
|||
|
||||
/// Updates the target, if the dirty area intersects with the specified rectangle.
|
||||
void UpdateIfDirtyIntersects(const GSVector4i& rc);
|
||||
|
||||
bool ResizeTexture(int new_width, int new_height, bool recycle_old = true);
|
||||
bool ResizeTexture(int new_width, int new_height, GSVector2 new_scale, bool recycle_old = true);
|
||||
};
|
||||
|
||||
class PaletteMap
|
||||
|
@ -298,15 +299,20 @@ public:
|
|||
protected:
|
||||
PaletteMap m_palette_map;
|
||||
SourceMap m_src;
|
||||
u64 m_source_memory_usage = 0;
|
||||
std::unordered_map<HashCacheKey, HashCacheEntry, HashCacheKeyHash> m_hash_cache;
|
||||
u64 m_hash_cache_memory_usage = 0;
|
||||
u64 m_hash_cache_replacement_memory_usage;
|
||||
u64 m_hash_cache_replacement_memory_usage = 0;
|
||||
|
||||
FastList<Target*> m_dst[2];
|
||||
FastList<TargetHeightElem> m_target_heights;
|
||||
static u8* m_temp;
|
||||
u64 m_target_memory_usage = 0;
|
||||
|
||||
constexpr static size_t S_SURFACE_OFFSET_CACHE_MAX_SIZE = std::numeric_limits<u16>::max();
|
||||
std::unordered_map<SurfaceOffsetKey, SurfaceOffset, SurfaceOffsetKeyHash, SurfaceOffsetKeyEqual> m_surface_offset_cache;
|
||||
|
||||
Source* m_temporary_source = nullptr; // invalidated after the draw
|
||||
|
||||
std::unique_ptr<GSDownloadTexture> m_color_download_texture;
|
||||
std::unique_ptr<GSDownloadTexture> m_uint16_download_texture;
|
||||
std::unique_ptr<GSDownloadTexture> m_uint32_download_texture;
|
||||
|
@ -336,6 +342,8 @@ public:
|
|||
__fi u64 GetHashCacheMemoryUsage() const { return m_hash_cache_memory_usage; }
|
||||
__fi u64 GetHashCacheReplacementMemoryUsage() const { return m_hash_cache_replacement_memory_usage; }
|
||||
__fi u64 GetTotalHashCacheMemoryUsage() const { return (m_hash_cache_memory_usage + m_hash_cache_replacement_memory_usage); }
|
||||
__fi u64 GetSourceMemoryUsage() const { return m_source_memory_usage; }
|
||||
__fi u64 GetTargetMemoryUsage() const { return m_target_memory_usage; }
|
||||
|
||||
void Read(Target* t, const GSVector4i& r);
|
||||
void Read(Source* t, const GSVector4i& r);
|
||||
|
@ -372,8 +380,6 @@ public:
|
|||
return (type == DepthStencil) ? "Depth" : "Color";
|
||||
}
|
||||
|
||||
void PrintMemoryUsage();
|
||||
|
||||
void AttachPaletteToSource(Source* s, u16 pal, bool need_gs_texture);
|
||||
void AttachPaletteToSource(Source* s, GSTexture* gpu_clut);
|
||||
SurfaceOffset ComputeSurfaceOffset(const GSOffset& off, const GSVector4i& r, const Target* t);
|
||||
|
|
Loading…
Reference in New Issue