Skip to content

fix(graphic): remove memory leaks#429

Merged
Divengerss merged 8 commits into
mainfrom
fix-graphic-memory-leaks
Jan 23, 2026
Merged

fix(graphic): remove memory leaks#429
Divengerss merged 8 commits into
mainfrom
fix-graphic-memory-leaks

Conversation

@Miou-zora

@Miou-zora Miou-zora commented Jan 23, 2026

Copy link
Copy Markdown
Contributor

Summary by CodeRabbit

  • New Features

    • Added camera reset functionality for input-triggered camera behavior restoration.
  • Bug Fixes

    • Improved GPU resource cleanup and proper destruction sequencing for rendering buffers.
    • Enhanced surface configuration with better backend detection and resource management.
    • Added proper texture handling in the render pipeline.
  • Refactor

    • Optimized resource ownership transfers using move semantics for graphics objects.

✏️ Tip: You can customize this high-level summary in your review settings.

@coderabbitai

coderabbitai Bot commented Jan 23, 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 13 minutes and 56 seconds before requesting another review.

⌛ 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.

📝 Walkthrough

Walkthrough

The PR introduces a new ResetCameraBehavior system for camera management, refactors multiple buffer classes in the default pipeline to use explicit destructors with centralized Destroy() methods, adds move semantics and RAII improvements to graphics resources (BindGroup and Shader), updates bind group ownership transfers to use std::move, and enhances resource cleanup in graphics system initialization and presentation phases.

Changes

Cohort / File(s) Summary
Camera Movement Plugin - ResetCameraBehavior System
src/plugin/camera-movement/src/CameraMovement.hpp, src/plugin/camera-movement/src/plugin/PluginCameraMovement.cpp, src/plugin/camera-movement/src/system/ResetCameraBehavior.hpp, src/plugin/camera-movement/src/system/ResetCameraBehavior.cpp
New system added to reset camera behavior to DontMoveBehavior. Includes header declaration, implementation, and plugin registration via RegisterSystems.
Default Pipeline - Buffer Resource Cleanup Pattern
src/plugin/default-pipeline/src/resource/buffer/AmbientLightBuffer.hpp, CameraGPUBuffer.hpp, IndexGPUBuffer.hpp, MaterialGPUBuffer.hpp, PointLightsBuffer.hpp, PointGPUBuffer.hpp, TransformGPUBuffer.hpp
Consistent refactoring across 6+ buffer classes: destructors changed from defaulted to call Destroy(); new parameterless Destroy() method centralizes resource release; existing Destroy(Engine::Core&) override delegates to parameterless variant.
Default Pipeline - GPU Component Management
src/plugin/default-pipeline/src/system/GPUComponentManagement/OnCameraCreation.cpp, src/plugin/default-pipeline/src/system/initialization/CreatePointLights.cpp
Updated BindGroup additions to use std\move(), transferring ownership instead of copying.
Graphic Plugin - Resource RAII & Move Semantics
src/plugin/graphic/src/resource/BindGroup.hpp, src/plugin/graphic/src/resource/Shader.hpp
BindGroup: made non-copyable, added move constructor/assignment, changed GetBindGroup() to return const reference. Shader: added destructor with pipeline release, move semantics, factory Create() method, and explicit resource cleanup after pipeline creation.
Graphic Plugin - Surface Resource Management
src/plugin/graphic/src/resource/Surface.hpp
Added default initializers (std\nullopt) for value and capabilities members; improved cleanup in updateCapabilities() and Release() to free previous members before reassignment.
Graphic Plugin - System Initialization & Presentation
src/plugin/graphic/src/system/initialization/ConfigureSurface.cpp, src/plugin/graphic/src/system/initialization/CreateAdapter.cpp, src/plugin/graphic/src/system/presentation/Present.cpp
ConfigureSurface: added early return for OpenGL/OpenGLES backend with explicit cleanup. CreateAdapter: added resource cleanup on error paths and for non-matching backends. Present: changed resource type resolution and added end-render texture ownership acquisition and removal.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

Suggested reviewers

  • Divengerss
  • ripel2

Poem

🐰 Hop hop, buffers clean,
Destroy() paths unseen,
Move semantics take the lead,
RAII's all we need!

🚥 Pre-merge checks | ✅ 2 | ❌ 1
❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'fix(graphic): remove memory leaks' directly summarizes the main objective of the PR, which is fixing memory leaks in the graphic plugin through proper resource cleanup and ownership semantics.

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


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.

@Miou-zora Miou-zora marked this pull request as ready for review January 23, 2026 13:43

@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: 8

🤖 Fix all issues with AI agents
In `@src/plugin/camera-movement/src/system/ResetCameraBehavior.hpp`:
- Around line 7-12: The comment for ResetCameraBehavior.hpp is misleading: it
describes input-triggered behavior but the system is actually registered to run
on Shutdown; update the docblock for the ResetCameraBehavior system to state
that it runs during the engine Shutdown phase (not on input events), describe
what it does at shutdown (resets camera behavior to default), and remove or
adjust any references to input-triggered resets so the lifecycle matches the
registration of ResetCameraBehavior.

In `@src/plugin/graphic/src/resource/BindGroup.hpp`:
- Around line 40-52: The class BindGroup defines a move constructor and
destructor but lacks a move assignment operator; add a noexcept move assignment
BindGroup& operator=(BindGroup&& other) that first releases this->_bindGroup if
non-null, then moves/transfers all members (_shaderId, _layoutIndex, _assets,
_entries, _bindGroup) from other (use std::move for containers/holders), sets
other._bindGroup = nullptr, and returns *this; ensure semantics mirror the
existing move constructor and keep copy operations deleted as currently
declared.

In `@src/plugin/graphic/src/resource/Shader.hpp`:
- Around line 25-30: The Shader move constructor currently copies descriptor;
change it to move descriptor to transfer ownership: in Shader(Shader &&other)
noexcept use descriptor = std::move(other.descriptor) (leave pipeline transfer
as pipeline = other.pipeline; other.pipeline = nullptr) so strings/vectors
inside ShaderDescriptor are moved instead of copied; ensure <utility> is
included if not already.
- Around line 31-40: The Shader::operator=(Shader&& other) currently overwrites
descriptor and pipeline without releasing the existing pipeline, causing a
resource leak; update Shader::operator=(Shader&&) to first check and release or
destroy the current pipeline owned by *this (matching the class's pipeline
cleanup pattern), then move-assign descriptor using std::move(descriptor) and
move the pipeline pointer from other to this, finally nulling other.pipeline;
follow the same move-semantics used in Texture::operator= and Sampler::operator=
to ensure proper ownership transfer and no leaks.

In `@src/plugin/graphic/src/resource/Surface.hpp`:
- Around line 15-26: The updateCapabilities method dereferences the optional
member value via value->getCapabilities(...) without checking value.has_value();
add a guard at the start of updateCapabilities to verify value.has_value()
(similar to Release()), and if it is not set return an appropriate wgpu::Status
error (or construct a failed Status) instead of dereferencing; this protects the
call to value->getCapabilities and prevents undefined behavior when value is
std::nullopt, while leaving the rest of the logic (freeMembers on existing
capabilities, assigning capabilities = caps, and returning status) unchanged.

In `@src/plugin/graphic/src/system/initialization/ConfigureSurface.cpp`:
- Around line 35-45: The call to AdapterInfo::freeMembers() must only happen if
context.adapter->getInfo(&info) returned wgpu::Status::Success; change
ConfigureSurface.cpp so that freeMembers() is invoked only inside the success
path (or use a bool success flag set when getInfo(...) == wgpu::Status::Success)
and remove the unconditional freeMembers() at the end; reference AdapterInfo,
context.adapter->getInfo, and freeMembers to locate and adjust the logic
accordingly.

In `@src/plugin/graphic/src/system/initialization/CreateAdapter.cpp`:
- Around line 39-47: The cleanup currently calls adapters.data()->release()
which only releases the first adapter, leaking others; update the cleanup logic
in the CreateAdapter code path so that before returning cand you iterate over
the adapters container and call release() on every adapter element except the
one you are returning (cand), and also ensure info.freeMembers() is still called
for each adapter's info; reference adapters (the vector), cand (the chosen
adapter), info.freeMembers(), and release() to locate and implement the loop
that releases all non-returned adapters.

In `@src/plugin/graphic/src/system/presentation/Present.cpp`:
- Around line 14-18: Add a defensive existence check before calling Get on the
texture container: use
core.GetResource<Resource::TextureContainer>().Contains(Utils::END_RENDER_TEXTURE_ID)
and only call Get(...).TakeOwnership() and Remove(...) if Contains returns true;
otherwise skip those calls to avoid throwing ResourceManagerError. Update the
block that currently uses
textureContainer.Get(Utils::END_RENDER_TEXTURE_ID).TakeOwnership() and
textureContainer.Remove(Utils::END_RENDER_TEXTURE_ID) to guard both operations
with the Contains check.
🧹 Nitpick comments (4)
src/plugin/graphic/src/resource/BindGroup.hpp (1)

84-89: Potential double-release if _CreateBindGroup throws.

In _RefreshBindGroup, if _CreateBindGroup succeeds but the assignment somehow fails (unlikely but possible with exceptions), or if future code changes introduce exceptions, the old _bindGroup would already be released. Consider using a safer swap pattern.

♻️ Safer pattern using swap
     void _RefreshBindGroup(Engine::Core &core)
     {
         auto newBindGroup = _CreateBindGroup(core);
-        _bindGroup.release();
-        _bindGroup = newBindGroup;
+        std::swap(_bindGroup, newBindGroup);
+        if (newBindGroup)
+            newBindGroup.release();
     }
src/plugin/graphic/src/resource/Shader.hpp (2)

16-23: Minor: Unnecessary nullptr assignment in destructor.

Setting pipeline = nullptr after release() in the destructor is redundant since the object is being destroyed immediately after. This doesn't affect correctness but is unnecessary code.

Suggested simplification
     virtual ~Shader()
     {
         if (pipeline != nullptr)
         {
             pipeline.release();
-            pipeline = nullptr;
         }
     }

127-131: Acknowledge TODO: GetBindGroupLayout returns unmanaged resource.

The returned wgpu::BindGroupLayout from pipeline.getBindGroupLayout() may need explicit release by callers, potentially causing leaks if not handled properly. The TODO correctly identifies the need for an RAII wrapper.

Would you like me to open an issue to track implementing an RAII wrapper class for BindGroupLayout management, or help draft the implementation?

src/plugin/camera-movement/src/system/ResetCameraBehavior.cpp (1)

1-2: Avoid transitive include coupling.
Add a direct include for resource/CameraManager.hpp to keep this TU robust if core/Core.hpp stops pulling it in.

♻️ Suggested include
 `#include` "core/Core.hpp"
+#include "resource/CameraManager.hpp"
 `#include` "utils/DontMoveBehavior.hpp"

Comment thread src/plugin/camera-movement/src/system/ResetCameraBehavior.hpp
Comment thread src/plugin/graphic/src/resource/BindGroup.hpp
Comment thread src/plugin/graphic/src/resource/Shader.hpp
Comment thread src/plugin/graphic/src/resource/Shader.hpp
Comment thread src/plugin/graphic/src/resource/Surface.hpp
Comment thread src/plugin/graphic/src/system/initialization/ConfigureSurface.cpp Outdated
Comment thread src/plugin/graphic/src/system/initialization/CreateAdapter.cpp Outdated
Comment thread src/plugin/graphic/src/system/presentation/Present.cpp
@sonarqubecloud

Copy link
Copy Markdown

Quality Gate Failed Quality Gate failed

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

See analysis details on SonarQube Cloud

@Divengerss Divengerss 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.

I've ran a local valgrind check and most of the memory leaks have been fixed. They are still 152 bytes leaked, but they appear to be from Mesa/XCB and wgpu internal calls used by the engine, meaning it's not from our implementation.

@Divengerss Divengerss merged commit e2ce2f3 into main Jan 23, 2026
14 of 15 checks passed
@Divengerss Divengerss deleted the fix-graphic-memory-leaks branch January 23, 2026 18:14
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