diff --git a/MobileGL/MG_Backend/DirectVulkan/Renderer/VkRenderPassManager.cpp b/MobileGL/MG_Backend/DirectVulkan/Renderer/VkRenderPassManager.cpp index 99c0671a..40985d90 100644 --- a/MobileGL/MG_Backend/DirectVulkan/Renderer/VkRenderPassManager.cpp +++ b/MobileGL/MG_Backend/DirectVulkan/Renderer/VkRenderPassManager.cpp @@ -1187,6 +1187,22 @@ namespace MobileGL::MG_Backend::DirectVulkan { } const Bool hasDepthStencilAttachment = depthAttachmentRef.attachment != VK_ATTACHMENT_UNUSED; + // Declare only the used colour-reference span. The GL draw-buffer array + // always spans 8 slots, so passes used to declare colorAttachmentCount=8 + // with trailing VK_ATTACHMENT_UNUSED holes - and Adreno configures its + // per-pixel render-backend/export path from the DECLARED count, so every + // fragment of every pass paid the 8-target export cost (measured on + // Adreno 650 / MC 26.2: 11.9 -> 7.5 ms of GPU time per frame, with the + // single-quad swapchain blit pass alone dropping 1.26 -> 0.40 ms). + // Interior GL_NONE holes keep their slots so fragment-output locations + // still line up; a fragment output at a location past the trimmed count + // is discarded, which is exactly GL's semantic for writing to a draw + // buffer set to GL_NONE. + while (!colorAttachmentRefs.empty() && + colorAttachmentRefs.back().attachment == VK_ATTACHMENT_UNUSED) { + colorAttachmentRefs.pop_back(); + } + // Subpass VkSubpassDescription subpassDesc; subpassDesc.flags = 0; diff --git a/MobileGL/MG_Backend/DirectVulkan/Renderer/VulkanRenderer.cpp b/MobileGL/MG_Backend/DirectVulkan/Renderer/VulkanRenderer.cpp index 8b653a6c..6bb989f5 100644 --- a/MobileGL/MG_Backend/DirectVulkan/Renderer/VulkanRenderer.cpp +++ b/MobileGL/MG_Backend/DirectVulkan/Renderer/VulkanRenderer.cpp @@ -4041,12 +4041,15 @@ void main() { payload.backStencilCompareOp = VK_COMPARE_OP_ALWAYS; } const Uint32 fragmentOutputMask = programObj.activeFragmentOutputLocationMask; - MOBILEGL_ASSERT( - (fragmentOutputMask >> payload.colorAttachmentCount) == 0, - "GetOrCreatePipeline: fragmentOutputMask=0x%x exceeds colorAttachmentCount=%u for program=%u", - fragmentOutputMask, - payload.colorAttachmentCount, - program.GetExternalIndex()); + // Outputs at locations past the render pass's trimmed colour span are + // simply discarded - GL's semantic for a fragment output whose draw + // buffer is GL_NONE (the trailing UNUSED slots no longer occupy + // references, see GetOrCreateRenderPass). + if ((fragmentOutputMask >> payload.colorAttachmentCount) != 0) { + MGLOG_D("GetOrCreatePipeline: fragmentOutputMask=0x%x exceeds colorAttachmentCount=%u for program=%u; " + "outputs past the span are discarded", + fragmentOutputMask, payload.colorAttachmentCount, program.GetExternalIndex()); + } MOBILEGL_ASSERT(payload.colorAttachmentCount <= PipelineFactory::PipelineCreatePayload::kMaxColorAttachments, "GetOrCreatePipeline: colorAttachmentCount=%u exceeds payload capacity", payload.colorAttachmentCount);