Size bgfx render-item arrays dynamically instead of reserving the maximum - #1806
Open
bghgary wants to merge 5 commits into
Open
Size bgfx render-item arrays dynamically instead of reserving the maximum#1806bghgary wants to merge 5 commits into
bghgary wants to merge 5 commits into
Conversation
…imum bgfx sizes its per-frame render-item arrays (sort keys, RenderItem, RenderBind) from Init::Limits::numDrawCalls. That defaults to BGFX_CONFIG_MAX_DRAW_CALLS, 65535, and is allocated up front for every Frame object, so a consumer that draws a handful of quads still reserves tens of megabytes. bgfx gained the ability to grow and shrink those arrays on demand, but it is opt-in: the defaults remain numDrawCalls = BGFX_CONFIG_MAX_DRAW_CALLS and numDrawCallPeakFrames = 0 (disabled), so simply picking up the newer bgfx changes nothing. Opt in by starting empty and letting bgfx grow up to the same BGFX_CONFIG_MAX_DRAW_CALLS ceiling, in BGFX_CONFIG_DRAW_CALL_BLOCK-sized steps. The headroom is unchanged for scenes that need it; it is just no longer paid for when unused. Lowering BGFX_CONFIG_MAX_DRAW_CALLS instead would also shrink the allocation, but it lowers the ceiling with it. Submissions past the limit are dropped rather than queued -- Frame::m_maxDrawCalls <= renderItemIdx discards the draw and counts it in m_numDropped -- so geometry disappears with nothing raised to say so. Growing on demand keeps the ceiling and the memory. Measured in a video-compositing embedder rendering 49 tiles: peak usage is 50 draw calls, and this change accounts for roughly 73 MB of a 111 MB reduction in process memory. No change to rendering output; UnitTests pass (17/17). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 714b4495-258e-4645-abf7-26c17bc29d5b
Contributor
There was a problem hiding this comment.
Pull request overview
This PR updates BabylonNative’s bgfx initialization to avoid reserving bgfx’s maximum per-frame render-item buffers up front, instead enabling bgfx’s dynamic resizing behavior to reduce baseline memory usage while preserving the same upper ceiling for draw-call-heavy scenes.
Changes:
- Set
bgfx::Init::Limits::numDrawCallsto0to avoid eager preallocation atBGFX_CONFIG_MAX_DRAW_CALLS. - Set
bgfx::Init::Limits::numDrawCallPeakFramesto a non-zero value to enable runtime growth/shrink behavior. - Add in-code rationale describing bgfx’s allocation behavior and why these settings are chosen.
bgfx::init clamps limits.numDrawCalls up to kDrawCallBlock
(BGFX_CONFIG_DRAW_CALL_BLOCK, 1024 by default):
init.limits.numDrawCalls = alignDrawCalls(
bx::max(init.limits.numDrawCalls, kDrawCallBlock) );
so 0 asks for one block, not for an empty allocation. Frame::create ->
allocArrays applies no floor of its own, which is what the previous comment
described, but the clamp happens a layer above it in bgfx::init.
The behaviour and the memory saving are unchanged: the reserved slot count
still drops from BGFX_CONFIG_MAX_DRAW_CALLS to one block. Only the comment
was wrong.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 714b4495-258e-4645-abf7-26c17bc29d5b
Requesting the smallest capacity bgfx allows meant any scene crossing one BGFX_CONFIG_DRAW_CALL_BLOCK (1024) lost the draws past the boundary for a frame, because bgfx grows reactively: the frame that overflows discards the excess and only the next frame sees the larger arrays. Babylon Native never dropped draws before this change, so that was a regression. Start at 4096 instead, which no realistic scene begins above, and expose the value as Configuration::InitialDrawCallCapacity so an embedder that knows its own ceiling can go lower. Paired with an override of BGFX_CONFIG_DRAW_CALL_BLOCK that lets a small embedder reserve well under a block. Reserved slots still drop from BGFX_CONFIG_MAX_DRAW_CALLS (65535) to 4096, so the bulk of the saving is unchanged. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 714b4495-258e-4645-abf7-26c17bc29d5b
Replaces the Configuration::InitialDrawCallCapacity field added in the previous commit. bgfx already has a compile-time setting for this: numDrawCalls = 0 asks for exactly one BGFX_CONFIG_DRAW_CALL_BLOCK, and the block is also the growth, shrink and floor granularity, so it is the only value a consumer needs to set. A runtime field alongside it was a second way to say the same thing. Set the block to 4096 for Babylon Native. Growth is reactive -- the frame that first exceeds capacity drops the draws past it -- so leaving the block at bgfx's default of 1024 would have cost a frame of geometry on any scene crossing 1024 draws. A consumer that knows its own ceiling can override the block down. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 714b4495-258e-4645-abf7-26c17bc29d5b
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 714b4495-258e-4645-abf7-26c17bc29d5b
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
[Created by Copilot on behalf of @bghgary]
Context
bgfx sizes its per-frame render-item arrays (sort keys,
RenderItem,RenderBind) fromInit::Limits::numDrawCalls, which defaults toBGFX_CONFIG_MAX_DRAW_CALLS(65535) and is allocated up front for everyFrame. A consumer drawing a handful of quads still reserves tens of megabytes.bgfx can grow and shrink those arrays on demand, but it is opt-in — the defaults are
numDrawCalls = BGFX_CONFIG_MAX_DRAW_CALLSandnumDrawCallPeakFrames = 0(disabled) — so picking up the newer bgfx alone changes nothing. This PR starts at 4096 slots and lets bgfx grow them.Worth a look
numDrawCallPeakFramesmust be non-zero: at0,adjustCapacity()returns immediately and the arrays stay fixed.BGFX_CONFIG_MAX_DRAW_CALLSinstead would shrink the allocation but lower the ceiling with it, and submissions past the limit are dropped rather than queued (m_maxDrawCalls <= renderItemIdxdiscards the draw and counts it inm_numDropped). Geometry disappears with nothing raised to say so.Measurements
At Babylon Native's configuration the slot is 522 bytes, so the 65536 reserved slots cost 65 MB across the submit and render
Frame. 4096 slots cost 4 MB, saving about 61 MB.UnitTests pass (17/17).