mirror of
https://github.com/MobileGL-Dev/MobileGL
synced 2026-09-11 21:58:31 +09:00
[Feat] (MG_Backend/DirectVulkan): wire glPolygonMode and glColorMaski into pipeline creation
Consume the polygon mode and per-draw-buffer color write masks that the frontend already tracks, with runtime fallback for the device features they require. glPolygonMode: - Add ConvertPolygonModeToVkEnum (GL_FILL/LINE/POINT -> VkPolygonMode). - Thread a polygonMode field through PipelineCreatePayload, fold it into the pipeline cache hash (distinct modes need distinct pipelines), and apply it in PipelineFactory instead of the hardcoded VK_POLYGON_MODE_FILL. - LINE/POINT require the fillModeNonSolid device feature: detect and enable it at device creation, cache m_fillModeNonSolidFeatureEnabled, and fall back to FILL at pipeline-build time when it is absent. glColorMaski: - The per-attachment color-blend loop now reads GetColorMaskIndexed(i) instead of the broadcast GetColorMask(), so each draw buffer gets its own write mask (already covered by the pipeline hash). - Divergent per-attachment masks require independentBlend: cache m_independentBlendFeatureEnabled (was enabled but never recorded) and fall back to draw buffer 0's mask for every attachment when it is absent. The internal depth-mipmap utility pipeline keeps VK_POLYGON_MODE_FILL (not GL-driven). Library builds clean; full SanityTest sweep green (30/30).
This commit is contained in:
@@ -126,6 +126,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
|||||||
XXHASH_VERIFY(XXH64_update(m_hashState, &payload.rasterizationSamples, sizeof(payload.rasterizationSamples)));
|
XXHASH_VERIFY(XXH64_update(m_hashState, &payload.rasterizationSamples, sizeof(payload.rasterizationSamples)));
|
||||||
XXHASH_VERIFY(XXH64_update(m_hashState, &payload.subpass, sizeof(payload.subpass)));
|
XXHASH_VERIFY(XXH64_update(m_hashState, &payload.subpass, sizeof(payload.subpass)));
|
||||||
XXHASH_VERIFY(XXH64_update(m_hashState, &payload.topology, sizeof(payload.topology)));
|
XXHASH_VERIFY(XXH64_update(m_hashState, &payload.topology, sizeof(payload.topology)));
|
||||||
|
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)));
|
||||||
XXHASH_VERIFY(XXH64_update(m_hashState, &payload.depthTestEnable, sizeof(payload.depthTestEnable)));
|
XXHASH_VERIFY(XXH64_update(m_hashState, &payload.depthTestEnable, sizeof(payload.depthTestEnable)));
|
||||||
@@ -217,7 +218,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
|||||||
vpci.scissorCount = 1;
|
vpci.scissorCount = 1;
|
||||||
|
|
||||||
VkPipelineRasterizationStateCreateInfo raster{VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO};
|
VkPipelineRasterizationStateCreateInfo raster{VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO};
|
||||||
raster.polygonMode = VK_POLYGON_MODE_FILL;
|
raster.polygonMode = payload.polygonMode;
|
||||||
raster.cullMode = payload.cullMode;
|
raster.cullMode = payload.cullMode;
|
||||||
raster.frontFace = payload.frontFace;
|
raster.frontFace = payload.frontFace;
|
||||||
raster.depthBiasEnable = payload.depthBiasEnable ? VK_TRUE : VK_FALSE;
|
raster.depthBiasEnable = payload.depthBiasEnable ? VK_TRUE : VK_FALSE;
|
||||||
|
|||||||
@@ -29,6 +29,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
|||||||
VkSampleCountFlagBits rasterizationSamples = VK_SAMPLE_COUNT_1_BIT;
|
VkSampleCountFlagBits rasterizationSamples = VK_SAMPLE_COUNT_1_BIT;
|
||||||
Uint32 subpass = 0;
|
Uint32 subpass = 0;
|
||||||
VkPrimitiveTopology topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;
|
VkPrimitiveTopology topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;
|
||||||
|
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;
|
||||||
Bool depthTestEnable = false;
|
Bool depthTestEnable = false;
|
||||||
|
|||||||
@@ -2964,12 +2964,14 @@ void main() {
|
|||||||
auto stencilTestEnabled = MG_State::pGLContext->IsCapabilityEnabled(CapabilityInput::StencilTest);
|
auto stencilTestEnabled = MG_State::pGLContext->IsCapabilityEnabled(CapabilityInput::StencilTest);
|
||||||
const StencilFaceState& frontStencil = MG_State::pGLContext->GetStencilState(StencilFace::Front);
|
const StencilFaceState& frontStencil = MG_State::pGLContext->GetStencilState(StencilFace::Front);
|
||||||
const StencilFaceState& backStencil = MG_State::pGLContext->GetStencilState(StencilFace::Back);
|
const StencilFaceState& backStencil = MG_State::pGLContext->GetStencilState(StencilFace::Back);
|
||||||
auto mask = MG_State::pGLContext->GetColorMask();
|
const VkPolygonMode requestedPolygonMode =
|
||||||
const auto colorWriteMask = static_cast<VkColorComponentFlags>(
|
MG_Util::ConvertPolygonModeToVkEnum(MG_State::pGLContext->GetPolygonModeFront());
|
||||||
(mask.r() ? VK_COLOR_COMPONENT_R_BIT : 0u) |
|
// VK_POLYGON_MODE_LINE/_POINT require the fillModeNonSolid device feature; fall back to
|
||||||
(mask.g() ? VK_COLOR_COMPONENT_G_BIT : 0u) |
|
// VK_POLYGON_MODE_FILL when the device lacks it.
|
||||||
(mask.b() ? VK_COLOR_COMPONENT_B_BIT : 0u) |
|
const VkPolygonMode effectivePolygonMode =
|
||||||
(mask.a() ? VK_COLOR_COMPONENT_A_BIT : 0u));
|
(requestedPolygonMode == VK_POLYGON_MODE_FILL || m_fillModeNonSolidFeatureEnabled)
|
||||||
|
? requestedPolygonMode
|
||||||
|
: VK_POLYGON_MODE_FILL;
|
||||||
|
|
||||||
PipelineFactory::PipelineCreatePayload payload {
|
PipelineFactory::PipelineCreatePayload payload {
|
||||||
.programHash = programObj.hash,
|
.programHash = programObj.hash,
|
||||||
@@ -2980,6 +2982,7 @@ void main() {
|
|||||||
.rasterizationSamples = renderPassEntry.sampleCount,
|
.rasterizationSamples = renderPassEntry.sampleCount,
|
||||||
.subpass = 0,
|
.subpass = 0,
|
||||||
.topology = MG_Util::ConvertPrimitiveModeToVkEnum(mode),
|
.topology = MG_Util::ConvertPrimitiveModeToVkEnum(mode),
|
||||||
|
.polygonMode = effectivePolygonMode,
|
||||||
.cullMode = cullFaceEnabled
|
.cullMode = cullFaceEnabled
|
||||||
? MG_Util::ConvertCullFaceModeToVkEnum(MG_State::pGLContext->GetCullFaceMode(), invertClockwise)
|
? MG_Util::ConvertCullFaceModeToVkEnum(MG_State::pGLContext->GetCullFaceMode(), invertClockwise)
|
||||||
: VK_CULL_MODE_NONE,
|
: VK_CULL_MODE_NONE,
|
||||||
@@ -3075,7 +3078,16 @@ void main() {
|
|||||||
MG_State::pGLContext->GetBlendFuncIndexed(i, srcRGB, dstRGB, srcAlpha, dstAlpha);
|
MG_State::pGLContext->GetBlendFuncIndexed(i, srcRGB, dstRGB, srcAlpha, dstAlpha);
|
||||||
MG_State::pGLContext->GetBlendEquationIndexed(i, colorEquation, alphaEquation);
|
MG_State::pGLContext->GetBlendEquationIndexed(i, colorEquation, alphaEquation);
|
||||||
const Bool blendEnabled = MG_State::pGLContext->IsCapabilityEnabledIndexed(CapabilityInput::Blend, i);
|
const Bool blendEnabled = MG_State::pGLContext->IsCapabilityEnabledIndexed(CapabilityInput::Blend, i);
|
||||||
VkColorComponentFlags attachmentColorWriteMask = colorWriteMask;
|
// Per-draw-buffer color write mask (glColorMaski). Divergent per-attachment masks require
|
||||||
|
// the independentBlend device feature; when it is absent, fall back to draw buffer 0's
|
||||||
|
// mask for every attachment (matching the non-indexed glColorMask broadcast).
|
||||||
|
const BoolVec4 bufferMask =
|
||||||
|
MG_State::pGLContext->GetColorMaskIndexed(m_independentBlendFeatureEnabled ? i : 0);
|
||||||
|
VkColorComponentFlags attachmentColorWriteMask = static_cast<VkColorComponentFlags>(
|
||||||
|
(bufferMask.r() ? VK_COLOR_COMPONENT_R_BIT : 0u) |
|
||||||
|
(bufferMask.g() ? VK_COLOR_COMPONENT_G_BIT : 0u) |
|
||||||
|
(bufferMask.b() ? VK_COLOR_COMPONENT_B_BIT : 0u) |
|
||||||
|
(bufferMask.a() ? VK_COLOR_COMPONENT_A_BIT : 0u));
|
||||||
Bool effectiveBlendEnabled = blendEnabled;
|
Bool effectiveBlendEnabled = blendEnabled;
|
||||||
MG_State::GLState::ITextureObject* colorAttachmentTexture = nullptr;
|
MG_State::GLState::ITextureObject* colorAttachmentTexture = nullptr;
|
||||||
if (!isDefaultDrawFbo && i < drawBuffers.size()) {
|
if (!isDefaultDrawFbo && i < drawBuffers.size()) {
|
||||||
@@ -6283,6 +6295,9 @@ void main() {
|
|||||||
VkPhysicalDeviceFeatures deviceFeatures{};
|
VkPhysicalDeviceFeatures deviceFeatures{};
|
||||||
deviceFeatures.geometryShader = supportedDeviceFeatures.geometryShader;
|
deviceFeatures.geometryShader = supportedDeviceFeatures.geometryShader;
|
||||||
deviceFeatures.independentBlend = supportedDeviceFeatures.independentBlend;
|
deviceFeatures.independentBlend = supportedDeviceFeatures.independentBlend;
|
||||||
|
m_independentBlendFeatureEnabled = deviceFeatures.independentBlend == VK_TRUE;
|
||||||
|
deviceFeatures.fillModeNonSolid = supportedDeviceFeatures.fillModeNonSolid;
|
||||||
|
m_fillModeNonSolidFeatureEnabled = deviceFeatures.fillModeNonSolid == VK_TRUE;
|
||||||
deviceFeatures.logicOp = supportedDeviceFeatures.logicOp;
|
deviceFeatures.logicOp = supportedDeviceFeatures.logicOp;
|
||||||
deviceFeatures.shaderClipDistance = supportedDeviceFeatures.shaderClipDistance;
|
deviceFeatures.shaderClipDistance = supportedDeviceFeatures.shaderClipDistance;
|
||||||
deviceFeatures.shaderCullDistance = supportedDeviceFeatures.shaderCullDistance;
|
deviceFeatures.shaderCullDistance = supportedDeviceFeatures.shaderCullDistance;
|
||||||
|
|||||||
@@ -342,6 +342,11 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
|||||||
Bool m_multiDrawIndirectFeatureEnabled = false;
|
Bool m_multiDrawIndirectFeatureEnabled = false;
|
||||||
Bool m_shaderDrawParametersExtensionEnabled = false;
|
Bool m_shaderDrawParametersExtensionEnabled = false;
|
||||||
Bool m_shaderDrawParametersFeatureEnabled = false;
|
Bool m_shaderDrawParametersFeatureEnabled = false;
|
||||||
|
// fillModeNonSolid gates VK_POLYGON_MODE_LINE/_POINT (glPolygonMode); independentBlend gates
|
||||||
|
// per-draw-buffer color write masks (glColorMaski). Both are cached at device creation and
|
||||||
|
// drive a runtime fallback when the device lacks them.
|
||||||
|
Bool m_fillModeNonSolidFeatureEnabled = false;
|
||||||
|
Bool m_independentBlendFeatureEnabled = false;
|
||||||
// Cached at device creation from the graphics queue family properties
|
// Cached at device creation from the graphics queue family properties
|
||||||
// and device limits; drives timer-query support.
|
// and device limits; drives timer-query support.
|
||||||
Uint32 m_timestampValidBits = 0;
|
Uint32 m_timestampValidBits = 0;
|
||||||
|
|||||||
@@ -31,6 +31,20 @@ namespace MobileGL {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
VkPolygonMode ConvertPolygonModeToVkEnum(GLenum mode) {
|
||||||
|
switch (mode) {
|
||||||
|
case GL_FILL:
|
||||||
|
return VK_POLYGON_MODE_FILL;
|
||||||
|
case GL_LINE:
|
||||||
|
return VK_POLYGON_MODE_LINE;
|
||||||
|
case GL_POINT:
|
||||||
|
return VK_POLYGON_MODE_POINT;
|
||||||
|
default:
|
||||||
|
MGLOG_W("Unrecognized polygon mode");
|
||||||
|
return VK_POLYGON_MODE_FILL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
VkCullModeFlags ConvertCullFaceModeToVkEnum(CullFaceMode v, Bool invertClockwise) {
|
VkCullModeFlags ConvertCullFaceModeToVkEnum(CullFaceMode v, Bool invertClockwise) {
|
||||||
switch (v) {
|
switch (v) {
|
||||||
case CullFaceMode::Front:
|
case CullFaceMode::Front:
|
||||||
|
|||||||
@@ -13,6 +13,10 @@
|
|||||||
namespace MobileGL {
|
namespace MobileGL {
|
||||||
namespace MG_Util {
|
namespace MG_Util {
|
||||||
VkPrimitiveTopology ConvertPrimitiveModeToVkEnum(GLenum mode);
|
VkPrimitiveTopology ConvertPrimitiveModeToVkEnum(GLenum mode);
|
||||||
|
// Maps GL_FILL/GL_LINE/GL_POINT to the matching VkPolygonMode. LINE/POINT require the
|
||||||
|
// fillModeNonSolid device feature; the caller is responsible for falling back to FILL when
|
||||||
|
// that feature is unavailable.
|
||||||
|
VkPolygonMode ConvertPolygonModeToVkEnum(GLenum mode);
|
||||||
VkCullModeFlags ConvertCullFaceModeToVkEnum(CullFaceMode value, Bool invertClockwise = false);
|
VkCullModeFlags ConvertCullFaceModeToVkEnum(CullFaceMode value, Bool invertClockwise = false);
|
||||||
VkLogicOp ConvertLogicOperationToVkEnum(LogicOperation value);
|
VkLogicOp ConvertLogicOperationToVkEnum(LogicOperation value);
|
||||||
VkCompareOp ConvertDepthTestFuncToVkEnum(DepthTestFunc value);
|
VkCompareOp ConvertDepthTestFuncToVkEnum(DepthTestFunc value);
|
||||||
|
|||||||
Reference in New Issue
Block a user