mirror of
https://github.com/MobileGL-Dev/MobileGL
synced 2026-09-09 20:58:31 +09:00
[Fix] (DirectVulkan): declare only the used colour attachment span per subpass
- every render pass declared colorAttachmentCount=8 (the full GL draw-buffer slot span) with trailing VK_ATTACHMENT_UNUSED references, and Adreno configures its per-pixel render-backend/export path from the DECLARED count - so every fragment of every pass paid an 8-render-target export cost; this was the bulk of the 1.5x per-pixel gap against MobileGlues+ANGLE on the same Qualcomm driver (their subpasses declare exactly the used span) - measured on Adreno 650 / MC 26.2 / 1440x3044: total GPU frame time 11.9 -> 7.5 ms (-37%, now below ANGLE's 7.87 ms), the single-quad swapchain blit pass alone 1.26 -> 0.40 ms, steady in-world FPS 82.8 -> 123 under the standard cooled-start protocol, matching the MobileGlues+ANGLE+system-Vulkan benchmark of 123.8 - trailing UNUSED references are popped before the subpass is built (the entry's colorAttachmentCount and every pipeline's colour-blend span follow it); interior GL_NONE holes keep their slots so fragment-output locations still line up - the pipeline-side fragmentOutputMask check downgrades from assert to a debug log: an output at a location past the trimmed span is discarded, which is GL's defined behaviour for a draw buffer set to GL_NONE
This commit is contained in:
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user