Skip to content

Conversation

@WSQS
Copy link
Owner

@WSQS WSQS commented Nov 16, 2025

Summary by CodeRabbit

Release Notes

  • New Features

    • Added interactive shader editor with three editing modes: Node (vertex position dragging), Vertex shader, and Fragment shader editing.
    • Real-time shader compilation and pipeline updates with visual feedback.
    • Enhanced error reporting for GPU operations.
  • Bug Fixes

    • Improved error handling and validation for GPU initialization and buffer operations.
  • Improvements

    • Strengthened graphics pipeline robustness and resource management during rendering.

@coderabbitai
Copy link

coderabbitai bot commented Nov 16, 2025

Walkthrough

This PR comprehensively refactors GPU resource management to employ std::expected-based error handling throughout. It introduces composite wrapper types for GPU contexts (DeviceHandle, WindowHandle, ClaimedWindow, GpuContext), updates BufferWrapper and PipelineWrapper public APIs to return expected-wrapped results with detailed error codes, expands UserApp initialization with staged GPU setup and Dear ImGui integration, and adds an interactive shader/vertex editor UI. Virtual keywords are removed from lifecycle methods.

Changes

Cohort / File(s) Summary
GPU Error Definitions
sdl_wrapper/sdl_wrapper.decl.ixx
Adds new public enum class GpuError with 16 error codes covering GPU initialization, resource creation, and data transfer failures.
GPU Wrapper Core Types & Factory
sdl_wrapper/sdl_wrapper.gpu.ixx
Introduces DeviceHandle, WindowHandle, ClaimedWindow, and GpuContext wrapper types with move semantics and validity checks; adds create_gpu_context() factory; refactors GpuWrapper to use GpuContext member and adds static create() factory returning std::expected<std::shared_ptr<GpuWrapper>, GpuError>.
GPU Wrapper Implementation
sdl_wrapper/sdl_wrapper.gpu.cpp
Updates create_buffer() to return std::expected<BufferWrapper, GpuError> with error handling; adds create_pipeline_wrapper() returning expected-wrapped result; updates error logging.
Buffer Wrapper Types
sdl_wrapper/sdl_wrapper.buffer.ixx
Refactors constructor to accept std::shared_ptr<GpuWrapper> and size parameter; deletes copy semantics, defaults move semantics; adds upload() and data() public methods returning expected-wrapped results with detailed error handling.
Buffer Wrapper Implementation
sdl_wrapper/sdl_wrapper.buffer.cpp
Updates upload() signature to return std::expected<std::monostate, GpuError> with bounds checking; implements transfer buffer mapping, copying, and GPU copy pass submission with granular error handling for each step.
Pipeline Wrapper Types
sdl_wrapper/sdl_wrapper.pipeline.ixx
Updates constructor signature to accept GpuWrapper and swapchain format; deletes copy semantics, defaults move semantics; adds public methods submit(), set_vertex_shader(), set_fragment_shader() all returning std::expected<std::monostate, GpuError>; adds data() accessor.
Pipeline Wrapper Implementation
sdl_wrapper/sdl_wrapper.pipeline.cpp
Adds spv_result_to_bytes() helper for SPIR-V conversion; updates constructor to use new GPU wrapper member; refactors shader compilation and pipeline creation to use GpuWrapper APIs; updates shader/pipeline methods to return expected-wrapped results with error logging.
SDL Callback Initialization
sdl_wrapper/sdl_callback_implement.cpp
Adds validation of SDL_Init(SDL_INIT_VIDEO) call with error logging and early failure return.
Main Application
main.cpp
Expands UserApp initialization with staged GPU setup (GpuWrapper creation, buffer/pipeline creation with error checks, shader compilation); removes virtual keywords from lifecycle methods; adds interactive ImGui editor UI with three-mode selector (Node/Vertex/Fragment); implements vertex position dragging and shader editing with error-handling upload paths; initializes Dear ImGui and SDL3/SDLGPU3 backends; updates drawing flow with robust error handling for command buffer, swapchain texture acquisition, and render pass setup.

Sequence Diagram(s)

sequenceDiagram
    participant Main as UserApp::init()
    participant GpuCreate as GpuWrapper::create()
    participant DevSetup as GPU Device/Window Setup
    participant BuffCreate as GpuWrapper::create_buffer()
    participant PipeCreate as GpuWrapper::create_pipeline_wrapper()
    participant ShaderSet as PipelineWrapper::set_vertex_shader()
    participant PipeSubmit as PipelineWrapper::submit()
    participant Upload as BufferWrapper::upload()
    participant ImGui as ImGui Init

    Main ->> GpuCreate: create()
    alt GPU Creation Success
        GpuCreate ->> DevSetup: Initialize device/window
        DevSetup -->> GpuCreate: GpuContext
        GpuCreate -->> Main: Ok(GpuWrapper)
        
        Main ->> BuffCreate: create_buffer()
        alt Buffer Success
            BuffCreate -->> Main: Ok(BufferWrapper)
            Main ->> PipeCreate: create_pipeline_wrapper()
            alt Pipeline Success
                PipeCreate -->> Main: Ok(PipelineWrapper)
                Main ->> ShaderSet: set_vertex_shader(src)
                alt Shader Compile Success
                    ShaderSet ->> PipeSubmit: submit()
                    PipeSubmit -->> Main: Ok(())
                else Shader Compile Failure
                    ShaderSet -->> Main: Err(GpuError)
                end
            else Pipeline Failure
                PipeCreate -->> Main: Err(GpuError)
            end
        else Buffer Failure
            BuffCreate -->> Main: Err(GpuError)
        end
        
        Main ->> Upload: upload(data, size, offset)
        alt Upload Success
            Upload -->> Main: Ok(())
        else Upload Failure
            Upload -->> Main: Err(GpuError)
        end
        
        Main ->> ImGui: Init ImGui + backends
    else GPU Creation Failure
        GpuCreate -->> Main: Err(GpuError)
    end
Loading
sequenceDiagram
    participant Editor as ImGui Editor UI
    participant App as UserApp
    participant PipeWrap as PipelineWrapper
    participant BuffWrap as BufferWrapper
    participant GPU as GpuWrapper

    loop Each Frame
        Editor ->> App: Vertex drag / Shader edit
        alt Vertex Position Changed
            App ->> BuffWrap: upload(new_vertex_data)
            BuffWrap ->> GPU: acquire command buffer
            BuffWrap ->> GPU: transfer buffer map/copy
            alt Upload Success
                BuffWrap -->> App: Ok(())
            else Upload Fails
                BuffWrap -->> App: Err(GpuError)
                App ->> App: Log error, continue
            end
        else Shader Source Changed
            App ->> PipeWrap: set_vertex_shader(src) or set_fragment_shader(src)
            PipeWrap ->> PipeWrap: shaderc compile
            alt Compile Success
                PipeWrap ->> GPU: create_shader()
                alt Shader Create Success
                    PipeWrap ->> GPU: release_shader(old)
                    PipeWrap ->> PipeWrap: Mark m_modified
                    PipeWrap -->> App: Ok(())
                else Shader Create Fails
                    PipeWrap -->> App: Err(GpuError)
                end
            else Compile Fails
                PipeWrap -->> App: Err(COMPILE_VERTEX_SHADER_FAILED)
            end
        end
        
        App ->> PipeWrap: submit() if m_modified
        alt Submit Success
            PipeWrap ->> GPU: create_pipeline(info)
            PipeWrap -->> App: Ok(())
        else Submit Fails
            PipeWrap -->> App: Err(GpuError)
        end
    end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

  • High logic density: Multiple error-propagation paths across GPU initialization, buffer upload, and pipeline submission require careful verification of error codes and handling.
  • Significant structural changes: Introduction of new composite types (DeviceHandle, WindowHandle, ClaimedWindow, GpuContext) with move semantics and ownership semantics requires thorough understanding of resource lifetime.
  • Heterogeneous changes: Mix of type definitions, API signature updates, error-handling refactors, and UI additions across distinct modules demands context switching.
  • Critical areas requiring extra attention:
    • sdl_wrapper/sdl_wrapper.gpu.ixx and .cpp: Resource ownership model and factory pattern implementation
    • sdl_wrapper/sdl_wrapper.buffer.cpp: Transfer buffer mapping, bounds checking, and GPU copy pass error handling
    • sdl_wrapper/sdl_wrapper.pipeline.cpp: Shader compilation, SPIR-V conversion, and pipeline lifecycle management
    • main.cpp: Staged initialization flow, error propagation in draw loop, and ImGui editor integration with shader/vertex updates

Possibly related PRs

  • Window wrapper #24: Directly modifies GpuWrapper window management and pipeline construction patterns—both PRs refactor how the GPU context is acquired and pipelines are created with the wrapper.
  • Pipeline Wrapper create #7: Refactors main.cpp to use GpuWrapper/BufferWrapper/PipelineWrapper abstractions for shader and pipeline creation—overlaps significantly with the core abstraction changes in this PR.
  • Buffer wrapper Implement #3: Modifies BufferWrapper upload and data access APIs—this PR evolves the same API surface with error handling and ownership semantics introduced there.

Poem

🐰 With expected types, we hop with care,
GPU errors caught and logged with flair,
Stages of setup, each one blessed,
Resources managed, put to test.
No virtual keywords, just override—
Monadic safety, our trusty guide!

Pre-merge checks and finishing touches

❌ Failed checks (1 warning, 1 inconclusive)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 33.33% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
Title check ❓ Inconclusive The title 'Error check' is vague and generic, using non-descriptive terms that don't convey meaningful information about the substantial refactoring performed in this changeset. Consider a more specific title like 'Refactor GPU resource management with std::expected error handling' or 'Add comprehensive error handling to GPU initialization and drawing flows' to better reflect the main changes.
✅ Passed checks (1 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
✨ Finishing touches
  • 📝 Docstrings were successfully generated.
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch error_check

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.

This commit fixes the style issues introduced in 13172f9 according to the output
from ClangFormat.

Details: #32
@deepsource-io
Copy link
Contributor

deepsource-io bot commented Nov 16, 2025

Here's the code health analysis summary for commits 6ec542c..4e0dd99. View details on DeepSource ↗.

Analysis Summary

AnalyzerStatusSummaryLink
DeepSource C & C++ LogoC & C++❌ Failure
❗ 11 occurences introduced
🎯 94 occurences resolved
View Check ↗

💡 If you’re a repository administrator, you can configure the quality gates from the settings.

Copy link

@github-actions github-actions bot left a comment

Choose a reason for hiding this comment

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

clang-tidy made some suggestions

There were too many comments to post at once. Showing the first 25 out of 86. Check the log or trigger a new build to see more.

#include <array>
#include <cmath>
#include <expected>
#include <iostream>

Choose a reason for hiding this comment

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

warning: included header expected is not used directly [misc-include-cleaner]

Suggested change
#include <iostream>
#include <iostream>

#include <expected>
#include <iostream>
#include <memory>
#include <numbers>

Choose a reason for hiding this comment

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

warning: included header memory is not used directly [misc-include-cleaner]

Suggested change
#include <numbers>
#include <numbers>

#include "SDL3/SDL_gpu.h"
#include "SDL3/SDL_keycode.h"

import sdl_wrapper;

Choose a reason for hiding this comment

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

warning: module 'sdl_wrapper' not found [clang-diagnostic-error]

import sdl_wrapper;
       ^

* components `(x, y, z)`.
*/
auto position() { return &x; }
float r, g, b, a; // vec4 color

Choose a reason for hiding this comment

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

warning: member variable 'a' has public visibility [misc-non-private-member-variables-in-classes]

    float r, g, b, a; // vec4 color
                   ^

* components `(x, y, z)`.
*/
auto position() { return &x; }
float r, g, b, a; // vec4 color

Choose a reason for hiding this comment

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

warning: member variable 'b' has public visibility [misc-non-private-member-variables-in-classes]

    float r, g, b, a; // vec4 color
                ^

[&](auto& vertex_buffer)
{ return vertex_buffer.upload(vertices.data(), static_cast<std::uint32_t>(sizeof(vertices)), 0); });

if (!upload_result)

Choose a reason for hiding this comment

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

warning: do not call c-style vararg functions [cppcoreguidelines-pro-type-vararg]

            SDL_LogError(SDL_LOG_CATEGORY_GPU, "Failed to upload initial vertex data, error = %d",
            ^

[&](auto& vertex_buffer)
{ return vertex_buffer.upload(vertices.data(), static_cast<std::uint32_t>(sizeof(vertices)), 0); });

if (!upload_result)

Choose a reason for hiding this comment

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

warning: no header providing "SDL_LOG_CATEGORY_GPU" is directly included [misc-include-cleaner]

            SDL_LogError(SDL_LOG_CATEGORY_GPU, "Failed to upload initial vertex data, error = %d",
                         ^

SDL_GetGPUSwapchainTextureFormat(gpu_wrapper->data(), gpu_wrapper->acquire_window());
init_info.MSAASamples = SDL_GPU_SAMPLECOUNT_1; // Only used in multi-viewports mode.
init_info.SwapchainComposition = SDL_GPU_SWAPCHAINCOMPOSITION_SDR; // Only used in multi-viewports mode.

Choose a reason for hiding this comment

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

warning: no header providing "SDL_Window" is directly included [misc-include-cleaner]

        if (SDL_Window* window = m_gpu->window())
            ^

SDL_GetGPUSwapchainTextureFormat(gpu_wrapper->data(), gpu_wrapper->acquire_window());
init_info.MSAASamples = SDL_GPU_SAMPLECOUNT_1; // Only used in multi-viewports mode.
init_info.SwapchainComposition = SDL_GPU_SWAPCHAINCOMPOSITION_SDR; // Only used in multi-viewports mode.

Choose a reason for hiding this comment

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

warning: variable 'window' is not initialized [cppcoreguidelines-init-variables]

Suggested change
if (SDL_Window* window = nullptr = m_gpu->window())

{
ImGui_ImplSDL3_InitForSDLGPU(window);
}
else

Choose a reason for hiding this comment

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

warning: do not call c-style vararg functions [cppcoreguidelines-pro-type-vararg]

            SDL_LogError(SDL_LOG_CATEGORY_ERROR,
            ^

Copy link

@github-actions github-actions bot left a comment

Choose a reason for hiding this comment

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

clang-tidy made some suggestions

There were too many comments to post at once. Showing the first 25 out of 69. Check the log or trigger a new build to see more.

* and sets up Dear ImGui and its SDL3/SDLGPU backends.
*/
virtual SDL_AppResult init(int argc, char** argv) override
SDL_AppResult init(int argc, char** argv) override

Choose a reason for hiding this comment

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

warning: method 'init' can be made static [readability-convert-member-functions-to-static]

Suggested change
SDL_AppResult init(int argc, char** argv) override
static SDL_AppResult init(int argc, char** argv) override

* and sets up Dear ImGui and its SDL3/SDLGPU backends.
*/
virtual SDL_AppResult init(int argc, char** argv) override
SDL_AppResult init(int argc, char** argv) override

Choose a reason for hiding this comment

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

warning: no header providing "SDL_AppResult" is directly included [misc-include-cleaner]

main.cpp:10:

- #include "imgui.h"
+ #include "SDL3/SDL_init.h"
+ #include "imgui.h"

* and sets up Dear ImGui and its SDL3/SDLGPU backends.
*/
virtual SDL_AppResult init(int argc, char** argv) override
SDL_AppResult init(int argc, char** argv) override

Choose a reason for hiding this comment

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

warning: parameter 'argc' is unused [misc-unused-parameters]

Suggested change
SDL_AppResult init(int argc, char** argv) override
SDL_AppResult init(int /*argc*/, char** argv) override

* and sets up Dear ImGui and its SDL3/SDLGPU backends.
*/
virtual SDL_AppResult init(int argc, char** argv) override
SDL_AppResult init(int argc, char** argv) override

Choose a reason for hiding this comment

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

warning: parameter 'argv' is unused [misc-unused-parameters]

Suggested change
SDL_AppResult init(int argc, char** argv) override
SDL_AppResult init(int argc, char** /*argv*/) override

auto gpu_result = sopho::GpuWrapper::create();
if (!gpu_result)
{
SDL_LogError(SDL_LOG_CATEGORY_ERROR, "Failed to create GpuWrapper, error = %d",

Choose a reason for hiding this comment

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

warning: do not call c-style vararg functions [cppcoreguidelines-pro-type-vararg]

            SDL_LogError(SDL_LOG_CATEGORY_ERROR, "Failed to create GpuWrapper, error = %d",
            ^

if (!result)
{
pipeline_wrapper.set_fragment_shader(fragment_source);
SDL_LogError(SDL_LOG_CATEGORY_RENDER, "Failed to set fragment shader from editor, error = %d",

Choose a reason for hiding this comment

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

warning: do not call c-style vararg functions [cppcoreguidelines-pro-type-vararg]

                        SDL_LogError(SDL_LOG_CATEGORY_RENDER, "Failed to set fragment shader from editor, error = %d",
                        ^

m_pipeline_wrapper.and_then([](auto& pipeline_wrapper) { return pipeline_wrapper.submit(); });
if (!pipeline_submit)
{
SDL_LogError(SDL_LOG_CATEGORY_GPU, "Pipeline submit failed, error = %d",

Choose a reason for hiding this comment

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

warning: do not call c-style vararg functions [cppcoreguidelines-pro-type-vararg]

            SDL_LogError(SDL_LOG_CATEGORY_GPU, "Pipeline submit failed, error = %d",
            ^

return SDL_APP_CONTINUE;
}

SDL_GPUDevice* device = m_gpu->device();

Choose a reason for hiding this comment

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

warning: variable 'device' is not initialized [cppcoreguidelines-init-variables]

Suggested change
SDL_GPUDevice* device = m_gpu->device();
SDL_GPUDevice* device = nullptr = m_gpu->device();

}

SDL_GPUDevice* device = m_gpu->device();
if (!device)

Choose a reason for hiding this comment

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

warning: implicit conversion 'SDL_GPUDevice *' -> 'bool' [readability-implicit-bool-conversion]

Suggested change
if (!device)
if (device == nullptr)

SDL_GPUDevice* device = m_gpu->device();
if (!device)
{
SDL_LogError(SDL_LOG_CATEGORY_GPU, "GpuWrapper::device() returned null in draw()");

Choose a reason for hiding this comment

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

warning: do not call c-style vararg functions [cppcoreguidelines-pro-type-vararg]

            SDL_LogError(SDL_LOG_CATEGORY_GPU, "GpuWrapper::device() returned null in draw()");
            ^

Copy link

@coderabbitai coderabbitai bot left a comment

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)
main.cpp (1)

361-427: Now let me verify the SDL3 GPU API documentation to confirm whether SDL_BeginGPURenderPass can return nullptr:

Let me search for more specific documentation on SDL_BeginGPURenderPass behavior:

Status after verification:

Based on my investigation, I found an important documentation discrepancy in SDL3:

SDL_CreateGPUTexture explicitly documents: "returns a texture object on success, or NULL on failure", but SDL_BeginGPURenderPass documentation only states: "returns a render pass handle" with no explicit failure case documented.

The review comment states that SDL_BeginGPURenderPass "can return nullptr" but this is not explicitly documented in the SDL3 API reference. However, SDL's general pattern is that "most SDL functions will return a specific value on failure. For functions that return pointers, this value is NULL".

Confirmed issue in the codebase: The current main.cpp code unconditionally uses renderPass without checking for null, following the pattern already established for swapchainTexture null checking in the same function.


Handle SDL_BeginGPURenderPass failure to avoid using a null render pass

The code unconditionally uses renderPass from SDL_BeginGPURenderPass (binding pipeline, binding vertex buffers, drawing), but following SDL's established pattern for pointer-returning functions, this should be guarded against null. The codebase already demonstrates careful null-checking for other GPU resources (command buffer, swapchain texture); the render pass should be treated consistently.

Suggested fix:

         SDL_GPURenderPass* renderPass = SDL_BeginGPURenderPass(commandBuffer, &colorTargetInfo, 1, nullptr);
+        if (!renderPass)
+        {
+            SDL_LogError(SDL_LOG_CATEGORY_GPU, "Failed to begin GPU render pass: %s", SDL_GetError());
+            SDL_SubmitGPUCommandBuffer(commandBuffer);
+            return SDL_APP_CONTINUE;
+        }
 
         // Bind pipeline if available.
         m_pipeline_wrapper.and_then(
🧹 Nitpick comments (4)
sdl_wrapper/sdl_wrapper.buffer.cpp (1)

42-135: Tighten bounds check and handle zero-size uploads explicitly

The overall upload flow (bounds check → transfer buffer resize → map/copy → copy pass + submit → std::expected errors) is solid. Two small robustness tweaks would help:

  • Avoid potential std::uint32_t overflow in offset + size.
  • Treat size == 0 as a no-op instead of running the full GPU path (and potentially mapping a null transfer buffer).

For example:

-    // Bounds check to avoid writing past the end of the GPU buffer.
-    if (offset + size > m_vertex_buffer_size)
+    // Early-out for zero-length uploads.
+    if (size == 0)
+    {
+        return std::monostate{};
+    }
+
+    // Bounds check to avoid writing past the end of the GPU buffer, without overflow.
+    if (offset > m_vertex_buffer_size || size > m_vertex_buffer_size - offset)
     {
         SDL_LogError(SDL_LOG_CATEGORY_GPU, "%s:%d buffer overflow: size=%u, offset=%u, buffer_size=%u",
                      __FILE__, __LINE__, size, offset, m_vertex_buffer_size);
         return std::unexpected(GpuError::BUFFER_OVERFLOW);
     }

The rest of the error reporting and GPU calls look consistent with the new GpuError model and the no-exceptions policy. Based on learnings.

sdl_wrapper/sdl_wrapper.pipeline.cpp (2)

20-40: spv_result_to_bytes is correct; consider pre-sizing for fewer allocations

The helper correctly walks the SPIR-V word range and appends bytes safely. If you ever want a micro-optimization, you could bytes.resize(word_count * sizeof(std::uint32_t)) once and std::memcpy into place instead of repeated insert, but the current version is perfectly fine for clarity.


42-246: Constructor and shader/pipeline methods compose cleanly with GpuWrapper

The constructor’s vertex layout, color target, and blend setup are internally consistent, submit() refreshes vector-backed pointers before creating a new pipeline and swaps it with proper cleanup, and set_vertex_shader / set_fragment_shader only replace existing shaders after successful creation, marking the pipeline modified and returning precise GpuErrors. Only minor nit: the “You may want to add this to your GpuError enum.” comments around the compile errors look stale now that the enum values are in use—either confirm they exist or update/remove the comments.

sdl_wrapper/sdl_wrapper.gpu.ixx (1)

189-287: GpuWrapper factory and helpers align with the new error model (minor style nit)

Using create_gpu_context().transform(...) to build a std::shared_ptr<GpuWrapper> gives a neat, std::expected-friendly factory, and the resource helpers (create_pipeline, create_shader, release_*, get_texture_format) do the right logging and error mapping. If you care about style, you could switch the factory to std::make_shared<GpuWrapper>(std::move(ctx)) instead of new, but semantically this is already fine.

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 6ec542c and 4e0dd99.

📒 Files selected for processing (9)
  • main.cpp (11 hunks)
  • sdl_wrapper/sdl_callback_implement.cpp (1 hunks)
  • sdl_wrapper/sdl_wrapper.buffer.cpp (1 hunks)
  • sdl_wrapper/sdl_wrapper.buffer.ixx (1 hunks)
  • sdl_wrapper/sdl_wrapper.decl.ixx (1 hunks)
  • sdl_wrapper/sdl_wrapper.gpu.cpp (1 hunks)
  • sdl_wrapper/sdl_wrapper.gpu.ixx (1 hunks)
  • sdl_wrapper/sdl_wrapper.pipeline.cpp (1 hunks)
  • sdl_wrapper/sdl_wrapper.pipeline.ixx (1 hunks)
🧰 Additional context used
🧠 Learnings (5)
📓 Common learnings
Learnt from: WSQS
Repo: WSQS/sdl_test PR: 7
File: sdl_wrapper/sdl_wrapper.gpu.ixx:0-0
Timestamp: 2025-11-13T02:58:26.892Z
Learning: The sdl_wrapper library (in the repository WSQS/sdl_test) does not allow throwing exceptions. Error handling must use return codes, validity checks, or other non-exception mechanisms.
Learnt from: WSQS
Repo: WSQS/sdl_test PR: 7
File: sdl_wrapper/sdl_wrapper.gpu.ixx:37-43
Timestamp: 2025-11-13T11:35:48.289Z
Learning: In sdl_wrapper/sdl_wrapper.gpu.ixx, null pointer validation for the GpuWrapper::create_buffer method (checking m_device, SDL_CreateGPUBuffer return value, and shared_from_this() validity) is deferred to a future issue and should not be flagged in reviews.
Learnt from: WSQS
Repo: WSQS/sdl_test PR: 7
File: sdl_wrapper/sdl_wrapper.gpu.ixx:73-76
Timestamp: 2025-11-14T00:45:09.403Z
Learning: In sdl_wrapper/sdl_wrapper.gpu.ixx, validation for m_window in the GpuWrapper::get_texture_formate() method (checking if m_window is nullptr before calling SDL_GetGPUSwapchainTextureFormat) is deferred to a future window wrapper implementation and should not be flagged in reviews.
Learnt from: WSQS
Repo: WSQS/sdl_test PR: 7
File: sdl_wrapper/sdl_wrapper.buffer.ixx:0-0
Timestamp: 2025-11-13T11:34:32.732Z
Learning: In sdl_wrapper/sdl_wrapper.buffer.ixx, null pointer validation for the BufferWrapper constructor (checking p_gpu, p_gpu->data(), and SDL_CreateGPUBuffer return value) is deferred to a future issue and should not be flagged in reviews.
📚 Learning: 2025-11-13T11:35:48.289Z
Learnt from: WSQS
Repo: WSQS/sdl_test PR: 7
File: sdl_wrapper/sdl_wrapper.gpu.ixx:37-43
Timestamp: 2025-11-13T11:35:48.289Z
Learning: In sdl_wrapper/sdl_wrapper.gpu.ixx, null pointer validation for the GpuWrapper::create_buffer method (checking m_device, SDL_CreateGPUBuffer return value, and shared_from_this() validity) is deferred to a future issue and should not be flagged in reviews.

Applied to files:

  • sdl_wrapper/sdl_wrapper.decl.ixx
  • sdl_wrapper/sdl_wrapper.gpu.cpp
  • sdl_wrapper/sdl_wrapper.pipeline.cpp
  • sdl_wrapper/sdl_wrapper.buffer.ixx
  • sdl_wrapper/sdl_callback_implement.cpp
  • sdl_wrapper/sdl_wrapper.gpu.ixx
  • sdl_wrapper/sdl_wrapper.buffer.cpp
  • sdl_wrapper/sdl_wrapper.pipeline.ixx
  • main.cpp
📚 Learning: 2025-11-14T00:45:09.403Z
Learnt from: WSQS
Repo: WSQS/sdl_test PR: 7
File: sdl_wrapper/sdl_wrapper.gpu.ixx:73-76
Timestamp: 2025-11-14T00:45:09.403Z
Learning: In sdl_wrapper/sdl_wrapper.gpu.ixx, validation for m_window in the GpuWrapper::get_texture_formate() method (checking if m_window is nullptr before calling SDL_GetGPUSwapchainTextureFormat) is deferred to a future window wrapper implementation and should not be flagged in reviews.

Applied to files:

  • sdl_wrapper/sdl_wrapper.decl.ixx
  • sdl_wrapper/sdl_wrapper.gpu.cpp
  • sdl_wrapper/sdl_wrapper.pipeline.cpp
  • sdl_wrapper/sdl_wrapper.buffer.ixx
  • sdl_wrapper/sdl_callback_implement.cpp
  • sdl_wrapper/sdl_wrapper.gpu.ixx
  • sdl_wrapper/sdl_wrapper.buffer.cpp
  • sdl_wrapper/sdl_wrapper.pipeline.ixx
  • main.cpp
📚 Learning: 2025-11-13T11:34:32.732Z
Learnt from: WSQS
Repo: WSQS/sdl_test PR: 7
File: sdl_wrapper/sdl_wrapper.buffer.ixx:0-0
Timestamp: 2025-11-13T11:34:32.732Z
Learning: In sdl_wrapper/sdl_wrapper.buffer.ixx, null pointer validation for the BufferWrapper constructor (checking p_gpu, p_gpu->data(), and SDL_CreateGPUBuffer return value) is deferred to a future issue and should not be flagged in reviews.

Applied to files:

  • sdl_wrapper/sdl_wrapper.decl.ixx
  • sdl_wrapper/sdl_wrapper.gpu.cpp
  • sdl_wrapper/sdl_wrapper.pipeline.cpp
  • sdl_wrapper/sdl_wrapper.buffer.ixx
  • sdl_wrapper/sdl_callback_implement.cpp
  • sdl_wrapper/sdl_wrapper.gpu.ixx
  • sdl_wrapper/sdl_wrapper.buffer.cpp
  • sdl_wrapper/sdl_wrapper.pipeline.ixx
  • main.cpp
📚 Learning: 2025-11-13T02:58:26.892Z
Learnt from: WSQS
Repo: WSQS/sdl_test PR: 7
File: sdl_wrapper/sdl_wrapper.gpu.ixx:0-0
Timestamp: 2025-11-13T02:58:26.892Z
Learning: The sdl_wrapper library (in the repository WSQS/sdl_test) does not allow throwing exceptions. Error handling must use return codes, validity checks, or other non-exception mechanisms.

Applied to files:

  • sdl_wrapper/sdl_wrapper.gpu.cpp
  • sdl_wrapper/sdl_callback_implement.cpp
  • sdl_wrapper/sdl_wrapper.gpu.ixx
🧬 Code graph analysis (2)
sdl_wrapper/sdl_wrapper.pipeline.cpp (1)
sdl_wrapper/sdl_wrapper.buffer.cpp (1)
  • nodiscard (42-135)
sdl_wrapper/sdl_wrapper.buffer.cpp (1)
sdl_wrapper/sdl_wrapper.pipeline.cpp (3)
  • nodiscard (133-173)
  • nodiscard (175-209)
  • nodiscard (211-246)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (9)
  • GitHub Check: build (Debug, clang)
  • GitHub Check: build (Debug, gcc)
  • GitHub Check: clang-tidy-review
  • GitHub Check: build (windows-latest, Debug, clang)
  • GitHub Check: build (windows-latest, Debug, cl)
  • GitHub Check: build (windows-latest, Release, gcc)
  • GitHub Check: build (Release, clang)
  • GitHub Check: build (Debug, gcc)
  • GitHub Check: build (Debug, clang)
🔇 Additional comments (8)
sdl_wrapper/sdl_wrapper.decl.ixx (1)

9-28: GpuError enum covers the expected GPU failure modes coherently

The new GpuError values line up with the failure cases in BufferWrapper::upload, GpuWrapper::create_buffer, and the pipeline shader compilation/submit paths, giving you a consistent error surface for the new std::expected APIs. Looks good.

sdl_wrapper/sdl_wrapper.buffer.cpp (1)

19-40: Destructor cleanup pattern aligns with move-only RAII semantics

The destructor’s early return on !m_gpu plus guarded releases for m_vertex_buffer and m_transfer_buffer works well with the move-only design of BufferWrapper, avoiding double frees on moved-from instances while still cleaning up owned resources.

sdl_wrapper/sdl_wrapper.gpu.cpp (1)

1-7: GpuWrapper factory methods integrate cleanly with the new expected-based API

create_buffer and create_pipeline_wrapper use std::expected<..., GpuError> consistently, log failures via SDL, and return properly constructed BufferWrapper / PipelineWrapper instances on success. The use of get_texture_format().transform(...) keeps the pipeline creation path concise while propagating texture-format errors unchanged. This fits well with the PR’s error-handling design. Based on learnings.

Also applies to: 13-28

sdl_wrapper/sdl_wrapper.buffer.ixx (1)

1-56: BufferWrapper’s move-only RAII design and upload API look well-structured

Constraining construction to GpuWrapper, making BufferWrapper move-only, tracking m_vertex_buffer_size, and exposing an upload that returns std::expected<std::monostate, GpuError> gives a clear, RAII-friendly interface that matches the implementation in sdl_wrapper.buffer.cpp and the overall error model.

sdl_wrapper/sdl_wrapper.pipeline.ixx (1)

20-70: PipelineWrapper interface matches the new expected-based GPU API

Private construction via GpuWrapper, deleted copy, move-only semantics, noexcept destructor, and the submit/set_*_shader methods returning std::expected all look coherent and consistent with the rest of the refactor. No issues from the interface side.

sdl_wrapper/sdl_wrapper.gpu.ixx (1)

19-187: RAII handles correctly manage device/window/claim on all paths

DeviceHandle, WindowHandle, and ClaimedWindow cleanly encapsulate their respective SDL* lifetimes, and create_gpu_context() uses them so that failures (device, window, or claim) all log and then release any partially-created resources via destructors. The resulting GpuContext is move-only and exposes raw device/window accessors, which fits the wrapper design; no issues here.

main.cpp (2)

40-210: init()’s staged std::expected flow is solid

Creating GpuWrapper, buffer, pipeline wrapper, compiling shaders, submitting the pipeline, uploading vertices, and initializing ImGui all follow a clear step-by-step pattern with early returns on error and useful SDL_LogError messages. The use of std::expected and .and_then() here is consistent and keeps the control flow straightforward.


223-296: ImGui editor integration and buffer/shader updates handle failures gracefully

The editor combo and the three modes (vertex positions, vertex shader, fragment shader) are wired so that:

  • Vertex drags re-upload the buffer only when something changed, and upload errors are logged.
  • Shader edits recompile via the pipeline wrapper, with compile/create errors logged without crashing.
    The use of std::expected::and_then keeps these flows compact while still surfacing failures; I don’t see functional issues here.

@coderabbitai
Copy link

coderabbitai bot commented Nov 16, 2025

Warning

Docstrings generation - IN PROGRESS

Generating docstrings for this pull request

@WSQS
Copy link
Owner Author

WSQS commented Nov 17, 2025

@coderabbitai generate docstrings

@coderabbitai
Copy link

coderabbitai bot commented Nov 17, 2025

✅ Actions performed

Initiated docstring generation; will generate only if new commits exist.

@WSQS WSQS merged commit b981a0c into dev Nov 17, 2025
23 of 24 checks passed
@WSQS WSQS deleted the error_check branch November 17, 2025 01:04
This was referenced Nov 23, 2025
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