mirror of
https://github.com/MobileGL-Dev/MobileGL
synced 2026-09-11 21:58:31 +09:00
[Feat] (MG_Backend, MG_Util): give DirectVulkan GL's provoking vertex
Vulkan's built-in convention is "provoking vertex first"; GL's default is LAST_VERTEX_CONVENTION, and GL derives both flat shading and the transform feedback vertex order from it. DirectVulkan had no way to say so, which is why direct_state_access.queries_functional failed on a value with nothing in its log - the primitives came back counted against a strip recorded in the wrong vertex order. VK_EXT_provoking_vertex is now enabled when present, and the mode is a hashed field of the pipeline payload rather than dynamic state, because it is baked into VkPipelineRasterizationStateCreateInfo: two draws differing only in it must not collide on one cached VkPipeline, or whichever mode built first would stick for the rest of the frame. The pNext is chained only when the mode is not Vulkan's default, so a device without the extension produces a byte-identical VkGraphicsPipelineCreateInfo to before. Two carve-outs, both measured rather than reasoned: A geometry shader already emits its triangles in GL's vertex order, so asking for LAST rotates them a second time and transform_feedback.geometry reads back the wrong vertices. The mode is one pipeline bit and the input-assembler path wants the opposite, so the two cannot both be satisfied: a program that runs a geometry shader and captures transform feedback keeps Vulkan's own convention. That test is read off the program's own shader list, not programObj.rasterizationProducerStage - the latter is filled by the clip-fixup analysis, which does not run for every program and reads Unknown for exactly the programs this guard exists to catch. Both halves are link-time facts folded into programObj.hash, so no pipeline memo can hand back one built for the other mode; keying on IsTransformFeedbackActive() instead would be a live bug, since neither memo key moves on glBeginTransformFeedback. transformFeedbackPreservesProvokingVertex is deliberately not requested. It buys nothing here - the capture order queries_functional needs comes from provokingVertexLast alone - and leaving it off keeps VUID-VkGraphicsPipelineCreateInfo-topology-04884 disarmed, so a TRIANGLE_FAN pipeline may take LAST on any device. The blit pipeline routes through the same selector: it has no flat varying and no capture, but on a device without provokingVertexModePerPipeline a blit left on FIRST inside a render pass whose draws are LAST is an illegal mix. Per the POST rule the new extension gets rows for provokingVertexLast and for the two properties that change what MobileGL can promise. Fixes queries_functional on Magma (370/371). An A/B over a 976-case transform feedback / geometry shader / layered rendering subset of GL30-GL45 is otherwise identical on both backends and additionally takes 14 geometry_shader rendering and layered_rendering cases from failing to passing on Magma.
This commit is contained in:
@@ -498,6 +498,30 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
|
||||
// VK_EXT_transform_feedback (GL transform feedback capture)
|
||||
Bool m_transformFeedbackFeatureEnabled = false;
|
||||
// VK_EXT_provoking_vertex. Vulkan's built-in convention is "provoking vertex first"; GL's
|
||||
// default is LAST_VERTEX_CONVENTION, and GL derives BOTH flat shading and the transform
|
||||
// feedback vertex order from it. provokingVertexLast alone fixes flat shading and the
|
||||
// input-assembler capture order and has no dependency on transform feedback; only
|
||||
// transformFeedbackPreservesProvokingVertex does.
|
||||
Bool m_provokingVertexLastEnabled = false;
|
||||
// transformFeedbackPreservesProvokingVertex was actually enabled at device creation. Kept
|
||||
// separate because it is the only thing that arms
|
||||
// VUID-VkGraphicsPipelineCreateInfo-topology-04884, the rule that forbids a TRIANGLE_FAN
|
||||
// pipeline from asking for LAST on a device that cannot preserve a fan's provoking vertex.
|
||||
Bool m_provokingVertexXfbPreserveEnabled = false;
|
||||
// provokingVertexModePerPipeline: when VK_FALSE every pipeline in one render pass instance
|
||||
// must agree on the mode, so glProvokingVertex(GL_FIRST_VERTEX_CONVENTION) cannot be honoured
|
||||
// per draw and every pipeline takes GL's default (LAST) instead.
|
||||
Bool m_provokingVertexModePerPipeline = false;
|
||||
// transformFeedbackPreservesTriangleFanProvokingVertex.
|
||||
Bool m_provokingVertexFanPreserved = false;
|
||||
// Per-pipeline provoking-vertex mode. capturesXfbFromGeometryStage must be a LINK-TIME
|
||||
// property of the program, never the dynamic "is transform feedback active" flag: the
|
||||
// 8-entry m_pipelineMemo and the SetupDrawSnapshot fast path key on programObj.hash and
|
||||
// GetRenderStateParametersVersion(), neither of which moves when glBeginTransformFeedback is
|
||||
// called, so a dynamic input here would hand back a stale VkPipeline.
|
||||
VkProvokingVertexModeEXT SelectProvokingVertexMode(VkPrimitiveTopology topology,
|
||||
Bool capturesXfbFromGeometryStage) const;
|
||||
// VK_EXT_vertex_attribute_divisor: without it every non-zero glVertexAttribDivisor
|
||||
// behaves as 1, because that is all Vulkan's instance input rate can express.
|
||||
Bool m_vertexAttributeDivisorEnabled = false;
|
||||
|
||||
Reference in New Issue
Block a user