mirror of
https://github.com/MobileGL-Dev/MobileGL
synced 2026-09-09 20: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:
@@ -209,6 +209,8 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
XXHASH_VERIFY(XXH64_update(m_hashState, &payload.polygonMode, sizeof(payload.polygonMode)));
|
||||
XXHASH_VERIFY(XXH64_update(m_hashState, &payload.cullMode, sizeof(payload.cullMode)));
|
||||
XXHASH_VERIFY(XXH64_update(m_hashState, &payload.frontFace, sizeof(payload.frontFace)));
|
||||
XXHASH_VERIFY(
|
||||
XXH64_update(m_hashState, &payload.provokingVertexMode, sizeof(payload.provokingVertexMode)));
|
||||
XXHASH_VERIFY(XXH64_update(m_hashState, &payload.depthTestEnable, sizeof(payload.depthTestEnable)));
|
||||
XXHASH_VERIFY(XXH64_update(m_hashState, &payload.depthWriteEnable, sizeof(payload.depthWriteEnable)));
|
||||
XXHASH_VERIFY(XXH64_update(m_hashState, &payload.depthBiasEnable, sizeof(payload.depthBiasEnable)));
|
||||
@@ -397,6 +399,17 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
raster.depthBiasEnable = payload.depthBiasEnable ? VK_TRUE : VK_FALSE;
|
||||
raster.rasterizerDiscardEnable = payload.rasterizerDiscardEnable ? VK_TRUE : VK_FALSE;
|
||||
raster.lineWidth = 1.0f;
|
||||
// Only chain the struct when the mode is not Vulkan's implicit default: a device without
|
||||
// VK_EXT_provoking_vertex enabled must never see this pNext entry, and the renderer's
|
||||
// selector already collapses to FIRST in exactly that case - so a device without the
|
||||
// extension produces a byte-identical VkGraphicsPipelineCreateInfo to before.
|
||||
VkPipelineRasterizationProvokingVertexStateCreateInfoEXT provokingVertexState{
|
||||
VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_PROVOKING_VERTEX_STATE_CREATE_INFO_EXT};
|
||||
if (payload.provokingVertexMode != VK_PROVOKING_VERTEX_MODE_FIRST_VERTEX_EXT) {
|
||||
provokingVertexState.provokingVertexMode = payload.provokingVertexMode;
|
||||
provokingVertexState.pNext = raster.pNext;
|
||||
raster.pNext = &provokingVertexState;
|
||||
}
|
||||
|
||||
VkPipelineMultisampleStateCreateInfo ms{VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO};
|
||||
ms.rasterizationSamples = payload.rasterizationSamples;
|
||||
|
||||
Reference in New Issue
Block a user