mirror of
https://github.com/MobileGL-Dev/MobileGL
synced 2026-09-11 21:58:31 +09:00
[Fix, Feat] (MG_Backend): make DirectVulkan multi-draw actually draw, then pick its best tier
The bug: DirectVulkan.cpp::MultiDrawElements had its entire body
commented out - plain glMultiDrawElements on Magma recorded NOTHING,
no error, no pixels (readback shows the deferred clear never even
materialized). It now shares the tuned base-vertex implementation, and
both plain entries are pixel-proven by a 4-sub-draw harness.
The feature: every CPU-side multi-draw form dispatches through three
tiers after round-9's contiguous-run merge (restructured to merge into
a span BEFORE dispatch, so every tier consumes the shrunken array):
1. VK_EXT_multi_draw: one vkCmdDrawMulti(Indexed)EXT, chunked by
maxMultiDrawCount; per-draw vertexOffset rides in the struct. The
extension is requested only when enumerated and its feature bit
confirmed, entry points via vkGetDeviceProcAddr, demoted if
missing.
2. multiDrawIndirect: the param span uploads DIRECTLY as a transient
INDIRECT-usage buffer - DrawIndexedCmdParam is layout-identical
to VkDrawIndexedIndirectCommand and DrawCmdParam's head is a
legal 24-byte-stride VkDrawIndirectCommand, both static_asserted,
so no repacking - then one vkCmdDraw(Indexed)Indirect per
maxDrawIndirectCount chunk. firstInstance!=0 additionally
requires drawIndirectFirstInstance or the batch drops a tier.
3. The byte-identical unroll.
gl_DrawID: tiers 1-2 are spec-correct (0,1,2,3 across a probe's
sub-draws); the unroll tier keeps the pre-existing always-0 contract.
The default tiers strictly improve DrawID correctness.
Adversarially verified: the five real DirectVulkan retrace images are
BIT-IDENTICAL (md5) across auto/ext/indirect/unroll; zero validation
VUIDs on every tier; a simulated no-EXT device resolves to indirect
and renders the same bytes; the known-red create-indirect fixture
crashes at the identical call before and after (not worse, not fixed).
Unit suite 423/423 on the rebased tree, retrace subset 10/10. Bench:
mc_sodium_multidraw's contiguous shape merges 32->1 before dispatch,
so no bench delta - the tiers' beneficiaries are non-contiguous real
streams (the sodium RETRACE pushes ~58-sub-draw batches, in=out
243101 with zero merges) and mobile drivers. A reproducible +3-4%
code-layout drift on mc_use_program (zero shared code, I-cache
displacement from +400 lines) stays under the action gate and is
booked here rather than hidden.
This commit is contained in:
@@ -327,6 +327,16 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
Bool RecreateSwapchain();
|
||||
|
||||
private:
|
||||
// Tiered emission for an already-set-up multi-draw batch (state bound, index
|
||||
// buffer bound for the indexed form). Tier 1: VK_EXT_multi_draw. Tier 2: one
|
||||
// vkCmdDraw(Indexed)Indirect over a transient command array. Tier 3: unrolled
|
||||
// vkCmdDraw(Indexed) loop. Tier eligibility is per-batch (uniform instance
|
||||
// state for tier 1, firstInstance/feature legality for tier 2); every tier
|
||||
// consumes the same param span, so contiguous-run merging done by the caller
|
||||
// benefits all of them.
|
||||
void EmitMultiDrawIndexed(VkCommandBuffer commandBuffer, const DrawIndexedCmdParam* pParams, Uint32 drawCount);
|
||||
void EmitMultiDraw(VkCommandBuffer commandBuffer, const DrawCmdParam* pParams, Uint32 drawCount);
|
||||
|
||||
struct BlitUniformData {
|
||||
float srcRect[4] = {0.f, 0.f, 1.f, 1.f};
|
||||
float dstRect[4] = {0.f, 0.f, 1.f, 1.f};
|
||||
@@ -477,6 +487,24 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
Bool m_indexTypeUint8ExtensionEnabled = false;
|
||||
Bool m_logicOpFeatureEnabled = false;
|
||||
Bool m_multiDrawIndirectFeatureEnabled = false;
|
||||
// drawIndirectFirstInstance gates indirect commands whose firstInstance != 0;
|
||||
// cached at device creation because the tier-2 multi-draw path (a transient
|
||||
// VkDrawIndexedIndirectCommand array) is illegal for such a sub-draw without it.
|
||||
Bool m_drawIndirectFirstInstanceFeatureEnabled = false;
|
||||
// VK_EXT_multi_draw: native batched submission for the CPU-side glMultiDraw*
|
||||
// families (tier 1 of the multi-draw dispatch).
|
||||
Bool m_multiDrawExtensionEnabled = false;
|
||||
Uint32 m_maxMultiDrawCount = 0;
|
||||
// Multi-draw dispatch tiers, resolved once at device creation from device support
|
||||
// clamped by MOBILEGL_MAGMA_MULTIDRAW_MODE (a preference, never a demand):
|
||||
// tier 1 (ext): one vkCmdDrawMulti(Indexed)EXT - m_multiDrawAllowExt
|
||||
// tier 2 (indirect): one vkCmdDraw(Indexed)Indirect batch - m_multiDrawAllowIndirect
|
||||
// tier 3 (unroll): one vkCmdDraw(Indexed) per sub-draw - always available
|
||||
// m_multiDrawForceUnrollIndirect additionally forces the GPU-parameter
|
||||
// glMultiDraw*Indirect paths onto their per-command loop (mode=unroll only).
|
||||
Bool m_multiDrawAllowExt = false;
|
||||
Bool m_multiDrawAllowIndirect = false;
|
||||
Bool m_multiDrawForceUnrollIndirect = false;
|
||||
Bool m_samplerAnisotropyFeatureEnabled = false;
|
||||
Bool m_shaderDrawParametersExtensionEnabled = false;
|
||||
Bool m_shaderDrawParametersFeatureEnabled = false;
|
||||
@@ -508,6 +536,10 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
VkDeviceSize countBufferOffset, Uint32 maxDrawCount,
|
||||
Uint32 stride);
|
||||
static inline PFNDrawIndexedIndirectCountFunc s_vkCmdDrawIndexedIndirectCount = nullptr;
|
||||
// VK_EXT_multi_draw entry points, loaded at device creation when the extension
|
||||
// (and its multiDraw feature) is enabled; null otherwise.
|
||||
static inline PFN_vkCmdDrawMultiEXT s_vkCmdDrawMultiEXT = nullptr;
|
||||
static inline PFN_vkCmdDrawMultiIndexedEXT s_vkCmdDrawMultiIndexedEXT = nullptr;
|
||||
|
||||
// VK_EXT_transform_feedback (GL transform feedback capture)
|
||||
Bool m_transformFeedbackFeatureEnabled = false;
|
||||
|
||||
Reference in New Issue
Block a user