mirror of
https://github.com/MobileGL-Dev/MobileGL
synced 2026-09-12 06:08:30 +09:00
[Feat] (DirectVulkan): run the tessellation stages
The backend already turned a tessellation control/evaluation shader into the right VkShaderStage, but nothing downstream knew what to do with it: GL_PATCHES had no topology, so it fell through to the triangle-list default, and the pipeline carried no tessellation state at all. A GL_PATCHES draw therefore ran the vertex and fragment stages over raw triangles. Map GL_PATCHES to VK_PRIMITIVE_TOPOLOGY_PATCH_LIST, carry GL_PATCH_VERTICES into the pipeline as patchControlPoints (part of the key, since two patch sizes are two pipelines), attach VkPipelineTessellationStateCreateInfo for a patch topology only, and enable the tessellationShader device feature. POST reports the feature, because without it a program with a tessellation stage cannot build a pipeline at all and GL_PATCHES draws render nothing.
This commit is contained in:
@@ -205,6 +205,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
|||||||
XXHASH_VERIFY(XXH64_update(m_hashState, &payload.topology, sizeof(payload.topology)));
|
XXHASH_VERIFY(XXH64_update(m_hashState, &payload.topology, sizeof(payload.topology)));
|
||||||
XXHASH_VERIFY(
|
XXHASH_VERIFY(
|
||||||
XXH64_update(m_hashState, &payload.primitiveRestartEnable, sizeof(payload.primitiveRestartEnable)));
|
XXH64_update(m_hashState, &payload.primitiveRestartEnable, sizeof(payload.primitiveRestartEnable)));
|
||||||
|
XXHASH_VERIFY(XXH64_update(m_hashState, &payload.patchControlPoints, sizeof(payload.patchControlPoints)));
|
||||||
XXHASH_VERIFY(XXH64_update(m_hashState, &payload.polygonMode, sizeof(payload.polygonMode)));
|
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.cullMode, sizeof(payload.cullMode)));
|
||||||
XXHASH_VERIFY(XXH64_update(m_hashState, &payload.frontFace, sizeof(payload.frontFace)));
|
XXHASH_VERIFY(XXH64_update(m_hashState, &payload.frontFace, sizeof(payload.frontFace)));
|
||||||
@@ -380,6 +381,11 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
|||||||
ia.topology = payload.topology;
|
ia.topology = payload.topology;
|
||||||
ia.primitiveRestartEnable = payload.primitiveRestartEnable ? VK_TRUE : VK_FALSE;
|
ia.primitiveRestartEnable = payload.primitiveRestartEnable ? VK_TRUE : VK_FALSE;
|
||||||
|
|
||||||
|
// Only a patch topology has a tessellation stage to configure; leaving the pointer null
|
||||||
|
// otherwise is what the spec expects.
|
||||||
|
VkPipelineTessellationStateCreateInfo tessellation{VK_STRUCTURE_TYPE_PIPELINE_TESSELLATION_STATE_CREATE_INFO};
|
||||||
|
tessellation.patchControlPoints = payload.patchControlPoints;
|
||||||
|
|
||||||
VkPipelineViewportStateCreateInfo vpci{VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO};
|
VkPipelineViewportStateCreateInfo vpci{VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO};
|
||||||
vpci.viewportCount = 1;
|
vpci.viewportCount = 1;
|
||||||
vpci.scissorCount = 1;
|
vpci.scissorCount = 1;
|
||||||
@@ -444,6 +450,8 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
|||||||
gpi.pStages = payload.stages->data();
|
gpi.pStages = payload.stages->data();
|
||||||
gpi.pVertexInputState = payload.vertexInputState;
|
gpi.pVertexInputState = payload.vertexInputState;
|
||||||
gpi.pInputAssemblyState = &ia;
|
gpi.pInputAssemblyState = &ia;
|
||||||
|
gpi.pTessellationState =
|
||||||
|
payload.topology == VK_PRIMITIVE_TOPOLOGY_PATCH_LIST ? &tessellation : nullptr;
|
||||||
gpi.pViewportState = &vpci;
|
gpi.pViewportState = &vpci;
|
||||||
gpi.pRasterizationState = &raster;
|
gpi.pRasterizationState = &raster;
|
||||||
gpi.pMultisampleState = &ms;
|
gpi.pMultisampleState = &ms;
|
||||||
|
|||||||
@@ -30,6 +30,8 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
|||||||
Uint32 subpass = 0;
|
Uint32 subpass = 0;
|
||||||
VkPrimitiveTopology topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;
|
VkPrimitiveTopology topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;
|
||||||
Bool primitiveRestartEnable = false;
|
Bool primitiveRestartEnable = false;
|
||||||
|
// GL_PATCH_VERTICES; only read for a PATCH_LIST topology.
|
||||||
|
Uint32 patchControlPoints = 3;
|
||||||
VkPolygonMode polygonMode = VK_POLYGON_MODE_FILL;
|
VkPolygonMode polygonMode = VK_POLYGON_MODE_FILL;
|
||||||
VkCullModeFlags cullMode = VK_CULL_MODE_BACK_BIT;
|
VkCullModeFlags cullMode = VK_CULL_MODE_BACK_BIT;
|
||||||
VkFrontFace frontFace = VK_FRONT_FACE_CLOCKWISE;
|
VkFrontFace frontFace = VK_FRONT_FACE_CLOCKWISE;
|
||||||
|
|||||||
@@ -4209,6 +4209,7 @@ void main() {
|
|||||||
.subpass = 0,
|
.subpass = 0,
|
||||||
.topology = vkTopology,
|
.topology = vkTopology,
|
||||||
.primitiveRestartEnable = primitiveRestartEnabled,
|
.primitiveRestartEnable = primitiveRestartEnabled,
|
||||||
|
.patchControlPoints = static_cast<Uint32>(MG_State::pGLContext->GetPatchVertices()),
|
||||||
.polygonMode = effectivePolygonMode,
|
.polygonMode = effectivePolygonMode,
|
||||||
.cullMode = cullFaceEnabled
|
.cullMode = cullFaceEnabled
|
||||||
? MG_Util::ConvertCullFaceModeToVkEnum(MG_State::pGLContext->GetCullFaceMode(), invertClockwise)
|
? MG_Util::ConvertCullFaceModeToVkEnum(MG_State::pGLContext->GetCullFaceMode(), invertClockwise)
|
||||||
@@ -9794,6 +9795,7 @@ void main() {
|
|||||||
? VK_FALSE
|
? VK_FALSE
|
||||||
: supportedDeviceFeatures.robustBufferAccess;
|
: supportedDeviceFeatures.robustBufferAccess;
|
||||||
deviceFeatures.geometryShader = supportedDeviceFeatures.geometryShader;
|
deviceFeatures.geometryShader = supportedDeviceFeatures.geometryShader;
|
||||||
|
deviceFeatures.tessellationShader = supportedDeviceFeatures.tessellationShader;
|
||||||
deviceFeatures.independentBlend = supportedDeviceFeatures.independentBlend;
|
deviceFeatures.independentBlend = supportedDeviceFeatures.independentBlend;
|
||||||
m_independentBlendFeatureEnabled = deviceFeatures.independentBlend == VK_TRUE;
|
m_independentBlendFeatureEnabled = deviceFeatures.independentBlend == VK_TRUE;
|
||||||
deviceFeatures.fillModeNonSolid = supportedDeviceFeatures.fillModeNonSolid;
|
deviceFeatures.fillModeNonSolid = supportedDeviceFeatures.fillModeNonSolid;
|
||||||
|
|||||||
@@ -38,6 +38,10 @@ namespace MobileGL {
|
|||||||
return VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST_WITH_ADJACENCY;
|
return VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST_WITH_ADJACENCY;
|
||||||
case GL_TRIANGLE_STRIP_ADJACENCY:
|
case GL_TRIANGLE_STRIP_ADJACENCY:
|
||||||
return VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP_WITH_ADJACENCY;
|
return VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP_WITH_ADJACENCY;
|
||||||
|
case GL_PATCHES:
|
||||||
|
// The tessellator decides what a patch becomes; its vertex count is pipeline
|
||||||
|
// state (patchControlPoints), not part of the topology.
|
||||||
|
return VK_PRIMITIVE_TOPOLOGY_PATCH_LIST;
|
||||||
default:
|
default:
|
||||||
MGLOG_W("Unrecognized primitive topology");
|
MGLOG_W("Unrecognized primitive topology");
|
||||||
return VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;
|
return VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;
|
||||||
|
|||||||
@@ -1431,6 +1431,18 @@ namespace MobileGL::MG_Util::SelfTest {
|
|||||||
"hard-fails at draw");
|
"hard-fails at draw");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Core 1.0 features the backend turns GL stages into pipeline stages with.
|
||||||
|
VkPhysicalDeviceFeatures coreFeatures{};
|
||||||
|
vkGetPhysicalDeviceFeatures(physicalDevice, &coreFeatures);
|
||||||
|
if (coreFeatures.tessellationShader == VK_TRUE) {
|
||||||
|
builder.Pass("tessellationShader",
|
||||||
|
"supported (GL_PATCHES draws run the tessellation control/evaluation stages)");
|
||||||
|
} else {
|
||||||
|
builder.Warn("tessellationShader",
|
||||||
|
"unsupported; a program with a tessellation control/evaluation shader cannot build a "
|
||||||
|
"pipeline, so GL_PATCHES draws render nothing");
|
||||||
|
}
|
||||||
|
|
||||||
Bool vertexAttributeInstanceRateDivisor = false;
|
Bool vertexAttributeInstanceRateDivisor = false;
|
||||||
if (vkGetPhysicalDeviceFeatures2Fn != nullptr &&
|
if (vkGetPhysicalDeviceFeatures2Fn != nullptr &&
|
||||||
HasVkExtension(deviceExtensions, VK_EXT_VERTEX_ATTRIBUTE_DIVISOR_EXTENSION_NAME)) {
|
HasVkExtension(deviceExtensions, VK_EXT_VERTEX_ATTRIBUTE_DIVISOR_EXTENSION_NAME)) {
|
||||||
|
|||||||
Reference in New Issue
Block a user