Skip to content

Conversation

@WSQS
Copy link
Owner

@WSQS WSQS commented Nov 26, 2025

Summary by CodeRabbit

  • New Features

    • Texture loading, runtime sampling and automatic test-asset download during install.
    • Shader fragment reflection to detect sampler usage and wire samplers into rendering.
    • New resource wrappers and builder-style APIs for textures and transfer/submit buffers.
  • Refactor

    • Overhauled render-data, buffer and upload flow to use ownership/move semantics and builder construction.
  • Tests

    • Added fragment reflection tests validating sampler counts.
  • Documentation

    • New "SDL Test" README progress checklist.

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

@coderabbitai
Copy link

coderabbitai bot commented Nov 26, 2025

Walkthrough

Refactors SDL wrapper into builder-based Buffer/Transfer/Texture and RenderDataImpl submodules, moves shader reflection types into data_type, adds fragment reflection and tests, integrates stb and image-asset handling, implements image loading and TextureWrapper usage, and updates create_shader/create_data APIs and corresponding call sites.

Changes

Cohort / File(s) Summary
Build & assets
CMakeLists.txt
Add stb INTERFACE target, change imgui include to SYSTEM PUBLIC, add asset dir/texture-download logic and install assets.
Docs
README.md
Add "SDL Test" progress track and checklist with textures noted.
Shared data types
data_type/modules/data_type.ixx
Add exported types: ImageData, BasicType, VertexInfo, VertexReflection, FragmentReflection; extend GpuError with multiple failure codes.
GLSL reflector
glsl_reflector/CMakeLists.txt, glsl_reflector/modules/glsl_reflector.ixx, glsl_reflector/modules/glsl_reflector.type.ixx, glsl_reflector/test/test.cpp
Remove old glsl_reflector:type module, import data_type, add reflect_fragment() (returns sampler_count), update vertex reflection to enumerate uniforms, and add fragment-reflection tests.
Application image & shader
main.cpp
Add load_image() returning sopho::ImageData; add m_image_data and m_texture_wrapper; build and bind TextureWrapper at init/draw; update fragment shader to sample uTexture.
sdl_wrapper layout & CMake
sdl_wrapper/CMakeLists.txt
Move module/source files into modules/ and src/, add new submodules (transfer_buffer, texture, render_data_impl) to FILE_SET.
RenderData split
sdl_wrapper/modules/sdl_wrapper.render_data.ixx, sdl_wrapper/modules/sdl_wrapper.render_data_impl.ixx, sdl_wrapper/sdl_wrapper.render_data.ixx
Remove old concrete RenderData file; add abstract RenderData interface module and concrete RenderDataImpl implementation module.
Buffer API & builder
sdl_wrapper/modules/sdl_wrapper.buffer.ixx, sdl_wrapper/src/sdl_wrapper.buffer.cpp
Replace raw SDL_GPUTransferBuffer* with TransferBufferWrapper value-type; add BufferWrapper::Builder (set_flag/set_size/build); update upload to use submit() and implement Builder::build.
TransferBuffer wrapper
sdl_wrapper/modules/sdl_wrapper.transfer_buffer.ixx, sdl_wrapper/src/sdl_wrapper.transfer_buffer.cpp
New TransferBufferWrapper with Builder, move semantics, submit(), reset() and usage_limit logic; implement builder and submit semantics.
Texture wrapper
sdl_wrapper/modules/sdl_wrapper.texture.ixx, sdl_wrapper/src/sdl_wrapper.texture.cpp
New TextureWrapper with Builder; create GPU texture, upload via transfer buffer and command-copy pass, create sampler, provide reset() and move-only semantics; Builder::build returns std::expected<TextureWrapper, GpuError>.
GPU wrapper changes
sdl_wrapper/modules/sdl_wrapper.gpu.ixx, sdl_wrapper/src/sdl_wrapper.gpu.cpp
Remove create_buffer(); change create_data() to return checkable<std::shared_ptr<RenderData>> and accept index_count; add num_samplers parameter to create_shader() and propagate sampler counts.
Module imports & decls
sdl_wrapper/modules/sdl_wrapper.ixx, sdl_wrapper/modules/sdl_wrapper.decl.ixx
Remove export import :buffer;, add export import :texture;, remove forward declaration of BufferWrapper.
Render procedural
sdl_wrapper/src/sdl_wrapper.render_procedural.cpp
Call reflect_fragment() for fragment shaders and pass sampler_count to create_shader(); vertex path passes explicit 0 samplers.

Sequence Diagram(s)

sequenceDiagram
    participant App as Application
    participant GLR as glsl_reflector
    participant GW as GpuWrapper
    participant BB as BufferWrapper::Builder
    participant TB as TransferBufferWrapper
    participant TW as TextureWrapper::Builder
    participant GPU as SDL GPU

    Note over App,GLR: Fragment reflection -> sampler count
    App->>GLR: reflect_fragment(fragment_source)
    GLR-->>App: FragmentReflection{sampler_count}

    Note over App,GW: Shader creation with sampler count
    App->>GW: create_shader(fragment_code, FRAGMENT, 0, sampler_count)
    GW-->>App: fragment shader handle

    Note over App,BB: Buffer builders create transfer buffers
    App->>BB: configure & build vertex/index buffers
    BB->>TB: Builder -> TransferBufferWrapper (create)
    TB->>GPU: SDL_GPUCreateTransferBuffer()
    GPU-->>TB: transfer handle
    BB-->>App: checkable<BufferWrapper>

    Note over App,TW: Texture build path uploads pixels
    App->>TW: set_image_data(img) -> build(gpu)
    TW->>TB: create transfer buffer & submit(pixel data)
    TB->>GPU: map/memcpy/unmap
    TW->>GPU: acquire command buffer -> copy to texture -> create sampler
    GPU-->>TW: texture+sampler handles
    TW-->>App: TextureWrapper
Loading
sequenceDiagram
    participant App as Application
    participant GW as GpuWrapper
    participant RD as RenderDataImpl

    App->>GW: create_data(proc, vertex_count, index_count)
    GW->>RD: construct shared RenderDataImpl using BufferWrapper::Builder results
    RD-->>GW: shared_ptr<RenderData>
    GW-->>App: checkable<std::shared_ptr<RenderData>>
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60–90 minutes

  • Review hotspots:
    • sdl_wrapper move semantics and resource lifecycle (TransferBufferWrapper, TextureWrapper, BufferWrapper).
    • Correctness of RenderDataImpl vs abstract RenderData contract and shared_ptr ownership.
    • Texture upload command-buffer / copy-pass ordering and error propagation (GpuError mapping).
    • All updated callers of create_shader/create_data and module import consistency.
    • glsl_reflector reflect_fragment implementation and its tests.

Possibly related PRs

  • Add index buffer #40 — Overlapping refactor touching RenderData/create_data and render-data/GPU APIs; likely directly related.
  • Error check #32 — Broad sdl_wrapper API changes (create_shader/create_data, builders, wrappers); strong code-level overlap.
  • Gl reflection #36 — Related glsl_reflector changes and type movement between modules; likely overlaps with fragment reflection work.

Poem

🐰 I hopped through headers, builders in paw,

Transfer buffers hum and textures I saw,
Samplers counted, pixels set free,
Command buffers hum a GPU melody,
A rabbit applauds — bright render spree! 🎨🥕

Pre-merge checks and finishing touches

❌ Failed checks (1 warning, 1 inconclusive)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 47.37% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
Title check ❓ Inconclusive The title 'Texture' is vague and does not clearly convey the scope and specifics of the changeset, which involves substantial refactoring of buffer and render data management, shader reflection, and texture loading. Use a more descriptive title that captures the main change, such as 'Add texture support with render data refactoring' or 'Implement texture loading and GPU resource abstraction'.
✅ Passed checks (1 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch texture

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.

@deepsource-io
Copy link
Contributor

deepsource-io bot commented Nov 26, 2025

Here's the code health analysis summary for commits 0abf71b..c1b759a. View details on DeepSource ↗.

Analysis Summary

AnalyzerStatusSummaryLink
DeepSource C & C++ LogoC & C++❌ Failure
❗ 22 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

#define STB_IMAGE_IMPLEMENTATION
#include "stb_image.h"

import data_type;

Choose a reason for hiding this comment

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

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

import data_type;
       ^

struct CameraUniform
{
std::array<float, 16> m{};
std::array<float, 16> m{}; ///< 4x4 transformation matrix as a flat array

Choose a reason for hiding this comment

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

warning: 16 is a magic number; consider replacing it with a named constant [cppcoreguidelines-avoid-magic-numbers]

    std::array<float, 16> m{}; ///< 4x4 transformation matrix as a flat array
                      ^

* @return sopho::ImageData Structure containing the loaded image dimensions, channels, and pixel data.
* Returns an empty structure if loading fails.
*/
sopho::ImageData load_image()

Choose a reason for hiding this comment

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

warning: function 'load_image' can be made static or moved into an anonymous namespace to enforce internal linkage [misc-use-internal-linkage]

Suggested change
sopho::ImageData load_image()
static sopho::ImageData load_image()

*/
sopho::ImageData load_image()
{
stbi_set_flip_vertically_on_load(true);

Choose a reason for hiding this comment

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

warning: implicit conversion 'bool' -> 'int' [readability-implicit-bool-conversion]

Suggested change
stbi_set_flip_vertically_on_load(true);
stbi_set_flip_vertically_on_load(1);


if (!data)
{
SDL_Log("stbi_load failed for %s: %s", file_name.data(), stbi_failure_reason());

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_Log("stbi_load failed for %s: %s", file_name.data(), stbi_failure_reason());
        ^

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: 6

🧹 Nitpick comments (12)
CMakeLists.txt (2)

91-91: stb integration looks fine; consider pinning revision for reproducible builds

Using an INTERFACE stb target and SYSTEM includes is clean. To keep builds reproducible and avoid surprises from upstream changes, consider pinning stb to a specific commit/tag instead of GIT_TAG master.

Also applies to: 97-107, 125-125


132-147: Unconditional network download in configure step may hurt offline/CI builds

The file(DOWNLOAD ...) in configure-time logic will fail when offline or behind strict proxies and also doesn’t verify content. Consider:

  • Guarding this behind an option (e.g., SDL_TEST_DOWNLOAD_ASSETS).
  • Allowing user-supplied assets if download fails.
  • Optionally adding EXPECTED_HASH for integrity.
sdl_wrapper/modules/sdl_wrapper.render_data.ixx (1)

16-32: Make the module self-contained by including <cstddef>

VertexView/IndexView use size_t and std::byte but the file doesn’t include <cstddef>. Relying on transitive includes from SDL headers is brittle; add the explicit include:

-#include <SDL3/SDL_gpu.h>
-#include <vector>
-#include <expected>
-#include <variant>
+#include <SDL3/SDL_gpu.h>
+#include <vector>
+#include <expected>
+#include <variant>
+#include <cstddef>

This keeps the module interface self-contained.

sdl_wrapper/modules/sdl_wrapper.transfer_buffer.ixx (1)

31-35: Clarify usage_limit semantics and align docs with implementation

m_usage_limit is commented as “Current usage count” while the Builder docs say it’s a maximum number of uploads before recycling. Also, other code (e.g., BufferWrapper::Builder) passes -1, which likely means “no limit”.

To avoid confusion/bugs in submit():

  • Decide on the contract (e.g., usage_limit < 0 ⇒ unlimited; >= 0 ⇒ remaining uses).
  • Update the member comment and Builder docs to state that clearly.
  • Ensure submit() only decrements/enforces the limit according to that contract.

Optionally, submit(void* data_source) could take const void* if it never mutates the source data, which would make it easier to call with const buffers.

Also applies to: 83-96

sdl_wrapper/modules/sdl_wrapper.ixx (1)

5-13: Top-level module now re-exports :texture instead of :buffer

Switching the umbrella module to export :texture changes what clients see when they import sdl_wrapper;. If any existing code relied on BufferWrapper via the umbrella import, it will now need to import sdl_wrapper:buffer explicitly, or you may want to re‑export both if backwards compatibility is desired.

sdl_wrapper/src/sdl_wrapper.buffer.cpp (1)

52-65: Align upload docs/logging with TransferBufferWrapper::submit behavior

upload() now delegates mapping/copy into the transfer buffer to m_transfer_buffer.submit(src_data), but the comment and log message still specifically talk about “failed to map transfer buffer”.

If submit() can fail for reasons other than mapping (e.g., usage limit reached, size mismatch), consider:

  • Updating the function comment to mention that upload can fail with whatever GpuError values submit() may return.
  • Generalizing the log message (or letting submit() handle logging itself) so the text doesn’t assume a mapping failure.

Functionally this is fine; it’s mainly a documentation/observability alignment issue.

Also applies to: 88-88

glsl_reflector/modules/glsl_reflector.ixx (1)

93-137: Good implementation of fragment reflection.

The reflect_fragment function correctly counts sampler uniforms by checking glslang::EbtSampler. The structure mirrors reflect_vertex appropriately.

Consider extracting the common parse/link boilerplate shared with reflect_vertex into a helper function to reduce duplication.

sdl_wrapper/src/sdl_wrapper.texture.cpp (1)

101-106: max_anisotropy = 1.f with enable_anisotropy = true has no effect.

Anisotropic filtering with a max anisotropy of 1 is equivalent to no anisotropic filtering. Either increase max_anisotropy to a meaningful value (e.g., 4.0f or 16.0f) or set enable_anisotropy = false.

-    info.max_anisotropy = 1.f;
+    info.max_anisotropy = 4.f;  // or 16.f for higher quality
sdl_wrapper/src/sdl_wrapper.gpu.cpp (1)

32-49: Consider parameterizing the index buffer size.

The index buffer is hardcoded to 6 * sizeof(int) (6 indices for a quad), while vertex_count is a parameter. This coupling may cause confusion if the caller expects a different primitive topology.

Consider adding an index_count parameter or documenting that this method specifically creates quad render data:

-    checkable<std::shared_ptr<RenderData>> GpuWrapper::create_data(const RenderProcedural& render_procedural,
-                                                                   uint32_t vertex_count)
+    checkable<std::shared_ptr<RenderData>> GpuWrapper::create_data(const RenderProcedural& render_procedural,
+                                                                   uint32_t vertex_count,
+                                                                   uint32_t index_count = 6)
main.cpp (1)

49-69: load_image() silently returns empty data on failure.

While the function logs an error, returning an empty ImageData can lead to downstream issues if callers don't check for validity. The texture builder will attempt to create a 0x0 texture.

Consider returning std::expected<ImageData, ...> or std::optional<ImageData> to make failure explicit:

-sopho::ImageData load_image()
+std::optional<sopho::ImageData> load_image()
 {
     ...
     if (!data)
     {
         SDL_Log("stbi_load failed for %s: %s", file_name.data(), stbi_failure_reason());
+        return std::nullopt;
     }
     ...
 }
sdl_wrapper/modules/sdl_wrapper.texture.ixx (2)

32-37: Consider breaking the long initializer list for readability.

The move constructor initializer list is quite long on a single line, which impacts readability.

-        TextureWrapper(TextureWrapper&& other) noexcept : m_gpu(std::move(other.m_gpu)), m_texture(other.m_texture), m_sampler(other.m_sampler),m_tex_binding(other.m_tex_binding)
+        TextureWrapper(TextureWrapper&& other) noexcept :
+            m_gpu(std::move(other.m_gpu)),
+            m_texture(other.m_texture),
+            m_sampler(other.m_sampler),
+            m_tex_binding(other.m_tex_binding)
         {
             other.m_texture = nullptr;
             other.m_sampler = nullptr;
             other.m_tex_binding = {};
         }

69-73: Use std::move to avoid unnecessary copy.

Since image_data is taken by value, moving it into img_data avoids a redundant copy when ImageData contains dynamically allocated resources (like pixel buffers).

             Builder& set_image_data(ImageData image_data)
             {
-                img_data = image_data;
+                img_data = std::move(image_data);
                 return *this;
             }
📜 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 0abf71b and b8e7d4d.

📒 Files selected for processing (23)
  • CMakeLists.txt (2 hunks)
  • README.md (1 hunks)
  • data_type/modules/data_type.ixx (2 hunks)
  • glsl_reflector/CMakeLists.txt (1 hunks)
  • glsl_reflector/modules/glsl_reflector.ixx (2 hunks)
  • glsl_reflector/modules/glsl_reflector.type.ixx (0 hunks)
  • glsl_reflector/test/test.cpp (1 hunks)
  • main.cpp (8 hunks)
  • sdl_wrapper/CMakeLists.txt (1 hunks)
  • sdl_wrapper/modules/sdl_wrapper.buffer.ixx (1 hunks)
  • sdl_wrapper/modules/sdl_wrapper.decl.ixx (0 hunks)
  • sdl_wrapper/modules/sdl_wrapper.gpu.ixx (2 hunks)
  • sdl_wrapper/modules/sdl_wrapper.ixx (1 hunks)
  • sdl_wrapper/modules/sdl_wrapper.render_data.ixx (1 hunks)
  • sdl_wrapper/modules/sdl_wrapper.render_data_impl.ixx (1 hunks)
  • sdl_wrapper/modules/sdl_wrapper.texture.ixx (1 hunks)
  • sdl_wrapper/modules/sdl_wrapper.transfer_buffer.ixx (1 hunks)
  • sdl_wrapper/sdl_wrapper.render_data.ixx (0 hunks)
  • sdl_wrapper/src/sdl_wrapper.buffer.cpp (3 hunks)
  • sdl_wrapper/src/sdl_wrapper.gpu.cpp (2 hunks)
  • sdl_wrapper/src/sdl_wrapper.render_procedural.cpp (2 hunks)
  • sdl_wrapper/src/sdl_wrapper.texture.cpp (1 hunks)
  • sdl_wrapper/src/sdl_wrapper.transfer_buffer.cpp (1 hunks)
💤 Files with no reviewable changes (3)
  • sdl_wrapper/modules/sdl_wrapper.decl.ixx
  • glsl_reflector/modules/glsl_reflector.type.ixx
  • sdl_wrapper/sdl_wrapper.render_data.ixx
🧰 Additional context used
🧠 Learnings (5)
📓 Common learnings
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.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.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/modules/sdl_wrapper.render_data_impl.ixx
  • sdl_wrapper/modules/sdl_wrapper.render_data.ixx
  • sdl_wrapper/modules/sdl_wrapper.buffer.ixx
  • sdl_wrapper/src/sdl_wrapper.transfer_buffer.cpp
  • sdl_wrapper/src/sdl_wrapper.texture.cpp
  • sdl_wrapper/modules/sdl_wrapper.texture.ixx
  • sdl_wrapper/src/sdl_wrapper.render_procedural.cpp
  • sdl_wrapper/modules/sdl_wrapper.ixx
  • sdl_wrapper/src/sdl_wrapper.gpu.cpp
  • sdl_wrapper/src/sdl_wrapper.buffer.cpp
  • sdl_wrapper/modules/sdl_wrapper.transfer_buffer.ixx
  • main.cpp
  • sdl_wrapper/modules/sdl_wrapper.gpu.ixx
📚 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/modules/sdl_wrapper.render_data_impl.ixx
  • sdl_wrapper/modules/sdl_wrapper.render_data.ixx
  • sdl_wrapper/modules/sdl_wrapper.buffer.ixx
  • sdl_wrapper/src/sdl_wrapper.transfer_buffer.cpp
  • sdl_wrapper/src/sdl_wrapper.texture.cpp
  • sdl_wrapper/modules/sdl_wrapper.texture.ixx
  • sdl_wrapper/src/sdl_wrapper.render_procedural.cpp
  • sdl_wrapper/modules/sdl_wrapper.ixx
  • sdl_wrapper/src/sdl_wrapper.gpu.cpp
  • sdl_wrapper/src/sdl_wrapper.buffer.cpp
  • sdl_wrapper/modules/sdl_wrapper.transfer_buffer.ixx
  • main.cpp
  • sdl_wrapper/modules/sdl_wrapper.gpu.ixx
📚 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/modules/sdl_wrapper.render_data_impl.ixx
  • sdl_wrapper/modules/sdl_wrapper.render_data.ixx
  • sdl_wrapper/modules/sdl_wrapper.buffer.ixx
  • sdl_wrapper/src/sdl_wrapper.transfer_buffer.cpp
  • sdl_wrapper/src/sdl_wrapper.texture.cpp
  • sdl_wrapper/modules/sdl_wrapper.texture.ixx
  • sdl_wrapper/src/sdl_wrapper.render_procedural.cpp
  • sdl_wrapper/modules/sdl_wrapper.ixx
  • sdl_wrapper/src/sdl_wrapper.gpu.cpp
  • sdl_wrapper/src/sdl_wrapper.buffer.cpp
  • sdl_wrapper/modules/sdl_wrapper.transfer_buffer.ixx
  • main.cpp
  • sdl_wrapper/modules/sdl_wrapper.gpu.ixx
📚 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/CMakeLists.txt
  • sdl_wrapper/modules/sdl_wrapper.buffer.ixx
  • sdl_wrapper/src/sdl_wrapper.transfer_buffer.cpp
🧬 Code graph analysis (3)
sdl_wrapper/src/sdl_wrapper.transfer_buffer.cpp (2)
sdl_wrapper/src/sdl_wrapper.texture.cpp (2)
  • build (30-119)
  • build (30-30)
sdl_wrapper/src/sdl_wrapper.buffer.cpp (2)
  • build (108-128)
  • build (108-108)
sdl_wrapper/src/sdl_wrapper.texture.cpp (2)
sdl_wrapper/src/sdl_wrapper.transfer_buffer.cpp (4)
  • reset (30-37)
  • reset (30-30)
  • build (63-77)
  • build (63-63)
sdl_wrapper/src/sdl_wrapper.buffer.cpp (2)
  • build (108-128)
  • build (108-108)
sdl_wrapper/src/sdl_wrapper.buffer.cpp (2)
sdl_wrapper/src/sdl_wrapper.texture.cpp (2)
  • build (30-119)
  • build (30-30)
sdl_wrapper/src/sdl_wrapper.transfer_buffer.cpp (2)
  • build (63-77)
  • build (63-63)
⏰ 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). (12)
  • GitHub Check: clang-tidy-review
  • GitHub Check: build (windows-latest, Release, cl)
  • GitHub Check: build (windows-latest, Debug, cl)
  • GitHub Check: build (windows-latest, Release, clang)
  • GitHub Check: build (windows-latest, Debug, gcc)
  • GitHub Check: build (windows-latest, Debug, clang)
  • GitHub Check: build (windows-latest, Release, gcc)
  • GitHub Check: build (Release, clang)
  • GitHub Check: build (Debug, gcc)
  • GitHub Check: build (Release, gcc)
  • GitHub Check: build (Debug, clang)
  • GitHub Check: CodeQL C++ Analysis
🔇 Additional comments (27)
README.md (2)

1-22: Clean progress tracking documentation.

The README clearly documents the project's learning objectives and current progress. The "Textures" milestone is appropriately marked as complete, reflecting the work introduced in this PR. The structure is readable and maintainable for future updates.


3-3: External link verified—no changes needed.

The referenced resource learnopengl.com is a well-established, free online learning platform by Joey de Vries covering modern OpenGL tutorials with clear examples and supporting materials. The link in your README is valid and appropriate for this learning project.

glsl_reflector/CMakeLists.txt (1)

13-13: Linking data_type here is appropriate

Adding data_type to target_link_libraries(glsl_reflector ...) matches the new module dependency and keeps the build graph consistent. No issues from this change.

glsl_reflector/test/test.cpp (1)

41-76: New fragment reflection tests are clear and targeted

Both tests directly exercise reflect_fragment for 1 and 2 sampler2D uniforms and assert sampler_count, which is exactly what this API is supposed to expose. Looks good.

sdl_wrapper/CMakeLists.txt (1)

10-21: Module/source reorganization looks coherent

Exposing the public module interfaces under modules/ and moving implementations to src/ aligns well with the new render/texture/transfer abstractions. The FILE_SET and PRIVATE source lists are consistent and should work fine with the existing linkage.

Also applies to: 23-28

glsl_reflector/modules/glsl_reflector.ixx (1)

85-89: Empty loop body appears to be incomplete.

The loop iterates over uniform variables but discards each var without any processing. If this is placeholder code for future uniform reflection, consider adding a TODO comment or removing the loop until it's needed.

sdl_wrapper/src/sdl_wrapper.render_procedural.cpp (2)

222-222: LGTM!

The vertex shader correctly specifies 1 uniform buffer and 0 samplers, which is the typical configuration for vertex shaders.


273-274: Good integration of fragment reflection.

Using reflect_fragment to dynamically determine the sampler count before shader creation is a clean approach that avoids hardcoding resource counts.

sdl_wrapper/src/sdl_wrapper.texture.cpp (1)

16-28: LGTM!

The reset() implementation correctly checks for both the resource and the GPU wrapper before releasing, and properly nullifies the pointers afterward.

sdl_wrapper/modules/sdl_wrapper.gpu.ixx (2)

246-256: LGTM!

The create_shader method correctly accepts num_samplers as a parameter and propagates it to the shader creation info. This enables dynamic sampler count configuration based on shader reflection.


213-214: All callers correctly handle the new checkable<std::shared_ptr<RenderData>> return type.

The checkable type is defined as std::expected<T, GpuError> in data_type/modules/data_type.ixx:37. Both call sites in main.cpp properly manage the new return type:

  • Line 163: Validates the result using if (!render_data) before accessing
  • Line 347: Extracts the value using .value() after a successful operation with std::move()

Both patterns are correct for std::expected and indicate the callers have been updated to handle the error-aware return type.

sdl_wrapper/src/sdl_wrapper.transfer_buffer.cpp (4)

17-29: Move assignment operator correctly handles self-assignment and resource transfer.

The implementation properly checks for self-assignment, resets current resources before taking ownership, and nullifies the source's transfer buffer. Good practice.


30-37: LGTM - reset() safely releases resources.

The method correctly checks all prerequisites (m_transfer_buffer, m_gpu, and m_gpu->device()) before releasing the GPU transfer buffer.


63-77: Builder::build() implementation looks correct.

Error handling properly returns std::unexpected on failure, and the wrapper is constructed with all necessary parameters on success.


39-62: Potential use-after-reset issue: submit() returns success after reset() invalidates the wrapper.

When m_usage_limit reaches zero, reset() is called which nullifies m_transfer_buffer. Subsequent calls to submit() will pass the assert (if m_usage_limit is still 0) but then dereference m_gpu->device() and use the null m_transfer_buffer, causing undefined behavior.

Consider either:

  1. Making the assert check m_usage_limit > 0 (or != 0 with additional null check)
  2. Adding a guard for null m_transfer_buffer at the start
 checkable<std::monostate> TransferBufferWrapper::submit(void* data_source)
 {
-    assert(m_usage_limit != 0);
+    assert(m_usage_limit != 0 && "submit called on exhausted transfer buffer");
+    if (!m_transfer_buffer || !m_gpu || !m_gpu->device())
+    {
+        SDL_LogError(SDL_LOG_CATEGORY_GPU, "%s:%d transfer buffer not valid", __FILE__, __LINE__);
+        return std::unexpected(GpuError::UNINITIALIZED);
+    }
     void* dst = SDL_MapGPUTransferBuffer(m_gpu->device(), m_transfer_buffer, false);
⛔ Skipped due to learnings
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.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.
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.
sdl_wrapper/src/sdl_wrapper.gpu.cpp (1)

36-48: Builder pattern for buffer creation is clean and readable.

The fluent builder interface for creating vertex and index buffers improves code clarity. Error propagation is handled correctly.

main.cpp (3)

496-503: Draw continues without texture binding, which may cause GPU validation errors or undefined rendering.

When m_texture_wrapper is null, the shader still expects a bound sampler (uTexture). This could cause driver validation errors or undefined rendering output.

Consider either:

  1. Binding a fallback 1x1 white texture
  2. Skipping the draw call entirely when no texture is available
  3. Using a shader variant without texture sampling

111-116: Fragment shader samples texture using v_color.xy as UV coordinates.

This assumes vertex colors contain UV coordinates in their xy components, which is unconventional. Typically a separate a_texcoord attribute would be used.

Verify this is intentional. If vertex colors are meant to be actual colors (RGBA), the texture sampling will produce unexpected results.


347-350: Unchecked access to new_data.value() may cause undefined behavior.

If create_data fails, calling .value() on an empty std::expected is undefined behavior (or throws if exceptions are enabled, which they are not per learnings).

                     auto new_data = m_gpu->create_data(*m_renderable->procedural(), 4);
+                    if (!new_data)
+                    {
+                        SDL_LogError(SDL_LOG_CATEGORY_GPU, "Failed to create new render data, error = %d",
+                                     static_cast<int>(new_data.error()));
+                        break;
+                    }
                     m_renderable->data() = std::move(new_data.value());
                     m_renderable->data()->upload();
⛔ Skipped due to learnings
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.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.
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.
data_type/modules/data_type.ixx (2)

39-51: New data structures look well-designed.

ImageData, BasicType, and the reflection structures are cleanly defined with appropriate default initialization.


13-33: GpuError enum extensions are comprehensive.

The new error codes cover texture, sampler, command buffer, copy pass, and shader compilation failures appropriately.

sdl_wrapper/modules/sdl_wrapper.buffer.ixx (3)

23-34: Good refactor: Transfer buffer now uses RAII wrapper.

Changing from raw SDL_GPUTransferBuffer* to TransferBufferWrapper improves resource management by ensuring proper cleanup. The move semantics in the constructor are correctly applied.


37-55: Builder pattern provides clean, fluent API for buffer construction.

The builder with chainable setters and a build() method returning checkable<BufferWrapper> aligns well with the pattern used for TransferBufferWrapper::Builder.


57-60: Move operations correctly defaulted.

With TransferBufferWrapper implementing proper move semantics, defaulting the move constructor and assignment operator for BufferWrapper is appropriate.

sdl_wrapper/modules/sdl_wrapper.texture.ixx (3)

17-27: LGTM!

The private constructor correctly takes the shared_ptr by value and moves it, and the member initialization is appropriate for managing SDL GPU resources.


56-59: LGTM!

The accessor is appropriately marked [[nodiscard]], const, and noexcept.


61-63: LGTM!

The destructor correctly delegates to reset() for resource cleanup, following RAII principles.

Copy link
Owner Author

@WSQS WSQS left a comment

Choose a reason for hiding this comment

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

Reviewed

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

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: 4

♻️ Duplicate comments (1)
sdl_wrapper/src/sdl_wrapper.texture.cpp (1)

62-67: GPU texture leaks on command buffer acquisition failure.

When SDL_AcquireGPUCommandBuffer fails, the texture created at line 42 is not released before returning, causing a resource leak.

Apply this diff to fix the leak:

         SDL_GPUCommandBuffer* cmd = SDL_AcquireGPUCommandBuffer(gpu.device());
         if (!cmd)
         {
             SDL_Log("SDL_AcquireGPUCommandBuffer failed: %s", SDL_GetError());
+            SDL_ReleaseGPUTexture(gpu.device(), texture);
             return std::unexpected{GpuError::ACQUIRE_COMMAND_BUFFER_FAILED};
         }
🧹 Nitpick comments (8)
sdl_wrapper/src/sdl_wrapper.buffer.cpp (1)

108-129: Resource cleanup on failure is correctly implemented.

The builder now properly releases gpu_buffer at line 125 if transfer buffer creation fails, addressing the previously flagged leak. The pattern aligns with BufferWrapper::Builder::build best practices.

One minor observation: set_usage_limit(-1) at line 120 implies "unlimited usage." Consider adding a brief comment or named constant (e.g., UNLIMITED_USAGE = -1) to document this convention for maintainability.

sdl_wrapper/modules/sdl_wrapper.render_data.ixx (1)

29-30: Consider returning const references for buffer bindings.

The current signatures return mutable references:

virtual std::vector<SDL_GPUBufferBinding>& get_vertex_buffer_binding() = 0;
virtual SDL_GPUBufferBinding& get_index_buffer_binding() = 0;

If callers don't need to modify these bindings, consider providing const overloads to express intent and prevent unintended mutations.

sdl_wrapper/src/sdl_wrapper.texture.cpp (1)

100-111: Consider extracting sampler creation info to a configurable builder field.

The sampler configuration is hardcoded with linear filtering and repeat addressing. If different textures need different sampling modes (e.g., clamp-to-edge for UI, point filtering for pixel art), consider making these configurable via the Builder.

sdl_wrapper/src/sdl_wrapper.gpu.cpp (1)

30-31: Incomplete Doxygen documentation.

The @param index_count tag is present but lacks a description. Add a brief explanation of the parameter's purpose.

- * @param index_count
+ * @param index_count Number of indices the allocated index buffer must hold.
main.cpp (2)

22-24: Consider moving STB implementation to a dedicated source file.

Defining STB_IMAGE_IMPLEMENTATION in the main application file works but can cause issues if the header is included elsewhere. For better maintainability, consider placing this in a dedicated stb_image.cpp file.


49-69: Caller cannot distinguish "load failed" from "empty image file".

load_image() returns a default ImageData on failure, but the caller has no explicit way to detect this other than checking pixels.empty(). Consider returning std::expected<ImageData, ...> or std::optional<ImageData> to make failures explicit.

Also, static analysis flagged this function should be static or in an anonymous namespace.

-sopho::ImageData load_image()
+static std::optional<sopho::ImageData> load_image()
 {
     stbi_set_flip_vertically_on_load(true);
     std::string file_name{"assets/test_texture.png"};
     sopho::ImageData result;
     auto data = stbi_load(file_name.data(), &result.width, &result.height, &result.channels, 4);
     result.channels = 4;
 
     if (!data)
     {
         SDL_Log("stbi_load failed for %s: %s", file_name.data(), stbi_failure_reason());
+        return std::nullopt;
     }
-    else
-    {
+
     result.pixels.assign(reinterpret_cast<std::byte*>(data),
                          reinterpret_cast<std::byte*>(data) + result.width * result.height * result.channels);
     stbi_image_free(data);
     SDL_Log("stbi_load succeeded, w: %d h:%d ch:%d", result.width, result.height, result.channels);
-    }
     return result;
 }
sdl_wrapper/modules/sdl_wrapper.transfer_buffer.ixx (2)

83-95: Consider validating Builder parameters before build.

The default size{1024} is reasonable, but usage_limit{1} means the buffer is released after a single use. Ensure this aligns with typical usage patterns. Also, consider adding validation in build() to reject size == 0 or usage_limit <= 0.

Could you verify the intended semantics of usage_limit? If it's meant to count down to zero, then usage_limit <= 0 at build time would be immediately invalid.


75-75: Clarify submit() behavior in documentation.

The submit method signature is declared but lacks documentation. Given this is a public API, consider adding a Doxygen comment explaining:

  • What data_source points to and expected size
  • When the buffer is automatically released (usage limit)
  • Return value semantics
+        /*
+         * @brief Copies data from the source into the transfer buffer and submits it.
+         * @param data_source Pointer to the data to copy (must be at least size() bytes)
+         * @return checkable with std::monostate on success, or an error code on failure
+         * @note When usage_limit reaches zero after submit, the buffer is automatically recycled.
+         */
         checkable<std::monostate> submit(const void* data_source);
📜 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 b8e7d4d and 2566e27.

📒 Files selected for processing (11)
  • data_type/modules/data_type.ixx (2 hunks)
  • main.cpp (8 hunks)
  • sdl_wrapper/modules/sdl_wrapper.gpu.ixx (2 hunks)
  • sdl_wrapper/modules/sdl_wrapper.render_data.ixx (1 hunks)
  • sdl_wrapper/modules/sdl_wrapper.render_data_impl.ixx (1 hunks)
  • sdl_wrapper/modules/sdl_wrapper.texture.ixx (1 hunks)
  • sdl_wrapper/modules/sdl_wrapper.transfer_buffer.ixx (1 hunks)
  • sdl_wrapper/src/sdl_wrapper.buffer.cpp (3 hunks)
  • sdl_wrapper/src/sdl_wrapper.gpu.cpp (2 hunks)
  • sdl_wrapper/src/sdl_wrapper.texture.cpp (1 hunks)
  • sdl_wrapper/src/sdl_wrapper.transfer_buffer.cpp (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (4)
  • sdl_wrapper/modules/sdl_wrapper.render_data_impl.ixx
  • data_type/modules/data_type.ixx
  • sdl_wrapper/modules/sdl_wrapper.texture.ixx
  • sdl_wrapper/modules/sdl_wrapper.gpu.ixx
🧰 Additional context used
🧠 Learnings (5)
📓 Common learnings
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.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.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: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/src/sdl_wrapper.buffer.cpp
  • sdl_wrapper/src/sdl_wrapper.texture.cpp
  • sdl_wrapper/src/sdl_wrapper.gpu.cpp
  • main.cpp
  • sdl_wrapper/modules/sdl_wrapper.render_data.ixx
  • sdl_wrapper/src/sdl_wrapper.transfer_buffer.cpp
  • sdl_wrapper/modules/sdl_wrapper.transfer_buffer.ixx
📚 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/src/sdl_wrapper.buffer.cpp
  • sdl_wrapper/src/sdl_wrapper.texture.cpp
  • sdl_wrapper/src/sdl_wrapper.gpu.cpp
  • main.cpp
  • sdl_wrapper/modules/sdl_wrapper.render_data.ixx
  • sdl_wrapper/src/sdl_wrapper.transfer_buffer.cpp
  • sdl_wrapper/modules/sdl_wrapper.transfer_buffer.ixx
📚 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/src/sdl_wrapper.buffer.cpp
  • sdl_wrapper/src/sdl_wrapper.texture.cpp
  • sdl_wrapper/src/sdl_wrapper.gpu.cpp
  • main.cpp
  • sdl_wrapper/modules/sdl_wrapper.render_data.ixx
  • sdl_wrapper/src/sdl_wrapper.transfer_buffer.cpp
  • sdl_wrapper/modules/sdl_wrapper.transfer_buffer.ixx
📚 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:

  • main.cpp
  • sdl_wrapper/src/sdl_wrapper.transfer_buffer.cpp
🧬 Code graph analysis (2)
sdl_wrapper/src/sdl_wrapper.texture.cpp (2)
sdl_wrapper/src/sdl_wrapper.transfer_buffer.cpp (4)
  • reset (30-37)
  • reset (30-30)
  • build (63-77)
  • build (63-63)
sdl_wrapper/src/sdl_wrapper.buffer.cpp (2)
  • build (108-129)
  • build (108-108)
sdl_wrapper/src/sdl_wrapper.transfer_buffer.cpp (2)
sdl_wrapper/src/sdl_wrapper.texture.cpp (4)
  • reset (16-28)
  • reset (16-16)
  • build (30-122)
  • build (30-30)
sdl_wrapper/src/sdl_wrapper.buffer.cpp (2)
  • build (108-129)
  • build (108-108)
⏰ 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). (19)
  • GitHub Check: build (windows-latest, Release, cl)
  • GitHub Check: build (windows-latest, Debug, gcc)
  • GitHub Check: build (Debug, clang)
  • GitHub Check: build (Release, clang)
  • GitHub Check: build (Debug, gcc)
  • GitHub Check: build (Release, gcc)
  • GitHub Check: CodeQL C++ Analysis
  • GitHub Check: clang-tidy-review
  • GitHub Check: build (Debug, clang)
  • GitHub Check: CodeQL C++ Analysis
  • GitHub Check: build (windows-latest, Release, clang)
  • GitHub Check: build (windows-latest, Debug, gcc)
  • GitHub Check: build (Release, clang)
  • GitHub Check: build (windows-latest, Release, cl)
  • GitHub Check: build (Debug, gcc)
  • GitHub Check: build (windows-latest, Debug, clang)
  • GitHub Check: build (windows-latest, Release, gcc)
  • GitHub Check: build (Release, gcc)
  • GitHub Check: build (windows-latest, Debug, cl)
🔇 Additional comments (14)
sdl_wrapper/src/sdl_wrapper.buffer.cpp (2)

25-38: LGTM!

The destructor properly releases the GPU buffer when the wrapper is valid, with appropriate null checks.


52-65: Clean error propagation with the new submit-based approach.

The refactor to use m_transfer_buffer.submit(src_data) simplifies the upload flow and properly propagates the error from the transfer buffer operation.

sdl_wrapper/modules/sdl_wrapper.render_data.ixx (1)

14-34: Clean abstract interface for render data management.

The RenderData interface provides a clear contract for vertex/index buffer management with appropriate virtual destructor. The VertexView and IndexView structs effectively encapsulate the view semantics.

sdl_wrapper/src/sdl_wrapper.texture.cpp (1)

16-28: LGTM!

The reset() method correctly releases both the texture and sampler resources with proper null checks.

sdl_wrapper/src/sdl_wrapper.transfer_buffer.cpp (4)

17-29: LGTM!

Move assignment correctly resets the current instance before taking ownership, and properly nullifies the source's transfer buffer to prevent double-free.


30-37: LGTM!

The reset() method properly validates all preconditions before releasing the transfer buffer.


39-62: Document or guard against post-exhaustion usage.

When m_usage_limit reaches 0, reset() is called at line 58, which nullifies m_transfer_buffer. Subsequent calls to submit() would then fail at the SDL_MapGPUTransferBuffer call (line 42), returning an error—which is acceptable behavior.

However, the assert(m_usage_limit != 0) at line 41 will fire in debug builds if submit() is called after exhaustion. Consider whether this is the intended behavior or if a graceful error return is preferable for a more defensive approach.


63-77: LGTM!

The builder correctly creates the transfer buffer with the configured parameters and returns a properly initialized wrapper.

sdl_wrapper/src/sdl_wrapper.gpu.cpp (2)

6-6: LGTM!

New imports are properly added to support the builder-based buffer creation pattern and the RenderDataImpl type.

Also applies to: 12-12, 15-16


49-51: LGTM!

The return correctly constructs a RenderDataImpl wrapped in a shared_ptr, aligning with the updated interface.

main.cpp (1)

239-250: Error handling for texture creation looks good.

The texture creation now properly handles the failure case with logging. This addresses the previous review concern.

sdl_wrapper/modules/sdl_wrapper.transfer_buffer.ixx (3)

28-41: Private constructor and builder pattern are well-structured.

The RAII design with a private constructor and Builder pattern ensures proper resource creation. The noexcept specifier on the constructor is appropriate.


43-51: Move constructor correctly transfers ownership.

The move constructor properly transfers the m_transfer_buffer pointer and nullifies the source to prevent double-free.


31-34: Consider [[nodiscard]] on accessors for clarity.

raw() and size() already have [[nodiscard]], which is good. The internal members are appropriately encapsulated.

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: 0

♻️ Duplicate comments (1)
sdl_wrapper/modules/sdl_wrapper.render_data_impl.ixx (1)

40-41: Move operations may invalidate buffer bindings.

After a move, m_bindings and m_index_binding still reference the old buffer pointers from the moved-from object. The defaulted move constructor/assignment will move m_vertex_buffer and m_index_buffer, but the bindings won't be updated to point to the new buffer locations.

Apply this diff to implement custom move operations that reinitialize the bindings:

-    RenderDataImpl(RenderDataImpl&&) = default;
-    RenderDataImpl& operator=(RenderDataImpl&&) = default;
+    RenderDataImpl(RenderDataImpl&& other) noexcept :
+        m_vertex_buffer(std::move(other.m_vertex_buffer)),
+        m_index_buffer(std::move(other.m_index_buffer)),
+        m_layouts(other.m_layouts),
+        m_vertex_count(other.m_vertex_count),
+        m_index_count(other.m_index_count)
+    {
+        m_bindings.emplace_back(m_vertex_buffer.gpu_buffer(), 0);
+        m_index_binding.buffer = m_index_buffer.gpu_buffer();
+        m_index_binding.offset = 0;
+    }
+    RenderDataImpl& operator=(RenderDataImpl&& other) noexcept
+    {
+        if (this != &other)
+        {
+            m_vertex_buffer = std::move(other.m_vertex_buffer);
+            m_index_buffer = std::move(other.m_index_buffer);
+            m_layouts = other.m_layouts;
+            m_vertex_count = other.m_vertex_count;
+            m_index_count = other.m_index_count;
+            m_bindings.clear();
+            m_bindings.emplace_back(m_vertex_buffer.gpu_buffer(), 0);
+            m_index_binding.buffer = m_index_buffer.gpu_buffer();
+            m_index_binding.offset = 0;
+        }
+        return *this;
+    }
🧹 Nitpick comments (2)
sdl_wrapper/modules/sdl_wrapper.render_data_impl.ixx (1)

29-32: Consider consistent index count type.

The index_count parameter is declared as std::uint32_t (line 30), but stored in m_index_count which is size_t (line 24). For consistency, consider using the same type for both.

sdl_wrapper/src/sdl_wrapper.gpu.cpp (1)

43-46: Use explicit index type for size calculation.

The index buffer size now correctly uses index_count, but sizeof(int) is platform-dependent. Consider using sizeof(std::uint32_t) to match the index_count parameter type in RenderDataImpl's constructor and ensure consistent index size across platforms.

Apply this diff:

         auto index_buffer = BufferWrapper::Builder{}
                                 .set_flag(SDL_GPU_BUFFERUSAGE_INDEX)
-                                .set_size(index_count * sizeof(int))
+                                .set_size(index_count * sizeof(std::uint32_t))
                                 .build(*this);
📜 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 2566e27 and c1b759a.

📒 Files selected for processing (2)
  • sdl_wrapper/modules/sdl_wrapper.render_data_impl.ixx (1 hunks)
  • sdl_wrapper/src/sdl_wrapper.gpu.cpp (2 hunks)
🧰 Additional context used
🧠 Learnings (4)
📓 Common learnings
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.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.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/src/sdl_wrapper.gpu.cpp
  • sdl_wrapper/modules/sdl_wrapper.render_data_impl.ixx
📚 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/src/sdl_wrapper.gpu.cpp
  • sdl_wrapper/modules/sdl_wrapper.render_data_impl.ixx
📚 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/src/sdl_wrapper.gpu.cpp
  • sdl_wrapper/modules/sdl_wrapper.render_data_impl.ixx
⏰ 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). (16)
  • GitHub Check: build (windows-latest, Release, cl)
  • GitHub Check: build (windows-latest, Debug, gcc)
  • GitHub Check: build (windows-latest, Release, gcc)
  • GitHub Check: build (windows-latest, Debug, cl)
  • GitHub Check: clang-tidy-review
  • GitHub Check: build (windows-latest, Release, cl)
  • GitHub Check: build (windows-latest, Release, clang)
  • GitHub Check: build (windows-latest, Release, gcc)
  • GitHub Check: build (windows-latest, Debug, gcc)
  • GitHub Check: build (windows-latest, Debug, cl)
  • GitHub Check: build (windows-latest, Debug, clang)
  • GitHub Check: build (Release, gcc)
  • GitHub Check: build (Debug, gcc)
  • GitHub Check: build (Release, clang)
  • GitHub Check: build (Debug, clang)
  • GitHub Check: CodeQL C++ Analysis
🔇 Additional comments (4)
sdl_wrapper/modules/sdl_wrapper.render_data_impl.ixx (2)

48-51: LGTM: Index count fix applied.

The index_view() method now correctly uses m_index_count instead of m_vertex_count. This resolves the previous review comment.


52-61: LGTM: Upload logic is correct.

The sequential upload of vertex and index buffers with proper error propagation is correct.

sdl_wrapper/src/sdl_wrapper.gpu.cpp (2)

37-42: LGTM: Vertex buffer creation is correct.

The builder-based vertex buffer creation with proper size calculation and error propagation is well-implemented.


51-52: LGTM: Return statement is correct.

The construction and return of RenderDataImpl via std::make_shared with proper move semantics for buffers is well-implemented.

@WSQS WSQS merged commit cdd286d into dev Nov 26, 2025
26 of 27 checks passed
@WSQS WSQS deleted the texture branch November 26, 2025 06:13
@coderabbitai coderabbitai bot mentioned this pull request Nov 27, 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.

3 participants