GS/HW: Only allocate as many mip levels as present

This prevents any possibility of sampling undefined or garbage/reused
texture data from levels which aren't used by the current draw.

And a tiny bit of VRAM. But nothing really measurable.

Also fixes a bug in Vulkan where a copied texture can get mip-generated
in the wrong command buffer when using basic mipmapping.
This commit is contained in:
Connor McLaughlin 2022-10-09 00:45:40 +10:00 committed by refractionpcsx2
parent 7f9932129d
commit 1910c8fc0f
8 changed files with 29 additions and 18 deletions

View File

@ -264,9 +264,9 @@ GSTexture* GSDevice::CreateDepthStencil(int w, int h, GSTexture::Format format,
return FetchSurface(GSTexture::Type::DepthStencil, w, h, 1, format, clear, true);
}
GSTexture* GSDevice::CreateTexture(int w, int h, bool mipmap, GSTexture::Format format, bool prefer_reuse /* = false */)
GSTexture* GSDevice::CreateTexture(int w, int h, int mipmap_levels, GSTexture::Format format, bool prefer_reuse /* = false */)
{
const int levels = mipmap ? MipmapLevelsForSize(w, h) : 1;
const int levels = mipmap_levels < 0 ? MipmapLevelsForSize(w, h) : mipmap_levels;
return FetchSurface(GSTexture::Type::Texture, w, h, levels, format, false, prefer_reuse);
}

View File

@ -812,7 +812,7 @@ public:
GSTexture* CreateRenderTarget(int w, int h, GSTexture::Format format, bool clear = true);
GSTexture* CreateDepthStencil(int w, int h, GSTexture::Format format, bool clear = true);
GSTexture* CreateTexture(int w, int h, bool mipmap, GSTexture::Format format, bool prefer_reuse = false);
GSTexture* CreateTexture(int w, int h, int mipmap_levels, GSTexture::Format format, bool prefer_reuse = false);
GSTexture* CreateOffscreen(int w, int h, GSTexture::Format format);
GSTexture::Format GetDefaultTextureFormat(GSTexture::Type type);

View File

@ -440,9 +440,12 @@ void GSDevice12::CopyRect(GSTexture* sTex, GSTexture* dTex, const GSVector4i& r,
dTexVK->CommitClear();
EndRenderPass();
sTexVK->TransitionToState(D3D12_RESOURCE_STATE_COPY_SOURCE);
dTexVK->SetState(GSTexture::State::Dirty);
sTexVK->SetUsedThisCommandBuffer();
dTexVK->TransitionToState(D3D12_RESOURCE_STATE_COPY_DEST);
dTexVK->SetUsedThisCommandBuffer();
D3D12_TEXTURE_COPY_LOCATION srcloc;
srcloc.pResource = sTexVK->GetResource();
@ -2514,7 +2517,7 @@ void GSDevice12::RenderHW(GSHWDrawConfig& config)
else if (config.require_one_barrier)
{
// requires a copy of the RT
draw_rt_clone = static_cast<GSTexture12*>(CreateTexture(rtsize.x, rtsize.y, false, GSTexture::Format::Color, false));
draw_rt_clone = static_cast<GSTexture12*>(CreateTexture(rtsize.x, rtsize.y, 1, GSTexture::Format::Color, false));
if (draw_rt_clone)
{
EndRenderPass();

View File

@ -4661,7 +4661,7 @@ bool GSRendererHW::OI_FFXII(GSTexture* rt, GSTexture* ds, GSTextureCache::Source
g_gs_device->Recycle(t->m_texture);
t->m_texture = g_gs_device->CreateTexture(512, 512, false, GSTexture::Format::Color);
t->m_texture = g_gs_device->CreateTexture(512, 512, 1, GSTexture::Format::Color);
t->m_texture->Update(GSVector4i(0, 0, 448, lines), video, 448 * 4);

View File

@ -1562,12 +1562,18 @@ GSTextureCache::Source* GSTextureCache::CreateSource(const GIFRegTEX0& TEX0, con
{
const GSLocalMemory::psm_t& psm = GSLocalMemory::m_psm[TEX0.PSM];
Source* src = new Source(TEX0, TEXA, false);
if (lod)
src->m_lod = *lod;
int tw = 1 << TEX0.TW;
int th = 1 << TEX0.TH;
//int tp = TEX0.TBW << 6;
int tlevels = 1;
if (lod)
{
// lod won't contain the full range when using basic mipmapping, only that
// which is hashed, so we just allocate the full thing.
tlevels = (GSConfig.HWMipmap != HWMipmapLevel::Full) ? -1 : (lod->y - lod->x + 1);
src->m_lod = *lod;
}
bool hack = false;
@ -1584,7 +1590,7 @@ GSTextureCache::Source* GSTextureCache::CreateSource(const GIFRegTEX0& TEX0, con
GSTexture* sTex = dst->m_texture;
GSTexture* dTex = outside_target ?
g_gs_device->CreateRenderTarget(w, h, GSTexture::Format::Color, true) :
g_gs_device->CreateTexture(w, h, false, GSTexture::Format::Color, true);
g_gs_device->CreateTexture(w, h, tlevels, GSTexture::Format::Color, true);
// copy the rt in
const GSVector4i area(GSVector4i(x, y, x + w, y + h).rintersect(GSVector4i(sTex->GetSize()).zwxy()));
@ -1816,7 +1822,7 @@ GSTextureCache::Source* GSTextureCache::CreateSource(const GIFRegTEX0& TEX0, con
// 'src' is the new texture cache entry (hence the output)
GSTexture* sTex = dst->m_texture;
GSTexture* dTex = use_texture ?
g_gs_device->CreateTexture(w, h, false, GSTexture::Format::Color, true) :
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;
@ -1880,12 +1886,12 @@ GSTextureCache::Source* GSTextureCache::CreateSource(const GIFRegTEX0& TEX0, con
}
else if (paltex)
{
src->m_texture = g_gs_device->CreateTexture(tw, th, false, GSTexture::Format::UNorm8);
src->m_texture = g_gs_device->CreateTexture(tw, th, tlevels, GSTexture::Format::UNorm8);
AttachPaletteToSource(src, psm.pal, true);
}
else
{
src->m_texture = g_gs_device->CreateTexture(tw, th, (lod != nullptr), GSTexture::Format::Color);
src->m_texture = g_gs_device->CreateTexture(tw, th, tlevels, GSTexture::Format::Color);
if (psm.pal > 0)
{
AttachPaletteToSource(src, psm.pal, false);
@ -2009,7 +2015,8 @@ GSTextureCache::HashCacheEntry* GSTextureCache::LookupHashCache(const GIFRegTEX0
// expand/upload texture
const int tw = 1 << TEX0.TW;
const int th = 1 << TEX0.TH;
GSTexture* tex = g_gs_device->CreateTexture(tw, th, paltex ? false : (lod != nullptr), paltex ? GSTexture::Format::UNorm8 : GSTexture::Format::Color);
const int tlevels = lod ? ((GSConfig.HWMipmap != HWMipmapLevel::Full) ? -1 : (lod->y - lod->x + 1)) : 1;
GSTexture* tex = g_gs_device->CreateTexture(tw, th, tlevels, paltex ? GSTexture::Format::UNorm8 : GSTexture::Format::Color);
if (!tex)
{
// out of video memory if we hit here
@ -2627,7 +2634,7 @@ void GSTextureCache::Target::Update()
TEXA.TA0 = 0;
TEXA.TA1 = 0x80;
GSTexture* t = g_gs_device->CreateTexture(w, h, false, GSTexture::Format::Color);
GSTexture* t = g_gs_device->CreateTexture(w, h, 1, GSTexture::Format::Color);
GSOffset off = g_gs_renderer->m_mem.GetOffset(m_TEX0.TBP0, m_TEX0.TBW, m_TEX0.PSM);
@ -3047,7 +3054,7 @@ void GSTextureCache::Palette::InitializeTexture()
// sampling such texture are always normalized by 255.
// This is because indexes are stored as normalized values of an RGBA texture (e.g. index 15 will be read as (15/255),
// and therefore will read texel 15/255 * texture size).
m_tex_palette = g_gs_device->CreateTexture(256, 1, false, GSTexture::Format::Color);
m_tex_palette = g_gs_device->CreateTexture(256, 1, 1, GSTexture::Format::Color);
m_tex_palette->Update(GSVector4i(0, 0, m_pal, 1), m_clut, m_pal * sizeof(m_clut[0]));
}
}

View File

@ -536,7 +536,7 @@ GSTexture* GSTextureReplacements::CreateReplacementTexture(const ReplacementText
mipmap = false;
}
GSTexture* tex = g_gs_device->CreateTexture(rtex.width, rtex.height, mipmap, rtex.format);
GSTexture* tex = g_gs_device->CreateTexture(rtex.width, rtex.height, static_cast<int>(rtex.mips.size()) + 1, rtex.format);
if (!tex)
return nullptr;

View File

@ -1873,7 +1873,7 @@ void GSDeviceOGL::RenderHW(GSHWDrawConfig& config)
else if (config.require_one_barrier && !m_features.texture_barrier)
{
// Requires a copy of the RT
draw_rt_clone = CreateTexture(rtsize.x, rtsize.y, false, GSTexture::Format::Color, false);
draw_rt_clone = CreateTexture(rtsize.x, rtsize.y, 1, GSTexture::Format::Color, false);
GL_PUSH("Copy RT to temp texture for fbmask {%d,%d %dx%d}",
config.drawarea.left, config.drawarea.top,
config.drawarea.width(), config.drawarea.height());

View File

@ -552,6 +552,7 @@ void GSDeviceVK::CopyRect(GSTexture* sTex, GSTexture* dTex, const GSVector4i& r,
EndRenderPass();
dTexVK->TransitionToLayout(VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL);
dTexVK->SetUsedThisCommandBuffer();
sTexVK->TransitionToLayout(VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL);
sTexVK->SetUsedThisCommandBuffer();
@ -2954,7 +2955,7 @@ void GSDeviceVK::RenderHW(GSHWDrawConfig& config)
else if (config.require_one_barrier && !m_features.texture_barrier)
{
// requires a copy of the RT
draw_rt_clone = static_cast<GSTextureVK*>(CreateTexture(rtsize.x, rtsize.y, false, GSTexture::Format::Color, false));
draw_rt_clone = static_cast<GSTextureVK*>(CreateTexture(rtsize.x, rtsize.y, 1, GSTexture::Format::Color, false));
if (draw_rt_clone)
{
EndRenderPass();