This commit is contained in:
TJnotJT 2025-12-15 02:28:59 -03:00 committed by GitHub
commit 86f565530a
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 49 additions and 34 deletions

View File

@ -4922,17 +4922,23 @@ bool GSRendererHW::VerifyIndices()
// Fix the colors in vertices in case the API only supports "provoking first vertex"
// (i.e., when using flat shading the color comes from the first vertex, unlike PS2
// which is "provoking last vertex").
void GSRendererHW::HandleProvokingVertexFirst()
void GSRendererHW::HandleProvokingVertexFirst(bool swap_indices)
{
// Early exit conditions:
if (g_gs_device->Features().provoking_vertex_last || // device supports provoking last vertex
m_conf.vs.iip || // we are doing Gouraud shading
m_vt.m_primclass == GS_POINT_CLASS || // drawing points (one vertex per primitive; color is unambiguous)
m_vt.m_primclass == GS_SPRITE_CLASS) // drawing sprites (handled by the sprites -> triangles expand shader)
return;
pxAssertRel(!g_gs_device->Features().provoking_vertex_last && !m_conf.vs.iip,
"Should not call HandleProvokingVertexFirst() when API uses provoking vertex last or interpolating colors.");
const int n = GSUtil::GetClassVertexCount(m_vt.m_primclass);
if (swap_indices)
{
// Fast path: just swap the indices. Used in cases where drawing order does not matter (triangles, expanded lines).
for (u32 i = 0; i < m_index.tail; i += n)
std::swap(m_index.buff[i], m_index.buff[i + n - 1]);
}
else
{
// Slow path: de-index and swap the vertex colors. Used in cases where the drawing order matters (lines).
// If all first/last vertices have the same color there is nothing to do.
bool first_eq_last = true;
for (u32 i = 0; i < m_index.tail; i += n)
@ -4964,6 +4970,7 @@ void GSRendererHW::HandleProvokingVertexFirst()
m_vertex.buff[i + n - 1].RGBAQ.U32[0] = 0xff; // Make last vertex red for debugging if used improperly
}
}
}
void GSRendererHW::SetupIA(float target_scale, float sx, float sy, bool req_vert_backup)
{
@ -5035,6 +5042,13 @@ void GSRendererHW::SetupIA(float target_scale, float sx, float sy, bool req_vert
ExpandLineIndices();
}
}
if (!features.provoking_vertex_last && !m_conf.vs.iip) // Flat shaded colors and API uses provoking vertex first
{
// Expanded lines are converted to triangles where drawing order does not matter so just swap first/last indices.
const bool swap_indices = m_conf.line_expand || (m_conf.vs.expand != GSHWDrawConfig::VSExpand::None);
HandleProvokingVertexFirst(swap_indices);
}
}
break;
@ -5093,6 +5107,9 @@ void GSRendererHW::SetupIA(float target_scale, float sx, float sy, bool req_vert
GSVector4::store<true>(&v[i].ST, v_st);
}
}
if (!features.provoking_vertex_last && !m_conf.vs.iip) // Flat shaded colors and API uses provoking vertex first
HandleProvokingVertexFirst(true); // Drawing order does not matter for triangles so just swap first/last indices.
}
break;
@ -8037,8 +8054,6 @@ __ri void GSRendererHW::DrawPrims(GSTextureCache::Target* rt, GSTextureCache::Ta
m_conf.drawarea = m_channel_shuffle ? scissor : scissor.rintersect(ComputeBoundingBox(rtsize, rtscale));
m_conf.scissor = (DATE && !DATE_BARRIER) ? m_conf.drawarea : scissor;
HandleProvokingVertexFirst();
SetupIA(rtscale, sx, sy, m_channel_shuffle_width != 0);
if (ate_second_pass)

View File

@ -93,7 +93,7 @@ private:
void DrawPrims(GSTextureCache::Target* rt, GSTextureCache::Target* ds, GSTextureCache::Source* tex, const TextureMinMaxResult& tmm);
void ResetStates();
void HandleProvokingVertexFirst();
void HandleProvokingVertexFirst(bool swap_indices);
void SetupIA(float target_scale, float sx, float sy, bool req_vert_backup);
void EmulateTextureShuffleAndFbmask(GSTextureCache::Target* rt, GSTextureCache::Source* tex);
bool EmulateChannelShuffle(GSTextureCache::Target* src, bool test_only, GSTextureCache::Target* rt = nullptr);