|
|
|
|
@@ -2230,6 +2230,7 @@ void GSRendererHW::Draw()
|
|
|
|
|
// We mess with this state as an optimization, so take a copy and use that instead.
|
|
|
|
|
const GSDrawingContext* context = m_context;
|
|
|
|
|
m_cached_ctx.TEX0 = context->TEX0;
|
|
|
|
|
m_cached_ctx.TEXA = m_draw_env->TEXA;
|
|
|
|
|
m_cached_ctx.CLAMP = context->CLAMP;
|
|
|
|
|
m_cached_ctx.TEST = context->TEST;
|
|
|
|
|
m_cached_ctx.FRAME = context->FRAME;
|
|
|
|
|
@@ -2363,7 +2364,7 @@ void GSRendererHW::Draw()
|
|
|
|
|
const GSLocalMemory::psm_t& tex_psm = GSLocalMemory::m_psm[m_cached_ctx.TEX0.PSM];
|
|
|
|
|
if (PRIM->TME && tex_psm.pal > 0)
|
|
|
|
|
{
|
|
|
|
|
m_mem.m_clut.Read32(m_cached_ctx.TEX0, env.TEXA);
|
|
|
|
|
m_mem.m_clut.Read32(m_cached_ctx.TEX0, m_cached_ctx.TEXA);
|
|
|
|
|
if (m_mem.m_clut.GetGPUTexture())
|
|
|
|
|
{
|
|
|
|
|
CalcAlphaMinMax(0, 255);
|
|
|
|
|
@@ -2672,6 +2673,48 @@ void GSRendererHW::Draw()
|
|
|
|
|
GSVector2i(1, 1));
|
|
|
|
|
height_invalid = false;
|
|
|
|
|
}
|
|
|
|
|
const u32 vert_index = (m_vt.m_primclass == GS_TRIANGLE_CLASS) ? 2 : 1;
|
|
|
|
|
u32 const_color = m_vertex.buff[m_index.buff[vert_index]].RGBAQ.U32[0];
|
|
|
|
|
u32 fb_mask = m_cached_ctx.FRAME.FBMSK;
|
|
|
|
|
|
|
|
|
|
// If we could just check the colour, it would be great, but Echo Night decided it's going to set the alpha and green to 128, for some reason, and actually be 32bit, so it ruined my day.
|
|
|
|
|
GSTextureCache::Target* rt_tgt = g_texture_cache->GetExactTarget(m_cached_ctx.FRAME.Block(), m_cached_ctx.FRAME.FBW, GSTextureCache::RenderTarget, m_cached_ctx.FRAME.Block() + 1);
|
|
|
|
|
const bool clear_16bit_likely = !(context->FRAME.PSM & 0x2) && ((rt_tgt && (rt_tgt->m_TEX0.PSM & 2)) || (!rt_tgt && ((static_cast<int>(context->FRAME.FBW) * 64) <= (PCRTCDisplays.GetResolution().x >> 1) || m_r.height() <= (PCRTCDisplays.GetResolution().y >> 1))));
|
|
|
|
|
|
|
|
|
|
rt_tgt = nullptr;
|
|
|
|
|
|
|
|
|
|
if (clear_16bit_likely && ((const_color != 0 && (const_color >> 16) == (const_color & 0xFFFF) && ((const_color >> 8) & 0xFF) != (const_color & 0xFF)) ||
|
|
|
|
|
(fb_mask != 0 && (fb_mask >> 16) == (fb_mask & 0xFFFF) && ((fb_mask >> 8) & 0xFF) != (fb_mask & 0xFF))))
|
|
|
|
|
{
|
|
|
|
|
const int get_next_ctx = m_env.PRIM.CTXT;
|
|
|
|
|
const GSDrawingContext& next_ctx = m_env.CTXT[get_next_ctx];
|
|
|
|
|
|
|
|
|
|
GL_CACHE("Clear 16bit with 32bit %d", s_n);
|
|
|
|
|
|
|
|
|
|
// May have already been resized through the split draw checks.
|
|
|
|
|
if (!(m_cached_ctx.FRAME.PSM & 2))
|
|
|
|
|
{
|
|
|
|
|
if (next_ctx.FRAME.FBW == (m_cached_ctx.FRAME.FBW * 2))
|
|
|
|
|
{
|
|
|
|
|
m_cached_ctx.FRAME.FBW *= 2;
|
|
|
|
|
m_r.z *= 2;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
m_r.w *= 2;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Convert colour and masks to 16bit and set a custom TEXA for this draw.
|
|
|
|
|
const_color = ((const_color & 0x1F) << 3) | ((const_color & 0x3E0) << 6) | ((const_color & 0x7C00) << 9) | ((const_color & 0x8000) << 16);
|
|
|
|
|
m_cached_ctx.FRAME.FBMSK = ((fb_mask & 0x1F) << 3) | ((fb_mask & 0x3E0) << 6) | ((fb_mask & 0x7C00) << 9) | ((fb_mask & 0x8000) << 16);
|
|
|
|
|
m_cached_ctx.TEXA.AEM = 0;
|
|
|
|
|
m_cached_ctx.TEXA.TA0 = 0;
|
|
|
|
|
m_cached_ctx.TEXA.TA1 = 128;
|
|
|
|
|
m_cached_ctx.FRAME.PSM = (m_cached_ctx.FRAME.PSM & 2) ? m_cached_ctx.FRAME.PSM : PSMCT16;
|
|
|
|
|
m_vertex.buff[m_index.buff[1]].RGBAQ.U32[0] = const_color;
|
|
|
|
|
ReplaceVerticesWithSprite(m_r, GSVector2i(m_r.width(), m_r.height()));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Be careful of being 1 pixel from filled.
|
|
|
|
|
const bool page_aligned = (m_r.w % pgs.y) == (pgs.y - 1) || (m_r.w % pgs.y) == 0;
|
|
|
|
|
@@ -2936,7 +2979,7 @@ void GSRendererHW::Draw()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
possible_shuffle = !no_rt && (((shuffle_target /*&& GSLocalMemory::m_psm[m_cached_ctx.FRAME.PSM].bpp == 16*/) /*|| (m_cached_ctx.FRAME.Block() == m_cached_ctx.TEX0.TBP0 && ((m_cached_ctx.TEX0.PSM & 0x6) || m_cached_ctx.FRAME.PSM != m_cached_ctx.TEX0.PSM))*/) || IsPossibleChannelShuffle());
|
|
|
|
|
const bool need_aem_color = GSLocalMemory::m_psm[m_cached_ctx.TEX0.PSM].trbpp <= 24 && GSLocalMemory::m_psm[m_cached_ctx.TEX0.PSM].pal == 0 && ((NeedsBlending() && m_context->ALPHA.C == 0) || IsDiscardingDstAlpha()) && m_draw_env->TEXA.AEM;
|
|
|
|
|
const bool need_aem_color = GSLocalMemory::m_psm[m_cached_ctx.TEX0.PSM].trbpp <= 24 && GSLocalMemory::m_psm[m_cached_ctx.TEX0.PSM].pal == 0 && ((NeedsBlending() && m_context->ALPHA.C == 0) || IsDiscardingDstAlpha()) && m_cached_ctx.TEXA.AEM;
|
|
|
|
|
const u32 color_mask = (m_vt.m_max.c > GSVector4i::zero()).mask();
|
|
|
|
|
const bool texture_function_color = m_cached_ctx.TEX0.TFX == TFX_DECAL || (color_mask & 0xFFF) || (m_cached_ctx.TEX0.TFX > TFX_DECAL && (color_mask & 0xF000));
|
|
|
|
|
const bool texture_function_alpha = m_cached_ctx.TEX0.TFX != TFX_MODULATE || (color_mask & 0xF000);
|
|
|
|
|
@@ -2953,8 +2996,8 @@ void GSRendererHW::Draw()
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
src = tex_psm.depth ? g_texture_cache->LookupDepthSource(true, TEX0, env.TEXA, MIP_CLAMP, tmm.coverage, possible_shuffle, m_vt.IsLinear(), m_cached_ctx.FRAME, req_color, req_alpha) :
|
|
|
|
|
g_texture_cache->LookupSource(true, TEX0, env.TEXA, MIP_CLAMP, tmm.coverage, (GSConfig.HWMipmap || GSConfig.TriFilter == TriFiltering::Forced) ? &hash_lod_range : nullptr,
|
|
|
|
|
src = tex_psm.depth ? g_texture_cache->LookupDepthSource(true, TEX0, m_cached_ctx.TEXA, MIP_CLAMP, tmm.coverage, possible_shuffle, m_vt.IsLinear(), m_cached_ctx.FRAME, req_color, req_alpha) :
|
|
|
|
|
g_texture_cache->LookupSource(true, TEX0, m_cached_ctx.TEXA, MIP_CLAMP, tmm.coverage, (GSConfig.HWMipmap || GSConfig.TriFilter == TriFiltering::Forced) ? &hash_lod_range : nullptr,
|
|
|
|
|
possible_shuffle, m_vt.IsLinear(), m_cached_ctx.FRAME, req_color, req_alpha);
|
|
|
|
|
|
|
|
|
|
if (!src) [[unlikely]]
|
|
|
|
|
@@ -3603,17 +3646,18 @@ void GSRendererHW::Draw()
|
|
|
|
|
if (ds && rt && (m_cached_ctx.ZBUF.Block() - ds->m_TEX0.TBP0) != (m_cached_ctx.FRAME.Block() - rt->m_TEX0.TBP0))
|
|
|
|
|
{
|
|
|
|
|
m_using_temp_z = true;
|
|
|
|
|
const int page_offset = (static_cast<int>(m_cached_ctx.ZBUF.Block() - ds->m_TEX0.TBP0) / 32);
|
|
|
|
|
const int z_vertical_offset = (page_offset / std::max(ds->m_TEX0.TBW, 1U)) * GSLocalMemory::m_psm[m_cached_ctx.ZBUF.PSM].pgs.y;
|
|
|
|
|
const int z_horizontal_offset = (page_offset % std::max(ds->m_TEX0.TBW, 1U)) * GSLocalMemory::m_psm[m_cached_ctx.ZBUF.PSM].pgs.x;
|
|
|
|
|
const int page_offset = static_cast<int>(m_cached_ctx.ZBUF.Block() - ds->m_TEX0.TBP0) / 32;
|
|
|
|
|
const int rt_page_offset = static_cast<int>(m_cached_ctx.FRAME.Block() - rt->m_TEX0.TBP0) / 32;
|
|
|
|
|
const int z_vertical_offset = (page_offset / std::max(static_cast<int>(ds->m_TEX0.TBW), 1)) * GSLocalMemory::m_psm[m_cached_ctx.ZBUF.PSM].pgs.y;
|
|
|
|
|
const int z_horizontal_offset = (page_offset % std::max(static_cast<int>(ds->m_TEX0.TBW), 1)) * GSLocalMemory::m_psm[m_cached_ctx.ZBUF.PSM].pgs.x;
|
|
|
|
|
if (g_texture_cache->GetTemporaryZ() != nullptr)
|
|
|
|
|
{
|
|
|
|
|
GSTextureCache::TempZAddress z_address_info = g_texture_cache->GetTemporaryZInfo();
|
|
|
|
|
|
|
|
|
|
const int old_z_vertical_offset = (page_offset / std::max(ds->m_TEX0.TBW, 1U)) * GSLocalMemory::m_psm[m_cached_ctx.ZBUF.PSM].pgs.y;
|
|
|
|
|
const int old_z_horizontal_offset = (page_offset % std::max(ds->m_TEX0.TBW, 1U)) * GSLocalMemory::m_psm[m_cached_ctx.ZBUF.PSM].pgs.x;
|
|
|
|
|
const int old_z_vertical_offset = (z_address_info.offset / std::max(static_cast<int>(ds->m_TEX0.TBW), 1)) * GSLocalMemory::m_psm[m_cached_ctx.ZBUF.PSM].pgs.y;
|
|
|
|
|
const int old_z_horizontal_offset = (z_address_info.offset % std::max(static_cast<int>(ds->m_TEX0.TBW), 1)) * GSLocalMemory::m_psm[m_cached_ctx.ZBUF.PSM].pgs.x;
|
|
|
|
|
|
|
|
|
|
if (ds->m_TEX0.TBP0 != z_address_info.ZBP || z_address_info.offset != page_offset)
|
|
|
|
|
if (ds->m_TEX0.TBP0 != z_address_info.ZBP || z_address_info.offset != page_offset || z_address_info.rt_offset != rt_page_offset)
|
|
|
|
|
g_texture_cache->InvalidateTemporaryZ();
|
|
|
|
|
else if (!m_r.rintersect(z_address_info.rect_since).rempty() && m_cached_ctx.TEST.ZTST > ZTST_ALWAYS)
|
|
|
|
|
{
|
|
|
|
|
@@ -3633,10 +3677,11 @@ void GSRendererHW::Draw()
|
|
|
|
|
|
|
|
|
|
if (g_texture_cache->GetTemporaryZ() == nullptr)
|
|
|
|
|
{
|
|
|
|
|
ds->Update(); // We need to update any dirty bits of Z before the copy
|
|
|
|
|
|
|
|
|
|
m_temp_z_full_copy = false;
|
|
|
|
|
const int get_next_ctx = m_env.PRIM.CTXT;
|
|
|
|
|
const GSDrawingContext& next_ctx = m_env.CTXT[get_next_ctx];
|
|
|
|
|
const int rt_page_offset = (static_cast<int>(m_cached_ctx.FRAME.Block() - rt->m_TEX0.TBP0) / 32);
|
|
|
|
|
const int vertical_page_offset = (rt_page_offset / std::max(static_cast<int>(rt->m_TEX0.TBW), 1));
|
|
|
|
|
const int vertical_offset = vertical_page_offset * frame_psm.pgs.y;
|
|
|
|
|
const int horizontal_offset = (rt_page_offset - (vertical_page_offset * std::max(static_cast<int>(rt->m_TEX0.TBW), 1))) * frame_psm.pgs.x;
|
|
|
|
|
@@ -3644,36 +3689,21 @@ void GSRendererHW::Draw()
|
|
|
|
|
const u32 horizontal_size = std::max(rt->m_unscaled_size.x, ds->m_unscaled_size.x);
|
|
|
|
|
const u32 vertical_size = std::max(rt->m_unscaled_size.y, ds->m_unscaled_size.y);
|
|
|
|
|
|
|
|
|
|
GSVector4i dRect = GSVector4i(horizontal_offset * ds->m_scale, vertical_offset * ds->m_scale, ds->m_unscaled_size.x * ds->m_scale, ds->m_unscaled_size.y * ds->m_scale);
|
|
|
|
|
GSVector4i dRect = GSVector4i(horizontal_offset * ds->m_scale, vertical_offset * ds->m_scale, (horizontal_offset + (ds->m_unscaled_size.x - z_horizontal_offset)) * ds->m_scale, (vertical_offset + (ds->m_unscaled_size.y - z_vertical_offset)) * ds->m_scale);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const int new_height = std::max(static_cast<int>(vertical_size * ds->m_scale), dRect.w);
|
|
|
|
|
const int new_width = std::max(static_cast<int>(horizontal_size * ds->m_scale), dRect.z);
|
|
|
|
|
// Size here should match whichever is biggest, since that's probably what's going to happen with it further down.
|
|
|
|
|
const int new_height = std::min(2048, std::max(t_size.y, static_cast<int>(vertical_size))) * ds->m_scale;
|
|
|
|
|
const int new_width = std::min(2048, std::max(t_size.x, static_cast<int>(horizontal_size))) * ds->m_scale;
|
|
|
|
|
const int height_diff = new_height - (ds->m_unscaled_size.y * ds->m_scale);
|
|
|
|
|
const int width_diff = new_width - (ds->m_unscaled_size.x * ds->m_scale);
|
|
|
|
|
|
|
|
|
|
if (GSTexture* tex = g_gs_device->CreateDepthStencil(new_width, new_height, GSTexture::Format::DepthStencil, true))
|
|
|
|
|
{
|
|
|
|
|
GSVector4 sRect = GSVector4(static_cast<float>(z_horizontal_offset) / static_cast<float>(ds->m_unscaled_size.x), static_cast<float>(z_vertical_offset) / static_cast<float>(ds->m_unscaled_size.y), 1.0f - (static_cast<float>(horizontal_offset - z_horizontal_offset) / static_cast<float>(ds->m_unscaled_size.x)), 1.0f - (static_cast<float>(vertical_offset - z_vertical_offset) / static_cast<float>(ds->m_unscaled_size.y)));
|
|
|
|
|
GSVector4 sRect = GSVector4(static_cast<float>(z_horizontal_offset) / static_cast<float>(ds->m_unscaled_size.x), static_cast<float>(z_vertical_offset) / static_cast<float>(ds->m_unscaled_size.y), 1.0f , 1.0f);
|
|
|
|
|
|
|
|
|
|
const bool restricted_copy = !(((next_ctx.ZBUF.ZBP == m_context->ZBUF.ZBP && next_ctx.FRAME.FBP == m_context->FRAME.FBP)) && !(IsPossibleChannelShuffle() && !IsPageCopy()));
|
|
|
|
|
|
|
|
|
|
if (!restricted_copy)
|
|
|
|
|
{
|
|
|
|
|
if (height_diff)
|
|
|
|
|
{
|
|
|
|
|
const int adjust = std::min(height_diff, (vertical_offset - z_vertical_offset));
|
|
|
|
|
sRect.w += static_cast<float>(adjust) / static_cast<float>(ds->m_unscaled_size.y);
|
|
|
|
|
dRect.w += adjust;
|
|
|
|
|
}
|
|
|
|
|
if (width_diff)
|
|
|
|
|
{
|
|
|
|
|
const int adjust = std::min(width_diff, (horizontal_offset - z_horizontal_offset));
|
|
|
|
|
sRect.z += static_cast<float>(adjust) / static_cast<float>(ds->m_unscaled_size.x);
|
|
|
|
|
dRect.z += adjust;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
if (restricted_copy)
|
|
|
|
|
{
|
|
|
|
|
// m_r already has horizontal_offset (rt offset) applied)
|
|
|
|
|
dRect = GSVector4i(m_r.x * ds->m_scale, m_r.y * ds->m_scale, ((1 + m_r.z) * ds->m_scale), ((1 + m_r.w) * ds->m_scale));
|
|
|
|
|
@@ -3686,10 +3716,13 @@ void GSRendererHW::Draw()
|
|
|
|
|
|
|
|
|
|
GL_CACHE("HW: RT in RT Z copy on draw %d z_vert_offset %d", s_n, page_offset);
|
|
|
|
|
|
|
|
|
|
g_gs_device->StretchRect(ds->m_texture, sRect, tex, GSVector4(dRect), ShaderConvert::DEPTH_COPY, false);
|
|
|
|
|
g_perfmon.Put(GSPerfMon::TextureCopies, 1);
|
|
|
|
|
if (m_cached_ctx.TEST.ZTST > ZTST_ALWAYS || !dRect.rintersect(GSVector4i(GSVector4(m_r) * ds->m_scale)).eq(dRect))
|
|
|
|
|
{
|
|
|
|
|
g_gs_device->StretchRect(ds->m_texture, sRect, tex, GSVector4(dRect), ShaderConvert::DEPTH_COPY, false);
|
|
|
|
|
g_perfmon.Put(GSPerfMon::TextureCopies, 1);
|
|
|
|
|
}
|
|
|
|
|
g_texture_cache->SetTemporaryZ(tex);
|
|
|
|
|
g_texture_cache->SetTemporaryZInfo(ds->m_TEX0.TBP0, page_offset);
|
|
|
|
|
g_texture_cache->SetTemporaryZInfo(ds->m_TEX0.TBP0, page_offset, rt_page_offset);
|
|
|
|
|
t_size.y = std::max(static_cast<int>(new_height / ds->m_scale), t_size.y);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
@@ -4328,7 +4361,10 @@ void GSRendererHW::Draw()
|
|
|
|
|
const GSLocalMemory::psm_t& z_psm = GSLocalMemory::m_psm[m_cached_ctx.ZBUF.PSM];
|
|
|
|
|
const int vertical_offset = ((static_cast<int>(m_cached_ctx.FRAME.Block() - rt->m_TEX0.TBP0) / 32) / std::max(static_cast<int>(rt->m_TEX0.TBW), 1)) * frame_psm.pgs.y;
|
|
|
|
|
const int z_vertical_offset = ((static_cast<int>(m_cached_ctx.ZBUF.Block() - ds->m_TEX0.TBP0) / 32) / std::max(static_cast<int>(ds->m_TEX0.TBW), 1)) * z_psm.pgs.y;
|
|
|
|
|
const GSVector4i ds_rect = m_r - GSVector4i(vertical_offset - z_vertical_offset);
|
|
|
|
|
const int z_horizontal_offset = ((static_cast<int>(m_cached_ctx.ZBUF.Block() - ds->m_TEX0.TBP0) / 32) % std::max(rt->m_TEX0.TBW, 1U)) * z_psm.pgs.x;
|
|
|
|
|
const int horizontal_offset = ((static_cast<int>(m_cached_ctx.FRAME.Block() - rt->m_TEX0.TBP0) / 32) % std::max(static_cast<int>(rt->m_TEX0.TBW), 1)) * frame_psm.pgs.x;
|
|
|
|
|
|
|
|
|
|
const GSVector4i ds_rect = m_r - GSVector4i(horizontal_offset - z_horizontal_offset, vertical_offset - z_vertical_offset).xyxy();
|
|
|
|
|
ds->UpdateValidity(ds_rect, z_update && (can_update_size || (ds_rect.w <= (resolution.y * 2) && !m_texture_shuffle)));
|
|
|
|
|
ds->UpdateDrawn(ds_rect, z_update && (can_update_size || (ds_rect.w <= (resolution.y * 2) && !m_texture_shuffle)));
|
|
|
|
|
}
|
|
|
|
|
@@ -4573,14 +4609,14 @@ void GSRendererHW::Draw()
|
|
|
|
|
{
|
|
|
|
|
const int get_next_ctx = m_env.PRIM.CTXT;
|
|
|
|
|
const GSDrawingContext& next_ctx = m_env.CTXT[get_next_ctx];
|
|
|
|
|
const int z_vertical_offset = ((static_cast<int>(m_cached_ctx.ZBUF.Block() - ds->m_TEX0.TBP0) / 32) / std::max(rt->m_TEX0.TBW, 1U)) * GSLocalMemory::m_psm[m_cached_ctx.ZBUF.PSM].pgs.y;
|
|
|
|
|
const int z_horizontal_offset = ((static_cast<int>(m_cached_ctx.ZBUF.Block() - ds->m_TEX0.TBP0) / 32) % std::max(rt->m_TEX0.TBW, 1U)) * GSLocalMemory::m_psm[m_cached_ctx.ZBUF.PSM].pgs.x;
|
|
|
|
|
const int z_vertical_offset = ((static_cast<int>(m_cached_ctx.ZBUF.Block() - ds->m_TEX0.TBP0) / 32) / std::max(static_cast<int>(rt->m_TEX0.TBW), 1)) * GSLocalMemory::m_psm[m_cached_ctx.ZBUF.PSM].pgs.y;
|
|
|
|
|
const int z_horizontal_offset = ((static_cast<int>(m_cached_ctx.ZBUF.Block() - ds->m_TEX0.TBP0) / 32) % std::max(static_cast<int>(rt->m_TEX0.TBW), 1)) * GSLocalMemory::m_psm[m_cached_ctx.ZBUF.PSM].pgs.x;
|
|
|
|
|
const int vertical_offset = ((static_cast<int>(m_cached_ctx.FRAME.Block() - rt->m_TEX0.TBP0) / 32) / std::max(static_cast<int>(rt->m_TEX0.TBW), 1)) * frame_psm.pgs.y;
|
|
|
|
|
const int horizontal_offset = ((static_cast<int>(m_cached_ctx.FRAME.Block() - rt->m_TEX0.TBP0) / 32) % std::max(static_cast<int>(rt->m_TEX0.TBW), 1)) * frame_psm.pgs.x;
|
|
|
|
|
|
|
|
|
|
if (was_written)
|
|
|
|
|
{
|
|
|
|
|
const GSVector4i ds_real_rect = real_rect - GSVector4i(vertical_offset - z_vertical_offset);
|
|
|
|
|
const GSVector4i ds_real_rect = real_rect - GSVector4i(horizontal_offset - z_horizontal_offset, vertical_offset - z_vertical_offset).xyxy();
|
|
|
|
|
ds->UpdateValidity(ds_real_rect, !z_masked && (can_update_size || (ds_real_rect.w <= (resolution.y * 2) && !m_texture_shuffle)));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@@ -6344,7 +6380,7 @@ __ri void GSRendererHW::EmulateTextureSampler(const GSTextureCache::Target* rt,
|
|
|
|
|
// 2/ Only keep aem when it is useful (avoid useless shader permutation)
|
|
|
|
|
if (m_conf.ps.shuffle)
|
|
|
|
|
{
|
|
|
|
|
const GIFRegTEXA& TEXA = m_draw_env->TEXA;
|
|
|
|
|
const GIFRegTEXA& TEXA = m_cached_ctx.TEXA;
|
|
|
|
|
|
|
|
|
|
// Force a 32 bits access (normally shuffle is done on 16 bits)
|
|
|
|
|
// m_ps_sel.tex_fmt = 0; // removed as an optimization
|
|
|
|
|
@@ -6398,7 +6434,7 @@ __ri void GSRendererHW::EmulateTextureSampler(const GSTextureCache::Target* rt,
|
|
|
|
|
}
|
|
|
|
|
else if (tex->m_target)
|
|
|
|
|
{
|
|
|
|
|
const GIFRegTEXA& TEXA = m_draw_env->TEXA;
|
|
|
|
|
const GIFRegTEXA& TEXA = m_cached_ctx.TEXA;
|
|
|
|
|
|
|
|
|
|
// Use an old target. AEM and index aren't resolved it must be done
|
|
|
|
|
// on the GPU
|
|
|
|
|
@@ -7235,13 +7271,13 @@ __ri void GSRendererHW::DrawPrims(GSTextureCache::Target* rt, GSTextureCache::Ta
|
|
|
|
|
const GSVector4i shuffle_rect = GSVector4i(m_vt.m_min.p.x, m_vt.m_min.p.y, m_vt.m_max.p.x, m_vt.m_max.p.y);
|
|
|
|
|
if (!rt->m_valid.rintersect(shuffle_rect).eq(rt->m_valid) || (m_cached_ctx.FRAME.FBMSK & 0xFFFC0000))
|
|
|
|
|
{
|
|
|
|
|
rt_new_alpha_max = std::max(static_cast<int>((std::max(m_draw_env->TEXA.TA1, m_draw_env->TEXA.TA0) & 0x80) + 127), rt_new_alpha_max) | fba_value;
|
|
|
|
|
rt_new_alpha_min = std::min(static_cast<int>(std::min(m_draw_env->TEXA.TA1, m_draw_env->TEXA.TA0) & 0x80), rt_new_alpha_min);
|
|
|
|
|
rt_new_alpha_max = std::max(static_cast<int>((std::max(m_cached_ctx.TEXA.TA1, m_cached_ctx.TEXA.TA0) & 0x80) + 127), rt_new_alpha_max) | fba_value;
|
|
|
|
|
rt_new_alpha_min = std::min(static_cast<int>(std::min(m_cached_ctx.TEXA.TA1, m_cached_ctx.TEXA.TA0) & 0x80), rt_new_alpha_min);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
rt_new_alpha_max = (std::max(m_draw_env->TEXA.TA1, m_draw_env->TEXA.TA0) & 0x80) + 127 | fba_value;
|
|
|
|
|
rt_new_alpha_min = (std::min(m_draw_env->TEXA.TA1, m_draw_env->TEXA.TA0) & 0x80) | fba_value;
|
|
|
|
|
rt_new_alpha_max = (std::max(m_cached_ctx.TEXA.TA1, m_cached_ctx.TEXA.TA0) & 0x80) + 127 | fba_value;
|
|
|
|
|
rt_new_alpha_min = (std::min(m_cached_ctx.TEXA.TA1, m_cached_ctx.TEXA.TA0) & 0x80) | fba_value;
|
|
|
|
|
}
|
|
|
|
|
rt->m_alpha_range = true;
|
|
|
|
|
}
|
|
|
|
|
@@ -8156,7 +8192,7 @@ bool GSRendererHW::CanUseSwPrimRender(bool no_rt, bool no_ds, bool draw_sprite_t
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const bool need_aem_color = GSLocalMemory::m_psm[m_cached_ctx.TEX0.PSM].trbpp <= 24 && GSLocalMemory::m_psm[m_cached_ctx.TEX0.PSM].pal == 0 && ((NeedsBlending() && m_context->ALPHA.C == 0) || IsDiscardingDstAlpha()) && m_draw_env->TEXA.AEM;
|
|
|
|
|
const bool need_aem_color = GSLocalMemory::m_psm[m_cached_ctx.TEX0.PSM].trbpp <= 24 && GSLocalMemory::m_psm[m_cached_ctx.TEX0.PSM].pal == 0 && ((NeedsBlending() && m_context->ALPHA.C == 0) || IsDiscardingDstAlpha()) && m_cached_ctx.TEXA.AEM;
|
|
|
|
|
const u32 color_mask = (m_vt.m_max.c > GSVector4i::zero()).mask();
|
|
|
|
|
const bool texture_function_color = m_cached_ctx.TEX0.TFX == TFX_DECAL || (color_mask & 0xFFF) || (m_cached_ctx.TEX0.TFX > TFX_DECAL && (color_mask & 0xF000));
|
|
|
|
|
const bool texture_function_alpha = m_cached_ctx.TEX0.TFX != TFX_MODULATE || (color_mask & 0xF000);
|
|
|
|
|
@@ -8336,8 +8372,8 @@ bool GSRendererHW::DetectDoubleHalfClear(bool& no_rt, bool& no_ds)
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Z and color must be constant and the same
|
|
|
|
|
if (m_vt.m_eq.rgba != 0xFFFF || !m_vt.m_eq.z)
|
|
|
|
|
// Z and color must be constant and the same and both are enabled.
|
|
|
|
|
if (m_vt.m_eq.rgba != 0xFFFF || !m_vt.m_eq.z || (no_ds != no_rt))
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
const u32 write_color = GetConstantDirectWriteMemClearColor();
|
|
|
|
|
@@ -8416,7 +8452,7 @@ bool GSRendererHW::DetectDoubleHalfClear(bool& no_rt, bool& no_ds)
|
|
|
|
|
// bang up next to each other, or a double half clear. The two are really difficult to differentiate.
|
|
|
|
|
// Have to check both contexts, because God of War 2 likes to do this in-between setting TRXDIR, which
|
|
|
|
|
// causes a flush, and we don't have the next context backed up index set.
|
|
|
|
|
bool horizontal = false;
|
|
|
|
|
bool horizontal = std::abs(static_cast<int>(m_cached_ctx.FRAME.FBP) - static_cast<int>(m_cached_ctx.ZBUF.ZBP)) == (m_cached_ctx.FRAME.FBW >> 1);
|
|
|
|
|
const bool possible_next_clear = !m_env.PRIM.TME && !(m_env.SCANMSK.MSK & 2) && !m_env.CTXT[next_ctx].TEST.ATE && !m_env.CTXT[next_ctx].TEST.DATE &&
|
|
|
|
|
(!m_env.CTXT[next_ctx].TEST.ZTE || m_env.CTXT[next_ctx].TEST.ZTST == ZTST_ALWAYS);
|
|
|
|
|
|
|
|
|
|
@@ -8499,6 +8535,14 @@ bool GSRendererHW::DetectDoubleHalfClear(bool& no_rt, bool& no_ds)
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
const int height = m_r.height();
|
|
|
|
|
|
|
|
|
|
// We don't want to double half clear already full sized targets, making them double the size, this could be very bad.
|
|
|
|
|
// This gets triggered by Monster Lab which clears the Z and FRAME in one go, butted up against each other.
|
|
|
|
|
// It's highly unlikely that it will actually require a > 600 high framebuffer, but check with the display height first.
|
|
|
|
|
const int display_height = PCRTCDisplays.GetResolution().y;
|
|
|
|
|
if ((display_height != 0 && height >= (display_height - 1)) || height > 300)
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
m_r.w = ((half - base) / m_cached_ctx.FRAME.FBW) * frame_psm.pgs.y;
|
|
|
|
|
m_r.w += m_r.y + height;
|
|
|
|
|
}
|
|
|
|
|
|