mirror of https://github.com/PCSX2/pcsx2.git
GS/HW: Fix possible texture leak on skipped draw
This commit is contained in:
parent
612c24e0c0
commit
fdb751ed1a
|
@ -396,6 +396,11 @@ bool GSDevice::UpdateImGuiFontTexture()
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void GSDevice::TextureRecycleDeleter::operator()(GSTexture* const tex)
|
||||||
|
{
|
||||||
|
g_gs_device->Recycle(tex);
|
||||||
|
}
|
||||||
|
|
||||||
GSTexture* GSDevice::FetchSurface(GSTexture::Type type, int width, int height, int levels, GSTexture::Format format, bool clear, bool prefer_unused_texture)
|
GSTexture* GSDevice::FetchSurface(GSTexture::Type type, int width, int height, int levels, GSTexture::Format format, bool clear, bool prefer_unused_texture)
|
||||||
{
|
{
|
||||||
const GSVector2i size(width, height);
|
const GSVector2i size(width, height);
|
||||||
|
|
|
@ -763,6 +763,12 @@ public:
|
||||||
GSHWDrawConfig::ColorMaskSelector wmask; // 0xf for all channels by default
|
GSHWDrawConfig::ColorMaskSelector wmask; // 0xf for all channels by default
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct TextureRecycleDeleter
|
||||||
|
{
|
||||||
|
void operator()(GSTexture* const tex);
|
||||||
|
};
|
||||||
|
using RecycledTexture = std::unique_ptr<GSTexture, TextureRecycleDeleter>;
|
||||||
|
|
||||||
enum BlendFactor : u8
|
enum BlendFactor : u8
|
||||||
{
|
{
|
||||||
// HW blend factors
|
// HW blend factors
|
||||||
|
|
|
@ -4586,7 +4586,8 @@ __ri static constexpr u8 EffectiveClamp(u8 clamp, bool has_region)
|
||||||
return (clamp >= CLAMP_REGION_CLAMP && has_region) ? (clamp ^ 3) : clamp;
|
return (clamp >= CLAMP_REGION_CLAMP && has_region) ? (clamp ^ 3) : clamp;
|
||||||
}
|
}
|
||||||
|
|
||||||
__ri void GSRendererHW::EmulateTextureSampler(const GSTextureCache::Target* rt, const GSTextureCache::Target* ds, GSTextureCache::Source* tex, const TextureMinMaxResult& tmm, GSTexture*& src_copy)
|
__ri void GSRendererHW::EmulateTextureSampler(const GSTextureCache::Target* rt, const GSTextureCache::Target* ds, GSTextureCache::Source* tex,
|
||||||
|
const TextureMinMaxResult& tmm, GSDevice::RecycledTexture& src_copy)
|
||||||
{
|
{
|
||||||
// don't overwrite the texture when using channel shuffle, but keep the palette
|
// don't overwrite the texture when using channel shuffle, but keep the palette
|
||||||
if (!m_channel_shuffle)
|
if (!m_channel_shuffle)
|
||||||
|
@ -4908,7 +4909,7 @@ __ri void GSRendererHW::EmulateTextureSampler(const GSTextureCache::Target* rt,
|
||||||
|
|
||||||
__ri void GSRendererHW::HandleTextureHazards(const GSTextureCache::Target* rt, const GSTextureCache::Target* ds,
|
__ri void GSRendererHW::HandleTextureHazards(const GSTextureCache::Target* rt, const GSTextureCache::Target* ds,
|
||||||
const GSTextureCache::Source* tex, const TextureMinMaxResult& tmm, GSTextureCache::SourceRegion& source_region,
|
const GSTextureCache::Source* tex, const TextureMinMaxResult& tmm, GSTextureCache::SourceRegion& source_region,
|
||||||
bool& target_region, GSVector2i& unscaled_size, float& scale, GSTexture*& src_copy)
|
bool& target_region, GSVector2i& unscaled_size, float& scale, GSDevice::RecycledTexture& src_copy)
|
||||||
{
|
{
|
||||||
// Detect framebuffer read that will need special handling
|
// Detect framebuffer read that will need special handling
|
||||||
const GSTextureCache::Target* src_target = nullptr;
|
const GSTextureCache::Target* src_target = nullptr;
|
||||||
|
@ -5051,11 +5052,11 @@ __ri void GSRendererHW::HandleTextureHazards(const GSTextureCache::Target* rt, c
|
||||||
GSVector2i(static_cast<int>(std::ceil(static_cast<float>(copy_dst_offset.x) * scale)),
|
GSVector2i(static_cast<int>(std::ceil(static_cast<float>(copy_dst_offset.x) * scale)),
|
||||||
static_cast<int>(std::ceil(static_cast<float>(copy_dst_offset.y) * scale)));
|
static_cast<int>(std::ceil(static_cast<float>(copy_dst_offset.y) * scale)));
|
||||||
|
|
||||||
src_copy = src_target->m_texture->IsDepthStencil() ?
|
src_copy.reset(src_target->m_texture->IsDepthStencil() ?
|
||||||
g_gs_device->CreateDepthStencil(
|
g_gs_device->CreateDepthStencil(
|
||||||
scaled_copy_size.x, scaled_copy_size.y, src_target->m_texture->GetFormat(), false) :
|
scaled_copy_size.x, scaled_copy_size.y, src_target->m_texture->GetFormat(), false) :
|
||||||
g_gs_device->CreateTexture(
|
g_gs_device->CreateTexture(
|
||||||
scaled_copy_size.x, scaled_copy_size.y, 1, src_target->m_texture->GetFormat(), true);
|
scaled_copy_size.x, scaled_copy_size.y, 1, src_target->m_texture->GetFormat(), true));
|
||||||
if (!src_copy) [[unlikely]]
|
if (!src_copy) [[unlikely]]
|
||||||
{
|
{
|
||||||
Console.Error("Failed to allocate %dx%d texture for hazard copy", scaled_copy_size.x, scaled_copy_size.y);
|
Console.Error("Failed to allocate %dx%d texture for hazard copy", scaled_copy_size.x, scaled_copy_size.y);
|
||||||
|
@ -5065,8 +5066,8 @@ __ri void GSRendererHW::HandleTextureHazards(const GSTextureCache::Target* rt, c
|
||||||
}
|
}
|
||||||
|
|
||||||
g_gs_device->CopyRect(
|
g_gs_device->CopyRect(
|
||||||
src_target->m_texture, src_copy, scaled_copy_range, scaled_copy_dst_offset.x, scaled_copy_dst_offset.y);
|
src_target->m_texture, src_copy.get(), scaled_copy_range, scaled_copy_dst_offset.x, scaled_copy_dst_offset.y);
|
||||||
m_conf.tex = src_copy;
|
m_conf.tex = src_copy.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool GSRendererHW::CanUseTexIsFB(const GSTextureCache::Target* rt, const GSTextureCache::Source* tex,
|
bool GSRendererHW::CanUseTexIsFB(const GSTextureCache::Target* rt, const GSTextureCache::Source* tex,
|
||||||
|
@ -5761,12 +5762,12 @@ __ri void GSRendererHW::DrawPrims(GSTextureCache::Target* rt, GSTextureCache::Ta
|
||||||
m_conf.datm = static_cast<SetDATM>(m_cached_ctx.TEST.DATM);
|
m_conf.datm = static_cast<SetDATM>(m_cached_ctx.TEST.DATM);
|
||||||
|
|
||||||
// If we're doing stencil DATE and we don't have a depth buffer, we need to allocate a temporary one.
|
// If we're doing stencil DATE and we don't have a depth buffer, we need to allocate a temporary one.
|
||||||
GSTexture* temp_ds = nullptr;
|
GSDevice::RecycledTexture temp_ds;
|
||||||
if (m_conf.destination_alpha >= GSHWDrawConfig::DestinationAlphaMode::Stencil &&
|
if (m_conf.destination_alpha >= GSHWDrawConfig::DestinationAlphaMode::Stencil &&
|
||||||
m_conf.destination_alpha <= GSHWDrawConfig::DestinationAlphaMode::StencilOne && !m_conf.ds)
|
m_conf.destination_alpha <= GSHWDrawConfig::DestinationAlphaMode::StencilOne && !m_conf.ds)
|
||||||
{
|
{
|
||||||
temp_ds = g_gs_device->CreateDepthStencil(m_conf.rt->GetWidth(), m_conf.rt->GetHeight(), GSTexture::Format::DepthStencil, false);
|
temp_ds.reset(g_gs_device->CreateDepthStencil(m_conf.rt->GetWidth(), m_conf.rt->GetHeight(), GSTexture::Format::DepthStencil, false));
|
||||||
m_conf.ds = temp_ds;
|
m_conf.ds = temp_ds.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
// vs
|
// vs
|
||||||
|
@ -5868,7 +5869,7 @@ __ri void GSRendererHW::DrawPrims(GSTextureCache::Target* rt, GSTextureCache::Ta
|
||||||
m_conf.cb_ps.FogColor_AREF = fc.blend32<8>(m_conf.cb_ps.FogColor_AREF);
|
m_conf.cb_ps.FogColor_AREF = fc.blend32<8>(m_conf.cb_ps.FogColor_AREF);
|
||||||
}
|
}
|
||||||
|
|
||||||
GSTexture* tex_copy = nullptr;
|
GSDevice::RecycledTexture tex_copy;
|
||||||
if (tex)
|
if (tex)
|
||||||
{
|
{
|
||||||
EmulateTextureSampler(rt, ds, tex, tmm, tex_copy);
|
EmulateTextureSampler(rt, ds, tex, tmm, tex_copy);
|
||||||
|
@ -5983,10 +5984,7 @@ __ri void GSRendererHW::DrawPrims(GSTextureCache::Target* rt, GSTextureCache::Ta
|
||||||
if (!ate_first_pass)
|
if (!ate_first_pass)
|
||||||
{
|
{
|
||||||
if (!m_conf.alpha_second_pass.enable)
|
if (!m_conf.alpha_second_pass.enable)
|
||||||
{
|
|
||||||
CleanupDraw(true);
|
|
||||||
return;
|
return;
|
||||||
}
|
|
||||||
|
|
||||||
// RenderHW always renders first pass, replace first pass with second
|
// RenderHW always renders first pass, replace first pass with second
|
||||||
std::memcpy(&m_conf.ps, &m_conf.alpha_second_pass.ps, sizeof(m_conf.ps));
|
std::memcpy(&m_conf.ps, &m_conf.alpha_second_pass.ps, sizeof(m_conf.ps));
|
||||||
|
@ -5999,11 +5997,6 @@ __ri void GSRendererHW::DrawPrims(GSTextureCache::Target* rt, GSTextureCache::Ta
|
||||||
m_conf.drawlist = (m_conf.require_full_barrier && m_vt.m_primclass == GS_SPRITE_CLASS) ? &m_drawlist : nullptr;
|
m_conf.drawlist = (m_conf.require_full_barrier && m_vt.m_primclass == GS_SPRITE_CLASS) ? &m_drawlist : nullptr;
|
||||||
|
|
||||||
g_gs_device->RenderHW(m_conf);
|
g_gs_device->RenderHW(m_conf);
|
||||||
|
|
||||||
if (tex_copy)
|
|
||||||
g_gs_device->Recycle(tex_copy);
|
|
||||||
if (temp_ds)
|
|
||||||
g_gs_device->Recycle(temp_ds);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// If the EE uploaded a new CLUT since the last draw, use that.
|
// If the EE uploaded a new CLUT since the last draw, use that.
|
||||||
|
|
|
@ -92,10 +92,10 @@ private:
|
||||||
void CleanupDraw(bool invalidate_temp_src);
|
void CleanupDraw(bool invalidate_temp_src);
|
||||||
|
|
||||||
void EmulateTextureSampler(const GSTextureCache::Target* rt, const GSTextureCache::Target* ds,
|
void EmulateTextureSampler(const GSTextureCache::Target* rt, const GSTextureCache::Target* ds,
|
||||||
GSTextureCache::Source* tex, const TextureMinMaxResult& tmm, GSTexture*& src_copy);
|
GSTextureCache::Source* tex, const TextureMinMaxResult& tmm, GSDevice::RecycledTexture& src_copy);
|
||||||
void HandleTextureHazards(const GSTextureCache::Target* rt, const GSTextureCache::Target* ds,
|
void HandleTextureHazards(const GSTextureCache::Target* rt, const GSTextureCache::Target* ds,
|
||||||
const GSTextureCache::Source* tex, const TextureMinMaxResult& tmm, GSTextureCache::SourceRegion& source_region,
|
const GSTextureCache::Source* tex, const TextureMinMaxResult& tmm, GSTextureCache::SourceRegion& source_region,
|
||||||
bool& target_region, GSVector2i& unscaled_size, float& scale, GSTexture*& src_copy);
|
bool& target_region, GSVector2i& unscaled_size, float& scale, GSDevice::RecycledTexture& src_copy);
|
||||||
bool CanUseTexIsFB(const GSTextureCache::Target* rt, const GSTextureCache::Source* tex,
|
bool CanUseTexIsFB(const GSTextureCache::Target* rt, const GSTextureCache::Source* tex,
|
||||||
const TextureMinMaxResult& tmm);
|
const TextureMinMaxResult& tmm);
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue