Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 25 additions & 6 deletions main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -70,11 +70,13 @@ void main()

public:
/**
* @brief Initialize application resources, GPU pipeline, vertex data, and Dear ImGui.
* @brief Initialize application GPU resources, shaders, vertex data, camera, and Dear ImGui.
*
* Creates the GPU device, window/pipeline/buffer wrappers, compiles shaders,
* uploads the initial vertex data, initializes the camera to identity,
* and sets up Dear ImGui and its SDL3/SDLGPU backends.
* Performs creation of the GPU wrapper and render procedural, compiles and submits the vertex
* and fragment shaders, creates and uploads initial render data, sets the camera uniform to the
* identity matrix, and initializes Dear ImGui with SDL3 and SDLGPU backends.
*
* @return SDL_AppResult `SDL_APP_CONTINUE` on successful initialization, `SDL_APP_FAILURE` on error.
*/
SDL_AppResult init(int argc, char** argv) override
{
Expand Down Expand Up @@ -192,7 +194,18 @@ void main()
}

/**
* @brief Advance the UI frame, present editors for triangle vertices and shader sources.
* @brief Advance the UI frame and present editors for vertex data and shader sources.
*
* Displays the ImGui demo and an "Editor" window with three modes:
* - Node/Vertex editing: exposes per-vertex attributes for editing and uploads the vertex buffer when modified.
* - Vertex shader editing: allows editing the vertex GLSL source and applies it to the procedural pipeline when
* changed.
* - Fragment shader editing: allows editing the fragment GLSL source and applies it to the procedural pipeline when
* changed.
*
* Any failures to upload vertex data or update shaders are logged.
*
* @return SDL_AppResult SDL_APP_CONTINUE to indicate the application should continue running.

Choose a reason for hiding this comment

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

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

Suggested change
* @return SDL_AppResult SDL_APP_CONTINUE to indicate the application should continue running.
static SDL_AppResult tick()

*/
SDL_AppResult tick()
{
Expand Down Expand Up @@ -296,7 +309,13 @@ void main()
}

/**
* @brief Render the triangle and ImGui UI to the GPU and present the swapchain frame.
* @brief Render the scene (triangle and ImGui) into the current swapchain image and present it.
*
* Performs pipeline submission if needed, prepares ImGui draw data, records GPU commands
* to clear and render the color target, uploads the camera uniform, binds vertex buffers
* and the graphics pipeline, issues the draw call, renders ImGui, and submits the command buffer.
*
* @return SDL_AppResult `SDL_APP_CONTINUE` to keep the application running.

Choose a reason for hiding this comment

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

warning: method 'draw' can be made const [readability-make-member-function-const]

Suggested change
* @return SDL_AppResult `SDL_APP_CONTINUE` to keep the application running.
SDL_AppResult draw() const

*/
SDL_AppResult draw()
{
Expand Down
18 changes: 18 additions & 0 deletions sdl_wrapper/sdl_wrapper.buffer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,12 @@ import :gpu;

namespace sopho
{
/**
* @brief Releases any owned GPU resources held by the wrapper.
*
* Ensures the associated GPU object is valid, then releases the GPU buffer and the
* GPU transfer buffer if they exist and clears their pointers.
*/
BufferWrapper::~BufferWrapper() noexcept
{
if (!m_gpu)
Expand All @@ -38,6 +44,18 @@ namespace sopho
}
}

/**
* @brief Uploads the internal CPU-side buffer to the GPU buffer via the transfer buffer and a GPU copy pass.
*
* Copies the contents of m_cpu_buffer into the existing transfer buffer, records a GPU copy pass that
* uploads that transfer buffer into m_gpu_buffer, submits the command buffer, and returns success status.
*
* @returns std::monostate on success; otherwise an unexpected `GpuError` indicating the failure:
* - `GpuError::MAP_TRANSFER_BUFFER_FAILED` if mapping the transfer buffer failed.
* - `GpuError::ACQUIRE_COMMAND_BUFFER_FAILED` if acquiring a GPU command buffer failed.
* - `GpuError::BEGIN_COPY_PASS_FAILED` if beginning the GPU copy pass failed.
* - `GpuError::SUBMIT_COMMAND_FAILED` if submitting the GPU command buffer failed.
*/
[[nodiscard]] std::expected<std::monostate, GpuError> BufferWrapper::upload()
{
auto src_data = m_cpu_buffer.data();
Expand Down
30 changes: 29 additions & 1 deletion sdl_wrapper/sdl_wrapper.gpu.cpp
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// sdl_wrapper.gpu.cpp
// sdl_wrapper.gpu.cpp
// Created by wsqsy on 11/14/2025.
//
module;
Expand All @@ -12,6 +12,14 @@ import :render_data;
import :vertex_layout;
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, GpuError> BufferWrapper containing the created GPU buffer, its transfer
* buffer, and the buffer size on success; `std::unexpected` with a `GpuError` on failure.
*/
std::expected<BufferWrapper, GpuError> GpuWrapper::create_buffer(SDL_GPUBufferUsageFlags flag, uint32_t size)
{
SDL_GPUBufferCreateInfo create_info{.usage = flag, .size = size};
Expand All @@ -33,6 +41,18 @@ namespace sopho
}
return BufferWrapper{shared_from_this(), gpu_buffer, transfer_buffer, size};
}
/**
* @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`.
*/
std::expected<RenderData, GpuError> GpuWrapper::create_data(const RenderProcedural& render_procedural,
uint32_t vertex_count)
{
Expand All @@ -44,6 +64,14 @@ namespace sopho
}
return RenderData{std::move(buffer.value()), render_procedural.vertex_layout(), vertex_count};
}
/**
* @brief Create a RenderProcedural configured for the device's texture format.
*
* Queries the GPU's texture format and constructs a RenderProcedural associated with this GpuWrapper.
*
* @return std::expected<RenderProcedural, GpuError> Contains the constructed RenderProcedural on success, or an
* unexpected holding the corresponding GpuError on failure.
*/
std::expected<RenderProcedural, GpuError> GpuWrapper::create_render_procedural()
{
// Query texture format, then construct RenderProcedural
Expand Down
58 changes: 57 additions & 1 deletion sdl_wrapper/sdl_wrapper.render_procedural.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,15 @@ import :gpu;

namespace sopho
{
// Helper: convert shaderc SPIR-V result (words) into a byte buffer.
/**
* @brief Convert a shaderc SPIR-V compilation result into a contiguous byte buffer.
*
* Converts the iterable sequence of 32-bit words produced by shaderc into a
* std::vector<std::uint8_t> containing the raw SPIR-V bytes in order.
*
* @param result The shaderc SPIR-V compilation result (iterable of uint32_t words).
* @return std::vector<std::uint8_t> Raw SPIR-V byte sequence suitable for creating GPU shader modules.
*/
static std::vector<std::uint8_t> spv_result_to_bytes(const shaderc::SpvCompilationResult& result)
{
// shaderc::SpvCompilationResult is an iterable sequence of uint32_t words.
Expand All @@ -39,6 +47,16 @@ namespace sopho
return bytes;
}

/**
* @brief Construct a RenderProcedural configured for the given GPU and swapchain format.
*
* Initializes default GPU pipeline state: vertex layout (positions + colors), shaderc options
* targeting Vulkan/SPIR-V, a vertex buffer description, an alpha blend color target using the
* provided swapchain format, and a default graphics pipeline create-info with no shaders.
* Marks the pipeline as modified so it will be (re)created on the next submit.
*
* @param swapchain_format Pixel format to use for the pipeline's color target.
*/
RenderProcedural::RenderProcedural(std::shared_ptr<GpuWrapper> gpu, SDL_GPUTextureFormat swapchain_format) noexcept
: m_gpu(std::move(gpu))
{
Expand Down Expand Up @@ -92,6 +110,13 @@ namespace sopho
m_modified = true;
}

/**
* @brief Releases owned GPU pipeline and shader resources and clears their handles.
*
* If a GPU wrapper is available, releases the graphics pipeline, vertex shader,
* and fragment shader held by this object (if present) and resets their pointers
* to nullptr.
*/
RenderProcedural::~RenderProcedural() noexcept
{
if (!m_gpu)
Expand All @@ -118,6 +143,16 @@ namespace sopho
}
}

/**
* @brief Ensures the GPU graphics pipeline matches the current pipeline description, creating or replacing the
* pipeline if changes are pending.
*
* If no modifications are pending this function is a no-op. On success it updates the stored graphics pipeline and
* clears the modified flag.
*
* @return std::monostate on success; `std::unexpected<GpuError>` containing the GPU error if pipeline creation
* fails.
*/
[[nodiscard]] std::expected<std::monostate, GpuError> RenderProcedural::submit()
{
if (!m_modified)
Expand Down Expand Up @@ -160,6 +195,16 @@ namespace sopho
return std::monostate{};
}

/**
* Compile the provided GLSL vertex shader source, create a GPU vertex shader, and install it into the pipeline.
*
* This updates the stored vertex shader, sets the pipeline's vertex_shader to the new shader, and marks the
* pipeline as modified so a new graphics pipeline will be created on the next submit.
*
* @param source GLSL source code for the vertex shader.
* @return std::monostate on success; `std::unexpected(GpuError::COMPILE_VERTEX_SHADER_FAILED)` if shader
* compilation fails, or `std::unexpected(<other GpuError>)` if shader creation on the GPU fails.
*/
[[nodiscard]] std::expected<std::monostate, GpuError> RenderProcedural::set_vertex_shader(const std::string& source)
{
auto result = m_compiler.CompileGlslToSpv(source, shaderc_glsl_vertex_shader, "vertex.glsl", m_options);
Expand Down Expand Up @@ -196,6 +241,17 @@ namespace sopho
return std::monostate{};
}

/**
* @brief Compiles GLSL fragment shader source, creates a GPU fragment shader, and installs it into the pipeline.
*
* Compiles the provided GLSL fragment source to SPIR-V, converts the result into a byte vector, and asks the GPU
* wrapper to create a fragment shader; on success the new shader replaces any existing fragment shader in the
* object, updates the pipeline's fragment shader reference, and marks the pipeline state as modified.
*
* @param source GLSL source code for the fragment shader.
* @return std::monostate on success; `std::unexpected<GpuError>` on failure (compilation error or GPU
* shader-creation error).
*/
[[nodiscard]] std::expected<std::monostate, GpuError>
RenderProcedural::set_fragment_shader(const std::string& source)
{
Expand Down
Loading