Skip to content

fix(pipeline): keep MANAGED render targets alive across frames in release builds - #19198

Open
hakastein wants to merge 1 commit into
cocos:v3.8.9from
hakastein:fix/managed-resources-released-every-frame
Open

fix(pipeline): keep MANAGED render targets alive across frames in release builds#19198
hakastein wants to merge 1 commit into
cocos:v3.8.9from
hakastein:fix/managed-resources-released-every-frame

Conversation

@hakastein

Copy link
Copy Markdown

Re: #19197

Changelog

  • Custom pipeline: collect the frame's resource names from the render graph at the start of Executor._removeDeviceResource(). pipeline.resourceUses is filled only by Compiler, which does not contribute in a release build, so every MANAGED device texture and buffer — the cascaded shadow map among them — was released at the start of each frame and reallocated during it.

Where I put it, and why there

I looked for an existing per-frame traversal of the frame's resource names to fill the list from, and
did not find one — but I may well be missing something, and a better home for this is entirely
possible. What I checked:

  • Compiler fills the list at compiler.ts:170, but that line sits after if (validPass) return;, and web-pipeline.ts:1648 wraps the whole compiler in if (DEBUG).
  • The resourceUses.push() at executor.ts:156 is in the ResourceVisitor constructor, and the visitor looks like a module-level singleton created once at executor.ts:754 with the default resName = '', while the resName setter does not push. If that is right, the registration may have been intended to sit in the setter.
  • DeviceRenderPass does iterate rasterPass.rasterViews, but instances appear to be cached by pass hash in context.devicePasses and dropped only in release(), so that loop would not run per frame.

If there is a more natural place for this, happy to move it.

Alternative worth considering

pipeline.resourceUses has exactly one consumer — this method — and it is queried with Array.includes() in two loops below. A local Set built here and queried with has() would drop the linear scans and make the deduplication free, and would remove the need for the array to carry state between the compile and execute phases at all. That would make both existing writers dead code, so it is a call for the maintainers rather than something to slip into a bug fix; this PR keeps the public field and its semantics untouched and only deduplicates on insert.

Verification

Web Mobile release build, Redmi 9C (Helio G35, PowerVR GE8320, 3 GB): 8 fps before, 24 after, output unchanged. Texture allocations over 150 frames drop from 300 (two 2048×2048 per frame) to 0. Tested on a scene with cascaded shadows and no post-processing; Compute and Copy passes were not exercised.


Continuous Integration

This pull request:

  • needs automatic test cases check.

    Manual trigger with @cocos-robot run test cases afterward.

  • does not change any runtime related code or build configuration

    If any reviewer thinks the CI checks are needed, please uncheck this option, then close and reopen the issue.


Compatibility Check

This pull request:

  • changes public API, and have ensured backward compatibility with deprecated features.
  • affects platform compatibility, e.g. system version, browser version, platform sdk version, platform toolchain, language version, hardware compatibility etc.
  • affects file structure of the build package or build configuration which requires user project upgrade.
  • introduces breaking changes, please list all changes, affected features and the scope of violation.

…ease builds

pipeline.resourceUses is filled only by Compiler, which does not contribute in a
release build: web-pipeline.ts wraps the compiler in `if (DEBUG)`, and the
RasterPass node is created with `valid = !DEBUG` so _fetchValidPass returns
before the loop that fills the list. Executor._removeDeviceResource then finds
no name in it and releases every MANAGED device texture and buffer, so the
cascaded shadow map was reallocated once per frame.

Collect the names from the frame's render graph before the sweep instead.

@greptile-apps greptile-apps Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Your trial has ended. Reactivate Greptile to resume code reviews.

@github-actions

Copy link
Copy Markdown

Code Size Check Report

Wechat (WASM) Before After Diff
2D Empty (legacy pipeline) 1009838 bytes 1009838 bytes ✅ 0 bytes
2D All (legacy pipeline) 2675490 bytes 2675490 bytes ✅ 0 bytes
2D All (new pipeline) 2767226 bytes 2767531 bytes ⚠️ +305 bytes
(2D + 3D) All 10024224 bytes 10024529 bytes ⚠️ +305 bytes
Web (WASM + ASMJS) Before After Diff
(2D + 3D) All 16843286 bytes 16843591 bytes ⚠️ +305 bytes

Interface Check Report

This pull request does not change any public interfaces !

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.

1 participant