diff --git a/bin/resources/shaders/dx11/tfx.fx b/bin/resources/shaders/dx11/tfx.fx index 80962b378c..5f1bd97a59 100644 --- a/bin/resources/shaders/dx11/tfx.fx +++ b/bin/resources/shaders/dx11/tfx.fx @@ -2014,11 +2014,6 @@ VS_OUTPUT vs_main_expand(uint vid : SV_VertexID) vtx.inv_cov = is_near_corner ? 0.0f : 1.0f; // Full coverage at near corner, otherwise none. vtx.interior = 0; - - #if !VS_IIP - // Get the provoking vertex color (first vertex in DX) - vtx.c = i0 == 0 ? vtx.c : (i1 == 0 ? other.c : opposite.c); - #endif } return vtx; diff --git a/bin/resources/shaders/opengl/tfx_vgs.glsl b/bin/resources/shaders/opengl/tfx_vgs.glsl index 41fb300071..95135e2b4d 100644 --- a/bin/resources/shaders/opengl/tfx_vgs.glsl +++ b/bin/resources/shaders/opengl/tfx_vgs.glsl @@ -455,11 +455,6 @@ void main() VSout.inv_cov = is_near_corner ? 0.0f : 1.0f; // Full coverage at near corner, otherwise none. VSout.interior = 0; - - #if !VS_IIP - // Get the provoking vertex color (last vertex in GL) - vtx.c = i0 == 2 ? vtx.c : (i1 == 2 ? other.c : opposite.c); - #endif } #endif diff --git a/bin/resources/shaders/vulkan/tfx.glsl b/bin/resources/shaders/vulkan/tfx.glsl index a1adbb2d91..12736ff9a7 100644 --- a/bin/resources/shaders/vulkan/tfx.glsl +++ b/bin/resources/shaders/vulkan/tfx.glsl @@ -450,11 +450,6 @@ void main() vsOut.inv_cov = is_near_corner ? 0.0f : 1.0f; // Full coverage at near corner, otherwise none. vsOut.interior = 0; - - #if !VS_IIP - // Get the provoking vertex color (last vertex in VK) - vtx.c = i0 == 2 ? vtx.c : (i1 == 2 ? other.c : opposite.c); - #endif } #endif diff --git a/pcsx2/GS/Renderers/HW/GSRendererHW.cpp b/pcsx2/GS/Renderers/HW/GSRendererHW.cpp index 4ab585cbed..1a3879ca0a 100644 --- a/pcsx2/GS/Renderers/HW/GSRendererHW.cpp +++ b/pcsx2/GS/Renderers/HW/GSRendererHW.cpp @@ -5331,31 +5331,36 @@ bool GSRendererHW::VerifyIndices() return true; } -// 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::HandleFlatShadedVertices() { - // 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) + // These cases might need fixing. + const bool maybe_fix_vertices = !m_conf.vs.iip && + (!g_gs_device->Features().provoking_vertex_last || IsCoverageAlphaSupported()); + + // These cases definitely don't need fixing. + const bool dont_fix_vertices = m_vt.m_primclass == GS_POINT_CLASS || m_vt.m_primclass == GS_SPRITE_CLASS; + + if (!maybe_fix_vertices || dont_fix_vertices) return; const int n = GSUtil::GetClassVertexCount(m_vt.m_primclass); - // If all first/last vertices have the same color there is nothing to do. - bool first_eq_last = true; + // If all vertices of each prim have the same color there is nothing to do. + bool prims_flat = true; for (u32 i = 0; i < m_index->tail; i += n) { - if (m_vertex->buff[m_index->buff[i]].RGBAQ.U32[0] != m_vertex->buff[m_index->buff[i + n - 1]].RGBAQ.U32[0]) + for (u32 j = 0; j < n - 1; j++) { - first_eq_last = false; - break; + if (m_vertex->buff[m_index->buff[i + j]].RGBAQ.U32[0] != m_vertex->buff[m_index->buff[i + n - 1]].RGBAQ.U32[0]) + { + prims_flat = false; + break; + } } + if (!prims_flat) + break; } - if (first_eq_last) + if (prims_flat) return; // De-index the vertices using the copy buffer @@ -5369,11 +5374,11 @@ void GSRendererHW::HandleProvokingVertexFirst() std::swap(m_vertex->buff, m_vertex->buff_copy); m_vertex->head = m_vertex->next = m_vertex->tail = m_index->tail; - // Put correct color in the first vertex + // Make all vertices the same color to simplify handling in expand shaders. for (u32 i = 0; i < m_index->tail; i += n) { - m_vertex->buff[i].RGBAQ.U32[0] = m_vertex->buff[i + n - 1].RGBAQ.U32[0]; - m_vertex->buff[i + n - 1].RGBAQ.U32[0] = 0xff; // Make last vertex red for debugging if used improperly + for (u32 j = 0; j < n - 1; j++) + m_vertex->buff[i + j].RGBAQ.U32[0] = m_vertex->buff[i + n - 1].RGBAQ.U32[0]; } } @@ -9450,7 +9455,7 @@ __ri void GSRendererHW::DrawPrims(GSTextureCache::Target* rt, GSTextureCache::Ta DetermineROVUsage(rt, ds); ConvertTextureTypeROV(rt, ds); - // Barriers must be determined before indices are modified via HandleProvokingVertexFirst/SetupIA. + // Barriers must be determined before indices are modified via HandleFlatShadedVertices/SetupIA. // This also computes the drawlist if needed. DetermineBarriers(rt, tex); @@ -9475,7 +9480,7 @@ __ri void GSRendererHW::DrawPrims(GSTextureCache::Target* rt, GSTextureCache::Ta m_conf.scissor = (date_options.enabled && !date_options.barrier) ? m_conf.drawarea : scissor; - HandleProvokingVertexFirst(); + HandleFlatShadedVertices(); SetupIA(rtscale, vs_scale_x, vs_scale_y, m_channel_shuffle_width != 0, no_rt); diff --git a/pcsx2/GS/Renderers/HW/GSRendererHW.h b/pcsx2/GS/Renderers/HW/GSRendererHW.h index bce5419503..4ee9d556ee 100644 --- a/pcsx2/GS/Renderers/HW/GSRendererHW.h +++ b/pcsx2/GS/Renderers/HW/GSRendererHW.h @@ -215,7 +215,7 @@ private: void DrawPrims(GSTextureCache::Target* rt, GSTextureCache::Target* ds, GSTextureCache::Source* tex, const TextureMinMaxResult& tmm); void ResetStates(); - void HandleProvokingVertexFirst(); + void HandleFlatShadedVertices(); void SetupIA(float target_scale, float sx, float sy, bool req_vert_backup, const bool no_rt); void EmulateTextureShuffleAndFbmask(GSTextureCache::Target* rt, GSTextureCache::Source* tex); u32 EmulateChannelShuffle(GSTextureCache::Target* src, bool test_only, GSTextureCache::Target* rt = nullptr); diff --git a/pcsx2/GS/Renderers/Metal/tfx.metal b/pcsx2/GS/Renderers/Metal/tfx.metal index 7ed2eec78e..d56ce2dd3a 100644 --- a/pcsx2/GS/Renderers/Metal/tfx.metal +++ b/pcsx2/GS/Renderers/Metal/tfx.metal @@ -555,12 +555,6 @@ vertex MainVSOut vs_main_expand( out.inv_cov = is_near_corner ? 0.0f : 1.0f; // Full coverage at near corner, otherwise none. out.interior = 0; - - if (NOT_IIP) - { - // Get the provoking vertex color (first vertex in Metal) - out.fc = i0 == 0 ? out.fc : (i1 == 0 ? other.fc : opposite.fc); - } } return out; diff --git a/pcsx2/ShaderCacheVersion.h b/pcsx2/ShaderCacheVersion.h index f767c68783..da27be88cb 100644 --- a/pcsx2/ShaderCacheVersion.h +++ b/pcsx2/ShaderCacheVersion.h @@ -3,4 +3,4 @@ /// Version number for GS and other shaders. Increment whenever any of the contents of the /// shaders change, to invalidate the cache. -static constexpr u32 SHADER_CACHE_VERSION = 106; // Last changed in PR 14643 +static constexpr u32 SHADER_CACHE_VERSION = 107; // Last changed in PR 14634