mirror of
https://github.com/MobileGL-Dev/MobileGL
synced 2026-09-10 13:18:31 +09:00
[Fix] (DirectVulkan): suppress blended depth writes on Qualcomm and mark gl_Position invariant to fix MC 26.3 OIT cloud flicker
This commit is contained in:
@@ -8,6 +8,7 @@
|
||||
|
||||
#include "PipelineFactory.h"
|
||||
|
||||
|
||||
namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
static const char* PrimitiveTopologyToString(VkPrimitiveTopology topology) {
|
||||
switch (topology) {
|
||||
@@ -108,6 +109,10 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
"vkCreatePipelineCache");
|
||||
}
|
||||
|
||||
void PipelineFactory::SetSuppressBlendedDepthWrite(Bool enabled) {
|
||||
s_suppressBlendedDepthWrite = enabled;
|
||||
}
|
||||
|
||||
PipelineFactory::~PipelineFactory() {
|
||||
DestroyAll();
|
||||
if (m_pipelineCache != VK_NULL_HANDLE) {
|
||||
@@ -258,6 +263,18 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
for (Uint32 i = 0; i < payload.colorAttachmentCount; ++i) {
|
||||
colorAttachments[i] = payload.colorBlendAttachments[i];
|
||||
}
|
||||
// Suppress depth writes on blended pipelines when the active driver cannot keep
|
||||
// vertex positions invariant across the pipelines of a multi-pass depth-equality
|
||||
// chain (see SetSuppressBlendedDepthWrite). Blended draws that write depth are rare
|
||||
// and the equality-dependent prepass pattern is exactly the case that breaks.
|
||||
if (s_suppressBlendedDepthWrite && depthStencil.depthWriteEnable == VK_TRUE) {
|
||||
for (Uint32 i = 0; i < payload.colorAttachmentCount; ++i) {
|
||||
if (colorAttachments[i].blendEnable == VK_TRUE) {
|
||||
depthStencil.depthWriteEnable = VK_FALSE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
VkPipelineColorBlendStateCreateInfo blend{VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO};
|
||||
blend.logicOpEnable = payload.logicOpEnable ? VK_TRUE : VK_FALSE;
|
||||
blend.logicOp = payload.logicOp;
|
||||
|
||||
@@ -62,6 +62,14 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
VkPipeline GetOrCreatePipeline(const PipelineCreatePayload& payload);
|
||||
void DestroyAll();
|
||||
|
||||
// Driver quirk: suppress depth writes on blended pipelines. Multi-pass depth-equality
|
||||
// rendering (a blended prepass writes depth that later passes re-test with an
|
||||
// equality-inclusive compare on the re-rasterized geometry) requires cross-pipeline
|
||||
// position invariance that some mobile compilers do not provide, even with the
|
||||
// SPIR-V Invariant decoration; whole primitives then drop out of the later passes.
|
||||
// Set at renderer initialization based on the active driver.
|
||||
static void SetSuppressBlendedDepthWrite(Bool enabled);
|
||||
|
||||
private:
|
||||
VkPipeline CreatePipeline(const PipelineCreatePayload& payload) const;
|
||||
|
||||
@@ -70,5 +78,6 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
VkPipelineCache m_pipelineCache = VK_NULL_HANDLE;
|
||||
UnorderedMap<HashType, VkPipeline> m_cache;
|
||||
static inline XXH64_state_t* m_hashState = XXH64_createState();
|
||||
static inline Bool s_suppressBlendedDepthWrite = false;
|
||||
};
|
||||
} // namespace MobileGL::MG_Backend::DirectVulkan
|
||||
|
||||
@@ -1697,6 +1697,22 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
moduleSpirvs[i] = spv;
|
||||
}
|
||||
|
||||
// GL apps depend on cross-program position invariance for multi-pass equality
|
||||
// depth tests (MC 26.3's OIT re-draws the cloud geometry with GEQUAL against the
|
||||
// depth its own first pass wrote); decorate Position outputs Invariant so
|
||||
// per-pipeline compilers cannot vary the position math between passes.
|
||||
{
|
||||
Vector<Uint> invariantSpirv;
|
||||
if (MG_Util::ShaderTranspiler::ShaderCompiler::DecoratePositionInvariantForVulkan(
|
||||
moduleSpirvs[i], invariantSpirv)) {
|
||||
moduleSpirvs[i] = std::move(invariantSpirv);
|
||||
} else {
|
||||
MGLOG_W("ProgramFactory: position-invariant decoration failed for program %u; "
|
||||
"keeping the original module",
|
||||
program.GetExternalIndex());
|
||||
}
|
||||
}
|
||||
|
||||
// glslang's relaxed-Vulkan mode aliases GL's zero-based gl_InstanceID to Vulkan's
|
||||
// gl_InstanceIndex, which wrongly includes the draw's baseInstance. Rebase vertex-stage
|
||||
// loads to (InstanceIndex - BaseInstance) so shaders observe GL semantics. Reflection
|
||||
|
||||
@@ -25,6 +25,9 @@
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#include <vulkan/vulkan_core.h>
|
||||
#ifdef __ANDROID__
|
||||
#include <sys/system_properties.h>
|
||||
#endif
|
||||
|
||||
#if defined(__APPLE__)
|
||||
#include <CoreGraphics/CoreGraphics.h>
|
||||
@@ -947,6 +950,7 @@ void main() {
|
||||
}
|
||||
)";
|
||||
|
||||
|
||||
static Uint32 ComputeFullMipLevelCount(const IntVec3& baseTexelSize) {
|
||||
Int maxDimension = std::max<Int>(
|
||||
baseTexelSize.x(),
|
||||
@@ -1884,6 +1888,28 @@ void main() {
|
||||
|
||||
m_pipelineFactory = MakeUnique<PipelineFactory>(m_device, m_config);
|
||||
MOBILEGL_ASSERT(m_pipelineFactory != nullptr, "PipelineFactory creation failed.");
|
||||
{
|
||||
// Qualcomm's pipeline compiler does not keep vertex positions invariant across
|
||||
// the pipelines of a multi-pass depth-equality chain (even with the SPIR-V
|
||||
// Invariant decoration), so a blended depth-writing prepass makes later
|
||||
// equality-compare passes drop whole primitives (MC 26.3 improved-transparency
|
||||
// clouds flicker black). Suppress blended depth writes there; the env variable
|
||||
// forces the quirk on ("0") or off ("1") on any driver.
|
||||
static constexpr Uint32 kVendorIdQualcomm = 0x5143;
|
||||
Bool suppressBlendedDepthWrite = m_physicalDevice.properties.vendorID == kVendorIdQualcomm;
|
||||
if (const char* env = getenv("MOBILEGL_MAGMA_BLENDED_DEPTH_WRITE")) {
|
||||
if (env[0] == '0') {
|
||||
suppressBlendedDepthWrite = true;
|
||||
} else if (env[0] == '1') {
|
||||
suppressBlendedDepthWrite = false;
|
||||
}
|
||||
}
|
||||
if (suppressBlendedDepthWrite) {
|
||||
MGLOG_I("DirectVulkan: suppressing depth writes on blended pipelines "
|
||||
"(driver lacks cross-pipeline position invariance)");
|
||||
}
|
||||
PipelineFactory::SetSuppressBlendedDepthWrite(suppressBlendedDepthWrite);
|
||||
}
|
||||
m_programFactory = MakeUnique<ProgramFactory>(m_device, m_config, maxProgramBindings,
|
||||
m_shaderDrawParametersFeatureEnabled);
|
||||
MOBILEGL_ASSERT(m_programFactory != nullptr, "ProgramFactory creation failed.");
|
||||
|
||||
Reference in New Issue
Block a user