mirror of
https://github.com/MobileGL-Dev/MobileGL
synced 2026-09-08 04:08:32 +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.subpass, sizeof(payload.subpass)));
|
||||
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.frontFace, sizeof(payload.frontFace)));
|
||||
XXHASH_VERIFY(XXH64_update(m_hashState, &payload.depthTestEnable, sizeof(payload.depthTestEnable)));
|
||||
@@ -217,7 +218,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
vpci.scissorCount = 1;
|
||||
|
||||
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.frontFace = payload.frontFace;
|
||||
raster.depthBiasEnable = payload.depthBiasEnable ? VK_TRUE : VK_FALSE;
|
||||
|
||||
@@ -29,6 +29,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
VkSampleCountFlagBits rasterizationSamples = VK_SAMPLE_COUNT_1_BIT;
|
||||
Uint32 subpass = 0;
|
||||
VkPrimitiveTopology topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;
|
||||
VkPolygonMode polygonMode = VK_POLYGON_MODE_FILL;
|
||||
VkCullModeFlags cullMode = VK_CULL_MODE_BACK_BIT;
|
||||
VkFrontFace frontFace = VK_FRONT_FACE_CLOCKWISE;
|
||||
Bool depthTestEnable = false;
|
||||
|
||||
@@ -2964,12 +2964,14 @@ void main() {
|
||||
auto stencilTestEnabled = MG_State::pGLContext->IsCapabilityEnabled(CapabilityInput::StencilTest);
|
||||
const StencilFaceState& frontStencil = MG_State::pGLContext->GetStencilState(StencilFace::Front);
|
||||
const StencilFaceState& backStencil = MG_State::pGLContext->GetStencilState(StencilFace::Back);
|
||||
auto mask = MG_State::pGLContext->GetColorMask();
|
||||
const auto colorWriteMask = static_cast<VkColorComponentFlags>(
|
||||
(mask.r() ? VK_COLOR_COMPONENT_R_BIT : 0u) |
|
||||
(mask.g() ? VK_COLOR_COMPONENT_G_BIT : 0u) |
|
||||
(mask.b() ? VK_COLOR_COMPONENT_B_BIT : 0u) |
|
||||
(mask.a() ? VK_COLOR_COMPONENT_A_BIT : 0u));
|
||||
const VkPolygonMode requestedPolygonMode =
|
||||
MG_Util::ConvertPolygonModeToVkEnum(MG_State::pGLContext->GetPolygonModeFront());
|
||||
// VK_POLYGON_MODE_LINE/_POINT require the fillModeNonSolid device feature; fall back to
|
||||
// VK_POLYGON_MODE_FILL when the device lacks it.
|
||||
const VkPolygonMode effectivePolygonMode =
|
||||
(requestedPolygonMode == VK_POLYGON_MODE_FILL || m_fillModeNonSolidFeatureEnabled)
|
||||
? requestedPolygonMode
|
||||
: VK_POLYGON_MODE_FILL;
|
||||
|
||||
PipelineFactory::PipelineCreatePayload payload {
|
||||
.programHash = programObj.hash,
|
||||
@@ -2980,6 +2982,7 @@ void main() {
|
||||
.rasterizationSamples = renderPassEntry.sampleCount,
|
||||
.subpass = 0,
|
||||
.topology = MG_Util::ConvertPrimitiveModeToVkEnum(mode),
|
||||
.polygonMode = effectivePolygonMode,
|
||||
.cullMode = cullFaceEnabled
|
||||
? MG_Util::ConvertCullFaceModeToVkEnum(MG_State::pGLContext->GetCullFaceMode(), invertClockwise)
|
||||
: VK_CULL_MODE_NONE,
|
||||
@@ -3075,7 +3078,16 @@ void main() {
|
||||
MG_State::pGLContext->GetBlendFuncIndexed(i, srcRGB, dstRGB, srcAlpha, dstAlpha);
|
||||
MG_State::pGLContext->GetBlendEquationIndexed(i, colorEquation, alphaEquation);
|
||||
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;
|
||||
MG_State::GLState::ITextureObject* colorAttachmentTexture = nullptr;
|
||||
if (!isDefaultDrawFbo && i < drawBuffers.size()) {
|
||||
@@ -6283,6 +6295,9 @@ void main() {
|
||||
VkPhysicalDeviceFeatures deviceFeatures{};
|
||||
deviceFeatures.geometryShader = supportedDeviceFeatures.geometryShader;
|
||||
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.shaderClipDistance = supportedDeviceFeatures.shaderClipDistance;
|
||||
deviceFeatures.shaderCullDistance = supportedDeviceFeatures.shaderCullDistance;
|
||||
|
||||
@@ -342,6 +342,11 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
Bool m_multiDrawIndirectFeatureEnabled = false;
|
||||
Bool m_shaderDrawParametersExtensionEnabled = 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
|
||||
// and device limits; drives timer-query support.
|
||||
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) {
|
||||
switch (v) {
|
||||
case CullFaceMode::Front:
|
||||
|
||||
@@ -13,6 +13,10 @@
|
||||
namespace MobileGL {
|
||||
namespace MG_Util {
|
||||
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);
|
||||
VkLogicOp ConvertLogicOperationToVkEnum(LogicOperation value);
|
||||
VkCompareOp ConvertDepthTestFuncToVkEnum(DepthTestFunc value);
|
||||
|
||||
Reference in New Issue
Block a user