Skip to content

fix(graphic): resolve memory leaks and improve texture view management#573

Merged
Miou-zora merged 3 commits into
mainfrom
564-fix-fix-memory-leaks-in-gbuffertest
Apr 9, 2026
Merged

fix(graphic): resolve memory leaks and improve texture view management#573
Miou-zora merged 3 commits into
mainfrom
564-fix-fix-memory-leaks-in-gbuffertest

Conversation

@Miou-zora

@Miou-zora Miou-zora commented Apr 8, 2026

Copy link
Copy Markdown
Contributor

Pull Request

Description

I fixed the memory leak when using other TextureView than the default one.

Related Issues (Put "None" if there are no related issues)

close #564

Type of Change

Please delete options that are not relevant.

  • Bug fix (non-breaking change which fixes an issue)

Changes Made

List the main changes in this PR:

  • Added a new class TextureView to handle it using raii

Testing

Describe the tests you ran to verify your changes. Please delete options that are not relevant.

  • Unit tests pass (xmake test)
  • Manual testing performed (describe what you tested): run xmake check_leaks -v GBufferTest

Test Environment

  • OS: macOS
  • Compiler: Clang

Screenshots/Videos (Put "None" if there are no related issues)

None

Documentation

Please delete options that are not relevant.

  • No documentation changes are required

Checklist (Don't delete any options)

  • My code follows the style guidelines of this project
  • I have performed a self-review of my own code
  • I have commented my code, particularly in hard-to-understand areas
  • My changes generate no new warnings
  • I have added tests that prove my fix is effective or that my feature works
  • New and existing unit tests pass locally with my changes
  • Any dependent changes have been merged and published

Breaking Changes (Put "None" if there are no related issues)

None

Additional Notes (Put "None" if there are no related issues)

None

Summary by CodeRabbit

Release Notes

Refactor

  • Enhanced graphics resource management with improved texture lifecycle handling and systematic cleanup procedures throughout the rendering pipeline.

@Miou-zora Miou-zora linked an issue Apr 8, 2026 that may be closed by this pull request
@Miou-zora Miou-zora self-assigned this Apr 8, 2026
@coderabbitai

coderabbitai Bot commented Apr 8, 2026

Copy link
Copy Markdown
Contributor

Warning

Rate limit exceeded

@Miou-zora has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 6 minutes and 52 seconds before requesting another review.

Your organization is not enrolled in usage-based pricing. Contact your admin to enable usage-based pricing to continue reviews beyond the rate limit, or try again in 6 minutes and 52 seconds.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 9308b003-3899-4c1e-a45f-394731b720d9

📥 Commits

Reviewing files that changed from the base of the PR and between 0d5e15d and 690503f.

📒 Files selected for processing (3)
  • src/plugin/default-pipeline/src/component/GPUDirectionalLight.hpp
  • src/plugin/graphic/src/resource/Texture.hpp
  • src/plugin/graphic/src/resource/TextureView.hpp
📝 Walkthrough

Walkthrough

The changes introduce a TextureView resource wrapper class and container system to replace direct wgpu::TextureView storage with ID-based references. Shadow texture views, depth output views, and texture bindings throughout the graphics pipeline now use identifiers to retrieve wrapped texture views from a centralized container, enabling proper RAII-style lifecycle management.

Changes

Cohort / File(s) Summary
TextureView Resource Management
src/plugin/graphic/src/resource/TextureView.hpp, src/plugin/graphic/src/resource/TextureViewContainer.hpp
New header-only TextureView RAII wrapper with move semantics, default construction, and WebGPU view accessor; new TextureViewContainer type alias for resource manager.
Texture API Updates
src/plugin/graphic/src/resource/Texture.hpp
Changed _defaultView from raw wgpu::TextureView to Resource::TextureView wrapper; updated GetDefaultView() return type to const reference and CreateView() to return wrapped view; added Delete() call in destructor.
Render Pass Depth Handling
src/plugin/graphic/src/resource/ARenderPass.hpp
Replaced depthTextureView member (std::optional<wgpu::TextureView>) with depthTextureViewId (std::optional<entt::hashed_string>).
Single/Multiple Execution Render Passes
src/plugin/graphic/src/resource/ASingleExecutionRenderPass.hpp, src/plugin/graphic/src/resource/AMultipleExecutionRenderPass.hpp
Updated render pass construction to chain .GetWebGPUView() on color/resolve/depth texture views; changed depth presence check from depthTextureView.has_value() to depthTextureViewId.has_value() and retrieve via TextureViewContainer::Get(id).
DirectionalLight Shadow Management
src/plugin/default-pipeline/src/component/GPUDirectionalLight.hpp, src/plugin/default-pipeline/src/system/GPUComponentManagement/OnDirectionalLightCreation.cpp, src/plugin/default-pipeline/src/resource/pass/Shadow.hpp
Changed shadowTextureView from wgpu::TextureView to Id; added destructor to GPUDirectionalLight; updated creation to store shadow view in container and assign ID; updated shadow pass to use depthTextureViewId.
System Registration & Shutdown
src/plugin/graphic/src/plugin/PluginGraphic.cpp, src/plugin/graphic/src/system/shutdown/ReleaseTextureView.hpp, src/plugin/graphic/src/system/shutdown/ReleaseTextureView.cpp
Registered TextureViewContainer as exported resource; added ReleaseTextureView system to shutdown scheduler between shader and texture release systems; implemented ReleaseTextureView() to delete container.
Include Headers & Dependencies
src/plugin/graphic/src/Graphic.hpp
Added includes for TextureView, TextureViewContainer, and ReleaseTextureView headers.
Bind Group & Test Updates
src/plugin/graphic/src/resource/BindGroup.hpp, src/plugin/graphic/tests/BindGroupTest.cpp, src/plugin/rmlui/src/utils/RenderInterface.cpp
Updated bind group entry texture view assignment to use .GetWebGPUView() accessor on wrapped views; updated test assertions to compare against converted WebGPU views.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

  • PR #442 — Directly modifies GPUDirectionalLight.shadowTextureView and related shadow texture initialization logic.
  • PR #428 — Introduces TextureView API changes and GetWebGPUView() adapter pattern used throughout graphic rendering.

Suggested labels

test, ci

Suggested reviewers

  • Divengerss
  • ripel2

Poem

🐰 A TextureView wrapper hops into the fray,
With IDs and containers to manage the day,
No more direct views causing memory strays,
RAII magic cleans up every way! ✨

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 3.13% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately summarizes the main change: fixing memory leaks and improving texture view management through a new RAII-based TextureView class.
Linked Issues check ✅ Passed The PR fully addresses issue #564 by introducing an RAII TextureView class that properly manages texture view lifecycle, eliminating the memory leaks reported in GBufferTest.
Out of Scope Changes check ✅ Passed All changes are directly related to fixing memory leaks by introducing proper texture view management. No unrelated modifications were introduced.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch 564-fix-fix-memory-leaks-in-gbuffertest

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 and usage tips.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/plugin/default-pipeline/src/system/GPUComponentManagement/OnDirectionalLightCreation.cpp (1)

22-22: ⚠️ Potential issue | 🟡 Minor

Static lightIndex counter is never decremented, causing issues with light re-creation.

The lightIndex is incremented but never decremented when lights are destroyed. If a directional light is destroyed and a new one created, baseArrayLayer will keep increasing, potentially exceeding the texture array bounds.

Consider tracking available indices or resetting appropriately.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@src/plugin/default-pipeline/src/system/GPUComponentManagement/OnDirectionalLightCreation.cpp`
at line 22, The static counter lightIndex in OnDirectionalLightCreation.cpp is
only incremented and never returned when lights are destroyed, so change the
allocation strategy to use a reusable pool: add a container (e.g.,
std::vector<uint32_t> freeLightIndices or std::stack<uint32_t> availableIndices)
and modify the creation path in OnDirectionalLightCreation (where lightIndex is
used to compute baseArrayLayer) to pop an index from availableIndices if
non-empty, otherwise use and increment lightIndex; also add logic in the
directional light destruction handler (or destructor for the directional light
class) to push the freed index back into availableIndices so baseArrayLayer
cannot grow past bounds. Ensure all references to lightIndex and baseArrayLayer
in OnDirectionalLightCreation.cpp use the new allocation function to obtain
indices.
🧹 Nitpick comments (4)
src/plugin/default-pipeline/src/resource/pass/Shadow.hpp (1)

93-93: Consider renaming shadowTextureView to reflect ID semantics.

This assignment now passes an ID (depthTextureViewId), so keeping the source field name as shadowTextureView can be misleading for future call sites.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/plugin/default-pipeline/src/resource/pass/Shadow.hpp` at line 93, The
field lightGPUComponent.shadowTextureView is misleading because it actually
holds an ID assigned to outputs.depthBuffer->depthTextureViewId; rename the
field to shadowTextureViewId across the LightGPUComponent (or whatever
class/struct defines it) and update all usages (including the assignment
outputs.depthBuffer->depthTextureViewId = lightGPUComponent.shadowTextureViewId)
to reflect the ID semantics while keeping the underlying type unchanged; ensure
any serialization, constructors, or comments referencing shadowTextureView are
updated too.
src/plugin/default-pipeline/src/component/GPUDirectionalLight.hpp (1)

20-21: Use = default for the trivial destructor.

The empty destructor should use = default instead of an empty body. This follows modern C++ best practices and allows the compiler to potentially optimize better.

♻️ Proposed fix
-    ~GPUDirectionalLight() {}
-
+    ~GPUDirectionalLight() = default;
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/plugin/default-pipeline/src/component/GPUDirectionalLight.hpp` around
lines 20 - 21, Replace the trivial empty destructor definition
"~GPUDirectionalLight() {}" in the GPUDirectionalLight class with a defaulted
destructor using "= default;" (i.e., make ~GPUDirectionalLight() = default;) so
the compiler can treat it as a defaulted special member; update the
declaration/definition where "~GPUDirectionalLight()" appears in
GPUDirectionalLight.hpp accordingly.
src/plugin/graphic/src/resource/TextureView.hpp (2)

50-50: Add explicit to the conversion operator.

Implicit conversion operators can cause unintended type conversions and make code harder to reason about. Since GetWebGPUView() already provides explicit access to the underlying handle, consider making this conversion explicit.

♻️ Proposed fix
-    operator wgpu::TextureView() const { return _webgpuView; }
+    explicit operator wgpu::TextureView() const { return _webgpuView; }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/plugin/graphic/src/resource/TextureView.hpp` at line 50, Mark the
conversion operator operator wgpu::TextureView() const as explicit to prevent
implicit conversions; update the declaration/definition of that operator to be
explicit and ensure existing call sites use either GetWebGPUView() or an
explicit cast (e.g., static_cast<wgpu::TextureView>(...)) where needed.

3-17: Remove unnecessary includes.

This header only defines a simple wrapper around wgpu::TextureView. The includes for Image.hpp, GetBytesPerPixel.hpp, <array>, <bit>, <cstddef>, <cstdint>, <cstring>, <functional>, <glm/gtc/packing.hpp>, <glm/vec2.hpp>, <glm/vec4.hpp>, and <vector> appear to be copy-pasted from Texture.hpp and are not used here.

♻️ Proposed fix
 `#pragma` once

-#include "exception/UnsupportedTextureFormatError.hpp"
-#include "resource/Context.hpp"
-#include "resource/Image.hpp"
-#include "utils/GetBytesPerPixel.hpp"
 `#include` "utils/webgpu.hpp"
-#include <array>
-#include <bit>
-#include <cstddef>
-#include <cstdint>
-#include <cstring>
-#include <functional>
-#include <glm/gtc/packing.hpp>
-#include <glm/vec2.hpp>
-#include <glm/vec4.hpp>
-#include <vector>

 namespace Graphic::Resource {
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/plugin/graphic/src/resource/TextureView.hpp` around lines 3 - 17,
TextureView.hpp currently pulls in many unused headers copied from Texture.hpp;
remove the unnecessary includes (Image.hpp, GetBytesPerPixel.hpp, <array>,
<bit>, <cstddef>, <cstdint>, <cstring>, <functional>, <glm/gtc/packing.hpp>,
<glm/vec2.hpp>, <glm/vec4.hpp>, and <vector>) and keep only the headers required
for the simple wrapper around wgpu::TextureView (e.g., utils/webgpu.hpp and any
minimal exception or forward-declaration headers actually referenced by the
TextureView class); update the include list in TextureView.hpp so it only
contains the minimal set needed by the TextureView symbol and any directly used
types like UnsupportedTextureFormatError if it is used.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/plugin/graphic/src/resource/TextureView.hpp`:
- Line 24: The TextureView constructor should be marked explicit and must move
the rvalue parameter into the member to avoid an unintended copy; update the
TextureView(wgpu::TextureView &&textureView) constructor to be explicit and
initialize _webgpuView with std::move(textureView) (referencing the TextureView
constructor and the _webgpuView member) so the rvalue is forwarded correctly.

---

Outside diff comments:
In
`@src/plugin/default-pipeline/src/system/GPUComponentManagement/OnDirectionalLightCreation.cpp`:
- Line 22: The static counter lightIndex in OnDirectionalLightCreation.cpp is
only incremented and never returned when lights are destroyed, so change the
allocation strategy to use a reusable pool: add a container (e.g.,
std::vector<uint32_t> freeLightIndices or std::stack<uint32_t> availableIndices)
and modify the creation path in OnDirectionalLightCreation (where lightIndex is
used to compute baseArrayLayer) to pop an index from availableIndices if
non-empty, otherwise use and increment lightIndex; also add logic in the
directional light destruction handler (or destructor for the directional light
class) to push the freed index back into availableIndices so baseArrayLayer
cannot grow past bounds. Ensure all references to lightIndex and baseArrayLayer
in OnDirectionalLightCreation.cpp use the new allocation function to obtain
indices.

---

Nitpick comments:
In `@src/plugin/default-pipeline/src/component/GPUDirectionalLight.hpp`:
- Around line 20-21: Replace the trivial empty destructor definition
"~GPUDirectionalLight() {}" in the GPUDirectionalLight class with a defaulted
destructor using "= default;" (i.e., make ~GPUDirectionalLight() = default;) so
the compiler can treat it as a defaulted special member; update the
declaration/definition where "~GPUDirectionalLight()" appears in
GPUDirectionalLight.hpp accordingly.

In `@src/plugin/default-pipeline/src/resource/pass/Shadow.hpp`:
- Line 93: The field lightGPUComponent.shadowTextureView is misleading because
it actually holds an ID assigned to outputs.depthBuffer->depthTextureViewId;
rename the field to shadowTextureViewId across the LightGPUComponent (or
whatever class/struct defines it) and update all usages (including the
assignment outputs.depthBuffer->depthTextureViewId =
lightGPUComponent.shadowTextureViewId) to reflect the ID semantics while keeping
the underlying type unchanged; ensure any serialization, constructors, or
comments referencing shadowTextureView are updated too.

In `@src/plugin/graphic/src/resource/TextureView.hpp`:
- Line 50: Mark the conversion operator operator wgpu::TextureView() const as
explicit to prevent implicit conversions; update the declaration/definition of
that operator to be explicit and ensure existing call sites use either
GetWebGPUView() or an explicit cast (e.g., static_cast<wgpu::TextureView>(...))
where needed.
- Around line 3-17: TextureView.hpp currently pulls in many unused headers
copied from Texture.hpp; remove the unnecessary includes (Image.hpp,
GetBytesPerPixel.hpp, <array>, <bit>, <cstddef>, <cstdint>, <cstring>,
<functional>, <glm/gtc/packing.hpp>, <glm/vec2.hpp>, <glm/vec4.hpp>, and
<vector>) and keep only the headers required for the simple wrapper around
wgpu::TextureView (e.g., utils/webgpu.hpp and any minimal exception or
forward-declaration headers actually referenced by the TextureView class);
update the include list in TextureView.hpp so it only contains the minimal set
needed by the TextureView symbol and any directly used types like
UnsupportedTextureFormatError if it is used.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 1ffeea6c-2933-421e-b3ae-989912bea1e9

📥 Commits

Reviewing files that changed from the base of the PR and between 7df789c and 0d5e15d.

📒 Files selected for processing (16)
  • src/plugin/default-pipeline/src/component/GPUDirectionalLight.hpp
  • src/plugin/default-pipeline/src/resource/pass/Shadow.hpp
  • src/plugin/default-pipeline/src/system/GPUComponentManagement/OnDirectionalLightCreation.cpp
  • src/plugin/graphic/src/Graphic.hpp
  • src/plugin/graphic/src/plugin/PluginGraphic.cpp
  • src/plugin/graphic/src/resource/AMultipleExecutionRenderPass.hpp
  • src/plugin/graphic/src/resource/ARenderPass.hpp
  • src/plugin/graphic/src/resource/ASingleExecutionRenderPass.hpp
  • src/plugin/graphic/src/resource/BindGroup.hpp
  • src/plugin/graphic/src/resource/Texture.hpp
  • src/plugin/graphic/src/resource/TextureView.hpp
  • src/plugin/graphic/src/resource/TextureViewContainer.hpp
  • src/plugin/graphic/src/system/shutdown/ReleaseTextureView.cpp
  • src/plugin/graphic/src/system/shutdown/ReleaseTextureView.hpp
  • src/plugin/graphic/tests/BindGroupTest.cpp
  • src/plugin/rmlui/src/utils/RenderInterface.cpp

Comment thread src/plugin/graphic/src/resource/TextureView.hpp Outdated
@sonarqubecloud

sonarqubecloud Bot commented Apr 8, 2026

Copy link
Copy Markdown

Quality Gate Failed Quality Gate failed

Failed conditions
10.0% Duplication on New Code (required ≤ 3%)

See analysis details on SonarQube Cloud

@Miou-zora Miou-zora merged commit 5019723 into main Apr 9, 2026
27 of 28 checks passed
@Miou-zora Miou-zora deleted the 564-fix-fix-memory-leaks-in-gbuffertest branch April 9, 2026 07:26
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.

[FIX] Fix memory leaks in GBufferTest

1 participant