From 52af3f590a810533166c3b1ef4349e6417b4edc6 Mon Sep 17 00:00:00 2001 From: SpinnerX Date: Fri, 27 Mar 2026 12:39:20 -0700 Subject: [PATCH 1/3] Removed std::print statements from implementations including header --- vulkan-cpp/buffer_streams.cppm | 5 ----- vulkan-cpp/command_buffer.cppm | 6 +++--- vulkan-cpp/uniform_buffer.cppm | 2 -- 3 files changed, 3 insertions(+), 10 deletions(-) diff --git a/vulkan-cpp/buffer_streams.cppm b/vulkan-cpp/buffer_streams.cppm index 991515b..c4f2c5f 100644 --- a/vulkan-cpp/buffer_streams.cppm +++ b/vulkan-cpp/buffer_streams.cppm @@ -3,7 +3,6 @@ module; #include #include #include -#include export module vk:buffer_streams; @@ -60,10 +59,6 @@ export namespace vk { uint32_t memory_index = std::countr_zero(mapped_memory_requirements); - std::println("Memory Requirement Mapped: {} (Buffer Stream)", - mapped_memory_requirements); - std::println("Memory Index: {}", memory_index); - VkMemoryAllocateInfo memory_alloc_info = { .sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO, .allocationSize = memory_requirements.size, diff --git a/vulkan-cpp/command_buffer.cppm b/vulkan-cpp/command_buffer.cppm index 852ab70..30661f8 100644 --- a/vulkan-cpp/command_buffer.cppm +++ b/vulkan-cpp/command_buffer.cppm @@ -258,7 +258,7 @@ export namespace vk { * ``` * */ - void bind_index_buffers8(const VkBuffer p_index_buffer, + void bind_index_buffers8(const VkBuffer& p_index_buffer, const uint64_t p_offset = 0) { vkCmdBindIndexBuffer(m_command_buffer, p_index_buffer, @@ -280,7 +280,7 @@ export namespace vk { * ``` * */ - void bind_index_buffers16(const VkBuffer p_index_buffer, + void bind_index_buffers16(const VkBuffer& p_index_buffer, const uint64_t p_offset = 0) { vkCmdBindIndexBuffer(m_command_buffer, p_index_buffer, @@ -303,7 +303,7 @@ export namespace vk { * ``` * */ - void bind_index_buffers32(const VkBuffer p_index_buffer, + void bind_index_buffers32(const VkBuffer& p_index_buffer, const uint64_t p_offset = 0) { vkCmdBindIndexBuffer(m_command_buffer, p_index_buffer, diff --git a/vulkan-cpp/uniform_buffer.cppm b/vulkan-cpp/uniform_buffer.cppm index 94a236c..a9a311d 100644 --- a/vulkan-cpp/uniform_buffer.cppm +++ b/vulkan-cpp/uniform_buffer.cppm @@ -4,7 +4,6 @@ module; #include #include #include -#include export module vk:uniform_buffer; @@ -28,7 +27,6 @@ export namespace vk { const buffer_parameters& p_uniform_params) : m_device(p_device) , m_size_bytes(p_size_bytes) { - std::println("vk::uniform_buffer!"); m_uniform_handle = buffer_stream(m_device, p_size_bytes, p_uniform_params); } From 7a52057d1a767cfac1734d66c14445a9eb127792 Mon Sep 17 00:00:00 2001 From: SpinnerX Date: Mon, 30 Mar 2026 12:47:11 -0700 Subject: [PATCH 2/3] Updated the README with updated instructions to make sure it is updated with lot of the newer API's these are small updates that are WIP --- demos/6-graphics-pipeline/README.md | 199 ++++++++++++++-------- demos/6-graphics-pipeline/application.cpp | 15 +- demos/6-graphics-pipeline/conanfile.py | 2 +- 3 files changed, 138 insertions(+), 78 deletions(-) diff --git a/demos/6-graphics-pipeline/README.md b/demos/6-graphics-pipeline/README.md index 0132671..e68afaa 100644 --- a/demos/6-graphics-pipeline/README.md +++ b/demos/6-graphics-pipeline/README.md @@ -8,11 +8,11 @@ The vulkan tutorial website goes over more in-depth of the responsibility of the # Process of the Graphics Pipeline -This section will briefly touch on the graphics pipeline and the process behind it. +In this section will briefly begin to introduce the graphics pipeline using the vulkan-cpp abstraction, `vk::pipeline` class. -This is the following graphics sequence diagram: +The sequence diagram shows stages for the graphics pipeline: -![NOTE] +> [!NOTE] > Credit to the vulkan web-page that can be seen used in this [link](https://vulkan-tutorial.com/Drawing_a_triangle/Graphics_pipeline_basics/Introduction) @@ -57,48 +57,43 @@ These normalized device coordinates are `homogeneous coordinates` that map the f # Graphics Pipeline Concepts -## Programmable Stages +## How to use `vk::pipeline`? -Diagrams marked green are process in the graphics pipeline you can upload your code to modify its parameters. +Now, in this section will show you how to setup the graphics pipeline using vulkan-cpp parameters to construct the `vk::pipeline` object. -Which involve: -* Offload code to the GPU -* Sending uniform data such as (textures, lighting, ray tracing, etc) -* Process data on multiple GPU cores simultaneously to process objects in parallel. +### What are optional parameters to use? +Noting the geometry and tesselation shader parameters are **optional** to be set if you do not plan to do operations that require you have computations involving the topology of your geometry. -## Optional Stages +Whereas the **fragment** shaders can be disabled in situations such as shadow-mapping generations. -These are stages that can be entirely optional. Optional because they are not required for a variety of different reasons. +# Constructing the actual Graphics Pipeline -Stages involved are: -* `geometry` and `tessellation` can be disabled if you plan to deal with simpler geometry. -* `fragment shaders` can be disabled, if you need depth values only. Useful for `shadow-mapping` generation. - -# Building the Graphics Pipeline - -![NOTE] +> [!NOTE] > `vk::pipeline` implementation is still in-progress as I have not exposed the other stages quite yet. That will be worked in exposing soon. -Previously in demo 5. We focused on how to setup the swapchain, command buffers, images, and framebuffers to make sure we can send some data to the screen. Which was changing the background color to a specific color. +Previously in demo 5 focused in setting up the swapchain, command buffers, images, and framebuffers to ensure we can at least be able to change the background color to a different color. -In this demo, we are going to try and get a triangle drawn to the screen. Which wont focus too much in getting transforms to work, we will focus in specifying the raw vertices to the GPU to draw the triangle. +To indicate the changes we have made are working with no additional errors from the validation layers. -Since the triangle, we will not be applying any transformations. We will specify the positions of the three vertices directly as normalized device coordinates to create the following shape: +Goal for this demo, where we setup the graphics pipeline is to finally get us a triangle to render to the screen. triangle_coordinates_colors -# Loading Shaders +## Loading Shaders using `vk::shader_resource` + +The graphics pipeline handle requires there to be a shader to be loaded with. This will load into the shader module handles using the `vk::shader_resource` abstraction. -In Vulkan before building the graphics pipeline. You need to specify both the source to the shader compiled code and the stage this shader is being compiled as. +The shader resource class helps with loading in the shaders and associating the stage and loading in N amount of handles with the shaders specified. -Since Vulkan does not have a runtime shader compiler that comes with it, you have to compile your glsl shader to spirv binary format. +You should be able to copy shaders, `test.vert` and `test.frag` glsl shaders into your project location. For the demos, which are contained in a folder called `shader_samples/sample1/`. -In this case, you'd compile `shader_samples/sample1/test.vert` to `shader_samples/sample1/test.vert.spv`. Same needs to happen compiling `sample1/test.frag` to `shader_samples/sample1/test.frag.spv` +Here are what each of the shaders contain: -## Vertex Shader +## Vertex Shader (Update) -In the next demo, we will actually use a vertex buffer to store these vertices. For now we will type in the raw vertices in the vertex shader. If you -look at the `shader_samples/sample1/test.vert` shader. As shown below: +In the next and incoming demos, we would typically have these vertices handled via vertex attributes. For getting this triangle to render. The next demo will cover vertex buffers that will show how to get vertex attributes working. + +For now, the vertices will be hardcoded. ```glsl #version 450 @@ -117,12 +112,9 @@ void main() { ## Fragment Shader -In the fragment shader is what forms using the position vertices you pass from the vertex shader. Then fills that area onto the screen with fragments. - -The fragment shader is involved in executing on those fragments to produce color and depth for the framebuffer (or framebuffers). - -A simple fragment shader outputs color gradient. Adding this into your vertex shader. +The fragment shader is what processes the vertices of your 3D geometry, in this case the triangle for this demo. +Here is what the current fragment shader code looks like: ```glsl #version 450 @@ -147,7 +139,7 @@ void main() { } ``` -In the fragment shader, add the following code: +In that same fragment shader, add the following code: ```glsl @@ -170,24 +162,29 @@ Where `layout(location = 0)` modifier specifies index of the framebuffer. The co ## Compiling Shaders -I have mentioned that previously vulkan does not know what to do with your shader source code and expects only the final binary blob that is after compiling the source code. -To compile the shaders to SPIRV-bytecode, you should already have glsl install and be able to reference similarily to your platform-specific file paths. +If you have used OpenGL, it would provide API's to automatically compile your shaders to `.spv`, BUT in Vulkan this responsibility will be on you. the developer. Therefore, before you can load in your shaders. You are going to need to compile your shaders to .spv + +For context, `.spv` is the binary format of the compiled-down shader code. ```bash glslc.exe shader_samples/sample1/test.vert -o shader_samples/sample1/test.vert.spv glslc.exe shader_samples/sample1/test.frag -o shader_samples/sample1/test.frag.spv ``` -## Finalized Setting up Shaders + + +## Setting up `vk::shader_source` -Now, that you have setup the glsl shaders to specify what data it should expect to render the triangle on the GPU. We will now continue to building the graphics pipeline. + -In vulkan-cpp you only need to specify the .spv shader sources and their stages. +Now, the shaders are compiled to `.spv`. In this section, I am going to show how to load the spirv compiled binaries. -Here is how you specify the shader sources: +Each `vk::shader_source` contains the location to the individual binaries along with the stage of the shader they are used for. + +This is important to distinction to know how these shaders are going to be utilized. ```C++ std::array shader_sources = { @@ -202,13 +199,11 @@ std::array shader_sources = { }; ``` -## Creating `vk::shader_resource` - -Before you create the shader_resource, you need to specify the `logical device` and the `vk::shader_resource_info`. +## Initializing the `vk::shader_resource` -The shader resource information are parameters required to be specified for the shader resource such as vertex attributes. +Now, the shader sources are already configured. Now use pass that into `vk::shader_resource_info`. -Here is how to specify the parameters: +For this demo, we will now initialize the `vk::shader_resource`. Firstly passing the `shader_info` parameters to the constructor. Followed by passing the logical device as the first parameter. ```C++ vk::shader_resource_info shader_info = { @@ -221,43 +216,96 @@ vk::shader_resource geometry_resource(logical_device, shader_info); The `vk::shader_resource` does allow you to set the vertex attributes as the following below. Though for the triangle, it will be brought up in the next few demos. +If you have no vertex attributes that needs to be set. Then you can completely ignore invoking this API. + +This is what the API looks like. In later demos, we will cover how you may setup the vertex attributes for `vk::shader_resource`. + ```C++ geoemetry_resource.vertex_attributes(...); ``` -## Creating the Graphics Pipeline +## Configuring the Graphics Pipeline -In vulkan-cpp, it is quite simple to create a graphics pipeline. vulkan-cpp was designed to be quite simple in the workflow for specifying work through Vulkan. This includes specifying the graphics pipeline. +In vulkan-cpp, I tried to consider ways of approaching the design for the graphics pipeline for simplifying steps needed to configure the graphics pipeline. -In the `vk::shader_resource` implementation is supposed to be wrapper for creating the raw `VkShaderModule` handles needed to be specified by the vulkan-cpp graphics pipeline. Specifically `vk::pipeline`. +Parmaters to configure `vk::pipeline` with: +* `VkRenderPass`. +* `span` +* `span` +* `span` -Now, that you have created the shader sources and loaded them into the vulkan shader handles. Here is how you setup the graphics pipeline. +Which are provided to you by the `vk::shader_resource` class. -The `vk::shader_resource` gives you access to the handles created. +### Parameters for `vk::pipeline` -These are handles returned in that order: +When configuring the graphics pipeline, there are an extensive amount of parameters. Which are set to default values that can be changed. -* span -* span -* span +These are the list of parameters that need to be set for the graphics pipeline set to default values. ```C++ -vk::pipeline_settings pipeline_configuration = { +struct pipeline_params { + VkRenderPass renderpass = nullptr; + std::span shader_modules{}; + std::span + vertex_attributes; + std::span + vertex_bind_attributes; + std::span descriptor_layouts; + + input_assembly_state input_assembly; + viewport_state viewport; + rasterization_state rasterization; + multisample_state multisample; + color_blend_state color_blend; + bool depth_stencil_enabled = false; + depth_stencil_state depth_stencil; + std::span dynamic_states = {}; +}; +``` + +For this demo, we are only going to be setting the color blend states and the dynamic states. + +### Color Blend States + +These parameters tell the rasterization (when enabled) how to access any color attachments during rendering operations. + +`vk::color_blend_attachment_state` defaults `.blend_enabled` to true. This can be used to enable alpha blending via transparency. + +### Dynamic States + +Enabling parameters `vk::dynamic_state::viewport` and `vk::dynamic_state::scissor`, this allows the graphics pipeline handles to handle dynamically changing when resizing the window and updating the graphics pipeline handles. + + +```C++ +// Sets up the default color blend attachment state +std::array color_blend_attachments = { + vk::color_blend_attachment_state{}, +}; + +// Setting up graphics pipeline to having a dynamic state +// So we are not needing to invalidate and have the driver be responsible for that. +std::array dynamic_states = { + vk::dynamic_state::viewport, vk::dynamic_state::scissor +}; + +vk::pipeline_params pipeline_params = { .renderpass = main_renderpass, .shader_modules = geometry_resource.handles(), .vertex_attributes = geometry_resource.vertex_attributes(), - .vertex_bind_attributes = geometry_resource.vertex_bind_attributes() + .vertex_bind_attributes = geometry_resource.vertex_bind_attributes(), + .color_blend = { + .attachments = color_blend_attachments, + }, + .dynamic_states = dynamic_states, }; -vk::pipeline main_graphics_pipeline(logical_device, pipeline_configuration); +vk::pipeline main_graphics_pipeline(logical_device, pipeline_params); ``` -# Finally Created the Graphics Pipeline +# Graphics Pipeline Instantiated -As soon the graphics pipeline as been created using `vk::pipeline`. This demo will introduce a few of the `vk::pipeline` API's. +Now the graphics pipeline has been initialized and to check you can print out using the `.alive` API to see if the handle was initialized successfully. As it should return true if it initialized successfully. -`vk::pipeline` gives you a `.bind(const VkCommandBuffer&)` API. This just means making a particular resource available to be used by the GPU. This is a common operation done in Computer Graphics. - -Here is the additional code to add in the mainloop: +Now, let us go ahead and start using the `vk::pipeline` API's, which includes calling the bind and draw call API to render our first triangle ```C++ @@ -266,22 +314,29 @@ while (!glfwWindowShouldClose(window)) { uint32_t current_frame = presentation_queue.acquire_next_image(); vk::command_buffer current = swapchain_command_buffers[current_frame]; - // Binding to make resources available and accessible by the GPU - // Add + // ... + // current.begin(...) + // main_renderpass.begin(current, ...) + + // NEW: Using graphics pipeline bind API to bind resource to the command buffer main_graphics_pipeline.bind(current); - // Draw call to render to the screen - // Add + // NEW: Add draw call here + // vkCmdDraw(VkCommandBuffer, vertexCount, instanceCount, firstVertex, firstInstance) vkCmdDraw(current, 3, 1, 0, 0); - // .... + // main_renderpass.end(current) + // current.end(); + // ... } ``` -# Cleanup +# Post Cleanup -After you have created the graphics pipeline. Do not forget to do the post cleanup after the mainloop call. +After creating the graphics pipeline, be sure to invoke the `.destroy` API to ensure the handles are destroyed properly. + +> [!NOTE] This will be replaced to fully using RAII to automate cleanup for your objects. ```C++ @@ -298,6 +353,8 @@ logical_device.destroy(); # Final Result -As soon those two lines of code have been added. This is what the final result should look like: +If you followed this demo tutorial correctly with no given issue. + +You should be able to see this triangle get rendered: Screenshot 2025-12-06 201645 diff --git a/demos/6-graphics-pipeline/application.cpp b/demos/6-graphics-pipeline/application.cpp index 7ee21e1..ac28a35 100644 --- a/demos/6-graphics-pipeline/application.cpp +++ b/demos/6-graphics-pipeline/application.cpp @@ -13,6 +13,8 @@ #include #include #include +#include + import vk; static VKAPI_ATTR VkBool32 VKAPI_CALL @@ -124,7 +126,7 @@ main() { // We provide a selection of format support that we want to check is // supported on current hardware device. VkFormat depth_format = - vk::select_depth_format(physical_device, format_support); + physical_device.request_depth_format(format_support); vk::queue_indices queue_indices = physical_device.family_indices(); std::println("Graphics Queue Family Index = {}", queue_indices.graphics); @@ -153,7 +155,7 @@ main() { std::println("Starting implementation of the swapchain!!!"); vk::surface_params surface_properties = - vk::enumerate_surface(physical_device, window_surface); + physical_device.request_surface(window_surface); if (surface_properties.format.format != VK_FORMAT_UNDEFINED) { std::println("Surface Format.format is not undefined!!!"); @@ -187,11 +189,12 @@ main() { .extent = { .width = swapchain_extent.width, .height = swapchain_extent.height }, .format = surface_properties.format.format, + .memory_mask = physical_device.memory_properties( + vk::memory_property::device_local_bit), .aspect = vk::image_aspect_flags::color_bit, .usage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT, .mip_levels = 1, .layer_count = 1, - .phsyical_memory_properties = physical_device.memory_properties(), }; swapchain_images[i] = @@ -202,11 +205,12 @@ main() { .extent = { .width = swapchain_extent.width, .height = swapchain_extent.height }, .format = depth_format, + .memory_mask = physical_device.memory_properties( + vk::memory_property::device_local_bit), .aspect = vk::image_aspect_flags::depth_bit, .usage = VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT, .mip_levels = 1, .layer_count = 1, - .phsyical_memory_properties = physical_device.memory_properties(), }; swapchain_depth_images[i] = vk::sample_image(logical_device, image_config); @@ -351,13 +355,12 @@ main() { // renderpass begin/end must be within a recording command buffer vk::renderpass_begin_params begin_renderpass = { - .current_command = current, .extent = swapchain_extent, .current_framebuffer = swapchain_framebuffers[current_frame], .color = color, .subpass = vk::subpass_contents::inline_bit }; - main_renderpass.begin(begin_renderpass); + main_renderpass.begin(current, begin_renderpass); // Binding a graphics pipeline -- before drawing stuff // Inside of this graphics pipeline bind, is where you want to do the diff --git a/demos/6-graphics-pipeline/conanfile.py b/demos/6-graphics-pipeline/conanfile.py index 708fb66..eb977f5 100644 --- a/demos/6-graphics-pipeline/conanfile.py +++ b/demos/6-graphics-pipeline/conanfile.py @@ -22,7 +22,7 @@ def requirements(self): self.requires("glm/1.0.1") self.requires("stb/cci.20230920") self.requires("tinyobjloader/2.0.0-rc10") - self.requires("vulkan-cpp/5.0") + self.requires("vulkan-cpp/6.0") def build(self): cmake = CMake(self) From e63897659e35211eaebca61f3c06792b761b7da0 Mon Sep 17 00:00:00 2001 From: SpinnerX Date: Tue, 31 Mar 2026 20:24:51 -0700 Subject: [PATCH 3/3] Added missing include --- vulkan-cpp/buffer_streams.cppm | 1 + 1 file changed, 1 insertion(+) diff --git a/vulkan-cpp/buffer_streams.cppm b/vulkan-cpp/buffer_streams.cppm index c4f2c5f..db2e92a 100644 --- a/vulkan-cpp/buffer_streams.cppm +++ b/vulkan-cpp/buffer_streams.cppm @@ -3,6 +3,7 @@ module; #include #include #include +#include export module vk:buffer_streams;