mirror of https://github.com/PCSX2/pcsx2.git
GS/HW: Calculate target alpha min/max
This commit is contained in:
parent
472f4922bd
commit
189f6fa2a3
|
@ -3669,12 +3669,13 @@ GSState::TextureMinMaxResult GSState::GetTextureMinMax(GIFRegTEX0 TEX0, GIFRegCL
|
|||
return { vr, uses_border };
|
||||
}
|
||||
|
||||
void GSState::CalcAlphaMinMax()
|
||||
void GSState::CalcAlphaMinMax(const int tex_alpha_min, const int tex_alpha_max)
|
||||
{
|
||||
if (m_vt.m_alpha.valid)
|
||||
if (m_vt.m_alpha.valid && tex_alpha_min == 0 && tex_alpha_max == 255)
|
||||
return;
|
||||
|
||||
int min = 0, max = 0;
|
||||
// We wanted to force an update as we now know the alpha of the non-indexed texture.
|
||||
int min = tex_alpha_min, max = tex_alpha_max;
|
||||
|
||||
if (IsCoverageAlpha())
|
||||
{
|
||||
|
@ -3692,8 +3693,8 @@ void GSState::CalcAlphaMinMax()
|
|||
switch (GSLocalMemory::m_psm[context->TEX0.PSM].fmt)
|
||||
{
|
||||
case 0:
|
||||
a.y = 0;
|
||||
a.w = 0xff;
|
||||
a.y = min;
|
||||
a.w = max;
|
||||
break;
|
||||
case 1:
|
||||
a.y = env.TEXA.AEM ? 0 : env.TEXA.TA0;
|
||||
|
|
|
@ -134,9 +134,6 @@ private:
|
|||
|
||||
} m_tr;
|
||||
|
||||
private:
|
||||
void CalcAlphaMinMax();
|
||||
|
||||
protected:
|
||||
GSVertex m_v = {};
|
||||
float m_q = 1.0f;
|
||||
|
@ -179,7 +176,7 @@ protected:
|
|||
GSVertexTrace::VertexAlpha& GetAlphaMinMax()
|
||||
{
|
||||
if (!m_vt.m_alpha.valid)
|
||||
CalcAlphaMinMax();
|
||||
CalcAlphaMinMax(0, 255);
|
||||
return m_vt.m_alpha;
|
||||
}
|
||||
struct TextureMinMaxResult
|
||||
|
@ -202,6 +199,7 @@ protected:
|
|||
bool IsMipMapDraw();
|
||||
bool IsMipMapActive();
|
||||
bool IsCoverageAlpha();
|
||||
void CalcAlphaMinMax(const int tex_min, const int tex_max);
|
||||
|
||||
public:
|
||||
struct GSUploadQueue
|
||||
|
|
|
@ -846,6 +846,8 @@ bool GSHwHack::OI_RozenMaidenGebetGarden(GSRendererHW& r, GSTexture* rt, GSTextu
|
|||
{
|
||||
GL_INS("OI_RozenMaidenGebetGarden FB clear");
|
||||
g_gs_device->ClearRenderTarget(tmp_rt->m_texture, 0);
|
||||
tmp_rt->m_alpha_max = 0;
|
||||
tmp_rt->m_alpha_min = 0;
|
||||
}
|
||||
|
||||
return false;
|
||||
|
|
|
@ -2116,6 +2116,9 @@ void GSRendererHW::Draw()
|
|||
cleanup_cancelled_draw();
|
||||
return;
|
||||
}
|
||||
|
||||
if (src->m_target)
|
||||
CalcAlphaMinMax(src->m_from_target->m_alpha_min, src->m_from_target->m_alpha_max);
|
||||
}
|
||||
|
||||
// Estimate size based on the scissor rectangle and height cache.
|
||||
|
@ -4736,6 +4739,52 @@ __ri void GSRendererHW::DrawPrims(GSTextureCache::Target* rt, GSTextureCache::Ta
|
|||
}
|
||||
|
||||
// Blend
|
||||
if (rt)
|
||||
{
|
||||
if (!m_channel_shuffle && !m_texture_shuffle)
|
||||
{
|
||||
const int fba_value = m_prev_env.CTXT[m_prev_env.PRIM.CTXT].FBA.FBA * 128;
|
||||
if ((m_cached_ctx.FRAME.FBMSK & 0xff000000) == 0)
|
||||
{
|
||||
if (rt->m_valid.rintersect(m_r).eq(rt->m_valid) && PrimitiveCoversWithoutGaps() && !(m_cached_ctx.TEST.DATE || m_cached_ctx.TEST.ATE || m_cached_ctx.TEST.ZTST != ZTST_ALWAYS))
|
||||
{
|
||||
rt->m_alpha_max = GetAlphaMinMax().max | fba_value;
|
||||
rt->m_alpha_min = GetAlphaMinMax().min | fba_value;
|
||||
}
|
||||
else
|
||||
{
|
||||
rt->m_alpha_max = std::max(GetAlphaMinMax().max | fba_value, rt->m_alpha_max);
|
||||
rt->m_alpha_min = std::min(GetAlphaMinMax().min | fba_value, rt->m_alpha_min);
|
||||
}
|
||||
}
|
||||
else if ((m_cached_ctx.FRAME.FBMSK & 0xff000000) != 0xff000000) // We can't be sure of the alpha if it's partially masked.
|
||||
{
|
||||
rt->m_alpha_max |= std::max(GetAlphaMinMax().max | fba_value, rt->m_alpha_max);
|
||||
rt->m_alpha_min = std::min(GetAlphaMinMax().min | fba_value, rt->m_alpha_min);
|
||||
}
|
||||
else
|
||||
{
|
||||
// If both are zero then we probably don't know what the alpha is.
|
||||
if (rt->m_alpha_max == 0 && rt->m_alpha_min == 0)
|
||||
{
|
||||
rt->m_alpha_max = 255;
|
||||
rt->m_alpha_min = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if ((m_texture_shuffle && m_conf.ps.write_rg == false) || m_channel_shuffle)
|
||||
{
|
||||
rt->m_alpha_max = 255;
|
||||
rt->m_alpha_min = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// Not gonna spend too much time with this, it's not likely to be used much, can't be less accurate than it was.
|
||||
if (ds)
|
||||
{
|
||||
ds->m_alpha_max = std::max(ds->m_alpha_max, static_cast<int>(m_vt.m_max.p.z) >> 24);
|
||||
ds->m_alpha_min = std::min(ds->m_alpha_min, static_cast<int>(m_vt.m_min.p.z) >> 24);
|
||||
}
|
||||
|
||||
bool blending_alpha_pass = false;
|
||||
if ((!IsOpaque() || m_context->ALPHA.IsBlack()) && rt && (m_conf.colormask.wrgba & 0x7))
|
||||
|
@ -5511,6 +5560,8 @@ bool GSRendererHW::TryTargetClear(GSTextureCache::Target* rt, GSTextureCache::Ta
|
|||
const u32 c = GetConstantDirectWriteMemClearColor();
|
||||
GL_INS("TryTargetClear(): RT at %x <= %08X", rt->m_TEX0.TBP0, c);
|
||||
g_gs_device->ClearRenderTarget(rt->m_texture, c);
|
||||
rt->m_alpha_max = c >> 24;
|
||||
rt->m_alpha_min = c >> 24;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -5527,6 +5578,8 @@ bool GSRendererHW::TryTargetClear(GSTextureCache::Target* rt, GSTextureCache::Ta
|
|||
const float d = static_cast<float>(z) * (g_gs_device->Features().clip_control ? 0x1p-32f : 0x1p-24f);
|
||||
GL_INS("TryTargetClear(): DS at %x <= %f", ds->m_TEX0.TBP0, d);
|
||||
g_gs_device->ClearDepth(ds->m_texture, d);
|
||||
ds->m_alpha_max = z >> 24;
|
||||
ds->m_alpha_min = z >> 24;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
|
@ -1403,6 +1403,7 @@ GSTextureCache::Target* GSTextureCache::LookupTarget(GIFRegTEX0 TEX0, const GSVe
|
|||
|
||||
dst->m_32_bits_fmt = dst_match->m_32_bits_fmt;
|
||||
dst->OffsetHack_modxy = dst_match->OffsetHack_modxy;
|
||||
dst->m_end_block = dst_match->m_end_block; // If we're copying the size, we need to keep the end block.
|
||||
|
||||
ShaderConvert shader;
|
||||
// m_32_bits_fmt gets set on a shuffle or if the format isn't 16bit.
|
||||
|
@ -1432,6 +1433,8 @@ GSTextureCache::Target* GSTextureCache::LookupTarget(GIFRegTEX0 TEX0, const GSVe
|
|||
// so just move the dirty rects across.
|
||||
dst->m_dirty = std::move(dst_match->m_dirty);
|
||||
dst_match->m_dirty = {};
|
||||
dst->m_alpha_max = dst_match->m_alpha_max;
|
||||
dst->m_alpha_min = dst_match->m_alpha_min;
|
||||
|
||||
// Don't bother copying the old target in if the whole thing is dirty.
|
||||
if (dst->m_dirty.empty() || (~dst->m_dirty.GetDirtyChannels() & GSUtil::GetChannelMask(TEX0.PSM)) != 0 ||
|
||||
|
@ -2876,6 +2879,8 @@ bool GSTextureCache::Move(u32 SBP, u32 SBW, u32 SPSM, int sx, int sy, u32 DBP, u
|
|||
dst->UpdateValidBits(GSLocalMemory::m_psm[DPSM].fmsk);
|
||||
dst->UpdateValidity(GSVector4i(dx, dy, dx + w, dy + h));
|
||||
dst->UpdateDrawn(GSVector4i(dx, dy, dx + w, dy + h));
|
||||
dst->m_alpha_max = src->m_alpha_max;
|
||||
dst->m_alpha_min = src->m_alpha_min;
|
||||
// Invalidate any sources that overlap with the target (since they're now stale).
|
||||
InvalidateVideoMem(g_gs_renderer->m_mem.GetOffset(DBP, DBW, DPSM), GSVector4i(dx, dy, dx + w, dy + h), false);
|
||||
return true;
|
||||
|
@ -4736,6 +4741,8 @@ GSTextureCache::Target::Target(GIFRegTEX0 TEX0, int type, const GSVector2i& unsc
|
|||
m_unscaled_size = unscaled_size;
|
||||
m_scale = scale;
|
||||
m_texture = texture;
|
||||
m_alpha_min = 0;
|
||||
m_alpha_max = 0;
|
||||
m_32_bits_fmt |= (GSLocalMemory::m_psm[TEX0.PSM].trbpp != 16);
|
||||
}
|
||||
|
||||
|
@ -4872,7 +4879,9 @@ void GSTextureCache::Target::Update()
|
|||
}
|
||||
|
||||
UpdateValidity(total_rect);
|
||||
|
||||
// We don't know what the dirty alpha is gonna be, so assume max.
|
||||
m_alpha_min = 0;
|
||||
m_alpha_max = 255;
|
||||
g_gs_device->Recycle(t);
|
||||
m_dirty.clear();
|
||||
}
|
||||
|
|
|
@ -212,6 +212,8 @@ public:
|
|||
{
|
||||
public:
|
||||
const int m_type = 0;
|
||||
int m_alpha_max = 0;
|
||||
int m_alpha_min = 0;
|
||||
|
||||
// Valid alpha means "we have rendered to the alpha channel of this target".
|
||||
// A false value means that the alpha in local memory is still valid/up-to-date.
|
||||
|
|
Loading…
Reference in New Issue