From 4a76175c64dec83ba4b04547823f2503d5eed58e Mon Sep 17 00:00:00 2001 From: Sophomore <17792626+WSQS@users.noreply.github.com> Date: Sun, 23 Nov 2025 19:50:38 +0800 Subject: [PATCH 01/57] fix: add library stb --- CMakeLists.txt | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index 757c702..9494cd9 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -94,6 +94,17 @@ target_include_directories(imgui PUBLIC ) target_link_libraries(imgui PUBLIC SDL3::SDL3) +FetchContent_Declare( + stb + GIT_REPOSITORY https://github.com/nothings/stb.git + GIT_TAG master + GIT_SHALLOW TRUE + GIT_PROGRESS TRUE +) +FetchContent_MakeAvailable(stb) +add_library(stb INTERFACE) +target_include_directories(stb INTERFACE ${stb_SOURCE_DIR}) + FetchContent_Declare( googletest GIT_REPOSITORY https://github.com/google/googletest.git From d6f5c9364f4961415a035fc304b0bc9df4ddd11a Mon Sep 17 00:00:00 2001 From: Sophomore <17792626+WSQS@users.noreply.github.com> Date: Sun, 23 Nov 2025 19:51:03 +0800 Subject: [PATCH 02/57] feat: add asset library --- CMakeLists.txt | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 9494cd9..450a93f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -122,8 +122,20 @@ add_subdirectory(sdl_wrapper) add_subdirectory(glsl_reflector) add_executable(SDL_TEST main.cpp) -target_link_libraries(SDL_TEST PRIVATE imgui sdl_wrapper) +target_link_libraries(SDL_TEST PRIVATE imgui sdl_wrapper stb) +set(ASSETS_DST_DIR ${CMAKE_BINARY_DIR}/assets) +file(MAKE_DIRECTORY ${ASSETS_DST_DIR}) + +set(TEST_TEXTURE_PATH ${ASSETS_DST_DIR}/test_texture.png) + +if (NOT EXISTS ${TEST_TEXTURE_PATH}) + file(DOWNLOAD + "https://opengameart.org/sites/default/files/slime_25.png" + "${TEST_TEXTURE_PATH}" + SHOW_PROGRESS + ) +endif() include(GNUInstallDirs) install(TARGETS SDL_TEST From 05107bbd9365e65df35dd363b005ccfe03ebbdfa Mon Sep 17 00:00:00 2001 From: Sophomore <17792626+WSQS@users.noreply.github.com> Date: Sun, 23 Nov 2025 19:54:19 +0800 Subject: [PATCH 03/57] feat: call function stbi_load and successfully load png --- main.cpp | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/main.cpp b/main.cpp index 7b7f488..44945a6 100644 --- a/main.cpp +++ b/main.cpp @@ -20,6 +20,10 @@ #include "SDL3/SDL.h" #include "SDL3/SDL_gpu.h" #include "SDL3/SDL_keycode.h" + +#define STB_IMAGE_IMPLEMENTATION +#include "stb_image.h" + import data_type; import glsl_reflector; import sdl_wrapper; @@ -193,6 +197,18 @@ void main() ImGui_ImplSDLGPU3_Init(&init_info); + int w{}, h{}, ch{}; + auto data = stbi_load("assets/test_texture.png", &w, &h, &ch, 4); + + if (!data) + { + SDL_Log("stbi_load failed for %s: %s", "test.png", stbi_failure_reason()); + } + else + { + SDL_Log("stbi_load succeeded, w: %d h:%d ch:%d", w, h, ch); + } + return SDL_APP_CONTINUE; } From bad42034ea37c63b2870c3a13d3a6443cceea9b5 Mon Sep 17 00:00:00 2001 From: Sophomore <17792626+WSQS@users.noreply.github.com> Date: Sun, 23 Nov 2025 19:57:21 +0800 Subject: [PATCH 04/57] feat: also install png --- CMakeLists.txt | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 450a93f..a9896e4 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -124,6 +124,11 @@ add_subdirectory(glsl_reflector) add_executable(SDL_TEST main.cpp) target_link_libraries(SDL_TEST PRIVATE imgui sdl_wrapper stb) +include(GNUInstallDirs) +install(TARGETS SDL_TEST + RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} +) + set(ASSETS_DST_DIR ${CMAKE_BINARY_DIR}/assets) file(MAKE_DIRECTORY ${ASSETS_DST_DIR}) @@ -137,7 +142,6 @@ if (NOT EXISTS ${TEST_TEXTURE_PATH}) ) endif() -include(GNUInstallDirs) -install(TARGETS SDL_TEST - RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} -) \ No newline at end of file +install(DIRECTORY ${ASSETS_DST_DIR}/ + DESTINATION ${CMAKE_INSTALL_BINDIR}/assets +) From c2b5fecbdbd4a2c39a5d32ec09c7ac7ef6b5d5c7 Mon Sep 17 00:00:00 2001 From: Sophomore <17792626+WSQS@users.noreply.github.com> Date: Sun, 23 Nov 2025 21:32:00 +0800 Subject: [PATCH 05/57] feat: Add data type ImageData --- data_type/modules/data_type.ixx | 22 +++++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) diff --git a/data_type/modules/data_type.ixx b/data_type/modules/data_type.ixx index d8a3a2e..cf2f2e6 100644 --- a/data_type/modules/data_type.ixx +++ b/data_type/modules/data_type.ixx @@ -2,11 +2,14 @@ // Created by sophomore on 11/23/25. // module; -#include +#include +#include export module data_type; -export namespace sopho { - enum class GpuError { +export namespace sopho +{ + enum class GpuError + { UNINITIALIZED, CREATE_DEVICE_FAILED, CREATE_WINDOW_FAILED, @@ -26,6 +29,15 @@ export namespace sopho { }; using TError = GpuError; - template + template using checkable = std::expected; -} + + struct ImageData + { + int width{}; + int height{}; + int channels{}; + std::vector pixels{}; + }; + +} // namespace sopho From 874bec7e598c51df5cac0e4c90a6229d98f6479c Mon Sep 17 00:00:00 2001 From: Sophomore <17792626+WSQS@users.noreply.github.com> Date: Sun, 23 Nov 2025 21:37:05 +0800 Subject: [PATCH 06/57] feat: extract function load_image --- main.cpp | 35 ++++++++++++++++++++++------------- 1 file changed, 22 insertions(+), 13 deletions(-) diff --git a/main.cpp b/main.cpp index 44945a6..6d854df 100644 --- a/main.cpp +++ b/main.cpp @@ -33,6 +33,27 @@ struct CameraUniform std::array m{}; }; +auto load_image() +{ + sopho::ImageData result; + auto data = stbi_load("assets/test_texture.png", &result.width, &result.height, &result.channels, 4); + + if (!data) + { + SDL_Log("stbi_load failed for %s: %s", "test.png", stbi_failure_reason()); + } + else + { + result.pixels.assign(reinterpret_cast(data), + reinterpret_cast(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; +} + class UserApp : public sopho::App { // GPU + resources @@ -196,19 +217,7 @@ void main() init_info.PresentMode = SDL_GPU_PRESENTMODE_VSYNC; ImGui_ImplSDLGPU3_Init(&init_info); - - int w{}, h{}, ch{}; - auto data = stbi_load("assets/test_texture.png", &w, &h, &ch, 4); - - if (!data) - { - SDL_Log("stbi_load failed for %s: %s", "test.png", stbi_failure_reason()); - } - else - { - SDL_Log("stbi_load succeeded, w: %d h:%d ch:%d", w, h, ch); - } - + load_image(); return SDL_APP_CONTINUE; } From 030e899177b91e2512d7f0571c84260d3dd8bff6 Mon Sep 17 00:00:00 2001 From: Sophomore <17792626+WSQS@users.noreply.github.com> Date: Sun, 23 Nov 2025 21:38:07 +0800 Subject: [PATCH 07/57] feat: add property m_image_data --- main.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/main.cpp b/main.cpp index 6d854df..cf42a95 100644 --- a/main.cpp +++ b/main.cpp @@ -61,6 +61,8 @@ class UserApp : public sopho::App std::shared_ptr m_renderable{}; + sopho::ImageData m_image_data; + // camera state float yaw = 0.0f; float pitch = 0.0f; @@ -217,7 +219,7 @@ void main() init_info.PresentMode = SDL_GPU_PRESENTMODE_VSYNC; ImGui_ImplSDLGPU3_Init(&init_info); - load_image(); + m_image_data = load_image(); return SDL_APP_CONTINUE; } From 6a24d89294832cf20e9832eae6cdca6248a862fb Mon Sep 17 00:00:00 2001 From: Sophomore <17792626+WSQS@users.noreply.github.com> Date: Sun, 23 Nov 2025 21:55:46 +0800 Subject: [PATCH 08/57] feat: add function create_texture_from_image --- main.cpp | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/main.cpp b/main.cpp index cf42a95..d12d4cd 100644 --- a/main.cpp +++ b/main.cpp @@ -37,6 +37,7 @@ auto load_image() { sopho::ImageData result; auto data = stbi_load("assets/test_texture.png", &result.width, &result.height, &result.channels, 4); + result.channels = 4; if (!data) { @@ -49,11 +50,23 @@ auto load_image() stbi_image_free(data); SDL_Log("stbi_load succeeded, w: %d h:%d ch:%d", result.width, result.height, result.channels); } - - return result; } +SDL_GPUTexture* create_texture_from_image(SDL_GPUDevice* device, const sopho::ImageData& img) +{ + SDL_GPUTextureCreateInfo create_info{.type = SDL_GPU_TEXTURETYPE_2D, + .format = SDL_GPU_TEXTUREFORMAT_R8G8B8A8_UNORM, + .usage = SDL_GPU_TEXTUREUSAGE_SAMPLER, + .width = static_cast(img.width), + .height = static_cast(img.height), + .layer_count_or_depth = 1, + .num_levels = 1, + .sample_count = SDL_GPU_SAMPLECOUNT_1, + .props = 0}; + return SDL_CreateGPUTexture(device, &create_info); +} + class UserApp : public sopho::App { // GPU + resources @@ -220,6 +233,7 @@ void main() ImGui_ImplSDLGPU3_Init(&init_info); m_image_data = load_image(); + create_texture_from_image(m_gpu->device(),m_image_data); return SDL_APP_CONTINUE; } From 90106a36a12949dc0502d62d41e42219e6fd4fca Mon Sep 17 00:00:00 2001 From: Sophomore <17792626+WSQS@users.noreply.github.com> Date: Sun, 23 Nov 2025 23:03:35 +0800 Subject: [PATCH 09/57] breaking: trying to implement --- main.cpp | 105 +++++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 103 insertions(+), 2 deletions(-) diff --git a/main.cpp b/main.cpp index d12d4cd..db79ebe 100644 --- a/main.cpp +++ b/main.cpp @@ -67,6 +67,79 @@ SDL_GPUTexture* create_texture_from_image(SDL_GPUDevice* device, const sopho::Im return SDL_CreateGPUTexture(device, &create_info); } +SDL_GPUTransferBuffer* create_texture_transfer_buffer(SDL_GPUDevice* device, const sopho::ImageData& img) +{ + const Uint32 bytes_per_pixel = 4; + const Uint32 size_in_bytes = static_cast(img.width) * static_cast(img.height) * bytes_per_pixel; + + SDL_GPUTransferBufferCreateInfo info{ + .usage = SDL_GPU_TRANSFERBUFFERUSAGE_UPLOAD, .size = size_in_bytes, .props = 0}; + + SDL_GPUTransferBuffer* transfer = SDL_CreateGPUTransferBuffer(device, &info); + if (!transfer) + { + SDL_Log("Failed to create transfer buffer: %s", SDL_GetError()); + return nullptr; + } + + void* ptr = SDL_MapGPUTransferBuffer(device, transfer, false); + if (!ptr) + { + SDL_Log("Failed to map transfer buffer: %s", SDL_GetError()); + SDL_ReleaseGPUTransferBuffer(device, transfer); + return nullptr; + } + + // SDL_memcpy(ptr, img.pixels.data(), size_in_bytes); + SDL_memset(ptr, 0xFF, size_in_bytes); // RGBA 全是 255 → 纯白 + SDL_UnmapGPUTransferBuffer(device, transfer); + + return transfer; +} + +void upload_texture_full(SDL_GPUDevice* device, SDL_GPUTexture* texture, SDL_GPUTransferBuffer* transfer, int width, + int height) +{ + SDL_GPUCommandBuffer* cmd = SDL_AcquireGPUCommandBuffer(device); + if (!cmd) + { + SDL_Log("SDL_AcquireGPUCommandBuffer failed: %s", SDL_GetError()); + return; + } + + SDL_GPUCopyPass* copy_pass = SDL_BeginGPUCopyPass(cmd); + if (!copy_pass) + { + SDL_Log("SDL_BeginGPUCopyPass failed: %s", SDL_GetError()); + return; + } + + const Uint32 bytes_per_pixel = 4; // RGBA8 + const Uint32 row_bytes = static_cast(width) * bytes_per_pixel; + + SDL_GPUTextureTransferInfo src{}; + src.transfer_buffer = transfer; + src.offset = 0; + src.pixels_per_row = 0; + src.rows_per_layer = 0; + + SDL_GPUTextureRegion dst{}; + dst.texture = texture; + dst.mip_level = 0; + dst.layer = 0; + dst.x = 0; + dst.y = 0; + dst.z = 0; + dst.w = static_cast(width); + dst.h = static_cast(height); + dst.d = 1; + + SDL_UploadToGPUTexture(copy_pass, &src, &dst, false); + + SDL_EndGPUCopyPass(copy_pass); + SDL_SubmitGPUCommandBuffer(cmd); +} + class UserApp : public sopho::App { // GPU + resources @@ -75,6 +148,8 @@ class UserApp : public sopho::App std::shared_ptr m_renderable{}; sopho::ImageData m_image_data; + SDL_GPUSampler* m_sampler; + SDL_GPUTexture* m_texture; // camera state float yaw = 0.0f; @@ -106,9 +181,13 @@ void main() layout (location = 0) in vec4 v_color; layout (location = 0) out vec4 FragColor; +layout(set = 2, binding = 0) uniform sampler2D uTexture; + void main() { - FragColor = v_color; + FragColor = texture(uTexture, vec2(0.5, 0.5)); + //FragColor = vec4(v_color.xy,0,0); + FragColor.a = 1; })WSQ"; public: @@ -233,7 +312,23 @@ void main() ImGui_ImplSDLGPU3_Init(&init_info); m_image_data = load_image(); - create_texture_from_image(m_gpu->device(),m_image_data); + m_texture = create_texture_from_image(m_gpu->device(), m_image_data); + auto transfer_buffer = create_texture_transfer_buffer(m_gpu->device(), m_image_data); + upload_texture_full(m_gpu->device(), m_texture, transfer_buffer, m_image_data.width, m_image_data.height); + SDL_ReleaseGPUTransferBuffer(m_gpu->device(), transfer_buffer); + SDL_GPUSamplerCreateInfo info{}; + info.min_filter = SDL_GPU_FILTER_LINEAR; + info.mag_filter = SDL_GPU_FILTER_LINEAR; + info.mipmap_mode = SDL_GPU_SAMPLERMIPMAPMODE_LINEAR; + info.address_mode_u = SDL_GPU_SAMPLERADDRESSMODE_REPEAT; + info.address_mode_v = SDL_GPU_SAMPLERADDRESSMODE_REPEAT; + info.address_mode_w = SDL_GPU_SAMPLERADDRESSMODE_REPEAT; + info.enable_anisotropy = true; + info.enable_compare = false; + info.compare_op = SDL_GPU_COMPAREOP_ALWAYS; + info.props = 0; + + m_sampler = SDL_CreateGPUSampler(m_gpu->device(), &info); return SDL_APP_CONTINUE; } @@ -485,6 +580,12 @@ void main() SDL_BindGPUIndexBuffer(renderPass, &m_renderable->data()->get_index_buffer_binding(), SDL_GPU_INDEXELEMENTSIZE_32BIT); + SDL_GPUTextureSamplerBinding tex_binding{}; + tex_binding.texture = m_texture; + tex_binding.sampler = m_sampler; + + SDL_BindGPUFragmentSamplers(renderPass, 0, &tex_binding, 1); + SDL_DrawGPUIndexedPrimitives(renderPass, 6, 1, 0, 0, 0); ImGui_ImplSDLGPU3_RenderDrawData(draw_data, commandBuffer, renderPass); From 0c7098dffefea9cfc1f1c4b5abd3b94c7bbad61c Mon Sep 17 00:00:00 2001 From: Sophomore Date: Mon, 24 Nov 2025 11:02:51 +0800 Subject: [PATCH 10/57] feat:add num_samplers --- sdl_wrapper/sdl_wrapper.gpu.ixx | 11 ++++++----- sdl_wrapper/sdl_wrapper.render_procedural.cpp | 4 ++-- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/sdl_wrapper/sdl_wrapper.gpu.ixx b/sdl_wrapper/sdl_wrapper.gpu.ixx index 572aa09..e5e1cd6 100644 --- a/sdl_wrapper/sdl_wrapper.gpu.ixx +++ b/sdl_wrapper/sdl_wrapper.gpu.ixx @@ -210,11 +210,11 @@ export namespace sopho GpuWrapper& operator=(GpuWrapper&&) = delete; [[nodiscard]] auto device() const { return m_ctx.device.raw; } - [[nodiscard]] SDL_Window *window() const { return m_ctx.window.raw; } + [[nodiscard]] SDL_Window* window() const { return m_ctx.window.raw; } [[nodiscard]] std::expected create_buffer(SDL_GPUBufferUsageFlags flag, uint32_t size); - [[nodiscard]] std::expected - create_data(const RenderProcedural& render_procedural, uint32_t vertex_count); + [[nodiscard]] std::expected create_data(const RenderProcedural& render_procedural, + uint32_t vertex_count); auto release_buffer(SDL_GPUBuffer* buffer) { @@ -247,7 +247,8 @@ export namespace sopho } [[nodiscard]] auto create_shader(const std::vector& shader, SDL_GPUShaderStage stage, - uint32_t num_uniform_buffers) -> std::expected + uint32_t num_uniform_buffers, uint32_t num_samplers) + -> std::expected { SDL_GPUShaderCreateInfo info{}; info.code = shader.data(); @@ -255,7 +256,7 @@ export namespace sopho info.entrypoint = "main"; info.format = SDL_GPU_SHADERFORMAT_SPIRV; info.stage = stage; - info.num_samplers = 0; + info.num_samplers = num_samplers; info.num_storage_buffers = 0; info.num_storage_textures = 0; info.num_uniform_buffers = num_uniform_buffers; diff --git a/sdl_wrapper/sdl_wrapper.render_procedural.cpp b/sdl_wrapper/sdl_wrapper.render_procedural.cpp index 9558bdc..e22a3f7 100644 --- a/sdl_wrapper/sdl_wrapper.render_procedural.cpp +++ b/sdl_wrapper/sdl_wrapper.render_procedural.cpp @@ -219,7 +219,7 @@ namespace sopho // Convert SPIR-V words to a byte vector std::vector code = spv_result_to_bytes(result); - auto shader_result = m_gpu->create_shader(code, SDL_GPU_SHADERSTAGE_VERTEX, 1); + auto shader_result = m_gpu->create_shader(code, SDL_GPU_SHADERSTAGE_VERTEX, 1, 0); if (!shader_result) { return std::unexpected(shader_result.error()); @@ -270,7 +270,7 @@ namespace sopho // Convert SPIR-V words to a byte vector std::vector code = spv_result_to_bytes(result); - auto shader_result = m_gpu->create_shader(code, SDL_GPU_SHADERSTAGE_FRAGMENT, 0); + auto shader_result = m_gpu->create_shader(code, SDL_GPU_SHADERSTAGE_FRAGMENT, 0, 1); if (!shader_result) { return std::unexpected(shader_result.error()); From 611ce5e21cac2436aecd5483cb499b85891f1044 Mon Sep 17 00:00:00 2001 From: Sophomore Date: Mon, 24 Nov 2025 11:03:28 +0800 Subject: [PATCH 11/57] feat:implement texture --- main.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/main.cpp b/main.cpp index db79ebe..a11f671 100644 --- a/main.cpp +++ b/main.cpp @@ -90,8 +90,7 @@ SDL_GPUTransferBuffer* create_texture_transfer_buffer(SDL_GPUDevice* device, con return nullptr; } - // SDL_memcpy(ptr, img.pixels.data(), size_in_bytes); - SDL_memset(ptr, 0xFF, size_in_bytes); // RGBA 全是 255 → 纯白 + SDL_memcpy(ptr, img.pixels.data(), size_in_bytes); SDL_UnmapGPUTransferBuffer(device, transfer); return transfer; @@ -185,7 +184,7 @@ layout(set = 2, binding = 0) uniform sampler2D uTexture; void main() { - FragColor = texture(uTexture, vec2(0.5, 0.5)); + FragColor = texture(uTexture, v_color.xy); //FragColor = vec4(v_color.xy,0,0); FragColor.a = 1; })WSQ"; @@ -319,6 +318,7 @@ void main() SDL_GPUSamplerCreateInfo info{}; info.min_filter = SDL_GPU_FILTER_LINEAR; info.mag_filter = SDL_GPU_FILTER_LINEAR; + info.max_anisotropy = 1.f; info.mipmap_mode = SDL_GPU_SAMPLERMIPMAPMODE_LINEAR; info.address_mode_u = SDL_GPU_SAMPLERADDRESSMODE_REPEAT; info.address_mode_v = SDL_GPU_SAMPLERADDRESSMODE_REPEAT; From 19b32899a8a515db7b9268ec13d25cd066c6f98b Mon Sep 17 00:00:00 2001 From: Sophomore Date: Mon, 24 Nov 2025 11:29:26 +0800 Subject: [PATCH 12/57] feat:release texture and sampler --- main.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/main.cpp b/main.cpp index a11f671..bc4e06e 100644 --- a/main.cpp +++ b/main.cpp @@ -646,6 +646,8 @@ void main() ImGui_ImplSDL3_Shutdown(); ImGui_ImplSDLGPU3_Shutdown(); ImGui::DestroyContext(); + SDL_ReleaseGPUTexture(m_gpu->device(),m_texture); + SDL_ReleaseGPUSampler(m_gpu->device(),m_sampler); } }; From 9709c35da7fbcc0029628cbca057bbb09221bd3a Mon Sep 17 00:00:00 2001 From: Sophomore Date: Mon, 24 Nov 2025 11:29:57 +0800 Subject: [PATCH 13/57] fix: remote unused header file --- main.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/main.cpp b/main.cpp index bc4e06e..f17406e 100644 --- a/main.cpp +++ b/main.cpp @@ -6,7 +6,6 @@ #include #include #include -#include #include #include #include From 3230a5ad4ecf3140e6bf6c73c8db5df3aa8785a8 Mon Sep 17 00:00:00 2001 From: Sophomore Date: Mon, 24 Nov 2025 11:32:51 +0800 Subject: [PATCH 14/57] feat: flip vertical on load --- main.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/main.cpp b/main.cpp index f17406e..9cc6b6d 100644 --- a/main.cpp +++ b/main.cpp @@ -34,6 +34,7 @@ struct CameraUniform auto load_image() { + stbi_set_flip_vertically_on_load(true); sopho::ImageData result; auto data = stbi_load("assets/test_texture.png", &result.width, &result.height, &result.channels, 4); result.channels = 4; @@ -645,8 +646,8 @@ void main() ImGui_ImplSDL3_Shutdown(); ImGui_ImplSDLGPU3_Shutdown(); ImGui::DestroyContext(); - SDL_ReleaseGPUTexture(m_gpu->device(),m_texture); - SDL_ReleaseGPUSampler(m_gpu->device(),m_sampler); + SDL_ReleaseGPUTexture(m_gpu->device(), m_texture); + SDL_ReleaseGPUSampler(m_gpu->device(), m_sampler); } }; From 942c941241faa4a4b7de0b534bfad29964938277 Mon Sep 17 00:00:00 2001 From: Sophomore Date: Mon, 24 Nov 2025 11:38:58 +0800 Subject: [PATCH 15/57] feat: change hierarchy --- sdl_wrapper/CMakeLists.txt | 26 +++++++++---------- sdl_wrapper/{ => modules}/sdl_wrapper.app.ixx | 0 .../{ => modules}/sdl_wrapper.buffer.ixx | 0 .../{ => modules}/sdl_wrapper.decl.ixx | 0 sdl_wrapper/{ => modules}/sdl_wrapper.gpu.ixx | 0 sdl_wrapper/{ => modules}/sdl_wrapper.ixx | 0 .../{ => modules}/sdl_wrapper.render_data.ixx | 0 .../sdl_wrapper.render_procedural.ixx | 0 .../{ => modules}/sdl_wrapper.renderable.ixx | 0 .../sdl_wrapper.vertex_layout.ixx | 0 .../{ => src}/sdl_callback_implement.cpp | 0 sdl_wrapper/{ => src}/sdl_wrapper.buffer.cpp | 0 sdl_wrapper/{ => src}/sdl_wrapper.gpu.cpp | 0 .../sdl_wrapper.render_procedural.cpp | 0 14 files changed, 13 insertions(+), 13 deletions(-) rename sdl_wrapper/{ => modules}/sdl_wrapper.app.ixx (100%) rename sdl_wrapper/{ => modules}/sdl_wrapper.buffer.ixx (100%) rename sdl_wrapper/{ => modules}/sdl_wrapper.decl.ixx (100%) rename sdl_wrapper/{ => modules}/sdl_wrapper.gpu.ixx (100%) rename sdl_wrapper/{ => modules}/sdl_wrapper.ixx (100%) rename sdl_wrapper/{ => modules}/sdl_wrapper.render_data.ixx (100%) rename sdl_wrapper/{ => modules}/sdl_wrapper.render_procedural.ixx (100%) rename sdl_wrapper/{ => modules}/sdl_wrapper.renderable.ixx (100%) rename sdl_wrapper/{ => modules}/sdl_wrapper.vertex_layout.ixx (100%) rename sdl_wrapper/{ => src}/sdl_callback_implement.cpp (100%) rename sdl_wrapper/{ => src}/sdl_wrapper.buffer.cpp (100%) rename sdl_wrapper/{ => src}/sdl_wrapper.gpu.cpp (100%) rename sdl_wrapper/{ => src}/sdl_wrapper.render_procedural.cpp (100%) diff --git a/sdl_wrapper/CMakeLists.txt b/sdl_wrapper/CMakeLists.txt index c2c6297..f2e4056 100644 --- a/sdl_wrapper/CMakeLists.txt +++ b/sdl_wrapper/CMakeLists.txt @@ -7,20 +7,20 @@ add_library(sdl_wrapper STATIC) target_sources(sdl_wrapper PUBLIC FILE_SET cxx_modules TYPE CXX_MODULES FILES - sdl_wrapper.ixx - sdl_wrapper.buffer.ixx - sdl_wrapper.app.ixx - sdl_wrapper.render_procedural.ixx - sdl_wrapper.render_data.ixx - sdl_wrapper.renderable.ixx - sdl_wrapper.gpu.ixx - sdl_wrapper.decl.ixx - sdl_wrapper.vertex_layout.ixx + modules/sdl_wrapper.ixx + modules/sdl_wrapper.buffer.ixx + modules/sdl_wrapper.app.ixx + modules/sdl_wrapper.render_procedural.ixx + modules/sdl_wrapper.render_data.ixx + modules/sdl_wrapper.renderable.ixx + modules/sdl_wrapper.gpu.ixx + modules/sdl_wrapper.decl.ixx + modules/sdl_wrapper.vertex_layout.ixx PRIVATE - sdl_wrapper.buffer.cpp - sdl_wrapper.render_procedural.cpp - sdl_wrapper.gpu.cpp - sdl_callback_implement.cpp + src/sdl_wrapper.buffer.cpp + src/sdl_wrapper.render_procedural.cpp + src/sdl_wrapper.gpu.cpp + src/sdl_callback_implement.cpp ) target_link_libraries(sdl_wrapper PUBLIC SDL3::SDL3 shaderc glsl_reflector data_type) diff --git a/sdl_wrapper/sdl_wrapper.app.ixx b/sdl_wrapper/modules/sdl_wrapper.app.ixx similarity index 100% rename from sdl_wrapper/sdl_wrapper.app.ixx rename to sdl_wrapper/modules/sdl_wrapper.app.ixx diff --git a/sdl_wrapper/sdl_wrapper.buffer.ixx b/sdl_wrapper/modules/sdl_wrapper.buffer.ixx similarity index 100% rename from sdl_wrapper/sdl_wrapper.buffer.ixx rename to sdl_wrapper/modules/sdl_wrapper.buffer.ixx diff --git a/sdl_wrapper/sdl_wrapper.decl.ixx b/sdl_wrapper/modules/sdl_wrapper.decl.ixx similarity index 100% rename from sdl_wrapper/sdl_wrapper.decl.ixx rename to sdl_wrapper/modules/sdl_wrapper.decl.ixx diff --git a/sdl_wrapper/sdl_wrapper.gpu.ixx b/sdl_wrapper/modules/sdl_wrapper.gpu.ixx similarity index 100% rename from sdl_wrapper/sdl_wrapper.gpu.ixx rename to sdl_wrapper/modules/sdl_wrapper.gpu.ixx diff --git a/sdl_wrapper/sdl_wrapper.ixx b/sdl_wrapper/modules/sdl_wrapper.ixx similarity index 100% rename from sdl_wrapper/sdl_wrapper.ixx rename to sdl_wrapper/modules/sdl_wrapper.ixx diff --git a/sdl_wrapper/sdl_wrapper.render_data.ixx b/sdl_wrapper/modules/sdl_wrapper.render_data.ixx similarity index 100% rename from sdl_wrapper/sdl_wrapper.render_data.ixx rename to sdl_wrapper/modules/sdl_wrapper.render_data.ixx diff --git a/sdl_wrapper/sdl_wrapper.render_procedural.ixx b/sdl_wrapper/modules/sdl_wrapper.render_procedural.ixx similarity index 100% rename from sdl_wrapper/sdl_wrapper.render_procedural.ixx rename to sdl_wrapper/modules/sdl_wrapper.render_procedural.ixx diff --git a/sdl_wrapper/sdl_wrapper.renderable.ixx b/sdl_wrapper/modules/sdl_wrapper.renderable.ixx similarity index 100% rename from sdl_wrapper/sdl_wrapper.renderable.ixx rename to sdl_wrapper/modules/sdl_wrapper.renderable.ixx diff --git a/sdl_wrapper/sdl_wrapper.vertex_layout.ixx b/sdl_wrapper/modules/sdl_wrapper.vertex_layout.ixx similarity index 100% rename from sdl_wrapper/sdl_wrapper.vertex_layout.ixx rename to sdl_wrapper/modules/sdl_wrapper.vertex_layout.ixx diff --git a/sdl_wrapper/sdl_callback_implement.cpp b/sdl_wrapper/src/sdl_callback_implement.cpp similarity index 100% rename from sdl_wrapper/sdl_callback_implement.cpp rename to sdl_wrapper/src/sdl_callback_implement.cpp diff --git a/sdl_wrapper/sdl_wrapper.buffer.cpp b/sdl_wrapper/src/sdl_wrapper.buffer.cpp similarity index 100% rename from sdl_wrapper/sdl_wrapper.buffer.cpp rename to sdl_wrapper/src/sdl_wrapper.buffer.cpp diff --git a/sdl_wrapper/sdl_wrapper.gpu.cpp b/sdl_wrapper/src/sdl_wrapper.gpu.cpp similarity index 100% rename from sdl_wrapper/sdl_wrapper.gpu.cpp rename to sdl_wrapper/src/sdl_wrapper.gpu.cpp diff --git a/sdl_wrapper/sdl_wrapper.render_procedural.cpp b/sdl_wrapper/src/sdl_wrapper.render_procedural.cpp similarity index 100% rename from sdl_wrapper/sdl_wrapper.render_procedural.cpp rename to sdl_wrapper/src/sdl_wrapper.render_procedural.cpp From 8ef6d46a404e49ba67abb127a928c7b90b125e92 Mon Sep 17 00:00:00 2001 From: Sophomore Date: Mon, 24 Nov 2025 11:48:21 +0800 Subject: [PATCH 16/57] feat: move reflector type into data_type module --- data_type/modules/data_type.ixx | 21 +++++++++++++ glsl_reflector/CMakeLists.txt | 3 +- glsl_reflector/modules/glsl_reflector.ixx | 2 +- .../modules/glsl_reflector.type.ixx | 30 ------------------- 4 files changed, 23 insertions(+), 33 deletions(-) delete mode 100644 glsl_reflector/modules/glsl_reflector.type.ixx diff --git a/data_type/modules/data_type.ixx b/data_type/modules/data_type.ixx index cf2f2e6..2ca9fd0 100644 --- a/data_type/modules/data_type.ixx +++ b/data_type/modules/data_type.ixx @@ -2,7 +2,9 @@ // Created by sophomore on 11/23/25. // module; +#include #include +#include #include export module data_type; @@ -40,4 +42,23 @@ export namespace sopho std::vector pixels{}; }; + enum class BasicType : std::uint8_t + { + NONE, + FLOAT + }; + + struct VertexInfo + { + std::uint32_t location{}; + std::string name{}; + BasicType basic_type{}; + int vector_size{}; + }; + + struct VertexReflection + { + std::vector inputs{}; + }; + } // namespace sopho diff --git a/glsl_reflector/CMakeLists.txt b/glsl_reflector/CMakeLists.txt index 2b0dc45..5e0ec26 100644 --- a/glsl_reflector/CMakeLists.txt +++ b/glsl_reflector/CMakeLists.txt @@ -8,10 +8,9 @@ target_sources(glsl_reflector PUBLIC FILE_SET cxx_modules TYPE CXX_MODULES FILES modules/glsl_reflector.ixx - modules/glsl_reflector.type.ixx ) -target_link_libraries(glsl_reflector PUBLIC glslang glslang::glslang-default-resource-limits) +target_link_libraries(glsl_reflector PUBLIC glslang glslang::glslang-default-resource-limits data_type) add_executable(glslr test/test.cpp) diff --git a/glsl_reflector/modules/glsl_reflector.ixx b/glsl_reflector/modules/glsl_reflector.ixx index ad7e841..a01dff8 100644 --- a/glsl_reflector/modules/glsl_reflector.ixx +++ b/glsl_reflector/modules/glsl_reflector.ixx @@ -10,7 +10,7 @@ module; #include "glslang/Public/ResourceLimits.h" #include "glslang/Public/ShaderLang.h" export module glsl_reflector; -export import :type; +export import data_type; namespace sopho { diff --git a/glsl_reflector/modules/glsl_reflector.type.ixx b/glsl_reflector/modules/glsl_reflector.type.ixx deleted file mode 100644 index 29f83af..0000000 --- a/glsl_reflector/modules/glsl_reflector.type.ixx +++ /dev/null @@ -1,30 +0,0 @@ -// glsl_reflector.type.ixx -// Created by wsqsy on 11/20/2025. -// -module; -#include -#include -#include -export module glsl_reflector:type; - -export namespace sopho -{ - enum class BasicType : std::uint8_t - { - NONE, - FLOAT - }; - - struct VertexInfo - { - std::uint32_t location{}; - std::string name{}; - BasicType basic_type{}; - int vector_size{}; - }; - - struct VertexReflection - { - std::vector inputs{}; - }; -} // namespace sopho From 8681328cfd3809ea12634077e487df0bafe2d66a Mon Sep 17 00:00:00 2001 From: Sophomore Date: Mon, 24 Nov 2025 12:22:09 +0800 Subject: [PATCH 17/57] feat: trying to get reflection of uniform --- glsl_reflector/modules/glsl_reflector.ixx | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/glsl_reflector/modules/glsl_reflector.ixx b/glsl_reflector/modules/glsl_reflector.ixx index a01dff8..f577947 100644 --- a/glsl_reflector/modules/glsl_reflector.ixx +++ b/glsl_reflector/modules/glsl_reflector.ixx @@ -82,6 +82,11 @@ namespace sopho .basic_type = to_basic_type(type->getBasicType()), .vector_size = type->getVectorSize()}); } + count = program.getNumUniformVariables(); + for (auto i = 0; i < count; i++) + { + auto var = program.getUniform(i); + } return result; } } // namespace sopho From 53e8e893cba154934fa24c2d0a087fa3de254492 Mon Sep 17 00:00:00 2001 From: Sophomore Date: Mon, 24 Nov 2025 17:37:54 +0800 Subject: [PATCH 18/57] feat: add type FragmentReflection --- data_type/modules/data_type.ixx | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/data_type/modules/data_type.ixx b/data_type/modules/data_type.ixx index 2ca9fd0..be836a1 100644 --- a/data_type/modules/data_type.ixx +++ b/data_type/modules/data_type.ixx @@ -61,4 +61,9 @@ export namespace sopho std::vector inputs{}; }; + struct FragmentReflection + { + std::uint32_t sampler_count; + }; + } // namespace sopho From d7832d25f2ccce2ac99d3728099acd361fb1825b Mon Sep 17 00:00:00 2001 From: Sophomore Date: Mon, 24 Nov 2025 17:38:05 +0800 Subject: [PATCH 19/57] feat: add function reflect_fragment --- glsl_reflector/modules/glsl_reflector.ixx | 48 +++++++++++++++++++++++ 1 file changed, 48 insertions(+) diff --git a/glsl_reflector/modules/glsl_reflector.ixx b/glsl_reflector/modules/glsl_reflector.ixx index f577947..5d5f5ab 100644 --- a/glsl_reflector/modules/glsl_reflector.ixx +++ b/glsl_reflector/modules/glsl_reflector.ixx @@ -89,4 +89,52 @@ namespace sopho } return result; } + + export auto reflect_fragment(const std::string& fragment_source) + { + GlslangProcessGuard glslang_initializer{}; + FragmentReflection result{}; + glslang::TShader shader(EShLangFragment); + std::vector sources{fragment_source.data()}; + shader.setStrings(sources.data(), sources.size()); + + int clientInputSemanticsVersion = 100; // not used for desktop GL + glslang::EShTargetClientVersion clientVersion = glslang::EShTargetOpenGL_450; + glslang::EShTargetLanguageVersion targetVersion = glslang::EShTargetSpv_1_0; + + shader.setEnvInput(glslang::EShSourceGlsl, EShLangFragment, glslang::EShClientOpenGL, + clientInputSemanticsVersion); + shader.setEnvClient(glslang::EShClientOpenGL, clientVersion); + shader.setEnvTarget(glslang::EShTargetSpv, targetVersion); + + EShMessages messages = (EShMessages)(EShMsgDefault | EShMsgSpvRules | EShMsgVulkanRules); + + if (!shader.parse(GetDefaultResources(), 450, ENoProfile, false, false, messages)) + { + std::cerr << "Parse failed:\n" << shader.getInfoLog() << std::endl; + return result; + } + + glslang::TProgram program; + program.addShader(&shader); + if (!program.link(messages)) + { + std::cerr << "Link failed:\n" << program.getInfoLog() << std::endl; + return result; + } + program.buildReflection(); + auto count = program.getNumUniformVariables(); + for (auto i = 0; i < count; i++) + { + auto var = program.getUniform(i); + auto type = var.getType(); + auto basic_type = type->getBasicType(); + if (basic_type == glslang::EbtSampler) + { + result.sampler_count++; + } + } + return result; + } + } // namespace sopho From ccfb6f43cacf80aff6c26c8a6e232c4c1461e8bd Mon Sep 17 00:00:00 2001 From: Sophomore Date: Mon, 24 Nov 2025 17:38:21 +0800 Subject: [PATCH 20/57] feat: add test case for reflect_fragment --- glsl_reflector/test/test.cpp | 38 ++++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/glsl_reflector/test/test.cpp b/glsl_reflector/test/test.cpp index 4bb8d00..0184eda 100644 --- a/glsl_reflector/test/test.cpp +++ b/glsl_reflector/test/test.cpp @@ -36,3 +36,41 @@ TEST(reflect_vertex, Basic) EXPECT_EQ(reflect_info.inputs[1].basic_type, sopho::BasicType::FLOAT); EXPECT_EQ(reflect_info.inputs[1].vector_size, 3); } + + +TEST(reflect_fragment, Basic) +{ + auto reflect_info = sopho::reflect_fragment(R"( +#version 460 + +layout (location = 0) in vec4 v_color; +layout (location = 0) out vec4 FragColor; + +layout(set = 2, binding = 0) uniform sampler2D uTexture; + +void main() +{ + FragColor = texture(uTexture, v_color.xy); +} + )"); + EXPECT_EQ(reflect_info.sampler_count, 1); +} + +TEST(reflect_fragment, Multi) +{ + auto reflect_info = sopho::reflect_fragment(R"( +#version 460 + +layout (location = 0) in vec4 v_color; +layout (location = 0) out vec4 FragColor; + +layout(set = 2, binding = 0) uniform sampler2D uTexture; +layout(set = 2, binding = 1) uniform sampler2D uTexture1; + +void main() +{ + FragColor = texture(uTexture, v_color.xy) + texture(uTexture1, v_color.xy); +} + )"); + EXPECT_EQ(reflect_info.sampler_count, 2); +} From 84327f7629fb18c7d5e0e7f41912b2685184f4cf Mon Sep 17 00:00:00 2001 From: Sophomore <17792626+WSQS@users.noreply.github.com> Date: Mon, 24 Nov 2025 19:35:08 +0800 Subject: [PATCH 21/57] fix: cleanup code --- main.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/main.cpp b/main.cpp index 9cc6b6d..324a872 100644 --- a/main.cpp +++ b/main.cpp @@ -185,8 +185,6 @@ layout(set = 2, binding = 0) uniform sampler2D uTexture; void main() { FragColor = texture(uTexture, v_color.xy); - //FragColor = vec4(v_color.xy,0,0); - FragColor.a = 1; })WSQ"; public: From 727cae2d219ad5b33bcfe4be23c4b778ee519846 Mon Sep 17 00:00:00 2001 From: Sophomore <17792626+WSQS@users.noreply.github.com> Date: Mon, 24 Nov 2025 19:39:29 +0800 Subject: [PATCH 22/57] feat: add readme --- README.md | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 README.md diff --git a/README.md b/README.md new file mode 100644 index 0000000..ced3dfa --- /dev/null +++ b/README.md @@ -0,0 +1,3 @@ +# SDL Test + +This is a personal learning project following [Learn OpenGL](https://learnopengl.com/) From 50f06587729577c994a17d84d23747339393e706 Mon Sep 17 00:00:00 2001 From: Sophomore <17792626+WSQS@users.noreply.github.com> Date: Mon, 24 Nov 2025 20:05:12 +0800 Subject: [PATCH 23/57] doc: add limit for document --- README.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/README.md b/README.md index ced3dfa..14f884e 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,7 @@ # SDL Test This is a personal learning project following [Learn OpenGL](https://learnopengl.com/) + +## Comment Format + +Using block comments `/*...*/`. From fe4679780b2d0fddd2f6baef44fc32cd3600e51e Mon Sep 17 00:00:00 2001 From: Sophomore <17792626+WSQS@users.noreply.github.com> Date: Mon, 24 Nov 2025 20:05:29 +0800 Subject: [PATCH 24/57] doc: add document --- main.cpp | 45 ++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 44 insertions(+), 1 deletion(-) diff --git a/main.cpp b/main.cpp index 324a872..ae3dfe4 100644 --- a/main.cpp +++ b/main.cpp @@ -27,11 +27,25 @@ import data_type; import glsl_reflector; import sdl_wrapper; +/** + * @brief Structure to hold camera transformation matrix data. + * + * Contains a 4x4 matrix (16 elements) representing the camera's view transformation. + */ struct CameraUniform { - std::array m{}; + std::array m{}; ///< 4x4 transformation matrix as a flat array }; +/** + * @brief Loads image data from the test texture file. + * + * Uses stb_image library to load a PNG file (assets/test_texture.png) into an ImageData structure. + * The image is flipped vertically on load and the pixel data is stored as a vector of bytes. + * + * @return sopho::ImageData Structure containing the loaded image dimensions, channels, and pixel data. + * Returns an empty structure if loading fails. + */ auto load_image() { stbi_set_flip_vertically_on_load(true); @@ -53,6 +67,15 @@ auto load_image() return result; } +/** + * @brief Creates a GPU texture from image data. + * + * Creates a 2D RGBA8 texture with sampler usage based on the provided image data. + * + * @param device Pointer to the SDL GPU device. + * @param img Reference to the ImageData structure containing image information. + * @return SDL_GPUTexture* Pointer to the created GPU texture, or nullptr on failure. + */ SDL_GPUTexture* create_texture_from_image(SDL_GPUDevice* device, const sopho::ImageData& img) { SDL_GPUTextureCreateInfo create_info{.type = SDL_GPU_TEXTURETYPE_2D, @@ -67,6 +90,15 @@ SDL_GPUTexture* create_texture_from_image(SDL_GPUDevice* device, const sopho::Im return SDL_CreateGPUTexture(device, &create_info); } +/** + * @brief Creates a GPU transfer buffer for texture data upload. + * + * Creates an upload transfer buffer containing the image data for efficient GPU upload. + * + * @param device Pointer to the SDL GPU device. + * @param img Reference to the ImageData structure containing image information. + * @return SDL_GPUTransferBuffer* Pointer to the created GPU transfer buffer, or nullptr on failure. + */ SDL_GPUTransferBuffer* create_texture_transfer_buffer(SDL_GPUDevice* device, const sopho::ImageData& img) { const Uint32 bytes_per_pixel = 4; @@ -96,6 +128,17 @@ SDL_GPUTransferBuffer* create_texture_transfer_buffer(SDL_GPUDevice* device, con return transfer; } +/** + * @brief Uploads texture data from transfer buffer to GPU texture. + * + * Performs a GPU copy operation to upload texture data from the provided transfer buffer to the target texture. + * + * @param device Pointer to the SDL GPU device. + * @param texture Pointer to the target GPU texture. + * @param transfer Pointer to the source GPU transfer buffer containing texture data. + * @param width Width of the texture in pixels. + * @param height Height of the texture in pixels. + */ void upload_texture_full(SDL_GPUDevice* device, SDL_GPUTexture* texture, SDL_GPUTransferBuffer* transfer, int width, int height) { From 39af3494b63a77bac13778ab48628769ceda8ba0 Mon Sep 17 00:00:00 2001 From: Sophomore <17792626+WSQS@users.noreply.github.com> Date: Mon, 24 Nov 2025 20:14:58 +0800 Subject: [PATCH 25/57] feat: using reflector to define sampler --- sdl_wrapper/src/sdl_wrapper.render_procedural.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/sdl_wrapper/src/sdl_wrapper.render_procedural.cpp b/sdl_wrapper/src/sdl_wrapper.render_procedural.cpp index e22a3f7..448163e 100644 --- a/sdl_wrapper/src/sdl_wrapper.render_procedural.cpp +++ b/sdl_wrapper/src/sdl_wrapper.render_procedural.cpp @@ -270,7 +270,9 @@ namespace sopho // Convert SPIR-V words to a byte vector std::vector code = spv_result_to_bytes(result); - auto shader_result = m_gpu->create_shader(code, SDL_GPU_SHADERSTAGE_FRAGMENT, 0, 1); + auto reflect_result = reflect_fragment(source); + auto shader_result = m_gpu->create_shader(code, SDL_GPU_SHADERSTAGE_FRAGMENT, 0, reflect_result.sampler_count); + if (!shader_result) { return std::unexpected(shader_result.error()); From cfba354a98ac4e2acf0b1a31965f0e6b316c560a Mon Sep 17 00:00:00 2001 From: Sophomore <17792626+WSQS@users.noreply.github.com> Date: Mon, 24 Nov 2025 23:00:14 +0800 Subject: [PATCH 26/57] feat: add class TransferBufferWrapper --- sdl_wrapper/CMakeLists.txt | 1 + .../modules/sdl_wrapper.transfer_buffer.ixx | 167 ++++++++++++++++++ 2 files changed, 168 insertions(+) create mode 100644 sdl_wrapper/modules/sdl_wrapper.transfer_buffer.ixx diff --git a/sdl_wrapper/CMakeLists.txt b/sdl_wrapper/CMakeLists.txt index f2e4056..1c69985 100644 --- a/sdl_wrapper/CMakeLists.txt +++ b/sdl_wrapper/CMakeLists.txt @@ -16,6 +16,7 @@ target_sources(sdl_wrapper modules/sdl_wrapper.gpu.ixx modules/sdl_wrapper.decl.ixx modules/sdl_wrapper.vertex_layout.ixx + modules/sdl_wrapper.transfer_buffer.ixx PRIVATE src/sdl_wrapper.buffer.cpp src/sdl_wrapper.render_procedural.cpp diff --git a/sdl_wrapper/modules/sdl_wrapper.transfer_buffer.ixx b/sdl_wrapper/modules/sdl_wrapper.transfer_buffer.ixx new file mode 100644 index 0000000..151714b --- /dev/null +++ b/sdl_wrapper/modules/sdl_wrapper.transfer_buffer.ixx @@ -0,0 +1,167 @@ +// sdl_wrapper.transfer_buffer.ixx +// Created by sophomore on 11/24/25. +// +/* + * @file sdl_wrapper.transfer_buffer.ixx + * @brief Transfer buffer wrapper module for SDL GPU operations. + * + * This module provides a wrapper for SDL GPU transfer buffers with a builder pattern + * that allows specifying usage limits for automatic resource management. + */ +module; +#include +#include +#include +#include "SDL3/SDL_gpu.h" +#include "SDL3/SDL_log.h" +export module sdl_wrapper:transfer_buffer; +import data_type; +import :gpu; +namespace sopho +{ + + /* + * @brief Wrapper class for SDL GPU transfer buffer operations. + */ + export class TransferBufferWrapper + { + private: + std::shared_ptr m_gpu{}; // Owns the device lifetime + SDL_GPUTransferBuffer* m_transfer_buffer{}; // The actual transfer buffer + std::int32_t m_usage_count{}; // Current usage count + std::uint32_t m_size{}; // Size of the transfer buffer in bytes + + // Private constructor to ensure only Builder can create instances + TransferBufferWrapper(std::shared_ptr gpu, SDL_GPUTransferBuffer* transfer_buffer, + std::int32_t usage_limit, std::uint32_t size) noexcept : + m_gpu(std::move(gpu)), m_transfer_buffer(transfer_buffer), m_usage_count(usage_limit), m_size(size) + { + } + + public: + TransferBufferWrapper(const TransferBufferWrapper&) = delete; + TransferBufferWrapper& operator=(const TransferBufferWrapper&) = delete; + TransferBufferWrapper(TransferBufferWrapper&& other) noexcept : + m_gpu(std::move(other.m_gpu)), m_transfer_buffer(other.m_transfer_buffer), + m_usage_count(other.m_usage_count), m_size(other.m_size) + { + other.m_transfer_buffer = nullptr; + } + + TransferBufferWrapper& operator=(TransferBufferWrapper&& other) noexcept + { + if (this != &other) + { + reset(); + m_gpu = std::move(other.m_gpu); + m_transfer_buffer = other.m_transfer_buffer; + m_usage_count = other.m_usage_count; + m_size = other.m_size; + other.m_transfer_buffer = nullptr; + } + return *this; + } + + /* + * @brief Destructor that releases the transfer buffer. + */ + ~TransferBufferWrapper() noexcept { reset(); } + + /* + * @brief Releases the underlying transfer buffer and resets state. + */ + void reset() noexcept + { + if (m_transfer_buffer && m_gpu && m_gpu->device()) + { + SDL_ReleaseGPUTransferBuffer(m_gpu->device(), m_transfer_buffer); + m_transfer_buffer = nullptr; + } + } + + /* + * @brief Returns the underlying SDL_GPUTransferBuffer pointer. + */ + [[nodiscard]] SDL_GPUTransferBuffer* raw() const noexcept { return m_transfer_buffer; } + + /* + * @brief Returns the size of the transfer buffer in bytes. + */ + [[nodiscard]] std::uint32_t size() const noexcept { return m_size; } + + /* + * @brief Builder pattern for creating TransferBufferWrapper instances. + * + * Provides a fluent interface for configuring transfer buffer properties + * such as usage limit, buffer type, and size. + */ + struct Builder + { + /* + * @brief Maximum number of uploads allowed before the buffer is recycled. + * When this limit is reached, the buffer will be automatically recycled. + */ + std::int32_t usage_limit{1}; + + /* @brief The usage type for the transfer buffer (e.g., upload/download). */ + SDL_GPUTransferBufferUsage usage{SDL_GPU_TRANSFERBUFFERUSAGE_UPLOAD}; + + /* @brief Size of the transfer buffer in bytes. */ + std::uint32_t size{1024}; + + /* + * @brief Sets the usage limit for the transfer buffer. + * @param limit Maximum number of uploads before the buffer is recycled + * @return Reference to this Builder for chaining + */ + Builder& set_usage_limit(std::int32_t limit) + { + usage_limit = limit; + return *this; + } + + /* + * @brief Sets the usage type for the transfer buffer. + * @param buffer_usage The SDL GPU transfer buffer usage type + * @return Reference to this Builder for chaining + */ + Builder& set_usage(SDL_GPUTransferBufferUsage buffer_usage) + { + usage = buffer_usage; + return *this; + } + + /* + * @brief Sets the size of the transfer buffer. + * @param buffer_size Size in bytes + * @return Reference to this Builder for chaining + */ + Builder& set_size(std::uint32_t buffer_size) + { + size = buffer_size; + return *this; + } + + /* + * @brief Builds the TransferBufferWrapper instance. + * @param gpu The GPU wrapper to use for creating the transfer buffer + * @return A checkable containing the TransferBufferWrapper on success, or an error on failure + */ + checkable build(GpuWrapper& gpu) + { + SDL_GPUTransferBufferCreateInfo create_info{}; + create_info.usage = usage; + create_info.size = size; + + auto* transfer_buffer = SDL_CreateGPUTransferBuffer(gpu.device(), &create_info); + if (!transfer_buffer) + { + SDL_LogError(SDL_LOG_CATEGORY_GPU, "%s:%d %s", __FILE__, __LINE__, SDL_GetError()); + return std::unexpected(GpuError::CREATE_TRANSFER_BUFFER_FAILED); + } + + return TransferBufferWrapper{gpu.shared_from_this(), transfer_buffer, usage_limit, size}; + } + }; + }; +} // namespace sopho From e3a44890f7df475165e92b14bab656591f1cc25e Mon Sep 17 00:00:00 2001 From: Sophomore Date: Tue, 25 Nov 2025 14:09:01 +0800 Subject: [PATCH 27/57] feat: Split Implement and interface of render data --- .../modules/sdl_wrapper.render_data.ixx | 49 +++-------------- .../modules/sdl_wrapper.render_data_impl.ixx | 54 +++++++++++++++++++ sdl_wrapper/src/sdl_wrapper.gpu.cpp | 11 ++-- 3 files changed, 68 insertions(+), 46 deletions(-) create mode 100644 sdl_wrapper/modules/sdl_wrapper.render_data_impl.ixx diff --git a/sdl_wrapper/modules/sdl_wrapper.render_data.ixx b/sdl_wrapper/modules/sdl_wrapper.render_data.ixx index 9f220d4..9dd758b 100644 --- a/sdl_wrapper/modules/sdl_wrapper.render_data.ixx +++ b/sdl_wrapper/modules/sdl_wrapper.render_data.ixx @@ -3,33 +3,14 @@ // module; #include -#include #include +#include export module sdl_wrapper:render_data; -import :buffer; import :vertex_layout; namespace sopho { export class RenderData { - BufferWrapper m_vertex_buffer; - BufferWrapper m_index_buffer; - VertexLayout m_layouts{}; - size_t m_vertex_count{}; - std::vector m_bindings{}; - SDL_GPUBufferBinding m_index_binding{}; - - public: - explicit RenderData(BufferWrapper&& vertex_buffer_wrapper, BufferWrapper&& index_buffer_wrapper, - const VertexLayout& layouts, size_t vertex_count) : - m_vertex_buffer(std::move(vertex_buffer_wrapper)), m_index_buffer(std::move(index_buffer_wrapper)), - m_layouts(layouts), m_vertex_count(vertex_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; - } - public: struct VertexView { @@ -42,27 +23,11 @@ namespace sopho size_t index_count{}; std::byte* raw{}; }; - RenderData(const RenderData&) = delete; - RenderData& operator=(const RenderData&) = delete; - RenderData(RenderData&&) = default; - RenderData& operator=(RenderData&&) = default; - auto& buffer() { return m_vertex_buffer; } - auto& get_vertex_buffer_binding() { return m_bindings; } - auto& get_index_buffer_binding() { return m_index_binding; } - auto vertex_view() - { - return VertexView{.layout = m_layouts, .vertex_count = m_vertex_count, .raw = m_vertex_buffer.cpu_buffer()}; - } - auto index_view() { return IndexView{.index_count = m_vertex_count, .raw = m_index_buffer.cpu_buffer()}; } - auto upload() - { - auto result = m_vertex_buffer.upload(); - if (!result) - { - return result; - } - result = m_index_buffer.upload(); - return result; - } + virtual ~RenderData() = default; + virtual std::vector& get_vertex_buffer_binding() = 0; + virtual SDL_GPUBufferBinding& get_index_buffer_binding() = 0; + virtual VertexView vertex_view() = 0; + virtual IndexView index_view() = 0; + virtual std::expected upload() = 0; }; } // namespace sopho diff --git a/sdl_wrapper/modules/sdl_wrapper.render_data_impl.ixx b/sdl_wrapper/modules/sdl_wrapper.render_data_impl.ixx new file mode 100644 index 0000000..de53365 --- /dev/null +++ b/sdl_wrapper/modules/sdl_wrapper.render_data_impl.ixx @@ -0,0 +1,54 @@ +// sdl_wrapper.render_data_impl.ixx +// Created by wsqsy on 11/25/2025. +// + +export module sdl_wrapper:render_data_impl; +import :render_data; +import :buffer; +namespace sopho +{ + class RenderDataImpl : public RenderData + { + BufferWrapper m_vertex_buffer; + BufferWrapper m_index_buffer; + VertexLayout m_layouts{}; + size_t m_vertex_count{}; + std::vector m_bindings{}; + SDL_GPUBufferBinding m_index_binding{}; + + public: + explicit RenderDataImpl(BufferWrapper&& vertex_buffer_wrapper, BufferWrapper&& index_buffer_wrapper, + const VertexLayout& layouts, size_t vertex_count) : + m_vertex_buffer(std::move(vertex_buffer_wrapper)), m_index_buffer(std::move(index_buffer_wrapper)), + m_layouts(layouts), m_vertex_count(vertex_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(const RenderDataImpl&) = delete; + RenderDataImpl& operator=(const RenderDataImpl&) = delete; + RenderDataImpl(RenderDataImpl&&) = default; + RenderDataImpl& operator=(RenderDataImpl&&) = default; + virtual std::vector& get_vertex_buffer_binding() override { return m_bindings; } + virtual SDL_GPUBufferBinding& get_index_buffer_binding() override { return m_index_binding; } + virtual VertexView vertex_view() override + { + return VertexView{.layout = m_layouts, .vertex_count = m_vertex_count, .raw = m_vertex_buffer.cpu_buffer()}; + } + virtual IndexView index_view() override + { + return IndexView{.index_count = m_vertex_count, .raw = m_index_buffer.cpu_buffer()}; + } + virtual std::expected upload() override + { + auto result = m_vertex_buffer.upload(); + if (!result) + { + return result; + } + result = m_index_buffer.upload(); + return result; + } + }; +} // namespace sopho diff --git a/sdl_wrapper/src/sdl_wrapper.gpu.cpp b/sdl_wrapper/src/sdl_wrapper.gpu.cpp index be90b62..ba37560 100644 --- a/sdl_wrapper/src/sdl_wrapper.gpu.cpp +++ b/sdl_wrapper/src/sdl_wrapper.gpu.cpp @@ -3,6 +3,7 @@ // module; #include +#include #include "SDL3/SDL_gpu.h" #include "SDL3/SDL_log.h" module sdl_wrapper; @@ -10,6 +11,8 @@ import :gpu; import :render_procedural; import :render_data; import :vertex_layout; +import :transfer_buffer; +import :render_data_impl; namespace sopho { /** @@ -53,8 +56,8 @@ namespace sopho * @param vertex_count Number of vertices the allocated buffer must hold. * @return RenderData RenderData containing the allocated vertex buffer, the vertex layout, and `vertex_count`. */ - std::expected GpuWrapper::create_data(const RenderProcedural& render_procedural, - uint32_t vertex_count) + checkable> GpuWrapper::create_data(const RenderProcedural& render_procedural, + uint32_t vertex_count) { auto size = render_procedural.vertex_layout().get_stride() * vertex_count; auto vertex_buffer = create_buffer(SDL_GPU_BUFFERUSAGE_VERTEX, size); @@ -67,8 +70,8 @@ namespace sopho { return std::unexpected(index_buffer.error()); } - return RenderData{std::move(vertex_buffer.value()), std::move(index_buffer.value()), - render_procedural.vertex_layout(), vertex_count}; + return std::make_unique(std::move(vertex_buffer.value()), std::move(index_buffer.value()), + render_procedural.vertex_layout(), vertex_count); } /** * @brief Create a RenderProcedural configured for the device's texture format. From 8d8f26156fc05b0b383b0705d788c7411b430401 Mon Sep 17 00:00:00 2001 From: Sophomore Date: Tue, 25 Nov 2025 14:09:21 +0800 Subject: [PATCH 28/57] feat: add file render_data_impl --- sdl_wrapper/CMakeLists.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/sdl_wrapper/CMakeLists.txt b/sdl_wrapper/CMakeLists.txt index 1c69985..e574666 100644 --- a/sdl_wrapper/CMakeLists.txt +++ b/sdl_wrapper/CMakeLists.txt @@ -12,6 +12,7 @@ target_sources(sdl_wrapper modules/sdl_wrapper.app.ixx modules/sdl_wrapper.render_procedural.ixx modules/sdl_wrapper.render_data.ixx + modules/sdl_wrapper.render_data_impl.ixx modules/sdl_wrapper.renderable.ixx modules/sdl_wrapper.gpu.ixx modules/sdl_wrapper.decl.ixx From e9414542b8e853f1f3eaa45ef59421375a846c61 Mon Sep 17 00:00:00 2001 From: Sophomore Date: Tue, 25 Nov 2025 14:10:17 +0800 Subject: [PATCH 29/57] feat: change signature of create_data --- sdl_wrapper/modules/sdl_wrapper.gpu.ixx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sdl_wrapper/modules/sdl_wrapper.gpu.ixx b/sdl_wrapper/modules/sdl_wrapper.gpu.ixx index e5e1cd6..cc0e0d4 100644 --- a/sdl_wrapper/modules/sdl_wrapper.gpu.ixx +++ b/sdl_wrapper/modules/sdl_wrapper.gpu.ixx @@ -213,8 +213,8 @@ export namespace sopho [[nodiscard]] SDL_Window* window() const { return m_ctx.window.raw; } [[nodiscard]] std::expected create_buffer(SDL_GPUBufferUsageFlags flag, uint32_t size); - [[nodiscard]] std::expected create_data(const RenderProcedural& render_procedural, - uint32_t vertex_count); + [[nodiscard]] checkable> create_data(const RenderProcedural& render_procedural, + uint32_t vertex_count); auto release_buffer(SDL_GPUBuffer* buffer) { From f47735fd0b35956adcc0680f8d8f6d4baee6b903 Mon Sep 17 00:00:00 2001 From: Sophomore Date: Tue, 25 Nov 2025 14:39:38 +0800 Subject: [PATCH 30/57] feat: Not export Module buffer --- main.cpp | 10 ++-- sdl_wrapper/modules/sdl_wrapper.buffer.ixx | 51 +++++++++++++++++-- sdl_wrapper/modules/sdl_wrapper.gpu.ixx | 5 +- sdl_wrapper/modules/sdl_wrapper.ixx | 1 - .../modules/sdl_wrapper.render_data_impl.ixx | 3 +- .../modules/sdl_wrapper.transfer_buffer.ixx | 34 +++++++++++-- sdl_wrapper/src/sdl_wrapper.buffer.cpp | 20 ++------ sdl_wrapper/src/sdl_wrapper.gpu.cpp | 41 +++------------ 8 files changed, 95 insertions(+), 70 deletions(-) diff --git a/main.cpp b/main.cpp index ae3dfe4..ed7962b 100644 --- a/main.cpp +++ b/main.cpp @@ -29,12 +29,12 @@ import sdl_wrapper; /** * @brief Structure to hold camera transformation matrix data. - * + * * Contains a 4x4 matrix (16 elements) representing the camera's view transformation. */ struct CameraUniform { - std::array m{}; ///< 4x4 transformation matrix as a flat array + std::array m{}; ///< 4x4 transformation matrix as a flat array }; /** @@ -284,7 +284,7 @@ void main() } // 5. Upload initial vertex data. - auto upload_result = render_data.and_then([&](auto& vertex_buffer) { return vertex_buffer.upload(); }); + auto upload_result = render_data.and_then([&](auto& vertex_buffer) { return vertex_buffer->upload(); }); if (!upload_result) { @@ -295,7 +295,7 @@ void main() m_renderable = std::make_shared(sopho::Renderable{ .m_render_procedural = std::make_shared(std::move(pw_result.value())), - .m_render_data = std::make_shared(std::move(render_data.value()))}); + .m_render_data = std::move(render_data.value())}); // 6. Initialize camera matrix to identity. { @@ -472,7 +472,7 @@ void main() else { auto new_data = m_gpu->create_data(*m_renderable->procedural(), 3); - m_renderable->data() = std::make_shared(std::move(new_data.value())); + m_renderable->data() = std::move(new_data.value()); m_renderable->data()->upload(); } } diff --git a/sdl_wrapper/modules/sdl_wrapper.buffer.ixx b/sdl_wrapper/modules/sdl_wrapper.buffer.ixx index 3467be4..f8c931a 100644 --- a/sdl_wrapper/modules/sdl_wrapper.buffer.ixx +++ b/sdl_wrapper/modules/sdl_wrapper.buffer.ixx @@ -6,12 +6,13 @@ module; #include #include #include - #include "SDL3/SDL_gpu.h" +#include "SDL3/SDL_log.h" export module sdl_wrapper:buffer; import data_type; -import :decl; +import :gpu; +import :transfer_buffer; namespace sopho { @@ -19,19 +20,59 @@ namespace sopho { std::shared_ptr m_gpu{}; // Owns the device lifetime SDL_GPUBuffer* m_gpu_buffer{}; // Target GPU buffer - SDL_GPUTransferBuffer* m_transfer_buffer{}; // Staging/transfer buffer + TransferBufferWrapper m_transfer_buffer; // Staging/transfer buffer std::uint32_t m_buffer_size{}; // Total size of the GPU buffer std::vector m_cpu_buffer{}; // Only GpuWrapper is allowed to construct this type. BufferWrapper(std::shared_ptr gpu, SDL_GPUBuffer* gpu_buffer, - SDL_GPUTransferBuffer* transfer_buffer, std::uint32_t size) noexcept : - m_gpu(std::move(gpu)), m_gpu_buffer(gpu_buffer), m_transfer_buffer(transfer_buffer), m_buffer_size(size) + TransferBufferWrapper transfer_buffer, std::uint32_t size) noexcept : + m_gpu(std::move(gpu)), m_gpu_buffer(gpu_buffer), m_transfer_buffer(std::move(transfer_buffer)), m_buffer_size(size) { m_cpu_buffer.resize(m_buffer_size); } public: + struct Builder + { + SDL_GPUBufferUsageFlags flag = SDL_GPU_BUFFERUSAGE_VERTEX; + std::uint32_t size = 0; + + Builder& set_flag(SDL_GPUBufferUsageFlags usage_flag) + { + flag = usage_flag; + return *this; + } + + Builder& set_size(std::uint32_t buffer_size) + { + size = buffer_size; + return *this; + } + + checkable build(GpuWrapper& gpu) + { + SDL_GPUBufferCreateInfo create_info{.usage = flag, .size = size}; + auto gpu_buffer = SDL_CreateGPUBuffer(gpu.device(), &create_info); + if (!gpu_buffer) + { + SDL_LogError(SDL_LOG_CATEGORY_GPU, "%s:%d %s", __FILE__, __LINE__, SDL_GetError()); + return std::unexpected(GpuError::CREATE_GPU_BUFFER_FAILED); + } + auto transfer_buffer = TransferBufferWrapper::Builder{} + .set_size(size) + .set_usage(SDL_GPU_TRANSFERBUFFERUSAGE_UPLOAD) + .set_usage_limit(-1) + .build(gpu); + if (!transfer_buffer) + { + SDL_LogError(SDL_LOG_CATEGORY_GPU, "%s:%d %s", __FILE__, __LINE__, SDL_GetError()); + return std::unexpected(transfer_buffer.error()); + } + return BufferWrapper{gpu.shared_from_this(), gpu_buffer, (std::move(transfer_buffer.value())), size}; + } + }; + BufferWrapper(const BufferWrapper&) = delete; BufferWrapper& operator=(const BufferWrapper&) = delete; BufferWrapper(BufferWrapper&&) = default; diff --git a/sdl_wrapper/modules/sdl_wrapper.gpu.ixx b/sdl_wrapper/modules/sdl_wrapper.gpu.ixx index cc0e0d4..00e28b7 100644 --- a/sdl_wrapper/modules/sdl_wrapper.gpu.ixx +++ b/sdl_wrapper/modules/sdl_wrapper.gpu.ixx @@ -11,7 +11,6 @@ module; #include "shaderc/shaderc.hpp" export module sdl_wrapper:gpu; import :decl; -import :buffer; import :render_procedural; export namespace sopho { @@ -211,9 +210,7 @@ export namespace sopho [[nodiscard]] auto device() const { return m_ctx.device.raw; } [[nodiscard]] SDL_Window* window() const { return m_ctx.window.raw; } - - [[nodiscard]] std::expected create_buffer(SDL_GPUBufferUsageFlags flag, uint32_t size); - [[nodiscard]] checkable> create_data(const RenderProcedural& render_procedural, + [[nodiscard]] checkable> create_data(const RenderProcedural& render_procedural, uint32_t vertex_count); auto release_buffer(SDL_GPUBuffer* buffer) diff --git a/sdl_wrapper/modules/sdl_wrapper.ixx b/sdl_wrapper/modules/sdl_wrapper.ixx index 94a2470..5d82468 100644 --- a/sdl_wrapper/modules/sdl_wrapper.ixx +++ b/sdl_wrapper/modules/sdl_wrapper.ixx @@ -6,7 +6,6 @@ export module sdl_wrapper; export import :decl; export import :app; export import :gpu; -export import :buffer; export import :render_procedural; export import :renderable; export import :vertex_layout; diff --git a/sdl_wrapper/modules/sdl_wrapper.render_data_impl.ixx b/sdl_wrapper/modules/sdl_wrapper.render_data_impl.ixx index de53365..1bcc7e6 100644 --- a/sdl_wrapper/modules/sdl_wrapper.render_data_impl.ixx +++ b/sdl_wrapper/modules/sdl_wrapper.render_data_impl.ixx @@ -1,7 +1,8 @@ // sdl_wrapper.render_data_impl.ixx // Created by wsqsy on 11/25/2025. // - +module; +#include export module sdl_wrapper:render_data_impl; import :render_data; import :buffer; diff --git a/sdl_wrapper/modules/sdl_wrapper.transfer_buffer.ixx b/sdl_wrapper/modules/sdl_wrapper.transfer_buffer.ixx index 151714b..6d33555 100644 --- a/sdl_wrapper/modules/sdl_wrapper.transfer_buffer.ixx +++ b/sdl_wrapper/modules/sdl_wrapper.transfer_buffer.ixx @@ -9,6 +9,7 @@ * that allows specifying usage limits for automatic resource management. */ module; +#include #include #include #include @@ -28,13 +29,13 @@ namespace sopho private: std::shared_ptr m_gpu{}; // Owns the device lifetime SDL_GPUTransferBuffer* m_transfer_buffer{}; // The actual transfer buffer - std::int32_t m_usage_count{}; // Current usage count + std::int32_t m_usage_limit{}; // Current usage count std::uint32_t m_size{}; // Size of the transfer buffer in bytes // Private constructor to ensure only Builder can create instances TransferBufferWrapper(std::shared_ptr gpu, SDL_GPUTransferBuffer* transfer_buffer, std::int32_t usage_limit, std::uint32_t size) noexcept : - m_gpu(std::move(gpu)), m_transfer_buffer(transfer_buffer), m_usage_count(usage_limit), m_size(size) + m_gpu(std::move(gpu)), m_transfer_buffer(transfer_buffer), m_usage_limit(usage_limit), m_size(size) { } @@ -43,7 +44,7 @@ namespace sopho TransferBufferWrapper& operator=(const TransferBufferWrapper&) = delete; TransferBufferWrapper(TransferBufferWrapper&& other) noexcept : m_gpu(std::move(other.m_gpu)), m_transfer_buffer(other.m_transfer_buffer), - m_usage_count(other.m_usage_count), m_size(other.m_size) + m_usage_limit(other.m_usage_limit), m_size(other.m_size) { other.m_transfer_buffer = nullptr; } @@ -55,7 +56,7 @@ namespace sopho reset(); m_gpu = std::move(other.m_gpu); m_transfer_buffer = other.m_transfer_buffer; - m_usage_count = other.m_usage_count; + m_usage_limit = other.m_usage_limit; m_size = other.m_size; other.m_transfer_buffer = nullptr; } @@ -89,6 +90,31 @@ namespace sopho */ [[nodiscard]] std::uint32_t size() const noexcept { return m_size; } + checkable submit(void* data_source) + { + assert(m_usage_limit != 0); + void* dst = SDL_MapGPUTransferBuffer(m_gpu->device(), m_transfer_buffer, false); + if (!dst) + { + SDL_LogError(SDL_LOG_CATEGORY_GPU, "%s:%d failed to map transfer buffer: %s", __FILE__, __LINE__, + SDL_GetError()); + + return std::unexpected(GpuError::MAP_TRANSFER_BUFFER_FAILED); + } + + SDL_memcpy(dst, data_source, m_size); + SDL_UnmapGPUTransferBuffer(m_gpu->device(), m_transfer_buffer); + if (m_usage_limit != -1) + { + m_usage_limit--; + if (m_usage_limit ==0) + { + reset(); + } + } + return {}; + } + /* * @brief Builder pattern for creating TransferBufferWrapper instances. * diff --git a/sdl_wrapper/src/sdl_wrapper.buffer.cpp b/sdl_wrapper/src/sdl_wrapper.buffer.cpp index 78e9323..090640b 100644 --- a/sdl_wrapper/src/sdl_wrapper.buffer.cpp +++ b/sdl_wrapper/src/sdl_wrapper.buffer.cpp @@ -35,13 +35,6 @@ namespace sopho m_gpu->release_buffer(m_gpu_buffer); m_gpu_buffer = nullptr; } - - // Release transfer buffer - if (m_transfer_buffer) - { - SDL_ReleaseGPUTransferBuffer(m_gpu->device(), m_transfer_buffer); - m_transfer_buffer = nullptr; - } } /** @@ -63,19 +56,14 @@ namespace sopho auto* device = m_gpu->device(); - // 2. Map the transfer buffer and copy data into it. - void* dst = SDL_MapGPUTransferBuffer(device, m_transfer_buffer, false); - if (!dst) + auto rst = m_transfer_buffer.submit(src_data); + if (!rst) { SDL_LogError(SDL_LOG_CATEGORY_GPU, "%s:%d failed to map transfer buffer: %s", __FILE__, __LINE__, SDL_GetError()); - - return std::unexpected(GpuError::MAP_TRANSFER_BUFFER_FAILED); + return std::unexpected(rst.error()); } - SDL_memcpy(dst, src_data, size); - SDL_UnmapGPUTransferBuffer(device, m_transfer_buffer); - // 3. Acquire a command buffer and enqueue the copy pass. auto* command_buffer = SDL_AcquireGPUCommandBuffer(device); if (!command_buffer) @@ -97,7 +85,7 @@ namespace sopho } SDL_GPUTransferBufferLocation location{}; - location.transfer_buffer = m_transfer_buffer; + location.transfer_buffer = m_transfer_buffer.raw(); location.offset = 0; SDL_GPUBufferRegion region{}; diff --git a/sdl_wrapper/src/sdl_wrapper.gpu.cpp b/sdl_wrapper/src/sdl_wrapper.gpu.cpp index ba37560..4193950 100644 --- a/sdl_wrapper/src/sdl_wrapper.gpu.cpp +++ b/sdl_wrapper/src/sdl_wrapper.gpu.cpp @@ -9,41 +9,13 @@ module; module sdl_wrapper; import :gpu; import :render_procedural; +import :buffer; import :render_data; import :vertex_layout; import :transfer_buffer; import :render_data_impl; namespace sopho { - /** - * @brief Create a GPU buffer and its associated upload transfer buffer. - * - * @param flag Usage flags for the GPU buffer. - * @param size Size in bytes of the buffer to allocate. - * @return std::expected BufferWrapper containing the created GPU buffer, its transfer - * buffer, and the buffer size on success; `std::unexpected` with a `GpuError` on failure. - */ - std::expected GpuWrapper::create_buffer(SDL_GPUBufferUsageFlags flag, uint32_t size) - { - SDL_GPUBufferCreateInfo create_info{.usage = flag, .size = size}; - auto gpu_buffer = SDL_CreateGPUBuffer(device(), &create_info); - if (!gpu_buffer) - { - SDL_LogError(SDL_LOG_CATEGORY_GPU, "%s:%d %s", __FILE__, __LINE__, SDL_GetError()); - return std::unexpected(GpuError::CREATE_GPU_BUFFER_FAILED); - } - SDL_GPUTransferBufferCreateInfo transfer_info{}; - transfer_info.usage = SDL_GPU_TRANSFERBUFFERUSAGE_UPLOAD; - transfer_info.size = size; - transfer_info.props = 0; - auto transfer_buffer = SDL_CreateGPUTransferBuffer(device(), &transfer_info); - if (!transfer_buffer) - { - SDL_LogError(SDL_LOG_CATEGORY_GPU, "%s:%d %s", __FILE__, __LINE__, SDL_GetError()); - return std::unexpected(GpuError::CREATE_TRANSFER_BUFFER_FAILED); - } - return BufferWrapper{shared_from_this(), gpu_buffer, transfer_buffer, size}; - } /** * @brief Create RenderData for a procedural render setup and given vertex count. * @@ -56,22 +28,23 @@ namespace sopho * @param vertex_count Number of vertices the allocated buffer must hold. * @return RenderData RenderData containing the allocated vertex buffer, the vertex layout, and `vertex_count`. */ - checkable> GpuWrapper::create_data(const RenderProcedural& render_procedural, + checkable> GpuWrapper::create_data(const RenderProcedural& render_procedural, uint32_t vertex_count) { auto size = render_procedural.vertex_layout().get_stride() * vertex_count; - auto vertex_buffer = create_buffer(SDL_GPU_BUFFERUSAGE_VERTEX, size); - auto index_buffer = create_buffer(SDL_GPU_BUFFERUSAGE_INDEX, 6 * sizeof(int)); + auto vertex_buffer = BufferWrapper::Builder{}.set_flag(SDL_GPU_BUFFERUSAGE_VERTEX).set_size(size).build(*this); if (!vertex_buffer) { return std::unexpected(vertex_buffer.error()); } + auto index_buffer = + BufferWrapper::Builder{}.set_flag(SDL_GPU_BUFFERUSAGE_INDEX).set_size(6 * sizeof(int)).build(*this); if (!index_buffer) { return std::unexpected(index_buffer.error()); } - return std::make_unique(std::move(vertex_buffer.value()), std::move(index_buffer.value()), - render_procedural.vertex_layout(), vertex_count); + return std::make_shared(std::move(vertex_buffer.value()), std::move(index_buffer.value()), + render_procedural.vertex_layout(), vertex_count); } /** * @brief Create a RenderProcedural configured for the device's texture format. From 8e5621523d955b7cf4ab5a1195177e112feb61a6 Mon Sep 17 00:00:00 2001 From: Sophomore Date: Tue, 25 Nov 2025 18:03:33 +0800 Subject: [PATCH 31/57] feat: Add type texture --- data_type/modules/data_type.ixx | 1 + main.cpp | 2 +- sdl_wrapper/CMakeLists.txt | 1 + sdl_wrapper/modules/sdl_wrapper.texture.ixx | 142 ++++++++++++++++++++ 4 files changed, 145 insertions(+), 1 deletion(-) create mode 100644 sdl_wrapper/modules/sdl_wrapper.texture.ixx diff --git a/data_type/modules/data_type.ixx b/data_type/modules/data_type.ixx index be836a1..e1b9478 100644 --- a/data_type/modules/data_type.ixx +++ b/data_type/modules/data_type.ixx @@ -18,6 +18,7 @@ export namespace sopho CLAIM_WINDOW_FAILED, CREATE_GPU_BUFFER_FAILED, CREATE_TRANSFER_BUFFER_FAILED, + CREATE_GPU_TEXTURE_FAILED, CREATE_SHADER_FAILED, CREATE_PIPELINE_FAILED, GET_TEXTUREFORMAT_FAILED, diff --git a/main.cpp b/main.cpp index ed7962b..58895e9 100644 --- a/main.cpp +++ b/main.cpp @@ -46,7 +46,7 @@ struct CameraUniform * @return sopho::ImageData Structure containing the loaded image dimensions, channels, and pixel data. * Returns an empty structure if loading fails. */ -auto load_image() +sopho::ImageData load_image() { stbi_set_flip_vertically_on_load(true); sopho::ImageData result; diff --git a/sdl_wrapper/CMakeLists.txt b/sdl_wrapper/CMakeLists.txt index e574666..299ab61 100644 --- a/sdl_wrapper/CMakeLists.txt +++ b/sdl_wrapper/CMakeLists.txt @@ -18,6 +18,7 @@ target_sources(sdl_wrapper modules/sdl_wrapper.decl.ixx modules/sdl_wrapper.vertex_layout.ixx modules/sdl_wrapper.transfer_buffer.ixx + modules/sdl_wrapper.texture.ixx PRIVATE src/sdl_wrapper.buffer.cpp src/sdl_wrapper.render_procedural.cpp diff --git a/sdl_wrapper/modules/sdl_wrapper.texture.ixx b/sdl_wrapper/modules/sdl_wrapper.texture.ixx new file mode 100644 index 0000000..caf7136 --- /dev/null +++ b/sdl_wrapper/modules/sdl_wrapper.texture.ixx @@ -0,0 +1,142 @@ +// sdl_wrapper.texture.ixx +// Created by wsqsy on 11/25/2025. +// + +module; +#include +#include +#include +#include +export module sdl_wrapper:texture; +import data_type; +import :decl; +import :gpu; + +namespace sopho +{ + class TextureWrapper + { + std::shared_ptr m_gpu{}; + SDL_GPUTexture* m_texture{}; + + TextureWrapper(std::shared_ptr gpu, SDL_GPUTexture* texture) noexcept : + m_gpu(std::move(gpu)), m_texture(texture) + { + } + + public: + TextureWrapper(const TextureWrapper&) = delete; + TextureWrapper& operator=(const TextureWrapper&) = delete; + TextureWrapper(TextureWrapper&& other) noexcept : m_gpu(std::move(other.m_gpu)), m_texture(other.m_texture) + { + other.m_texture = nullptr; + } + + TextureWrapper& operator=(TextureWrapper&& other) noexcept + { + if (this != &other) + { + reset(); + m_gpu = std::move(other.m_gpu); + m_texture = other.m_texture; + other.m_texture = nullptr; + } + return *this; + } + + [[nodiscard]] SDL_GPUTexture* get() const noexcept { return m_texture; } + + void reset() noexcept + { + if (m_texture && m_gpu) + { + SDL_ReleaseGPUTexture(m_gpu->device(), m_texture); + m_texture = nullptr; + } + } + + ~TextureWrapper() noexcept { reset(); } + + struct Builder + { + SDL_GPUTextureType type = SDL_GPU_TEXTURETYPE_2D; + SDL_GPUTextureFormat format = SDL_GPU_TEXTUREFORMAT_R8G8B8A8_UNORM; + SDL_GPUTextureUsageFlags usage = SDL_GPU_TEXTUREUSAGE_SAMPLER; + std::uint32_t width = 1; + std::uint32_t height = 1; + std::uint32_t layer_count_or_depth = 1; + std::uint32_t num_levels = 1; + SDL_GPUSampleCount sample_count = SDL_GPU_SAMPLECOUNT_1; + + Builder& set_type(SDL_GPUTextureType texture_type) + { + type = texture_type; + return *this; + } + + Builder& set_format(SDL_GPUTextureFormat texture_format) + { + format = texture_format; + return *this; + } + + Builder& set_usage(SDL_GPUTextureUsageFlags texture_usage) + { + usage = texture_usage; + return *this; + } + + Builder& set_width(std::uint32_t tex_width) + { + width = tex_width; + return *this; + } + + Builder& set_height(std::uint32_t tex_height) + { + height = tex_height; + return *this; + } + + Builder& set_layer_count_or_depth(std::uint32_t count_or_depth) + { + layer_count_or_depth = count_or_depth; + return *this; + } + + Builder& set_num_levels(std::uint32_t levels) + { + num_levels = levels; + return *this; + } + + Builder& set_sample_count(SDL_GPUSampleCount samples) + { + sample_count = samples; + return *this; + } + + std::expected build(GpuWrapper& gpu) + { + SDL_GPUTextureCreateInfo create_info{.type = type, + .format = format, + .usage = usage, + .width = width, + .height = height, + .layer_count_or_depth = layer_count_or_depth, + .num_levels = num_levels, + .sample_count = sample_count, + .props = 0}; + + auto* texture = SDL_CreateGPUTexture(gpu.device(), &create_info); + if (!texture) + { + SDL_LogError(SDL_LOG_CATEGORY_GPU, "Failed to create GPU texture: %s", SDL_GetError()); + return std::unexpected(GpuError::CREATE_GPU_TEXTURE_FAILED); + } + + return TextureWrapper{gpu.shared_from_this(), texture}; + } + }; + }; +} // namespace sopho From 3aeaf513164a6f6998a74cc86e1b0eafb7f28799 Mon Sep 17 00:00:00 2001 From: Sophomore <17792626+WSQS@users.noreply.github.com> Date: Tue, 25 Nov 2025 20:08:56 +0800 Subject: [PATCH 32/57] feat: export texture --- data_type/modules/data_type.ixx | 3 +- main.cpp | 1 + sdl_wrapper/CMakeLists.txt | 1 + sdl_wrapper/modules/sdl_wrapper.decl.ixx | 1 - sdl_wrapper/modules/sdl_wrapper.ixx | 1 + .../modules/sdl_wrapper.render_data.ixx | 1 + sdl_wrapper/modules/sdl_wrapper.texture.ixx | 102 ++------------- sdl_wrapper/src/sdl_wrapper.gpu.cpp | 35 ------ sdl_wrapper/src/sdl_wrapper.texture.cpp | 118 ++++++++++++++++++ 9 files changed, 136 insertions(+), 127 deletions(-) create mode 100644 sdl_wrapper/src/sdl_wrapper.texture.cpp diff --git a/data_type/modules/data_type.ixx b/data_type/modules/data_type.ixx index e1b9478..5c2ae6d 100644 --- a/data_type/modules/data_type.ixx +++ b/data_type/modules/data_type.ixx @@ -18,9 +18,10 @@ export namespace sopho CLAIM_WINDOW_FAILED, CREATE_GPU_BUFFER_FAILED, CREATE_TRANSFER_BUFFER_FAILED, - CREATE_GPU_TEXTURE_FAILED, + CREATE_TEXTURE_FAILED, CREATE_SHADER_FAILED, CREATE_PIPELINE_FAILED, + CREATE_SAMPLER_FAILED, GET_TEXTUREFORMAT_FAILED, BUFFER_OVERFLOW, MAP_TRANSFER_BUFFER_FAILED, diff --git a/main.cpp b/main.cpp index 58895e9..b7a7099 100644 --- a/main.cpp +++ b/main.cpp @@ -370,6 +370,7 @@ void main() info.props = 0; m_sampler = SDL_CreateGPUSampler(m_gpu->device(), &info); + sopho::TextureWrapper::Builder{}.set_image_data(m_image_data).build(*m_gpu.get()); return SDL_APP_CONTINUE; } diff --git a/sdl_wrapper/CMakeLists.txt b/sdl_wrapper/CMakeLists.txt index 299ab61..92ebfe3 100644 --- a/sdl_wrapper/CMakeLists.txt +++ b/sdl_wrapper/CMakeLists.txt @@ -24,6 +24,7 @@ target_sources(sdl_wrapper src/sdl_wrapper.render_procedural.cpp src/sdl_wrapper.gpu.cpp src/sdl_callback_implement.cpp + src/sdl_wrapper.texture.cpp ) target_link_libraries(sdl_wrapper PUBLIC SDL3::SDL3 shaderc glsl_reflector data_type) diff --git a/sdl_wrapper/modules/sdl_wrapper.decl.ixx b/sdl_wrapper/modules/sdl_wrapper.decl.ixx index 1bacec0..646621f 100644 --- a/sdl_wrapper/modules/sdl_wrapper.decl.ixx +++ b/sdl_wrapper/modules/sdl_wrapper.decl.ixx @@ -8,7 +8,6 @@ export namespace sopho { class App; class GpuWrapper; - class BufferWrapper; class RenderProcedural; class RenderData; } diff --git a/sdl_wrapper/modules/sdl_wrapper.ixx b/sdl_wrapper/modules/sdl_wrapper.ixx index 5d82468..430fbaf 100644 --- a/sdl_wrapper/modules/sdl_wrapper.ixx +++ b/sdl_wrapper/modules/sdl_wrapper.ixx @@ -10,3 +10,4 @@ export import :render_procedural; export import :renderable; export import :vertex_layout; export import :render_data; +export import :texture; diff --git a/sdl_wrapper/modules/sdl_wrapper.render_data.ixx b/sdl_wrapper/modules/sdl_wrapper.render_data.ixx index 9dd758b..160eed1 100644 --- a/sdl_wrapper/modules/sdl_wrapper.render_data.ixx +++ b/sdl_wrapper/modules/sdl_wrapper.render_data.ixx @@ -5,6 +5,7 @@ module; #include #include #include +#include export module sdl_wrapper:render_data; import :vertex_layout; namespace sopho diff --git a/sdl_wrapper/modules/sdl_wrapper.texture.ixx b/sdl_wrapper/modules/sdl_wrapper.texture.ixx index caf7136..7bc2c5c 100644 --- a/sdl_wrapper/modules/sdl_wrapper.texture.ixx +++ b/sdl_wrapper/modules/sdl_wrapper.texture.ixx @@ -4,32 +4,32 @@ module; #include -#include #include #include export module sdl_wrapper:texture; import data_type; import :decl; -import :gpu; namespace sopho { - class TextureWrapper + export class TextureWrapper { std::shared_ptr m_gpu{}; SDL_GPUTexture* m_texture{}; + SDL_GPUSampler* m_sampler{}; - TextureWrapper(std::shared_ptr gpu, SDL_GPUTexture* texture) noexcept : - m_gpu(std::move(gpu)), m_texture(texture) + TextureWrapper(std::shared_ptr gpu, SDL_GPUTexture* texture, SDL_GPUSampler* sampler) noexcept : + m_gpu(std::move(gpu)), m_texture(texture), m_sampler(sampler) { } public: TextureWrapper(const TextureWrapper&) = delete; TextureWrapper& operator=(const TextureWrapper&) = delete; - TextureWrapper(TextureWrapper&& other) noexcept : m_gpu(std::move(other.m_gpu)), m_texture(other.m_texture) + TextureWrapper(TextureWrapper&& other) noexcept : m_gpu(std::move(other.m_gpu)), m_texture(other.m_texture), m_sampler(other.m_sampler) { other.m_texture = nullptr; + other.m_sampler = nullptr; } TextureWrapper& operator=(TextureWrapper&& other) noexcept @@ -40,103 +40,25 @@ namespace sopho m_gpu = std::move(other.m_gpu); m_texture = other.m_texture; other.m_texture = nullptr; + m_sampler = other.m_sampler; + other.m_sampler = nullptr; } return *this; } [[nodiscard]] SDL_GPUTexture* get() const noexcept { return m_texture; } - void reset() noexcept - { - if (m_texture && m_gpu) - { - SDL_ReleaseGPUTexture(m_gpu->device(), m_texture); - m_texture = nullptr; - } - } + void reset() noexcept; ~TextureWrapper() noexcept { reset(); } struct Builder { - SDL_GPUTextureType type = SDL_GPU_TEXTURETYPE_2D; - SDL_GPUTextureFormat format = SDL_GPU_TEXTUREFORMAT_R8G8B8A8_UNORM; - SDL_GPUTextureUsageFlags usage = SDL_GPU_TEXTUREUSAGE_SAMPLER; - std::uint32_t width = 1; - std::uint32_t height = 1; - std::uint32_t layer_count_or_depth = 1; - std::uint32_t num_levels = 1; - SDL_GPUSampleCount sample_count = SDL_GPU_SAMPLECOUNT_1; - - Builder& set_type(SDL_GPUTextureType texture_type) - { - type = texture_type; - return *this; - } - - Builder& set_format(SDL_GPUTextureFormat texture_format) - { - format = texture_format; - return *this; - } - - Builder& set_usage(SDL_GPUTextureUsageFlags texture_usage) - { - usage = texture_usage; - return *this; - } + ImageData img_data{}; - Builder& set_width(std::uint32_t tex_width) - { - width = tex_width; - return *this; - } + Builder& set_image_data(ImageData image_data) { img_data = image_data; } - Builder& set_height(std::uint32_t tex_height) - { - height = tex_height; - return *this; - } - - Builder& set_layer_count_or_depth(std::uint32_t count_or_depth) - { - layer_count_or_depth = count_or_depth; - return *this; - } - - Builder& set_num_levels(std::uint32_t levels) - { - num_levels = levels; - return *this; - } - - Builder& set_sample_count(SDL_GPUSampleCount samples) - { - sample_count = samples; - return *this; - } - - std::expected build(GpuWrapper& gpu) - { - SDL_GPUTextureCreateInfo create_info{.type = type, - .format = format, - .usage = usage, - .width = width, - .height = height, - .layer_count_or_depth = layer_count_or_depth, - .num_levels = num_levels, - .sample_count = sample_count, - .props = 0}; - - auto* texture = SDL_CreateGPUTexture(gpu.device(), &create_info); - if (!texture) - { - SDL_LogError(SDL_LOG_CATEGORY_GPU, "Failed to create GPU texture: %s", SDL_GetError()); - return std::unexpected(GpuError::CREATE_GPU_TEXTURE_FAILED); - } - - return TextureWrapper{gpu.shared_from_this(), texture}; - } + std::expected build(GpuWrapper& gpu); }; }; } // namespace sopho diff --git a/sdl_wrapper/src/sdl_wrapper.gpu.cpp b/sdl_wrapper/src/sdl_wrapper.gpu.cpp index 4193950..baecd87 100644 --- a/sdl_wrapper/src/sdl_wrapper.gpu.cpp +++ b/sdl_wrapper/src/sdl_wrapper.gpu.cpp @@ -9,43 +9,8 @@ module; module sdl_wrapper; import :gpu; import :render_procedural; -import :buffer; -import :render_data; -import :vertex_layout; -import :transfer_buffer; -import :render_data_impl; namespace sopho { - /** - * @brief Create RenderData for a procedural render setup and given vertex count. - * - * Allocates a GPU vertex buffer sized to hold `vertex_count` vertices using the - * vertex layout from `render_procedural`, and returns a RenderData that owns - * the allocated buffer, the vertex layout, and the vertex count. If buffer - * creation fails, returns the corresponding GpuError. - * - * @param render_procedural Source procedural that provides the vertex layout. - * @param vertex_count Number of vertices the allocated buffer must hold. - * @return RenderData RenderData containing the allocated vertex buffer, the vertex layout, and `vertex_count`. - */ - checkable> GpuWrapper::create_data(const RenderProcedural& render_procedural, - uint32_t vertex_count) - { - auto size = render_procedural.vertex_layout().get_stride() * vertex_count; - auto vertex_buffer = BufferWrapper::Builder{}.set_flag(SDL_GPU_BUFFERUSAGE_VERTEX).set_size(size).build(*this); - if (!vertex_buffer) - { - return std::unexpected(vertex_buffer.error()); - } - auto index_buffer = - BufferWrapper::Builder{}.set_flag(SDL_GPU_BUFFERUSAGE_INDEX).set_size(6 * sizeof(int)).build(*this); - if (!index_buffer) - { - return std::unexpected(index_buffer.error()); - } - return std::make_shared(std::move(vertex_buffer.value()), std::move(index_buffer.value()), - render_procedural.vertex_layout(), vertex_count); - } /** * @brief Create a RenderProcedural configured for the device's texture format. * diff --git a/sdl_wrapper/src/sdl_wrapper.texture.cpp b/sdl_wrapper/src/sdl_wrapper.texture.cpp new file mode 100644 index 0000000..a1de4b7 --- /dev/null +++ b/sdl_wrapper/src/sdl_wrapper.texture.cpp @@ -0,0 +1,118 @@ +// sdl_wrapper.texture.cpp +// Created by sophomore on 11/25/25. +// +module; +#include +#include "SDL3/SDL_gpu.h" +#include "SDL3/SDL_log.h" +module sdl_wrapper; +import :texture; +import :transfer_buffer; +import :gpu; +namespace sopho +{ + + void TextureWrapper::reset() noexcept + { + if (m_texture && m_gpu) + { + SDL_ReleaseGPUTexture(m_gpu->device(), m_texture); + m_texture = nullptr; + } + if (m_sampler && m_gpu) + { + SDL_ReleaseGPUSampler(m_gpu->device(), m_sampler); + m_sampler = nullptr; + } + } + + std::expected TextureWrapper::Builder::build(GpuWrapper& gpu) + { + SDL_GPUTextureCreateInfo create_info{.type = SDL_GPU_TEXTURETYPE_2D, + .format = SDL_GPU_TEXTUREFORMAT_R8G8B8A8_UNORM, + .usage = SDL_GPU_TEXTUREUSAGE_SAMPLER, + .width = static_cast(img_data.width), + .height = static_cast(img_data.height), + .layer_count_or_depth = 1, + .num_levels = 1, + .sample_count = SDL_GPU_SAMPLECOUNT_1, + .props = 0}; + + auto* texture = SDL_CreateGPUTexture(gpu.device(), &create_info); + if (!texture) + { + SDL_LogError(SDL_LOG_CATEGORY_GPU, "Failed to create GPU texture: %s", SDL_GetError()); + return std::unexpected(GpuError::CREATE_TEXTURE_FAILED); + } + + auto c_tb = + TransferBufferWrapper::Builder{} + .set_usage_limit(2) + .set_size(static_cast(img_data.width) * static_cast(img_data.height) * 4) + .set_usage(SDL_GPU_TRANSFERBUFFERUSAGE_UPLOAD) + .build(gpu); + + auto submit_result = c_tb.and_then([&](auto tb) { return tb.submit(img_data.pixels.data()); }); + if (!submit_result) + { + return std::unexpected{submit_result.error()}; + } + SDL_GPUCommandBuffer* cmd = SDL_AcquireGPUCommandBuffer(gpu.device()); + if (!cmd) + { + SDL_Log("SDL_AcquireGPUCommandBuffer failed: %s", SDL_GetError()); + return std::unexpected{GpuError::ACQUIRE_COMMAND_BUFFER_FAILED}; + } + + SDL_GPUCopyPass* copy_pass = SDL_BeginGPUCopyPass(cmd); + if (!copy_pass) + { + SDL_Log("SDL_BeginGPUCopyPass failed: %s", SDL_GetError()); + return std::unexpected{GpuError::BEGIN_COPY_PASS_FAILED}; + } + + SDL_GPUTextureTransferInfo src{}; + src.transfer_buffer = c_tb.value().raw(); + src.offset = 0; + src.pixels_per_row = 0; + src.rows_per_layer = 0; + + SDL_GPUTextureRegion dst{}; + dst.texture = texture; + dst.mip_level = 0; + dst.layer = 0; + dst.x = 0; + dst.y = 0; + dst.z = 0; + dst.w = static_cast(img_data.width); + dst.h = static_cast(img_data.height); + dst.d = 1; + + SDL_UploadToGPUTexture(copy_pass, &src, &dst, false); + + SDL_EndGPUCopyPass(copy_pass); + SDL_SubmitGPUCommandBuffer(cmd); + + SDL_GPUSamplerCreateInfo info{}; + info.min_filter = SDL_GPU_FILTER_LINEAR; + info.mag_filter = SDL_GPU_FILTER_LINEAR; + info.max_anisotropy = 1.f; + info.mipmap_mode = SDL_GPU_SAMPLERMIPMAPMODE_LINEAR; + info.address_mode_u = SDL_GPU_SAMPLERADDRESSMODE_REPEAT; + info.address_mode_v = SDL_GPU_SAMPLERADDRESSMODE_REPEAT; + info.address_mode_w = SDL_GPU_SAMPLERADDRESSMODE_REPEAT; + info.enable_anisotropy = true; + info.enable_compare = false; + info.compare_op = SDL_GPU_COMPAREOP_ALWAYS; + info.props = 0; + + auto sampler = SDL_CreateGPUSampler(gpu.device(), &info); + if (!sampler) + { + SDL_Log("SDL_CreateGPUSampler failed: %s", SDL_GetError()); + return std::unexpected{GpuError::CREATE_SAMPLER_FAILED}; + } + + return TextureWrapper{gpu.shared_from_this(), texture, sampler}; + } +} // namespace sopho From b57945255e9f6a20cf253808bcc1ce265d48c796 Mon Sep 17 00:00:00 2001 From: Sophomore <17792626+WSQS@users.noreply.github.com> Date: Tue, 25 Nov 2025 20:22:59 +0800 Subject: [PATCH 33/57] feat: move transfer_buffer into cpp --- sdl_wrapper/CMakeLists.txt | 1 + .../modules/sdl_wrapper.transfer_buffer.ixx | 69 ++--------------- .../src/sdl_wrapper.transfer_buffer.cpp | 76 +++++++++++++++++++ 3 files changed, 84 insertions(+), 62 deletions(-) create mode 100644 sdl_wrapper/src/sdl_wrapper.transfer_buffer.cpp diff --git a/sdl_wrapper/CMakeLists.txt b/sdl_wrapper/CMakeLists.txt index 92ebfe3..e58f90c 100644 --- a/sdl_wrapper/CMakeLists.txt +++ b/sdl_wrapper/CMakeLists.txt @@ -25,6 +25,7 @@ target_sources(sdl_wrapper src/sdl_wrapper.gpu.cpp src/sdl_callback_implement.cpp src/sdl_wrapper.texture.cpp + src/sdl_wrapper.transfer_buffer.cpp ) target_link_libraries(sdl_wrapper PUBLIC SDL3::SDL3 shaderc glsl_reflector data_type) diff --git a/sdl_wrapper/modules/sdl_wrapper.transfer_buffer.ixx b/sdl_wrapper/modules/sdl_wrapper.transfer_buffer.ixx index 6d33555..af78667 100644 --- a/sdl_wrapper/modules/sdl_wrapper.transfer_buffer.ixx +++ b/sdl_wrapper/modules/sdl_wrapper.transfer_buffer.ixx @@ -9,15 +9,16 @@ * that allows specifying usage limits for automatic resource management. */ module; -#include +#include #include #include #include +#include #include "SDL3/SDL_gpu.h" #include "SDL3/SDL_log.h" export module sdl_wrapper:transfer_buffer; import data_type; -import :gpu; +import :decl; namespace sopho { @@ -49,19 +50,7 @@ namespace sopho other.m_transfer_buffer = nullptr; } - TransferBufferWrapper& operator=(TransferBufferWrapper&& other) noexcept - { - if (this != &other) - { - reset(); - m_gpu = std::move(other.m_gpu); - m_transfer_buffer = other.m_transfer_buffer; - m_usage_limit = other.m_usage_limit; - m_size = other.m_size; - other.m_transfer_buffer = nullptr; - } - return *this; - } + TransferBufferWrapper& operator=(TransferBufferWrapper&& other) noexcept; /* * @brief Destructor that releases the transfer buffer. @@ -71,14 +60,7 @@ namespace sopho /* * @brief Releases the underlying transfer buffer and resets state. */ - void reset() noexcept - { - if (m_transfer_buffer && m_gpu && m_gpu->device()) - { - SDL_ReleaseGPUTransferBuffer(m_gpu->device(), m_transfer_buffer); - m_transfer_buffer = nullptr; - } - } + void reset() noexcept; /* * @brief Returns the underlying SDL_GPUTransferBuffer pointer. @@ -90,30 +72,7 @@ namespace sopho */ [[nodiscard]] std::uint32_t size() const noexcept { return m_size; } - checkable submit(void* data_source) - { - assert(m_usage_limit != 0); - void* dst = SDL_MapGPUTransferBuffer(m_gpu->device(), m_transfer_buffer, false); - if (!dst) - { - SDL_LogError(SDL_LOG_CATEGORY_GPU, "%s:%d failed to map transfer buffer: %s", __FILE__, __LINE__, - SDL_GetError()); - - return std::unexpected(GpuError::MAP_TRANSFER_BUFFER_FAILED); - } - - SDL_memcpy(dst, data_source, m_size); - SDL_UnmapGPUTransferBuffer(m_gpu->device(), m_transfer_buffer); - if (m_usage_limit != -1) - { - m_usage_limit--; - if (m_usage_limit ==0) - { - reset(); - } - } - return {}; - } + checkable submit(void* data_source); /* * @brief Builder pattern for creating TransferBufferWrapper instances. @@ -173,21 +132,7 @@ namespace sopho * @param gpu The GPU wrapper to use for creating the transfer buffer * @return A checkable containing the TransferBufferWrapper on success, or an error on failure */ - checkable build(GpuWrapper& gpu) - { - SDL_GPUTransferBufferCreateInfo create_info{}; - create_info.usage = usage; - create_info.size = size; - - auto* transfer_buffer = SDL_CreateGPUTransferBuffer(gpu.device(), &create_info); - if (!transfer_buffer) - { - SDL_LogError(SDL_LOG_CATEGORY_GPU, "%s:%d %s", __FILE__, __LINE__, SDL_GetError()); - return std::unexpected(GpuError::CREATE_TRANSFER_BUFFER_FAILED); - } - - return TransferBufferWrapper{gpu.shared_from_this(), transfer_buffer, usage_limit, size}; - } + checkable build(GpuWrapper& gpu); }; }; } // namespace sopho diff --git a/sdl_wrapper/src/sdl_wrapper.transfer_buffer.cpp b/sdl_wrapper/src/sdl_wrapper.transfer_buffer.cpp new file mode 100644 index 0000000..3004438 --- /dev/null +++ b/sdl_wrapper/src/sdl_wrapper.transfer_buffer.cpp @@ -0,0 +1,76 @@ +// sdl_wrapper.transfer_buffer.cpp +// Created by sophomore on 11/25/25. +// +module; +#include + + +#include "SDL3/SDL_gpu.h" +#include "SDL3/SDL_log.h" +module sdl_wrapper; +import :transfer_buffer; +import :gpu; +namespace sopho +{ + TransferBufferWrapper& TransferBufferWrapper::operator=(TransferBufferWrapper&& other) noexcept + { + if (this != &other) + { + reset(); + m_gpu = std::move(other.m_gpu); + m_transfer_buffer = other.m_transfer_buffer; + m_usage_limit = other.m_usage_limit; + m_size = other.m_size; + other.m_transfer_buffer = nullptr; + } + return *this; + } + void TransferBufferWrapper::reset() + { + if (m_transfer_buffer && m_gpu && m_gpu->device()) + { + SDL_ReleaseGPUTransferBuffer(m_gpu->device(), m_transfer_buffer); + m_transfer_buffer = nullptr; + } + } + + checkable TransferBufferWrapper::submit(void* data_source) + { + assert(m_usage_limit != 0); + void* dst = SDL_MapGPUTransferBuffer(m_gpu->device(), m_transfer_buffer, false); + if (!dst) + { + SDL_LogError(SDL_LOG_CATEGORY_GPU, "%s:%d failed to map transfer buffer: %s", __FILE__, __LINE__, + SDL_GetError()); + + return std::unexpected(GpuError::MAP_TRANSFER_BUFFER_FAILED); + } + + SDL_memcpy(dst, data_source, m_size); + SDL_UnmapGPUTransferBuffer(m_gpu->device(), m_transfer_buffer); + if (m_usage_limit != -1) + { + m_usage_limit--; + if (m_usage_limit == 0) + { + reset(); + } + } + return {}; + } + checkable TransferBufferWrapper::Builder::build(GpuWrapper& gpu) + { + SDL_GPUTransferBufferCreateInfo create_info{}; + create_info.usage = usage; + create_info.size = size; + + auto* transfer_buffer = SDL_CreateGPUTransferBuffer(gpu.device(), &create_info); + if (!transfer_buffer) + { + SDL_LogError(SDL_LOG_CATEGORY_GPU, "%s:%d %s", __FILE__, __LINE__, SDL_GetError()); + return std::unexpected(GpuError::CREATE_TRANSFER_BUFFER_FAILED); + } + + return TransferBufferWrapper{gpu.shared_from_this(), transfer_buffer, usage_limit, size}; + } +} // namespace sopho From 80478b58a1cb014a4e8ae583cc24fa8ecacdc670 Mon Sep 17 00:00:00 2001 From: Sophomore <17792626+WSQS@users.noreply.github.com> Date: Tue, 25 Nov 2025 20:23:37 +0800 Subject: [PATCH 34/57] fix:Buffer not include gpu --- sdl_wrapper/modules/sdl_wrapper.buffer.ixx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sdl_wrapper/modules/sdl_wrapper.buffer.ixx b/sdl_wrapper/modules/sdl_wrapper.buffer.ixx index f8c931a..e4a2d07 100644 --- a/sdl_wrapper/modules/sdl_wrapper.buffer.ixx +++ b/sdl_wrapper/modules/sdl_wrapper.buffer.ixx @@ -11,7 +11,7 @@ module; export module sdl_wrapper:buffer; import data_type; -import :gpu; +import :decl; import :transfer_buffer; namespace sopho From 9c1c7a5831215ee8b3f7a1676d49c46fbe17089f Mon Sep 17 00:00:00 2001 From: Sophomore <17792626+WSQS@users.noreply.github.com> Date: Tue, 25 Nov 2025 20:46:07 +0800 Subject: [PATCH 35/57] fix: remove export on transfer buffer --- sdl_wrapper/modules/sdl_wrapper.buffer.ixx | 29 +++------------ .../modules/sdl_wrapper.render_data_impl.ixx | 6 +++ .../modules/sdl_wrapper.transfer_buffer.ixx | 2 +- sdl_wrapper/src/sdl_wrapper.buffer.cpp | 22 +++++++++++ sdl_wrapper/src/sdl_wrapper.gpu.cpp | 37 +++++++++++++++++++ sdl_wrapper/src/sdl_wrapper.texture.cpp | 3 +- .../src/sdl_wrapper.transfer_buffer.cpp | 4 +- 7 files changed, 76 insertions(+), 27 deletions(-) diff --git a/sdl_wrapper/modules/sdl_wrapper.buffer.ixx b/sdl_wrapper/modules/sdl_wrapper.buffer.ixx index e4a2d07..8294662 100644 --- a/sdl_wrapper/modules/sdl_wrapper.buffer.ixx +++ b/sdl_wrapper/modules/sdl_wrapper.buffer.ixx @@ -25,9 +25,10 @@ namespace sopho std::vector m_cpu_buffer{}; // Only GpuWrapper is allowed to construct this type. - BufferWrapper(std::shared_ptr gpu, SDL_GPUBuffer* gpu_buffer, - TransferBufferWrapper transfer_buffer, std::uint32_t size) noexcept : - m_gpu(std::move(gpu)), m_gpu_buffer(gpu_buffer), m_transfer_buffer(std::move(transfer_buffer)), m_buffer_size(size) + BufferWrapper(std::shared_ptr gpu, SDL_GPUBuffer* gpu_buffer, TransferBufferWrapper transfer_buffer, + std::uint32_t size) noexcept : + m_gpu(std::move(gpu)), m_gpu_buffer(gpu_buffer), m_transfer_buffer(std::move(transfer_buffer)), + m_buffer_size(size) { m_cpu_buffer.resize(m_buffer_size); } @@ -50,27 +51,7 @@ namespace sopho return *this; } - checkable build(GpuWrapper& gpu) - { - SDL_GPUBufferCreateInfo create_info{.usage = flag, .size = size}; - auto gpu_buffer = SDL_CreateGPUBuffer(gpu.device(), &create_info); - if (!gpu_buffer) - { - SDL_LogError(SDL_LOG_CATEGORY_GPU, "%s:%d %s", __FILE__, __LINE__, SDL_GetError()); - return std::unexpected(GpuError::CREATE_GPU_BUFFER_FAILED); - } - auto transfer_buffer = TransferBufferWrapper::Builder{} - .set_size(size) - .set_usage(SDL_GPU_TRANSFERBUFFERUSAGE_UPLOAD) - .set_usage_limit(-1) - .build(gpu); - if (!transfer_buffer) - { - SDL_LogError(SDL_LOG_CATEGORY_GPU, "%s:%d %s", __FILE__, __LINE__, SDL_GetError()); - return std::unexpected(transfer_buffer.error()); - } - return BufferWrapper{gpu.shared_from_this(), gpu_buffer, (std::move(transfer_buffer.value())), size}; - } + checkable build(GpuWrapper& gpu); }; BufferWrapper(const BufferWrapper&) = delete; diff --git a/sdl_wrapper/modules/sdl_wrapper.render_data_impl.ixx b/sdl_wrapper/modules/sdl_wrapper.render_data_impl.ixx index 1bcc7e6..b7065c7 100644 --- a/sdl_wrapper/modules/sdl_wrapper.render_data_impl.ixx +++ b/sdl_wrapper/modules/sdl_wrapper.render_data_impl.ixx @@ -2,7 +2,13 @@ // Created by wsqsy on 11/25/2025. // module; +#include +#include +#include #include +#include + +#include "SDL3/SDL_gpu.h" export module sdl_wrapper:render_data_impl; import :render_data; import :buffer; diff --git a/sdl_wrapper/modules/sdl_wrapper.transfer_buffer.ixx b/sdl_wrapper/modules/sdl_wrapper.transfer_buffer.ixx index af78667..7a85ac5 100644 --- a/sdl_wrapper/modules/sdl_wrapper.transfer_buffer.ixx +++ b/sdl_wrapper/modules/sdl_wrapper.transfer_buffer.ixx @@ -25,7 +25,7 @@ namespace sopho /* * @brief Wrapper class for SDL GPU transfer buffer operations. */ - export class TransferBufferWrapper + class TransferBufferWrapper { private: std::shared_ptr m_gpu{}; // Owns the device lifetime diff --git a/sdl_wrapper/src/sdl_wrapper.buffer.cpp b/sdl_wrapper/src/sdl_wrapper.buffer.cpp index 090640b..914e323 100644 --- a/sdl_wrapper/src/sdl_wrapper.buffer.cpp +++ b/sdl_wrapper/src/sdl_wrapper.buffer.cpp @@ -105,4 +105,26 @@ namespace sopho return std::monostate{}; } + checkable BufferWrapper::Builder::build(GpuWrapper& gpu) + { + SDL_GPUBufferCreateInfo create_info{.usage = flag, .size = size}; + auto gpu_buffer = SDL_CreateGPUBuffer(gpu.device(), &create_info); + if (!gpu_buffer) + { + SDL_LogError(SDL_LOG_CATEGORY_GPU, "%s:%d %s", __FILE__, __LINE__, SDL_GetError()); + return std::unexpected(GpuError::CREATE_GPU_BUFFER_FAILED); + } + auto transfer_buffer = TransferBufferWrapper::Builder{} + .set_size(size) + .set_usage(SDL_GPU_TRANSFERBUFFERUSAGE_UPLOAD) + .set_usage_limit(-1) + .build(gpu); + if (!transfer_buffer) + { + SDL_LogError(SDL_LOG_CATEGORY_GPU, "%s:%d %s", __FILE__, __LINE__, SDL_GetError()); + return std::unexpected(transfer_buffer.error()); + } + return BufferWrapper{gpu.shared_from_this(), gpu_buffer, (std::move(transfer_buffer.value())), size}; + } + } // namespace sopho diff --git a/sdl_wrapper/src/sdl_wrapper.gpu.cpp b/sdl_wrapper/src/sdl_wrapper.gpu.cpp index baecd87..5a967e1 100644 --- a/sdl_wrapper/src/sdl_wrapper.gpu.cpp +++ b/sdl_wrapper/src/sdl_wrapper.gpu.cpp @@ -9,8 +9,45 @@ module; module sdl_wrapper; import :gpu; import :render_procedural; +import :buffer; +import :render_data; +import :vertex_layout; +import :transfer_buffer; +import :render_data_impl; namespace sopho { + + /** + * @brief Create RenderData for a procedural render setup and given vertex count. + * + * Allocates a GPU vertex buffer sized to hold `vertex_count` vertices using the + * vertex layout from `render_procedural`, and returns a RenderData that owns + * the allocated buffer, the vertex layout, and the vertex count. If buffer + * creation fails, returns the corresponding GpuError. + * + * @param render_procedural Source procedural that provides the vertex layout. + * @param vertex_count Number of vertices the allocated buffer must hold. + * @return RenderData RenderData containing the allocated vertex buffer, the vertex layout, and `vertex_count`. + */ + checkable> GpuWrapper::create_data(const RenderProcedural& render_procedural, + uint32_t vertex_count) + { + auto size = render_procedural.vertex_layout().get_stride() * vertex_count; + auto vertex_buffer = BufferWrapper::Builder{}.set_flag(SDL_GPU_BUFFERUSAGE_VERTEX).set_size(size).build(*this); + if (!vertex_buffer) + { + return std::unexpected(vertex_buffer.error()); + } + auto index_buffer = + BufferWrapper::Builder{}.set_flag(SDL_GPU_BUFFERUSAGE_INDEX).set_size(6 * sizeof(int)).build(*this); + if (!index_buffer) + { + return std::unexpected(index_buffer.error()); + } + return std::make_shared(std::move(vertex_buffer.value()), std::move(index_buffer.value()), + render_procedural.vertex_layout(), vertex_count); + } + /** * @brief Create a RenderProcedural configured for the device's texture format. * diff --git a/sdl_wrapper/src/sdl_wrapper.texture.cpp b/sdl_wrapper/src/sdl_wrapper.texture.cpp index a1de4b7..be06b27 100644 --- a/sdl_wrapper/src/sdl_wrapper.texture.cpp +++ b/sdl_wrapper/src/sdl_wrapper.texture.cpp @@ -3,6 +3,7 @@ // module; #include +#include #include "SDL3/SDL_gpu.h" #include "SDL3/SDL_log.h" module sdl_wrapper; @@ -52,7 +53,7 @@ namespace sopho .set_usage(SDL_GPU_TRANSFERBUFFERUSAGE_UPLOAD) .build(gpu); - auto submit_result = c_tb.and_then([&](auto tb) { return tb.submit(img_data.pixels.data()); }); + auto submit_result = c_tb.and_then([&](auto& tb) { return tb.submit(img_data.pixels.data()); }); if (!submit_result) { return std::unexpected{submit_result.error()}; diff --git a/sdl_wrapper/src/sdl_wrapper.transfer_buffer.cpp b/sdl_wrapper/src/sdl_wrapper.transfer_buffer.cpp index 3004438..0611625 100644 --- a/sdl_wrapper/src/sdl_wrapper.transfer_buffer.cpp +++ b/sdl_wrapper/src/sdl_wrapper.transfer_buffer.cpp @@ -3,7 +3,9 @@ // module; #include - +#include +#include +#include #include "SDL3/SDL_gpu.h" #include "SDL3/SDL_log.h" From a8618c9665631f75ff8e3e96982a9b34e543bf44 Mon Sep 17 00:00:00 2001 From: Sophomore <17792626+WSQS@users.noreply.github.com> Date: Tue, 25 Nov 2025 20:50:34 +0800 Subject: [PATCH 36/57] fix: add missing return value for function --- sdl_wrapper/modules/sdl_wrapper.texture.ixx | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/sdl_wrapper/modules/sdl_wrapper.texture.ixx b/sdl_wrapper/modules/sdl_wrapper.texture.ixx index 7bc2c5c..702e2d0 100644 --- a/sdl_wrapper/modules/sdl_wrapper.texture.ixx +++ b/sdl_wrapper/modules/sdl_wrapper.texture.ixx @@ -56,7 +56,11 @@ namespace sopho { ImageData img_data{}; - Builder& set_image_data(ImageData image_data) { img_data = image_data; } + Builder& set_image_data(ImageData image_data) + { + img_data = image_data; + return *this; + } std::expected build(GpuWrapper& gpu); }; From 488e5569c33cde8c420b11c333c7de08ae75f018 Mon Sep 17 00:00:00 2001 From: Sophomore <17792626+WSQS@users.noreply.github.com> Date: Tue, 25 Nov 2025 21:02:00 +0800 Subject: [PATCH 37/57] feat: draw Texture using TextureWrapper --- main.cpp | 14 ++++++++------ sdl_wrapper/modules/sdl_wrapper.texture.ixx | 14 ++++++++++++-- 2 files changed, 20 insertions(+), 8 deletions(-) diff --git a/main.cpp b/main.cpp index b7a7099..b071f72 100644 --- a/main.cpp +++ b/main.cpp @@ -190,6 +190,7 @@ class UserApp : public sopho::App std::shared_ptr m_renderable{}; sopho::ImageData m_image_data; + std::shared_ptr m_texture_wrapper{}; SDL_GPUSampler* m_sampler; SDL_GPUTexture* m_texture; @@ -370,7 +371,12 @@ void main() info.props = 0; m_sampler = SDL_CreateGPUSampler(m_gpu->device(), &info); - sopho::TextureWrapper::Builder{}.set_image_data(m_image_data).build(*m_gpu.get()); + + auto texture = sopho::TextureWrapper::Builder{}.set_image_data(m_image_data).build(*m_gpu.get()); + if (texture) + { + m_texture_wrapper =std::make_shared(std::move(texture.value())); + } return SDL_APP_CONTINUE; } @@ -622,11 +628,7 @@ void main() SDL_BindGPUIndexBuffer(renderPass, &m_renderable->data()->get_index_buffer_binding(), SDL_GPU_INDEXELEMENTSIZE_32BIT); - SDL_GPUTextureSamplerBinding tex_binding{}; - tex_binding.texture = m_texture; - tex_binding.sampler = m_sampler; - - SDL_BindGPUFragmentSamplers(renderPass, 0, &tex_binding, 1); + SDL_BindGPUFragmentSamplers(renderPass, 0, m_texture_wrapper->get(), 1); SDL_DrawGPUIndexedPrimitives(renderPass, 6, 1, 0, 0, 0); diff --git a/sdl_wrapper/modules/sdl_wrapper.texture.ixx b/sdl_wrapper/modules/sdl_wrapper.texture.ixx index 702e2d0..0b07e1c 100644 --- a/sdl_wrapper/modules/sdl_wrapper.texture.ixx +++ b/sdl_wrapper/modules/sdl_wrapper.texture.ixx @@ -17,19 +17,23 @@ namespace sopho std::shared_ptr m_gpu{}; SDL_GPUTexture* m_texture{}; SDL_GPUSampler* m_sampler{}; + SDL_GPUTextureSamplerBinding m_tex_binding{}; TextureWrapper(std::shared_ptr gpu, SDL_GPUTexture* texture, SDL_GPUSampler* sampler) noexcept : m_gpu(std::move(gpu)), m_texture(texture), m_sampler(sampler) { + m_tex_binding.texture = m_texture; + m_tex_binding.sampler = m_sampler; } public: TextureWrapper(const TextureWrapper&) = delete; TextureWrapper& operator=(const TextureWrapper&) = delete; - TextureWrapper(TextureWrapper&& other) noexcept : m_gpu(std::move(other.m_gpu)), m_texture(other.m_texture), m_sampler(other.m_sampler) + 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 = {}; } TextureWrapper& operator=(TextureWrapper&& other) noexcept @@ -42,11 +46,17 @@ namespace sopho other.m_texture = nullptr; m_sampler = other.m_sampler; other.m_sampler = nullptr; + other.m_tex_binding = {}; + m_tex_binding.texture = m_texture; + m_tex_binding.sampler = m_sampler; } return *this; } - [[nodiscard]] SDL_GPUTexture* get() const noexcept { return m_texture; } + [[nodiscard]] const SDL_GPUTextureSamplerBinding* get() const noexcept + { + return &m_tex_binding; + } void reset() noexcept; From 9d97e617c5f686c92adc544514688de5f49b7fb9 Mon Sep 17 00:00:00 2001 From: Sophomore <17792626+WSQS@users.noreply.github.com> Date: Tue, 25 Nov 2025 21:03:17 +0800 Subject: [PATCH 38/57] fix: add noexcept identifier --- sdl_wrapper/src/sdl_wrapper.transfer_buffer.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sdl_wrapper/src/sdl_wrapper.transfer_buffer.cpp b/sdl_wrapper/src/sdl_wrapper.transfer_buffer.cpp index 0611625..fc45749 100644 --- a/sdl_wrapper/src/sdl_wrapper.transfer_buffer.cpp +++ b/sdl_wrapper/src/sdl_wrapper.transfer_buffer.cpp @@ -27,7 +27,7 @@ namespace sopho } return *this; } - void TransferBufferWrapper::reset() + void TransferBufferWrapper::reset() noexcept { if (m_transfer_buffer && m_gpu && m_gpu->device()) { From 8189d63ec5c001f857fea2cc7021fb8d87e430fe Mon Sep 17 00:00:00 2001 From: Sophomore <17792626+WSQS@users.noreply.github.com> Date: Tue, 25 Nov 2025 21:42:13 +0800 Subject: [PATCH 39/57] fix: remove test texture --- main.cpp | 139 +------------------------------------------------------ 1 file changed, 1 insertion(+), 138 deletions(-) diff --git a/main.cpp b/main.cpp index b071f72..4003662 100644 --- a/main.cpp +++ b/main.cpp @@ -67,121 +67,6 @@ sopho::ImageData load_image() return result; } -/** - * @brief Creates a GPU texture from image data. - * - * Creates a 2D RGBA8 texture with sampler usage based on the provided image data. - * - * @param device Pointer to the SDL GPU device. - * @param img Reference to the ImageData structure containing image information. - * @return SDL_GPUTexture* Pointer to the created GPU texture, or nullptr on failure. - */ -SDL_GPUTexture* create_texture_from_image(SDL_GPUDevice* device, const sopho::ImageData& img) -{ - SDL_GPUTextureCreateInfo create_info{.type = SDL_GPU_TEXTURETYPE_2D, - .format = SDL_GPU_TEXTUREFORMAT_R8G8B8A8_UNORM, - .usage = SDL_GPU_TEXTUREUSAGE_SAMPLER, - .width = static_cast(img.width), - .height = static_cast(img.height), - .layer_count_or_depth = 1, - .num_levels = 1, - .sample_count = SDL_GPU_SAMPLECOUNT_1, - .props = 0}; - return SDL_CreateGPUTexture(device, &create_info); -} - -/** - * @brief Creates a GPU transfer buffer for texture data upload. - * - * Creates an upload transfer buffer containing the image data for efficient GPU upload. - * - * @param device Pointer to the SDL GPU device. - * @param img Reference to the ImageData structure containing image information. - * @return SDL_GPUTransferBuffer* Pointer to the created GPU transfer buffer, or nullptr on failure. - */ -SDL_GPUTransferBuffer* create_texture_transfer_buffer(SDL_GPUDevice* device, const sopho::ImageData& img) -{ - const Uint32 bytes_per_pixel = 4; - const Uint32 size_in_bytes = static_cast(img.width) * static_cast(img.height) * bytes_per_pixel; - - SDL_GPUTransferBufferCreateInfo info{ - .usage = SDL_GPU_TRANSFERBUFFERUSAGE_UPLOAD, .size = size_in_bytes, .props = 0}; - - SDL_GPUTransferBuffer* transfer = SDL_CreateGPUTransferBuffer(device, &info); - if (!transfer) - { - SDL_Log("Failed to create transfer buffer: %s", SDL_GetError()); - return nullptr; - } - - void* ptr = SDL_MapGPUTransferBuffer(device, transfer, false); - if (!ptr) - { - SDL_Log("Failed to map transfer buffer: %s", SDL_GetError()); - SDL_ReleaseGPUTransferBuffer(device, transfer); - return nullptr; - } - - SDL_memcpy(ptr, img.pixels.data(), size_in_bytes); - SDL_UnmapGPUTransferBuffer(device, transfer); - - return transfer; -} - -/** - * @brief Uploads texture data from transfer buffer to GPU texture. - * - * Performs a GPU copy operation to upload texture data from the provided transfer buffer to the target texture. - * - * @param device Pointer to the SDL GPU device. - * @param texture Pointer to the target GPU texture. - * @param transfer Pointer to the source GPU transfer buffer containing texture data. - * @param width Width of the texture in pixels. - * @param height Height of the texture in pixels. - */ -void upload_texture_full(SDL_GPUDevice* device, SDL_GPUTexture* texture, SDL_GPUTransferBuffer* transfer, int width, - int height) -{ - SDL_GPUCommandBuffer* cmd = SDL_AcquireGPUCommandBuffer(device); - if (!cmd) - { - SDL_Log("SDL_AcquireGPUCommandBuffer failed: %s", SDL_GetError()); - return; - } - - SDL_GPUCopyPass* copy_pass = SDL_BeginGPUCopyPass(cmd); - if (!copy_pass) - { - SDL_Log("SDL_BeginGPUCopyPass failed: %s", SDL_GetError()); - return; - } - - const Uint32 bytes_per_pixel = 4; // RGBA8 - const Uint32 row_bytes = static_cast(width) * bytes_per_pixel; - - SDL_GPUTextureTransferInfo src{}; - src.transfer_buffer = transfer; - src.offset = 0; - src.pixels_per_row = 0; - src.rows_per_layer = 0; - - SDL_GPUTextureRegion dst{}; - dst.texture = texture; - dst.mip_level = 0; - dst.layer = 0; - dst.x = 0; - dst.y = 0; - dst.z = 0; - dst.w = static_cast(width); - dst.h = static_cast(height); - dst.d = 1; - - SDL_UploadToGPUTexture(copy_pass, &src, &dst, false); - - SDL_EndGPUCopyPass(copy_pass); - SDL_SubmitGPUCommandBuffer(cmd); -} - class UserApp : public sopho::App { // GPU + resources @@ -191,8 +76,6 @@ class UserApp : public sopho::App sopho::ImageData m_image_data; std::shared_ptr m_texture_wrapper{}; - SDL_GPUSampler* m_sampler; - SDL_GPUTexture* m_texture; // camera state float yaw = 0.0f; @@ -276,7 +159,7 @@ void main() } // 3. Create vertex buffer. - auto render_data = std::move(m_gpu->create_data(pw_result.value(), 4)); + auto render_data = m_gpu->create_data(pw_result.value(), 4); if (!render_data) { SDL_LogError(SDL_LOG_CATEGORY_ERROR, "Failed to create vertex buffer, error = %d", @@ -353,24 +236,6 @@ void main() ImGui_ImplSDLGPU3_Init(&init_info); m_image_data = load_image(); - m_texture = create_texture_from_image(m_gpu->device(), m_image_data); - auto transfer_buffer = create_texture_transfer_buffer(m_gpu->device(), m_image_data); - upload_texture_full(m_gpu->device(), m_texture, transfer_buffer, m_image_data.width, m_image_data.height); - SDL_ReleaseGPUTransferBuffer(m_gpu->device(), transfer_buffer); - SDL_GPUSamplerCreateInfo info{}; - info.min_filter = SDL_GPU_FILTER_LINEAR; - info.mag_filter = SDL_GPU_FILTER_LINEAR; - info.max_anisotropy = 1.f; - info.mipmap_mode = SDL_GPU_SAMPLERMIPMAPMODE_LINEAR; - info.address_mode_u = SDL_GPU_SAMPLERADDRESSMODE_REPEAT; - info.address_mode_v = SDL_GPU_SAMPLERADDRESSMODE_REPEAT; - info.address_mode_w = SDL_GPU_SAMPLERADDRESSMODE_REPEAT; - info.enable_anisotropy = true; - info.enable_compare = false; - info.compare_op = SDL_GPU_COMPAREOP_ALWAYS; - info.props = 0; - - m_sampler = SDL_CreateGPUSampler(m_gpu->device(), &info); auto texture = sopho::TextureWrapper::Builder{}.set_image_data(m_image_data).build(*m_gpu.get()); if (texture) @@ -690,8 +555,6 @@ void main() ImGui_ImplSDL3_Shutdown(); ImGui_ImplSDLGPU3_Shutdown(); ImGui::DestroyContext(); - SDL_ReleaseGPUTexture(m_gpu->device(), m_texture); - SDL_ReleaseGPUSampler(m_gpu->device(), m_sampler); } }; From 2921e9c50f4f1760c57e86a76e877549f8547a91 Mon Sep 17 00:00:00 2001 From: Sophomore <17792626+WSQS@users.noreply.github.com> Date: Tue, 25 Nov 2025 21:43:12 +0800 Subject: [PATCH 40/57] feat:set imgui and stb header file as system --- CMakeLists.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index a9896e4..21cf4db 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -88,7 +88,7 @@ add_library(imgui STATIC ${IMGUI_DIR}/backends/imgui_impl_sdlgpu3.cpp ${IMGUI_DIR}/misc/cpp/imgui_stdlib.cpp ) -target_include_directories(imgui PUBLIC +target_include_directories(imgui SYSTEM PUBLIC ${IMGUI_DIR} ${IMGUI_DIR}/backends ) @@ -103,7 +103,7 @@ FetchContent_Declare( ) FetchContent_MakeAvailable(stb) add_library(stb INTERFACE) -target_include_directories(stb INTERFACE ${stb_SOURCE_DIR}) +target_include_directories(stb SYSTEM INTERFACE ${stb_SOURCE_DIR}) FetchContent_Declare( googletest From 8849833c95479b607bf88272f577713773545e36 Mon Sep 17 00:00:00 2001 From: Sophomore <17792626+WSQS@users.noreply.github.com> Date: Tue, 25 Nov 2025 23:06:40 +0800 Subject: [PATCH 41/57] feat:clean up readme --- README.md | 4 ---- 1 file changed, 4 deletions(-) diff --git a/README.md b/README.md index 14f884e..ced3dfa 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,3 @@ # SDL Test This is a personal learning project following [Learn OpenGL](https://learnopengl.com/) - -## Comment Format - -Using block comments `/*...*/`. From 6cdeac1582263115d0949c16bfbb269db0b46005 Mon Sep 17 00:00:00 2001 From: Sophomore <17792626+WSQS@users.noreply.github.com> Date: Tue, 25 Nov 2025 23:14:05 +0800 Subject: [PATCH 42/57] feat:Add Track in Readme --- README.md | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/README.md b/README.md index ced3dfa..2dde53b 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,22 @@ # SDL Test This is a personal learning project following [Learn OpenGL](https://learnopengl.com/) + +## Track + +- [ ] Getting started + - [x] OpenGL + - [x] Creating a window + - [x] Hello Window + - [x] Hello Triangle + - [x] Shaders + - [x] Textures + - [ ] Transformations + - [ ] Coordinate Systems + - [ ] Camera +- [ ] Lighting +- [ ] Model Loading +- [ ] Advanced OpenGL +- [ ] Advanced Lighting +- [ ] PBR +- [ ] In Practice From dab40344df26e3592e7f872b30ffc79b92ebcbcf Mon Sep 17 00:00:00 2001 From: Sophomore Date: Wed, 26 Nov 2025 08:55:24 +0800 Subject: [PATCH 43/57] fix: release command buffer if begin copy pass failed --- sdl_wrapper/src/sdl_wrapper.texture.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/sdl_wrapper/src/sdl_wrapper.texture.cpp b/sdl_wrapper/src/sdl_wrapper.texture.cpp index be06b27..0130c6a 100644 --- a/sdl_wrapper/src/sdl_wrapper.texture.cpp +++ b/sdl_wrapper/src/sdl_wrapper.texture.cpp @@ -68,6 +68,7 @@ namespace sopho SDL_GPUCopyPass* copy_pass = SDL_BeginGPUCopyPass(cmd); if (!copy_pass) { + SDL_SubmitGPUCommandBuffer(cmd); SDL_Log("SDL_BeginGPUCopyPass failed: %s", SDL_GetError()); return std::unexpected{GpuError::BEGIN_COPY_PASS_FAILED}; } From 5df9b86116db9ff5596746f221916018da03cefa Mon Sep 17 00:00:00 2001 From: Sophomore Date: Wed, 26 Nov 2025 08:58:24 +0800 Subject: [PATCH 44/57] fix:check texture wrapper before using --- main.cpp | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/main.cpp b/main.cpp index 4003662..70c2d8c 100644 --- a/main.cpp +++ b/main.cpp @@ -492,8 +492,15 @@ void main() SDL_BindGPUIndexBuffer(renderPass, &m_renderable->data()->get_index_buffer_binding(), SDL_GPU_INDEXELEMENTSIZE_32BIT); + if (m_texture_wrapper) + { + SDL_BindGPUFragmentSamplers(renderPass, 0, m_texture_wrapper->get(), 1); + } + else + { + SDL_LogError(SDL_LOG_CATEGORY_GPU, "Texture not available, skip binding sampler"); + } - SDL_BindGPUFragmentSamplers(renderPass, 0, m_texture_wrapper->get(), 1); SDL_DrawGPUIndexedPrimitives(renderPass, 6, 1, 0, 0, 0); From e522e57d93f5b311c9ad4f6b14fdd1c1796e66aa Mon Sep 17 00:00:00 2001 From: Sophomore Date: Wed, 26 Nov 2025 08:58:45 +0800 Subject: [PATCH 45/57] fix: update vertex count --- main.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/main.cpp b/main.cpp index 70c2d8c..a7ba8b1 100644 --- a/main.cpp +++ b/main.cpp @@ -343,7 +343,7 @@ void main() } else { - auto new_data = m_gpu->create_data(*m_renderable->procedural(), 3); + auto new_data = m_gpu->create_data(*m_renderable->procedural(), 4); m_renderable->data() = std::move(new_data.value()); m_renderable->data()->upload(); } From bcd257e2c0f5e6cedb0aa3fd17cb467e69586e65 Mon Sep 17 00:00:00 2001 From: Sophomore Date: Wed, 26 Nov 2025 09:28:20 +0800 Subject: [PATCH 46/57] feat: make file name correct --- main.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/main.cpp b/main.cpp index a7ba8b1..c2fa599 100644 --- a/main.cpp +++ b/main.cpp @@ -49,13 +49,14 @@ struct CameraUniform 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("assets/test_texture.png", &result.width, &result.height, &result.channels, 4); + 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", "test.png", stbi_failure_reason()); + SDL_Log("stbi_load failed for %s: %s", file_name.data(), stbi_failure_reason()); } else { From b8e7d4d6ea1a3e5de88dd782135beae00e6f35aa Mon Sep 17 00:00:00 2001 From: Sophomore Date: Wed, 26 Nov 2025 09:28:45 +0800 Subject: [PATCH 47/57] feat: format document --- main.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/main.cpp b/main.cpp index c2fa599..c9402fd 100644 --- a/main.cpp +++ b/main.cpp @@ -241,7 +241,7 @@ void main() auto texture = sopho::TextureWrapper::Builder{}.set_image_data(m_image_data).build(*m_gpu.get()); if (texture) { - m_texture_wrapper =std::make_shared(std::move(texture.value())); + m_texture_wrapper = std::make_shared(std::move(texture.value())); } return SDL_APP_CONTINUE; } From 955f9d3571be582ffd478886d104e5f760988f3e Mon Sep 17 00:00:00 2001 From: Sophomore Date: Wed, 26 Nov 2025 10:36:42 +0800 Subject: [PATCH 48/57] feat: Add missing header file --- sdl_wrapper/modules/sdl_wrapper.render_data.ixx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/sdl_wrapper/modules/sdl_wrapper.render_data.ixx b/sdl_wrapper/modules/sdl_wrapper.render_data.ixx index 160eed1..50daeaf 100644 --- a/sdl_wrapper/modules/sdl_wrapper.render_data.ixx +++ b/sdl_wrapper/modules/sdl_wrapper.render_data.ixx @@ -3,9 +3,10 @@ // module; #include -#include +#include #include #include +#include export module sdl_wrapper:render_data; import :vertex_layout; namespace sopho From 3577ff3cb25e497d07dfb4320a3cb2e92ebc4d04 Mon Sep 17 00:00:00 2001 From: Sophomore Date: Wed, 26 Nov 2025 10:38:29 +0800 Subject: [PATCH 49/57] fix: change submit function signature --- sdl_wrapper/modules/sdl_wrapper.transfer_buffer.ixx | 2 +- sdl_wrapper/src/sdl_wrapper.transfer_buffer.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/sdl_wrapper/modules/sdl_wrapper.transfer_buffer.ixx b/sdl_wrapper/modules/sdl_wrapper.transfer_buffer.ixx index 7a85ac5..c169fe7 100644 --- a/sdl_wrapper/modules/sdl_wrapper.transfer_buffer.ixx +++ b/sdl_wrapper/modules/sdl_wrapper.transfer_buffer.ixx @@ -72,7 +72,7 @@ namespace sopho */ [[nodiscard]] std::uint32_t size() const noexcept { return m_size; } - checkable submit(void* data_source); + checkable submit(const void* data_source); /* * @brief Builder pattern for creating TransferBufferWrapper instances. diff --git a/sdl_wrapper/src/sdl_wrapper.transfer_buffer.cpp b/sdl_wrapper/src/sdl_wrapper.transfer_buffer.cpp index fc45749..b11e8e2 100644 --- a/sdl_wrapper/src/sdl_wrapper.transfer_buffer.cpp +++ b/sdl_wrapper/src/sdl_wrapper.transfer_buffer.cpp @@ -36,7 +36,7 @@ namespace sopho } } - checkable TransferBufferWrapper::submit(void* data_source) + checkable TransferBufferWrapper::submit(const void* data_source) { assert(m_usage_limit != 0); void* dst = SDL_MapGPUTransferBuffer(m_gpu->device(), m_transfer_buffer, false); From 8dff3d4a076a8fabdc2ae14b9e06e91aa508a935 Mon Sep 17 00:00:00 2001 From: Sophomore Date: Wed, 26 Nov 2025 10:44:00 +0800 Subject: [PATCH 50/57] fix: add initializer sampler_count --- data_type/modules/data_type.ixx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/data_type/modules/data_type.ixx b/data_type/modules/data_type.ixx index 5c2ae6d..5b4948e 100644 --- a/data_type/modules/data_type.ixx +++ b/data_type/modules/data_type.ixx @@ -65,7 +65,7 @@ export namespace sopho struct FragmentReflection { - std::uint32_t sampler_count; + std::uint32_t sampler_count{}; }; } // namespace sopho From 4557e6ea4b8a7f7597f27736f5ca105483f8631b Mon Sep 17 00:00:00 2001 From: Sophomore Date: Wed, 26 Nov 2025 10:46:01 +0800 Subject: [PATCH 51/57] fix: add std::move --- sdl_wrapper/modules/sdl_wrapper.texture.ixx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/sdl_wrapper/modules/sdl_wrapper.texture.ixx b/sdl_wrapper/modules/sdl_wrapper.texture.ixx index 0b07e1c..ec3a6db 100644 --- a/sdl_wrapper/modules/sdl_wrapper.texture.ixx +++ b/sdl_wrapper/modules/sdl_wrapper.texture.ixx @@ -6,6 +6,7 @@ module; #include #include #include +#include export module sdl_wrapper:texture; import data_type; import :decl; @@ -68,7 +69,7 @@ namespace sopho Builder& set_image_data(ImageData image_data) { - img_data = image_data; + img_data = std::move(image_data); return *this; } From 24645d1cf5506435731fcf7119710525e6cb9c1a Mon Sep 17 00:00:00 2001 From: Sophomore Date: Wed, 26 Nov 2025 10:50:19 +0800 Subject: [PATCH 52/57] log: add log for create texture failed --- main.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/main.cpp b/main.cpp index c9402fd..f8a71ac 100644 --- a/main.cpp +++ b/main.cpp @@ -243,6 +243,11 @@ void main() { m_texture_wrapper = std::make_shared(std::move(texture.value())); } + else + { + SDL_LogWarn(SDL_LOG_CATEGORY_GPU, "Failed to create texture: error = %d", + static_cast(texture.error())); + } return SDL_APP_CONTINUE; } From 5ae60b4193f8cd4adf312525b7231bf65eeab2ac Mon Sep 17 00:00:00 2001 From: Sophomore Date: Wed, 26 Nov 2025 10:56:44 +0800 Subject: [PATCH 53/57] fix: add index count for RenderData --- main.cpp | 4 ++-- sdl_wrapper/modules/sdl_wrapper.gpu.ixx | 3 +-- sdl_wrapper/modules/sdl_wrapper.render_data_impl.ixx | 9 +++++---- sdl_wrapper/src/sdl_wrapper.gpu.cpp | 6 ++++-- 4 files changed, 12 insertions(+), 10 deletions(-) diff --git a/main.cpp b/main.cpp index f8a71ac..81eef1a 100644 --- a/main.cpp +++ b/main.cpp @@ -160,7 +160,7 @@ void main() } // 3. Create vertex buffer. - auto render_data = m_gpu->create_data(pw_result.value(), 4); + auto render_data = m_gpu->create_data(pw_result.value(), 4, 6); if (!render_data) { SDL_LogError(SDL_LOG_CATEGORY_ERROR, "Failed to create vertex buffer, error = %d", @@ -349,7 +349,7 @@ void main() } else { - auto new_data = m_gpu->create_data(*m_renderable->procedural(), 4); + auto new_data = m_gpu->create_data(*m_renderable->procedural(), 4, 6); m_renderable->data() = std::move(new_data.value()); m_renderable->data()->upload(); } diff --git a/sdl_wrapper/modules/sdl_wrapper.gpu.ixx b/sdl_wrapper/modules/sdl_wrapper.gpu.ixx index 00e28b7..ea8c19a 100644 --- a/sdl_wrapper/modules/sdl_wrapper.gpu.ixx +++ b/sdl_wrapper/modules/sdl_wrapper.gpu.ixx @@ -210,8 +210,7 @@ export namespace sopho [[nodiscard]] auto device() const { return m_ctx.device.raw; } [[nodiscard]] SDL_Window* window() const { return m_ctx.window.raw; } - [[nodiscard]] checkable> create_data(const RenderProcedural& render_procedural, - uint32_t vertex_count); + [[nodiscard]] checkable> create_data(const RenderProcedural& render_procedural, std::uint32_t vertex_count, std::uint32_t index_count); auto release_buffer(SDL_GPUBuffer* buffer) { diff --git a/sdl_wrapper/modules/sdl_wrapper.render_data_impl.ixx b/sdl_wrapper/modules/sdl_wrapper.render_data_impl.ixx index b7065c7..5ee4bc1 100644 --- a/sdl_wrapper/modules/sdl_wrapper.render_data_impl.ixx +++ b/sdl_wrapper/modules/sdl_wrapper.render_data_impl.ixx @@ -20,14 +20,15 @@ namespace sopho BufferWrapper m_index_buffer; VertexLayout m_layouts{}; size_t m_vertex_count{}; + size_t m_index_count{}; std::vector m_bindings{}; SDL_GPUBufferBinding m_index_binding{}; public: - explicit RenderDataImpl(BufferWrapper&& vertex_buffer_wrapper, BufferWrapper&& index_buffer_wrapper, - const VertexLayout& layouts, size_t vertex_count) : + RenderDataImpl(BufferWrapper&& vertex_buffer_wrapper, BufferWrapper&& index_buffer_wrapper, + const VertexLayout& layouts, size_t vertex_count, std::uint32_t index_count) : m_vertex_buffer(std::move(vertex_buffer_wrapper)), m_index_buffer(std::move(index_buffer_wrapper)), - m_layouts(layouts), m_vertex_count(vertex_count) + m_layouts(layouts), m_vertex_count(vertex_count),m_index_count(index_count) { m_bindings.emplace_back(m_vertex_buffer.gpu_buffer(), 0); m_index_binding.buffer = m_index_buffer.gpu_buffer(); @@ -45,7 +46,7 @@ namespace sopho } virtual IndexView index_view() override { - return IndexView{.index_count = m_vertex_count, .raw = m_index_buffer.cpu_buffer()}; + return IndexView{.index_count = m_index_count, .raw = m_index_buffer.cpu_buffer()}; } virtual std::expected upload() override { diff --git a/sdl_wrapper/src/sdl_wrapper.gpu.cpp b/sdl_wrapper/src/sdl_wrapper.gpu.cpp index 5a967e1..3234354 100644 --- a/sdl_wrapper/src/sdl_wrapper.gpu.cpp +++ b/sdl_wrapper/src/sdl_wrapper.gpu.cpp @@ -27,10 +27,12 @@ namespace sopho * * @param render_procedural Source procedural that provides the vertex layout. * @param vertex_count Number of vertices the allocated buffer must hold. + * @param index_count * @return RenderData RenderData containing the allocated vertex buffer, the vertex layout, and `vertex_count`. */ checkable> GpuWrapper::create_data(const RenderProcedural& render_procedural, - uint32_t vertex_count) + std::uint32_t vertex_count, + std::uint32_t index_count) { auto size = render_procedural.vertex_layout().get_stride() * vertex_count; auto vertex_buffer = BufferWrapper::Builder{}.set_flag(SDL_GPU_BUFFERUSAGE_VERTEX).set_size(size).build(*this); @@ -45,7 +47,7 @@ namespace sopho return std::unexpected(index_buffer.error()); } return std::make_shared(std::move(vertex_buffer.value()), std::move(index_buffer.value()), - render_procedural.vertex_layout(), vertex_count); + render_procedural.vertex_layout(), vertex_count, index_count); } /** From b62817a9c44ec837641632e5be70c76f889b92ca Mon Sep 17 00:00:00 2001 From: Sophomore Date: Wed, 26 Nov 2025 10:58:10 +0800 Subject: [PATCH 54/57] fix: release buffer to avoid leak --- sdl_wrapper/src/sdl_wrapper.buffer.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/sdl_wrapper/src/sdl_wrapper.buffer.cpp b/sdl_wrapper/src/sdl_wrapper.buffer.cpp index 914e323..6454a93 100644 --- a/sdl_wrapper/src/sdl_wrapper.buffer.cpp +++ b/sdl_wrapper/src/sdl_wrapper.buffer.cpp @@ -122,6 +122,7 @@ namespace sopho if (!transfer_buffer) { SDL_LogError(SDL_LOG_CATEGORY_GPU, "%s:%d %s", __FILE__, __LINE__, SDL_GetError()); + gpu.release_buffer(gpu_buffer); return std::unexpected(transfer_buffer.error()); } return BufferWrapper{gpu.shared_from_this(), gpu_buffer, (std::move(transfer_buffer.value())), size}; From 2566e27ef86b1d5bd16c01e8132b62c4b19246e2 Mon Sep 17 00:00:00 2001 From: Sophomore Date: Wed, 26 Nov 2025 11:03:49 +0800 Subject: [PATCH 55/57] fix: avoid texture leak --- sdl_wrapper/src/sdl_wrapper.texture.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/sdl_wrapper/src/sdl_wrapper.texture.cpp b/sdl_wrapper/src/sdl_wrapper.texture.cpp index 0130c6a..24f6b7c 100644 --- a/sdl_wrapper/src/sdl_wrapper.texture.cpp +++ b/sdl_wrapper/src/sdl_wrapper.texture.cpp @@ -56,6 +56,7 @@ namespace sopho auto submit_result = c_tb.and_then([&](auto& tb) { return tb.submit(img_data.pixels.data()); }); if (!submit_result) { + SDL_ReleaseGPUTexture(gpu.device(), texture); return std::unexpected{submit_result.error()}; } SDL_GPUCommandBuffer* cmd = SDL_AcquireGPUCommandBuffer(gpu.device()); @@ -69,6 +70,7 @@ namespace sopho if (!copy_pass) { SDL_SubmitGPUCommandBuffer(cmd); + SDL_ReleaseGPUTexture(gpu.device(), texture); SDL_Log("SDL_BeginGPUCopyPass failed: %s", SDL_GetError()); return std::unexpected{GpuError::BEGIN_COPY_PASS_FAILED}; } @@ -112,6 +114,7 @@ namespace sopho if (!sampler) { SDL_Log("SDL_CreateGPUSampler failed: %s", SDL_GetError()); + SDL_ReleaseGPUTexture(gpu.device(), texture); return std::unexpected{GpuError::CREATE_SAMPLER_FAILED}; } From be8ca77ee6b7cdf406337854b36a589282f4936a Mon Sep 17 00:00:00 2001 From: Sophomore Date: Wed, 26 Nov 2025 11:10:27 +0800 Subject: [PATCH 56/57] fix: remove magic number and using parameter --- sdl_wrapper/src/sdl_wrapper.gpu.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/sdl_wrapper/src/sdl_wrapper.gpu.cpp b/sdl_wrapper/src/sdl_wrapper.gpu.cpp index 3234354..f23f665 100644 --- a/sdl_wrapper/src/sdl_wrapper.gpu.cpp +++ b/sdl_wrapper/src/sdl_wrapper.gpu.cpp @@ -40,8 +40,10 @@ namespace sopho { return std::unexpected(vertex_buffer.error()); } - auto index_buffer = - BufferWrapper::Builder{}.set_flag(SDL_GPU_BUFFERUSAGE_INDEX).set_size(6 * sizeof(int)).build(*this); + auto index_buffer = BufferWrapper::Builder{} + .set_flag(SDL_GPU_BUFFERUSAGE_INDEX) + .set_size(index_count * sizeof(int)) + .build(*this); if (!index_buffer) { return std::unexpected(index_buffer.error()); From c1b759a44b45a89c53aa404bcd1f184b17f8c2d1 Mon Sep 17 00:00:00 2001 From: Sophomore Date: Wed, 26 Nov 2025 11:13:59 +0800 Subject: [PATCH 57/57] fix: add missing header file --- sdl_wrapper/modules/sdl_wrapper.render_data_impl.ixx | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/sdl_wrapper/modules/sdl_wrapper.render_data_impl.ixx b/sdl_wrapper/modules/sdl_wrapper.render_data_impl.ixx index 5ee4bc1..09c0ae6 100644 --- a/sdl_wrapper/modules/sdl_wrapper.render_data_impl.ixx +++ b/sdl_wrapper/modules/sdl_wrapper.render_data_impl.ixx @@ -3,10 +3,11 @@ // module; #include -#include +#include #include #include #include +#include #include "SDL3/SDL_gpu.h" export module sdl_wrapper:render_data_impl; @@ -26,9 +27,9 @@ namespace sopho public: RenderDataImpl(BufferWrapper&& vertex_buffer_wrapper, BufferWrapper&& index_buffer_wrapper, - const VertexLayout& layouts, size_t vertex_count, std::uint32_t index_count) : + const VertexLayout& layouts, size_t vertex_count, std::uint32_t index_count) : m_vertex_buffer(std::move(vertex_buffer_wrapper)), m_index_buffer(std::move(index_buffer_wrapper)), - m_layouts(layouts), m_vertex_count(vertex_count),m_index_count(index_count) + m_layouts(layouts), m_vertex_count(vertex_count), m_index_count(index_count) { m_bindings.emplace_back(m_vertex_buffer.gpu_buffer(), 0); m_index_binding.buffer = m_index_buffer.gpu_buffer();