Skip to content

Update from task de872a38-c33d-412a-94b3-c7df7ffebd4e#24

Open
tronpis wants to merge 3 commits into
world-optimization-techniques-4a1eafrom
chunkkeyubfixsimulationmoduleperformance-ebd4e
Open

Update from task de872a38-c33d-412a-94b3-c7df7ffebd4e#24
tronpis wants to merge 3 commits into
world-optimization-techniques-4a1eafrom
chunkkeyubfixsimulationmoduleperformance-ebd4e

Conversation

@tronpis
Copy link
Copy Markdown
Owner

@tronpis tronpis commented Apr 2, 2026

This PR was created by qwen-chat coder for task de872a38-c33d-412a-94b3-c7df7ffebd4e.

…tion

Key features implemented:
- New RenderGraph.h/cpp: Core render graph implementation with resource management, pass compilation, and execution
- New RenderPipeline.h/cpp: Forward and deferred renderer examples with GBuffer setup and lighting passes
- New ExampleUsage.h: Multiple render graph examples including chunk rendering, shadow mapping, and SSAO
- New README.md: Comprehensive documentation covering render graph architecture, advantages, and usage
- Updated CMakeLists.txt: Added new render graph source files to FarmEngineRenderer library
- Modified ChunkSystem.h/cpp: Updated to 64 height and fixed mesh building vertex indexing
- Updated .gitignore: Refined ignore patterns for build artifacts and temporary files

The render graph system provides automatic synchronization, TBDR optimization, and memory aliasing as requested. The implementation includes comprehensive examples showing integration with the chunk system and advanced rendering techniques.
@qodo-code-review
Copy link
Copy Markdown

Review Summary by Qodo

Implement Render Graph system with ChunkSystem fixes and performance improvements

✨ Enhancement

Grey Divider

Walkthroughs

Description
• Implement comprehensive Render Graph system for Vulkan rendering
  - Core RenderGraph with resource management and pass compilation
  - Forward and Deferred renderer implementations with GBuffer setup
  - Automatic synchronization and TBDR optimization support
• Add multiple render graph usage examples for chunk rendering, shadows, SSAO
• Fix ChunkSystem mesh building vertex indexing calculation errors
  - Correct vertex stride from 3 to 6 components per vertex
  - Update chunk height to configurable parameter
  - Optimize distance calculations using squared length
• Improve ChunkManager threading with reduced lock contention
  - Refactor chunk generation to minimize mutex hold time
  - Fix chunk coordinate key packing for proper uint64 handling
Diagram
flowchart LR
  RG["RenderGraph<br/>Core System"]
  RGB["RenderGraphBuilder<br/>Configuration"]
  RP["RenderPass<br/>Definitions"]
  RR["ResourceRegistry<br/>Management"]
  
  FWD["ForwardRenderer<br/>Example"]
  DEF["DeferredRenderer<br/>Example"]
  
  CS["ChunkSystem<br/>Updates"]
  CM["ChunkManager<br/>Optimization"]
  
  RGB -->|builds| RG
  RP -->|configures| RGB
  RR -->|manages| RG
  
  FWD -->|uses| RG
  DEF -->|uses| RG
  
  CS -->|fixed indexing| CM
  CM -->|improved threading| RG
Loading

Grey Divider

File Changes

1. FarmEngine/src/rendering/graph/RenderGraph.h ✨ Enhancement +167/-0

Core render graph header with resource and pass definitions

FarmEngine/src/rendering/graph/RenderGraph.h


2. FarmEngine/src/rendering/graph/RenderGraph.cpp ✨ Enhancement +364/-0

Render graph implementation with compilation and execution

FarmEngine/src/rendering/graph/RenderGraph.cpp


3. FarmEngine/src/rendering/graph/RenderPipeline.h ✨ Enhancement +87/-0

Forward and deferred renderer pipeline definitions

FarmEngine/src/rendering/graph/RenderPipeline.h


View more (6)
4. FarmEngine/src/rendering/graph/RenderPipeline.cpp ✨ Enhancement +181/-0

Forward and deferred renderer implementations with GBuffer

FarmEngine/src/rendering/graph/RenderPipeline.cpp


5. FarmEngine/src/rendering/graph/ExampleUsage.h 📝 Documentation +189/-0

Multiple render graph usage examples for various scenarios

FarmEngine/src/rendering/graph/ExampleUsage.h


6. FarmEngine/src/rendering/graph/README.md 📝 Documentation +115/-0

Comprehensive render graph architecture and usage documentation

FarmEngine/src/rendering/graph/README.md


7. FarmEngine/world/chunks/ChunkSystem.h ✨ Enhancement +3/-2

Add configurable chunk height parameter to ChunkConfig

FarmEngine/world/chunks/ChunkSystem.h


8. FarmEngine/world/chunks/ChunkSystem.cpp 🐞 Bug fix +47/-34

Fix mesh vertex indexing and optimize chunk manager threading

FarmEngine/world/chunks/ChunkSystem.cpp


9. FarmEngine/CMakeLists.txt ⚙️ Configuration changes +5/-0

Add render graph source files to FarmEngineRenderer library

FarmEngine/CMakeLists.txt


Grey Divider

Qodo Logo

@qodo-code-review
Copy link
Copy Markdown

qodo-code-review Bot commented Apr 2, 2026

Code Review by Qodo

🐞 Bugs (6) 📘 Rule violations (0) 📎 Requirement gaps (0)

Grey Divider


Action required

1. Wrong CMake paths 🐞 Bug ≡ Correctness
Description
FarmEngineRenderer lists new RenderGraph sources under rendering/graph/... but the added files are
under src/rendering/graph/..., so the build will fail when CMake can’t find the sources.
Code

FarmEngine/CMakeLists.txt[R96-104]

add_library(FarmEngineRenderer STATIC
    renderer/Renderer.cpp
    renderer/Renderer.h
+    # Render Graph System
+    rendering/graph/RenderGraph.h
+    rendering/graph/RenderGraph.cpp
+    rendering/graph/RenderPipeline.h
+    rendering/graph/RenderPipeline.cpp
)
Evidence
CMake references a directory that doesn’t exist in the repo layout introduced by this PR; the actual
new module is placed under FarmEngine/src/rendering/graph.

FarmEngine/CMakeLists.txt[96-104]
FarmEngine/src/rendering/graph/RenderGraph.cpp[1-5]
FarmEngine/src/rendering/graph/RenderPipeline.cpp[1-4]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

### Issue description
`FarmEngine/CMakeLists.txt` adds RenderGraph sources using paths that don’t match where the files were added in this PR (`FarmEngine/src/rendering/graph/...`). This breaks the build because CMake won’t find the referenced files.

### Issue Context
The new files are located under `FarmEngine/src/rendering/graph`, but CMake lists them under `rendering/graph`.

### Fix Focus Areas
- FarmEngine/CMakeLists.txt[96-104]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


2. Invalid subpass indices 🐞 Bug ≡ Correctness
Description
RenderGraph compiles explicit dependencies by setting VkSubpassDependency.srcSubpass/dstSubpass to
pass indices, but each created render pass has only one subpass, making dependencies with
dstSubpass > 0 invalid and likely causing vkCreateRenderPass to fail when dependencies are used.
Code

FarmEngine/src/rendering/graph/RenderGraph.cpp[R203-216]

+    // Añadir dependencias explícitas
+    for (const auto& dep : builder.explicitDependencies) {
+        if (dep.from < compiledPasses.size() && dep.to < compiledPasses.size()) {
+            VkSubpassDependency vkDep{};
+            vkDep.srcSubpass = dep.from;
+            vkDep.dstSubpass = dep.to;
+            vkDep.srcStageMask = dep.srcStageMask;
+            vkDep.dstStageMask = dep.dstStageMask;
+            vkDep.srcAccessMask = dep.srcAccessMask;
+            vkDep.dstAccessMask = dep.dstAccessMask;
+            vkDep.dependencyFlags = VK_DEPENDENCY_BY_REGION_BIT;
+            
+            compiledPasses[dep.to].dependencies.push_back(vkDep);
+        }
Evidence
Dependencies are stored with srcSubpass=dep.from and dstSubpass=dep.to, but createRenderPasses
always sets subpassCount = 1 (only subpass 0 exists).

FarmEngine/src/rendering/graph/RenderGraph.cpp[203-216]
FarmEngine/src/rendering/graph/RenderGraph.cpp[223-239]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

### Issue description
`RenderGraphBuilder::addDependency()` is translated into `VkSubpassDependency` with `srcSubpass/dstSubpass` set to *pass indices*, but each `CompiledPass` is turned into a separate `VkRenderPass` with exactly one subpass. This makes any dependency where `to != 0` invalid.

### Issue Context
`VkSubpassDependency` subpass indices must refer to subpasses within the *same* `VkRenderPass`. The current architecture (one `VkRenderPass` per pass) cannot express cross-pass dependencies via `VkSubpassDependency`.

### Fix Focus Areas
- FarmEngine/src/rendering/graph/RenderGraph.cpp[203-216]
- FarmEngine/src/rendering/graph/RenderGraph.cpp[223-239]

### Suggested direction
Either:
- Build a single `VkRenderPass` with multiple subpasses (so subpass indices match passes), **or**
- Keep separate render passes but express dependencies via `vkCmdPipelineBarrier` / `VkImageMemoryBarrier` recorded between passes (and remove/replace the `VkSubpassDependency` logic).

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


3. Null framebuffer handles 🐞 Bug ≡ Correctness
Description
Framebuffers are built from ResourceHandle.imageView without validation, but typical graph setup
(e.g., ForwardRenderer) declares an External color target via addColorTarget which leaves
imageView as VK_NULL_HANDLE, causing framebuffer creation to fail.
Code

FarmEngine/src/rendering/graph/RenderGraph.cpp[R246-280]

+void RenderGraph::createFramebuffers(VkDevice dev, VkExtent2D swapchainExtent) {
+    for (auto& compiled : compiledPasses) {
+        std::vector<VkImageView> attachments;
+        VkExtent2D extent = swapchainExtent;
+        
+        // Obtener views de todos los attachments
+        for (const auto& colorName : compiled.definition.colorAttachments) {
+            const ResourceHandle* res = compiledRegistry.getResource(colorName);
+            if (res) {
+                attachments.push_back(res->imageView);
+                if (!res->isSwapchain) {
+                    extent = res->extent;
+                }
+            }
+        }
+        
+        if (!compiled.definition.depthAttachment.empty()) {
+            const ResourceHandle* res = compiledRegistry.getResource(compiled.definition.depthAttachment);
+            if (res) {
+                attachments.push_back(res->imageView);
+            }
+        }
+        
+        VkFramebufferCreateInfo fbInfo{};
+        fbInfo.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO;
+        fbInfo.renderPass = compiled.vkRenderPass;
+        fbInfo.attachmentCount = static_cast<uint32_t>(attachments.size());
+        fbInfo.pAttachments = attachments.data();
+        fbInfo.width = extent.width;
+        fbInfo.height = extent.height;
+        fbInfo.layers = 1;
+        
+        if (vkCreateFramebuffer(device, &fbInfo, nullptr, &compiled.framebuffer) != VK_SUCCESS) {
+            throw std::runtime_error("Failed to create framebuffer: " + compiled.definition.name);
+        }
Evidence
addColorTarget doesn’t populate image/imageView even for ResourceLifetime::External, and
createFramebuffers blindly pushes res->imageView into the framebuffer attachment list and calls
vkCreateFramebuffer. ForwardRenderer demonstrates creating an external render target using
addColorTarget.

FarmEngine/src/rendering/graph/RenderPipeline.cpp[14-19]
FarmEngine/src/rendering/graph/RenderGraph.cpp[50-62]
FarmEngine/src/rendering/graph/RenderGraph.cpp[246-280]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

### Issue description
`createFramebuffers()` uses `ResourceHandle.imageView` for all attachments, but graph construction can produce resources with `imageView == VK_NULL_HANDLE` (notably `External` targets created via `addColorTarget`). This will fail framebuffer creation.

### Issue Context
`ForwardRenderer::buildGraph()` uses `addColorTarget(..., ResourceLifetime::External)`, but `addColorTarget()` never sets `image/imageView`. Only `addExternalImage()` populates them.

### Fix Focus Areas
- FarmEngine/src/rendering/graph/RenderPipeline.cpp[14-19]
- FarmEngine/src/rendering/graph/RenderGraph.cpp[50-62]
- FarmEngine/src/rendering/graph/RenderGraph.cpp[246-280]

### Suggested direction
- For `ResourceLifetime::External`, require callers to use `addExternalImage()` (and/or make `addColorTarget` reject `External`).
- Add explicit validation in `createFramebuffers()` to throw with a clear message if any required attachment view is `VK_NULL_HANDLE`.
- Optionally track per-resource `isSwapchain` / external-ness consistently and enforce it at compile-time.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


View more (1)
4. Wrong renderArea clears 🐞 Bug ≡ Correctness
Description
RenderGraph::execute sets renderArea.extent from registry.resources[0] for every pass and pushes
only one VkClearValue for all color attachments, which can access out-of-bounds and break render
passes with multiple attachments.
Code

FarmEngine/src/rendering/graph/RenderGraph.cpp[R300-334]

+void RenderGraph::execute(VkCommandBuffer cmd, ResourceRegistry& registry, uint32_t frameIndex) {
+    if (compiledPasses.empty()) {
+        return;
+    }
+    
+    for (const auto& compiled : compiledPasses) {
+        // 1. Record barreras de transición
+        recordBarriers(cmd, compiled);
+        
+        // 2. Begin render pass
+        VkRenderPassBeginInfo rpBegin{};
+        rpBegin.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
+        rpBegin.renderPass = compiled.vkRenderPass;
+        rpBegin.framebuffer = compiled.framebuffer;
+        rpBegin.renderArea.extent = {compiled.attachments.empty() ? 0 : 
+                                     registry.resources[0].extent.width, 
+                                     compiled.attachments.empty() ? 0 : 
+                                     registry.resources[0].extent.height};
+        
+        // Clear values
+        std::vector<VkClearValue> clearValues;
+        if (!compiled.definition.colorAttachments.empty()) {
+            VkClearValue colorClear{};
+            colorClear.color = compiled.definition.clearColorValue;
+            clearValues.push_back(colorClear);
+        }
+        if (!compiled.definition.depthAttachment.empty()) {
+            VkClearValue depthClear{};
+            depthClear.depthStencil = compiled.definition.clearDepthValue;
+            clearValues.push_back(depthClear);
+        }
+        
+        rpBegin.clearValueCount = static_cast<uint32_t>(clearValues.size());
+        rpBegin.pClearValues = clearValues.data();
+        
Evidence
The render area is derived from registry.resources[0] rather than the pass/framebuffer extent, and
the clear value list is not sized to attachmentCount even though compile can add multiple color
attachments.

FarmEngine/src/rendering/graph/RenderGraph.cpp[300-334]
FarmEngine/src/rendering/graph/RenderGraph.cpp[151-174]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

### Issue description
`RenderGraph::execute()` currently:
- Computes `rpBegin.renderArea.extent` from `registry.resources[0]` (not per-pass/framebuffer)
- Supplies only one color `VkClearValue` even if the render pass has multiple color attachments

This can crash (out-of-bounds `resources[0]`) and violates expected clear-value sizing for render passes with multiple attachments.

### Issue Context
A compiled pass may have multiple color attachments (`compiled.attachments.size()` can exceed 2), but `clearValues` is built as `{ one color, optional depth }`.

### Fix Focus Areas
- FarmEngine/src/rendering/graph/RenderGraph.cpp[300-334]
- FarmEngine/src/rendering/graph/RenderGraph.cpp[151-174]

### Suggested direction
- Store the framebuffer extent per `CompiledPass` during framebuffer creation and use it for `renderArea`.
- Build `clearValues` sized to `compiled.attachments.size()` and fill each entry in attachment order (color attachments first, then depth), or otherwise ensure `clearValueCount` matches `attachmentCount`.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools



Remediation recommended

5. Recompile accumulates state 🐞 Bug ☼ Reliability
Description
RenderGraph::compile resizes compiledPasses but never clears attachments, colorRefs, or
dependencies for each CompiledPass, so recompiling the graph can append duplicates and corrupt
attachment indices.
Code

FarmEngine/src/rendering/graph/RenderGraph.cpp[R131-170]

+void RenderGraph::compile(RenderGraphBuilder&& builder) {
+    device = VK_NULL_HANDLE; // Se seteará cuando tengamos contexto Vulkan
+    
+    // Copiar recursos y passes
+    compiledRegistry.resources = std::move(builder.resources);
+    compiledPasses.resize(builder.passes.size());
+    
+    // Construir mapa nombre->índice
+    for (size_t i = 0; i < compiledRegistry.resources.size(); ++i) {
+        compiledRegistry.nameToIndex[compiledRegistry.resources[i].name] = i;
+    }
+    
+    // Compilar cada pass
+    for (size_t i = 0; i < builder.passes.size(); ++i) {
+        CompiledPass& compiled = compiledPasses[i];
+        compiled.definition = builder.passes[i];
+        
+        // Resolver attachments
+        uint32_t attachmentIndex = 0;
+        
+        // Color attachments
+        for (const auto& colorName : compiled.definition.colorAttachments) {
+            const ResourceHandle* res = compiledRegistry.getResource(colorName);
+            if (!res) {
+                throw std::runtime_error("Color attachment not found: " + colorName);
+            }
+            
+            VkAttachmentDescription desc{};
+            desc.format = res->format;
+            desc.samples = VK_SAMPLE_COUNT_1_BIT;
+            desc.loadOp = compiled.definition.colorLoadOp;
+            desc.storeOp = compiled.definition.colorStoreOp;
+            desc.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
+            desc.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
+            desc.initialLayout = res->currentLayout;
+            desc.finalLayout = res->currentLayout; // Se actualizará con barreras
+            
+            compiled.attachments.push_back(desc);
+            
+            VkAttachmentReference ref{};
Evidence
compiledPasses.resize(...) keeps existing CompiledPass objects, and the code then only
push_backs into vectors without resetting them.

FarmEngine/src/rendering/graph/RenderGraph.cpp[135-170]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

### Issue description
Calling `RenderGraph::compile()` multiple times can leave stale state because per-pass vectors are not cleared before new attachment/reference data is appended.

### Issue Context
`compiledPasses.resize(builder.passes.size())` does not reinitialize existing elements, and compile immediately starts `push_back` into `compiled.attachments` and `compiled.colorRefs`.

### Fix Focus Areas
- FarmEngine/src/rendering/graph/RenderGraph.cpp[135-170]

### Suggested direction
At the start of the per-pass loop, reset the struct, e.g.:
- `compiled = CompiledPass{}; compiled.definition = ...;` (taking care to destroy old Vulkan handles first), or
- Explicitly `clear()` all relevant vectors and reset `depthRef`/handles before rebuilding.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


6. glm::length2 header missing 🐞 Bug ☼ Reliability
Description
ChunkSystem.cpp switched to glm::length2 but doesn’t include the header that typically declares it
(glm/gtx/norm.hpp), which can break compilation depending on the GLM configuration/version.
Code

FarmEngine/world/chunks/ChunkSystem.cpp[R384-390]

    glm::vec2 playerChunkPos(playerChunkX, playerChunkZ);
    std::sort(chunkOrder.begin(), chunkOrder.end(),
        [playerChunkPos](const auto& a, const auto& b) {
-            float distA = glm::length(glm::vec2(a.first, a.second) - playerChunkPos);
-            float distB = glm::length(glm::vec2(b.first, b.second) - playerChunkPos);
+            // Use squared distance to avoid expensive sqrt operations
+            float distA = glm::length2(glm::vec2(a.first, a.second) - playerChunkPos);
+            float distB = glm::length2(glm::vec2(b.first, b.second) - playerChunkPos);
            return distA < distB;
Evidence
The file uses glm::length2 while ChunkSystem’s public header only includes <glm/glm.hpp>, and
there is no include of gtx/norm in this module.

FarmEngine/world/chunks/ChunkSystem.h[1-9]
FarmEngine/world/chunks/ChunkSystem.cpp[383-391]
FarmEngine/world/chunks/ChunkSystem.cpp[567-575]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

### Issue description
`glm::length2()` may not be declared with the currently included GLM headers in this module, causing build failures on some setups.

### Issue Context
ChunkSystem includes `<glm/glm.hpp>` but uses `glm::length2`.

### Fix Focus Areas
- FarmEngine/world/chunks/ChunkSystem.h[1-9]
- FarmEngine/world/chunks/ChunkSystem.cpp[383-391]
- FarmEngine/world/chunks/ChunkSystem.cpp[567-575]

### Suggested direction
Either:
- Add `#include <glm/gtx/norm.hpp>` (preferably in the `.cpp` to avoid propagating experimental headers), or
- Replace `glm::length2(v)` with `glm::dot(v, v)`.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


Grey Divider

ⓘ The new review experience is currently in Beta. Learn more

Grey Divider

Qodo Logo

Copy link
Copy Markdown
Contributor

@amazon-q-developer amazon-q-developer Bot left a comment

Choose a reason for hiding this comment

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

Review Summary

This PR adds a comprehensive render graph system and enhances the chunk system with improved performance optimizations. However, there are critical defects that must be fixed before merge.

Critical Issues (Must Fix)

Chunk Key Generation Bug: The chunk coordinate hashing in ChunkManager::getChunk() and ChunkManager::processPendingGenerations() has a logic error that causes hash collisions with negative chunk coordinates. When negative int32_t values are cast to uint32_t, they become large positive values (e.g., -1 becomes 0xFFFFFFFF), producing incorrect hash keys. This will cause chunks at negative world positions to collide, overwrite each other, or become inaccessible, breaking world generation for any player movement into negative coordinate spaces.

Changes Overview

Positive Changes:

  • Added modern render graph system with proper resource management and synchronization
  • Fixed hardcoded chunk height values throughout the codebase, now using configurable chunkHeight parameter
  • Corrected vertex buffer stride calculation bug in mesh generation (changed from /3 to /6 to match position+normal data)
  • Improved chunk generation performance by reducing lock contention (generation now happens outside mutex)
  • Optimized distance calculations using glm::length2 instead of glm::length to avoid expensive sqrt operations
  • Added LOD and culling systems for performance optimization

Areas of Concern:

  • The chunk key generation must be fixed to handle negative coordinates correctly
  • Verify that TerrainConfig and Biome types are properly defined in the included headers

Files Changed: 10 files with 1,183 additions and 79 deletions

Please address the critical chunk key generation issue before merging.


You can now have the agent implement changes and create commits directly on your pull request's source branch. Simply comment with /q followed by your request in natural language to ask the agent to make changes.

Comment thread FarmEngine/world/chunks/ChunkSystem.cpp Outdated
Comment thread FarmEngine/world/chunks/ChunkSystem.cpp Outdated
Copy link
Copy Markdown
Contributor

@gemini-code-assist gemini-code-assist Bot left a comment

Choose a reason for hiding this comment

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

Code Review

This pull request introduces a Render Graph system to FarmEngine for automated Vulkan synchronization and resource management, alongside significant improvements to the Chunk System. The Chunk System now supports configurable heights, optimized distance calculations using squared lengths, and reduced mutex contention during chunk generation. However, the Render Graph implementation contains several critical Vulkan synchronization and state management issues, including invalid subpass dependencies between separate render passes, incorrect attachment layout transitions, and hardcoded render area extents. Additionally, the .gitignore file requires cleanup of markdown delimiters.

Comment thread .gitignore
@@ -1,69 +1,51 @@
```
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.

high

The .gitignore file contains markdown code block delimiters (```) at the beginning and end of the file. These should be removed as they are not valid gitignore syntax and were likely included by mistake during code generation.

desc.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
desc.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
desc.initialLayout = res->currentLayout;
desc.finalLayout = res->currentLayout; // Se actualizará con barreras
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.

high

Setting desc.finalLayout to res->currentLayout is incorrect. The finalLayout specifies the layout the attachment will transition to automatically at the end of the render pass. For a color attachment, this should typically be VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL or the layout required by the next pass. Using the current layout (which might be UNDEFINED) will lead to incorrect state transitions.

Comment on lines +206 to +208
VkSubpassDependency vkDep{};
vkDep.srcSubpass = dep.from;
vkDep.dstSubpass = dep.to;
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.

high

Each CompiledPass is being created as a separate VkRenderPass (line 223), but you are adding VkSubpassDependency objects to them using the graph pass indices as srcSubpass and dstSubpass. In Vulkan, subpass dependencies only synchronize subpasses within the same VkRenderPass. Since your passes are in different VkRenderPass objects, these dependencies are invalid. You should use VK_SUBPASS_EXTERNAL for transitions between different render passes, or use VkMemoryBarrier/VkImageMemoryBarrier between vkCmdEndRenderPass and vkCmdBeginRenderPass calls.

Comment on lines +314 to +317
rpBegin.renderArea.extent = {compiled.attachments.empty() ? 0 :
registry.resources[0].extent.width,
compiled.attachments.empty() ? 0 :
registry.resources[0].extent.height};
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.

high

Accessing registry.resources[0].extent to set the render area for every pass is a major bug. 1) The registry might be empty. 2) The first resource in the registry is not necessarily the one this pass is rendering to. 3) Different passes can have different extents (e.g., shadow maps or half-res buffers). You should use the extent of the framebuffer associated with the current compiled pass.

Comment on lines +289 to +290
VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,
VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,
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.

medium

Using VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT and VK_PIPELINE_STAGE_ALL_COMMANDS_BIT for all barriers is extremely inefficient. It essentially flushes the entire GPU pipeline and prevents any overlapping execution of passes. You should use the specific stages where the resources are actually produced and consumed.

tronpis and others added 2 commits April 2, 2026 13:21
Co-authored-by: amazon-q-developer[bot] <208079219+amazon-q-developer[bot]@users.noreply.github.com>
Co-authored-by: amazon-q-developer[bot] <208079219+amazon-q-developer[bot]@users.noreply.github.com>
Comment thread FarmEngine/CMakeLists.txt
Comment on lines 96 to 104
add_library(FarmEngineRenderer STATIC
renderer/Renderer.cpp
renderer/Renderer.h
# Render Graph System
rendering/graph/RenderGraph.h
rendering/graph/RenderGraph.cpp
rendering/graph/RenderPipeline.h
rendering/graph/RenderPipeline.cpp
)
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Action required

1. Wrong cmake paths 🐞 Bug ≡ Correctness

FarmEngineRenderer lists new RenderGraph sources under rendering/graph/... but the added files are
under src/rendering/graph/..., so the build will fail when CMake can’t find the sources.
Agent Prompt
### Issue description
`FarmEngine/CMakeLists.txt` adds RenderGraph sources using paths that don’t match where the files were added in this PR (`FarmEngine/src/rendering/graph/...`). This breaks the build because CMake won’t find the referenced files.

### Issue Context
The new files are located under `FarmEngine/src/rendering/graph`, but CMake lists them under `rendering/graph`.

### Fix Focus Areas
- FarmEngine/CMakeLists.txt[96-104]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

Comment on lines +203 to +216
// Añadir dependencias explícitas
for (const auto& dep : builder.explicitDependencies) {
if (dep.from < compiledPasses.size() && dep.to < compiledPasses.size()) {
VkSubpassDependency vkDep{};
vkDep.srcSubpass = dep.from;
vkDep.dstSubpass = dep.to;
vkDep.srcStageMask = dep.srcStageMask;
vkDep.dstStageMask = dep.dstStageMask;
vkDep.srcAccessMask = dep.srcAccessMask;
vkDep.dstAccessMask = dep.dstAccessMask;
vkDep.dependencyFlags = VK_DEPENDENCY_BY_REGION_BIT;

compiledPasses[dep.to].dependencies.push_back(vkDep);
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Action required

2. Invalid subpass indices 🐞 Bug ≡ Correctness

RenderGraph compiles explicit dependencies by setting VkSubpassDependency.srcSubpass/dstSubpass to
pass indices, but each created render pass has only one subpass, making dependencies with
dstSubpass > 0 invalid and likely causing vkCreateRenderPass to fail when dependencies are used.
Agent Prompt
### Issue description
`RenderGraphBuilder::addDependency()` is translated into `VkSubpassDependency` with `srcSubpass/dstSubpass` set to *pass indices*, but each `CompiledPass` is turned into a separate `VkRenderPass` with exactly one subpass. This makes any dependency where `to != 0` invalid.

### Issue Context
`VkSubpassDependency` subpass indices must refer to subpasses within the *same* `VkRenderPass`. The current architecture (one `VkRenderPass` per pass) cannot express cross-pass dependencies via `VkSubpassDependency`.

### Fix Focus Areas
- FarmEngine/src/rendering/graph/RenderGraph.cpp[203-216]
- FarmEngine/src/rendering/graph/RenderGraph.cpp[223-239]

### Suggested direction
Either:
- Build a single `VkRenderPass` with multiple subpasses (so subpass indices match passes), **or**
- Keep separate render passes but express dependencies via `vkCmdPipelineBarrier` / `VkImageMemoryBarrier` recorded between passes (and remove/replace the `VkSubpassDependency` logic).

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

Comment on lines +246 to +280
void RenderGraph::createFramebuffers(VkDevice dev, VkExtent2D swapchainExtent) {
for (auto& compiled : compiledPasses) {
std::vector<VkImageView> attachments;
VkExtent2D extent = swapchainExtent;

// Obtener views de todos los attachments
for (const auto& colorName : compiled.definition.colorAttachments) {
const ResourceHandle* res = compiledRegistry.getResource(colorName);
if (res) {
attachments.push_back(res->imageView);
if (!res->isSwapchain) {
extent = res->extent;
}
}
}

if (!compiled.definition.depthAttachment.empty()) {
const ResourceHandle* res = compiledRegistry.getResource(compiled.definition.depthAttachment);
if (res) {
attachments.push_back(res->imageView);
}
}

VkFramebufferCreateInfo fbInfo{};
fbInfo.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO;
fbInfo.renderPass = compiled.vkRenderPass;
fbInfo.attachmentCount = static_cast<uint32_t>(attachments.size());
fbInfo.pAttachments = attachments.data();
fbInfo.width = extent.width;
fbInfo.height = extent.height;
fbInfo.layers = 1;

if (vkCreateFramebuffer(device, &fbInfo, nullptr, &compiled.framebuffer) != VK_SUCCESS) {
throw std::runtime_error("Failed to create framebuffer: " + compiled.definition.name);
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Action required

3. Null framebuffer handles 🐞 Bug ≡ Correctness

Framebuffers are built from ResourceHandle.imageView without validation, but typical graph setup
(e.g., ForwardRenderer) declares an External color target via addColorTarget which leaves
imageView as VK_NULL_HANDLE, causing framebuffer creation to fail.
Agent Prompt
### Issue description
`createFramebuffers()` uses `ResourceHandle.imageView` for all attachments, but graph construction can produce resources with `imageView == VK_NULL_HANDLE` (notably `External` targets created via `addColorTarget`). This will fail framebuffer creation.

### Issue Context
`ForwardRenderer::buildGraph()` uses `addColorTarget(..., ResourceLifetime::External)`, but `addColorTarget()` never sets `image/imageView`. Only `addExternalImage()` populates them.

### Fix Focus Areas
- FarmEngine/src/rendering/graph/RenderPipeline.cpp[14-19]
- FarmEngine/src/rendering/graph/RenderGraph.cpp[50-62]
- FarmEngine/src/rendering/graph/RenderGraph.cpp[246-280]

### Suggested direction
- For `ResourceLifetime::External`, require callers to use `addExternalImage()` (and/or make `addColorTarget` reject `External`).
- Add explicit validation in `createFramebuffers()` to throw with a clear message if any required attachment view is `VK_NULL_HANDLE`.
- Optionally track per-resource `isSwapchain` / external-ness consistently and enforce it at compile-time.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

Comment on lines +300 to +334
void RenderGraph::execute(VkCommandBuffer cmd, ResourceRegistry& registry, uint32_t frameIndex) {
if (compiledPasses.empty()) {
return;
}

for (const auto& compiled : compiledPasses) {
// 1. Record barreras de transición
recordBarriers(cmd, compiled);

// 2. Begin render pass
VkRenderPassBeginInfo rpBegin{};
rpBegin.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
rpBegin.renderPass = compiled.vkRenderPass;
rpBegin.framebuffer = compiled.framebuffer;
rpBegin.renderArea.extent = {compiled.attachments.empty() ? 0 :
registry.resources[0].extent.width,
compiled.attachments.empty() ? 0 :
registry.resources[0].extent.height};

// Clear values
std::vector<VkClearValue> clearValues;
if (!compiled.definition.colorAttachments.empty()) {
VkClearValue colorClear{};
colorClear.color = compiled.definition.clearColorValue;
clearValues.push_back(colorClear);
}
if (!compiled.definition.depthAttachment.empty()) {
VkClearValue depthClear{};
depthClear.depthStencil = compiled.definition.clearDepthValue;
clearValues.push_back(depthClear);
}

rpBegin.clearValueCount = static_cast<uint32_t>(clearValues.size());
rpBegin.pClearValues = clearValues.data();

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Action required

4. Wrong renderarea clears 🐞 Bug ≡ Correctness

RenderGraph::execute sets renderArea.extent from registry.resources[0] for every pass and pushes
only one VkClearValue for all color attachments, which can access out-of-bounds and break render
passes with multiple attachments.
Agent Prompt
### Issue description
`RenderGraph::execute()` currently:
- Computes `rpBegin.renderArea.extent` from `registry.resources[0]` (not per-pass/framebuffer)
- Supplies only one color `VkClearValue` even if the render pass has multiple color attachments

This can crash (out-of-bounds `resources[0]`) and violates expected clear-value sizing for render passes with multiple attachments.

### Issue Context
A compiled pass may have multiple color attachments (`compiled.attachments.size()` can exceed 2), but `clearValues` is built as `{ one color, optional depth }`.

### Fix Focus Areas
- FarmEngine/src/rendering/graph/RenderGraph.cpp[300-334]
- FarmEngine/src/rendering/graph/RenderGraph.cpp[151-174]

### Suggested direction
- Store the framebuffer extent per `CompiledPass` during framebuffer creation and use it for `renderArea`.
- Build `clearValues` sized to `compiled.attachments.size()` and fill each entry in attachment order (color attachments first, then depth), or otherwise ensure `clearValueCount` matches `attachmentCount`.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

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