Skip to content

Increase particle and segment render-buffer pool capacities - #165

Open
zhanghm18GIT wants to merge 6 commits into
FAForever:masterfrom
zhanghm18GIT:improvement/increase-particle-pool-capacity
Open

Increase particle and segment render-buffer pool capacities#165
zhanghm18GIT wants to merge 6 commits into
FAForever:masterfrom
zhanghm18GIT:improvement/increase-particle-pool-capacity

Conversation

@zhanghm18GIT

@zhanghm18GIT zhanghm18GIT commented Jul 27, 2026

Copy link
Copy Markdown

The memo

Summary

This PR raises two fixed render-resource pool counts created by the particle renderer during initialization:

  • particle render-buffer descriptors: 400 -> 4096;
  • segment-buffer descriptors: 100 -> 400.

The native pool, checkout, release, recycling, and exhaustion behavior remains unchanged. The patch increases the number of descriptors available before the existing pool-exhaustion path is reached.

The change is limited to the two initialization loop counts. Lua, simulation, synchronization, effect lifetime, per-buffer capacity, and renderer control flow are unchanged.


Problem

The initialization routine at 0x004928A0 constructs two render-resource pools using fixed loop counts.

Particle render-buffer pool

At 0x004928ED:

MOV DWORD PTR [ESP+0x10],0x190

The construction loop allocates 0x2C-byte descriptors. Each descriptor retains the native capacity of 0xC8 (200).

The original fixed capacity is therefore:

400 descriptors * 200 entries = 80,000 nominal entries

Particle-heavy battles and effect-heavy mods can exhaust this fixed descriptor pool. When no descriptor is available, the existing engine path cannot provide another render buffer until resources return to the pool.

Segment-buffer pool

At 0x004929B2:

MOV DWORD PTR [ESP+0x10],0x64

This is a separate construction loop for 0x18-byte segment-buffer descriptors. The existing per-buffer creation argument of 0x190 remains unchanged.


Implementation

The patch uses the repository's current fixed-address .hook format and changes only the two loop-count immediates.

hooks/ParticlePoolCapacity.hook

# Particle renderer initialization
# Increase the fixed particle render-buffer descriptor pool from 400 to 4096.
# Original instruction: mov dword ptr [esp + 0x10], 0x190
0x004928ED:
    mov dword ptr [esp + 0x10], 0x1000

# Increase the fixed segment-buffer descriptor pool from 100 to 400.
# Original instruction: mov dword ptr [esp + 0x10], 0x64
0x004929B2:
    mov dword ptr [esp + 0x10], 0x190

Particle render-buffer descriptor count

# VA 0x004928ED
MOV DWORD PTR [ESP+0x10],0x190
->
MOV DWORD PTR [ESP+0x10],0x1000

Exact bytes:

C7 44 24 10 90 01 00 00
->
C7 44 24 10 00 10 00 00

Segment-buffer descriptor count

# VA 0x004929B2
MOV DWORD PTR [ESP+0x10],0x64
->
MOV DWORD PTR [ESP+0x10],0x190

Exact bytes:

C7 44 24 10 64 00 00 00
->
C7 44 24 10 90 01 00 00

Both replacement instructions remain eight bytes long.

The decrement-and-branch loops, allocation sizes, list insertion, resource release, resource recycling, and native exhaustion guards remain unchanged.

Resulting fixed capacities

Particle render-buffer descriptors: 400 -> 4096  (10.24x)
Nominal particle entries:            80,000 -> 819,200
Segment-buffer descriptors:          100 -> 400   (4x)

Memory and performance impact

The initialization loops allocate descriptor objects of 0x2C and 0x18 bytes respectively.

The additional descriptor payload is:

(4096 - 400) * 0x2C = 162,624 bytes
(400 - 100)  * 0x18 =   7,200 bytes
------------------------------------
descriptor payload delta = 169,824 bytes (~165.8 KiB)

Allocator metadata is not included in this figure.

The patch adds no runtime branch, lookup, thread, periodic scan, dynamic table, or per-particle instruction. Its direct CPU cost is the one-time initialization of the additional descriptors.

Workloads that exceed the original limits can continue using additional render resources up to the new fixed capacities. In those workloads, CPU work, GPU work, process memory, and video-memory use can increase because effects that previously reached the original pool ceiling can continue to be processed.

The renderer remains bounded by the new fixed pool sizes and continues to use the native resource-recycling and exhaustion paths.


Validation performed

Repository and source review

  • based on FAForever/FA-Binary-Patches master commit 96af320e872a083fdb302fde7406d6d7f17c418d;
  • no existing hook or open Issue/PR matching these two addresses was found;
  • the repository contribution guidance and existing binary patches were reviewed;
  • the implementation now uses the repository's current .hook format for fixed-address assembly patches, following maintainer review feedback;
  • the PR changes only hooks/ParticlePoolCapacity.hook and changelog.md.

Instruction and control-flow validation

  • the original instructions were disassembled from the FAF 3836 baseline;
  • both replacement instructions were independently assembled as 32-bit x86;
  • replacement lengths remain exactly eight bytes;
  • stack destination and surrounding loop control remain unchanged;
  • the decrement and JNE control flow remains unchanged;
  • the replacement MOV instructions do not alter general-purpose registers or EFLAGS.

Binary reconstruction

Tested baseline:

size:   12,537,600 bytes
SHA256: a6acf849803f7f38fbaa612b77c910bde239f6b5a4ff8f8786f719e2aec0f09d

Known local particle-pool candidate:

size:   12,537,600 bytes
SHA256: 58a610668653295d3274db66b346a9d93e25f93b65d9331df35d203ca4cc4d43

Applying only the two immediate replacements to the baseline reproduces the known candidate byte-for-byte.

The candidate differs from the baseline at exactly four byte positions:

0x000928F1: 90 -> 00
0x000928F2: 01 -> 10
0x000929B6: 64 -> 90
0x000929B7: 00 -> 01

The PE entry point, image base, section table, file size, and Large Address Aware flag remain unchanged.

The .hook conversion preserves the same two target addresses and the same replacement instructions.

Runtime evidence

The same two particle-pool capacity changes were included in later combined user-test executables used in long, effect-heavy FAF games, providing startup and long-session smoke coverage.

A controlled particle-saturation A/B capture has not yet been attached, so this PR makes no measured FPS or effect-count claim.


Regression test instructions

  1. Build the executable from this branch.

  2. Verify the output instructions:

    • 0x004928ED: C7 44 24 10 00 10 00 00;
    • 0x004929B2: C7 44 24 10 90 01 00 00.
  3. Start and exit the game repeatedly to exercise pool construction and destruction.

  4. Run a vanilla sandbox and verify normal weapons, explosions, smoke, build effects, reclaim effects, trails, beams, and decals.

  5. Replay the same particle-heavy scenario on the current and patched builds.

  6. Continue until the current build begins omitting visible effects, then compare the patched build at the same time and camera position.

  7. Where instrumentation is available, record:

    • active and free particle render-buffer descriptors;
    • active and free segment-buffer descriptors;
    • entries through the native exhaustion/discard path;
    • frame time and FPS;
    • process private bytes;
    • video-memory use.
  8. Test long sessions, save/load, observer mode, camera and LOD transitions, and effect-heavy SIM mods.

  9. Verify safe pool exhaustion at the new fixed limits.

  10. Compare shutdown behavior and confirm that resources are released normally.


Scope

  • Particle render-buffer descriptor count: 400 -> 4096.
  • Segment-buffer descriptor count: 100 -> 400.
  • Per-particle-buffer capacity remains 200.
  • Segment-buffer creation size remains 400.
  • Effect blueprints, spawn rates, lifetimes, culling rules, and renderer discard policy remain unchanged.
  • Pool allocation, recycling, release, and exhaustion mechanisms remain native.
  • Controlled saturation telemetry remains the preferred final runtime validation.

Files changed

hooks/ParticlePoolCapacity.hook
changelog.md

Checklist

  • Read the repository contribution guidance and reviewed existing binary patches
  • Checked current master and searched for a duplicate particle-pool patch
  • Exact addresses, original/replacement instructions, and bytes documented
  • Same-size instruction replacements; no resume-address change
  • Loop control, stack destination, registers, and EFLAGS audited
  • Additional fixed descriptor payload quantified
  • Converted the implementation to the current .hook format following maintainer feedback
  • Changelog entry updated to reference hooks/ParticlePoolCapacity.hook
  • Test and regression instructions included
  • No executable or proprietary game artifact included
  • Equivalent local binary reconstructed byte-for-byte from the two intended instruction changes
  • Repository patcher build / CI execution
  • Controlled particle-saturation A/B capture
  • Maintainer re-review

@coderabbitai

coderabbitai Bot commented Jul 27, 2026

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

@zhanghm18GIT, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 16 minutes

You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository.

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 46477ecd-d378-4f66-8d1c-061917d9295d

📥 Commits

Reviewing files that changed from the base of the PR and between 28f523d and 80e7bfd.

📒 Files selected for processing (1)
  • changelog.md
📝 Walkthrough

Walkthrough

The particle renderer hooks increase the render-buffer pool from 400 to 4096 entries and the segment-buffer pool from 100 to 400 entries. The changelog documents these capacity changes.

Changes

Particle pool capacity

Layer / File(s) Summary
Patch constructor pool counts
hooks/ParticlePoolCapacity.hook, changelog.md
The hook replaces the pool count constants at 0x004928ED and 0x004929B2 with 0x1000 and 0x190. The changelog records the increased capacities.

Estimated code review effort: 1 (Trivial) | ~5 minutes

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Title check ✅ Passed The title clearly and concisely identifies the main change: increasing particle and segment render-buffer pool capacities.
Description check ✅ Passed The description is detailed, follows the repository template, documents scope and validation, and includes regression instructions despite pending CI and A/B testing.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

Comment thread hooks/ParticlePoolCapacity.cpp Outdated
@@ -0,0 +1,12 @@
asm(

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

use new hook format like here

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updated to the new .hook format as suggested. The patch still changes only the two immediate pool-count values at 0x004928ED and 0x004929B2; the functional binary changes are unchanged.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants