From 099bbcf0278e641ee41250cd4e75e94d13d35582 Mon Sep 17 00:00:00 2001 From: SpinnerX Date: Fri, 22 May 2026 17:01:34 -0700 Subject: [PATCH 01/11] Added vk::image interface for supporting varied image loading implementations --- CMakeLists.txt | 1 + .../17-buffer-device-address/application.cpp | 93 ++++++++++++++- vulkan-cpp/image.cppm | 40 +++++++ vulkan-cpp/texture.cppm | 108 +++++++++++++++--- vulkan-cpp/types.cppm | 7 ++ vulkan-cpp/vk.cppm | 1 + 6 files changed, 231 insertions(+), 19 deletions(-) create mode 100644 vulkan-cpp/image.cppm diff --git a/CMakeLists.txt b/CMakeLists.txt index fee275c..e1728a8 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -57,6 +57,7 @@ target_sources(${PROJECT_NAME} PUBLIC vulkan-cpp/descriptor_resource.cppm vulkan-cpp/texture.cppm vulkan-cpp/dyn/buffer.cppm + vulkan-cpp/image.cppm ) install( diff --git a/demos/17-buffer-device-address/application.cpp b/demos/17-buffer-device-address/application.cpp index e79f527..83a3e11 100644 --- a/demos/17-buffer-device-address/application.cpp +++ b/demos/17-buffer-device-address/application.cpp @@ -23,9 +23,15 @@ import vk; #define GLM_ENABLE_EXPERIMENTAL #include #include +#include #include +// #ifndef STB_IMAGE_IMPLEMENTATION +// #define STB_IMAGE_IMPLEMENTATION +#include +// #endif + static VKAPI_ATTR VkBool32 VKAPI_CALL debug_callback( [[maybe_unused]] VkDebugUtilsMessageSeverityFlagBitsEXT p_message_severity, @@ -240,6 +246,81 @@ struct push_constant_data { uint64_t global_ubo_addr = 0; }; + +/** + * @brief STBI-specific implementation of the vk::image interface +*/ +class stb_image : public vk::image { +public: + stb_image() = delete; + + stb_image(std::string_view p_path, vk::texture_params p_params) { + image_load(p_path, p_params); + } + + ~stb_image() = default; + +protected: + bool image_load(std::string_view p_path, vk::texture_params p_params) override { + int w = 0; + int h = 0; + int channels = 0; + + stbi_uc* image_pixel_data = stbi_load(p_path.data(), &w, &h, &channels, STBI_rgb_alpha); + + if(!image_pixel_data) { + return false; + } + + const VkFormat texture_format = static_cast(vk::format::r8g8b8a8_unorm); + int bytes_per_pixel = vk::bytes_per_texture_format(texture_format); + + m_extent = { + .width = static_cast(w), + .height = static_cast(h), + }; + + // Retrieving total size of bytes of the dimensions of the image and accounting for pixels of the image + uint32_t size_bytes = m_extent.width * m_extent.height * bytes_per_pixel; + + // Retrieving total image size to the count of the image layers + uint32_t size = size_bytes * p_params.layer_count; + + vk::image_params image_options = { + .extent = m_extent, + .format = texture_format, + .memory_mask = p_params.memory_mask, + .usage = + static_cast(vk::image_usage::transfer_dst_bit) | + static_cast(vk::image_usage::sampled_bit), + .mip_levels = p_params.mip_levels, + .layer_count = p_params.layer_count, + }; + + m_bytes.reserve(size); + std::span bytes_view = std::span(image_pixel_data, size); + + m_bytes.assign(bytes_view.begin(), bytes_view.end()); + + stbi_image_free(image_pixel_data); + + return true; + } + + std::span image_read() const override { + return m_bytes; + } + + vk::image_extent image_extent() const override { + return m_extent; + } + + +private: + vk::image_extent m_extent{}; + std::vector m_bytes{}; +}; + int main() { //! @note Just added the some test code to test the conan-starter setup code @@ -591,13 +672,13 @@ main() { vk::texture_params config_texture = { .memory_mask = - physical_device.memory_properties(static_cast( - vk::memory_property::host_visible_bit | - vk::memory_property::host_cached_bit)), + physical_device.memory_properties(vk::memory_property::host_visible_bit | vk::memory_property::host_cached_bit), }; - vk::texture texture1(logical_device, - std::filesystem::path("asset_samples/viking_room.png"), - config_texture); + // vk::texture texture1(logical_device, + // std::filesystem::path("asset_samples/viking_room.png"), + // config_texture); + stb_image img = stb_image("asset_samples/viking_room.png", config_texture); + vk::texture texture1(logical_device, &img, config_texture); // Setting the texture sampler/image view to descriptor resource std::array samplers = { diff --git a/vulkan-cpp/image.cppm b/vulkan-cpp/image.cppm new file mode 100644 index 0000000..b028671 --- /dev/null +++ b/vulkan-cpp/image.cppm @@ -0,0 +1,40 @@ +module; + +#include +#include + +export module vk:image; + +import :types; + +export namespace vk { + inline namespace v1 { + + /** + * @brief interface for the purpose of acting as an interface to + * different implementations for support variety of approaches in + * loading images. + */ + class image { + public: + virtual ~image() = default; + + bool load(std::string_view p_path, texture_params p_params) { + return image_load(p_path, p_params); + } + + [[nodiscard]] std::span read() const { + return image_read(); + } + + [[nodiscard]] image_extent extent() const { return image_extent(); } + + protected: + virtual bool image_load(std::string_view, texture_params) = 0; + + virtual std::span image_read() const = 0; + + virtual image_extent image_extent() const = 0; + }; + }; +}; \ No newline at end of file diff --git a/vulkan-cpp/texture.cppm b/vulkan-cpp/texture.cppm index d906f44..10fdd7e 100644 --- a/vulkan-cpp/texture.cppm +++ b/vulkan-cpp/texture.cppm @@ -12,11 +12,12 @@ module; export module vk:texture; -export import :types; -export import :utilities; -export import :buffer_streams; -export import :sample_image; -export import :command_buffer; +import :types; +import :utilities; +import :buffer_streams; +import :sample_image; +import :command_buffer; +import :image; export namespace vk { inline namespace v1 { @@ -110,13 +111,6 @@ export namespace vk { return texture_image; } - // TODO: Remove redundant struct and replace with vk::image_params - struct texture_params { - uint32_t memory_mask = 0; - uint32_t mip_levels = 1; - uint32_t layer_count = 1; - }; - class texture { public: texture() = default; @@ -225,6 +219,93 @@ export namespace vk { m_texture_loaded = true; } + texture(const VkDevice& p_device, image* p_image, const texture_params& p_texture_params) : m_device(p_device) { + construct(p_image, p_texture_params); + } + + + void construct(image* p_image, const texture_params& p_texture_params) { + m_extent = p_image->extent(); + + const VkFormat texture_format = static_cast(format::r8g8b8a8_unorm); + // NOTE To Self: Essentially passed to p_config parameter in create_texture_with_data + image_params img_options = { + .extent = p_image->extent(), + .format = texture_format, + .memory_mask = p_texture_params.memory_mask, + .usage = + static_cast(image_usage::transfer_dst_bit) | + static_cast(image_usage::sampled_bit), + .mip_levels = p_texture_params.mip_levels, + .layer_count = p_texture_params.layer_count, + }; + + m_image = sample_image(m_device, img_options); + + + // Setup staging buffer + uint32_t property_flag = memory_property::host_visible_bit | + memory_property::host_cached_bit; + + buffer_parameters staging_options = { + .memory_mask = img_options.memory_mask, + .property_flags = static_cast(property_flag), + .usage = static_cast(buffer_usage::transfer_src_bit), + }; + buffer_stream staging(m_device, p_image->read().size(), staging_options); + + staging.transfer(p_image->read()); + + // 5. Creating temporary command buffer for texture + command_params copy_command_params = { + .levels = command_levels::primary, + .queue_index = 0, + .flags = command_pool_flags::reset, + }; + command_buffer temp_command_buffer = command_buffer(m_device, copy_command_params); + + temp_command_buffer.begin(command_usage::one_time_submit); + + // Performing image layouts + VkImageLayout old_layout = VK_IMAGE_LAYOUT_UNDEFINED; + VkImageLayout new_layout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL; + m_image.memory_barrier(temp_command_buffer, img_options.format, old_layout, new_layout); + + std::array region_copies = { + vk::buffer_image_copy{ + .image_offset = { .width = 0, .height = 0, .depth = 0, }, + .image_extent = { .width = img_options.extent.width, .height = img_options.extent.height, .depth = 1, }, + } + }; + + staging.copy_to_image(temp_command_buffer, m_image, region_copies); + + old_layout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL; + new_layout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; + m_image.memory_barrier(temp_command_buffer, img_options.format, old_layout, new_layout); + + temp_command_buffer.end(); + + uint32_t queue_family = 0; + uint32_t queue_index = 0; + VkQueue temp_graphics_queue=nullptr; + vkGetDeviceQueue(m_device, queue_family, queue_index, &temp_graphics_queue); + + const VkCommandBuffer handle = temp_command_buffer; + VkSubmitInfo submit_info = { + .sType = VK_STRUCTURE_TYPE_SUBMIT_INFO, + .commandBufferCount = 1, + .pCommandBuffers = &handle, + }; + + vkQueueSubmit(temp_graphics_queue, 1, &submit_info, nullptr); + vkQueueWaitIdle(temp_graphics_queue); + + + temp_command_buffer.destroy(); + staging.destroy(); + } + //! @return true if image loaded, false if texture did not load //! correctly [[nodiscard]] bool loaded() const { return m_texture_loaded; } @@ -239,7 +320,8 @@ export namespace vk { VkDevice m_device = nullptr; bool m_texture_loaded = false; sample_image m_image{}; - image_extent m_extent{}; + image_extent m_extent; + class image* m_image_loader=nullptr; }; }; }; \ No newline at end of file diff --git a/vulkan-cpp/types.cppm b/vulkan-cpp/types.cppm index 1083d53..316123f 100644 --- a/vulkan-cpp/types.cppm +++ b/vulkan-cpp/types.cppm @@ -1604,6 +1604,13 @@ export namespace vk { uint32_t addrses_mode_w = sampler_address_mode::repeat; }; + // TODO: Remove redundant struct and replace with vk::image_params + struct texture_params { + uint32_t memory_mask = 0; + uint32_t mip_levels = 1; + uint32_t layer_count = 1; + }; + struct buffer_image_copy { uint32_t offset = 0; uint32_t row_length = 0; diff --git a/vulkan-cpp/vk.cppm b/vulkan-cpp/vk.cppm index 5a5e7b9..ac285de 100644 --- a/vulkan-cpp/vk.cppm +++ b/vulkan-cpp/vk.cppm @@ -23,6 +23,7 @@ export import :uniform_buffer; export import :descriptor_resource; export import :texture; export import :buffer_device_address; +export import :image; namespace vk { inline namespace v1 {}; From 7eea488a1df3009c52e31102260ff3eb01344a5f Mon Sep 17 00:00:00 2001 From: SpinnerX Date: Fri, 22 May 2026 17:05:09 -0700 Subject: [PATCH 02/11] Added doc comments to vk::image APIs --- vulkan-cpp/image.cppm | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/vulkan-cpp/image.cppm b/vulkan-cpp/image.cppm index b028671..c79458a 100644 --- a/vulkan-cpp/image.cppm +++ b/vulkan-cpp/image.cppm @@ -19,14 +19,23 @@ export namespace vk { public: virtual ~image() = default; + /** + * @brief Perform loading operations specific to the implementation of this interface + */ bool load(std::string_view p_path, texture_params p_params) { return image_load(p_path, p_params); } + /** + * @brief Read you the bytes read from the specific image loading implementations + */ [[nodiscard]] std::span read() const { return image_read(); } + /** + * @return the extent that contains properties about the image (dimensions, depth, etc) + */ [[nodiscard]] image_extent extent() const { return image_extent(); } protected: From 6e1893fcbd0fc7f760be1e5261698abf1422d787 Mon Sep 17 00:00:00 2001 From: SpinnerX Date: Fri, 22 May 2026 17:10:01 -0700 Subject: [PATCH 03/11] Remove old constructor of vk::texture --- vulkan-cpp/texture.cppm | 66 ----------------------------------------- 1 file changed, 66 deletions(-) diff --git a/vulkan-cpp/texture.cppm b/vulkan-cpp/texture.cppm index 10fdd7e..08110d7 100644 --- a/vulkan-cpp/texture.cppm +++ b/vulkan-cpp/texture.cppm @@ -153,72 +153,6 @@ export namespace vk { m_texture_loaded = true; } - // TODO: Replace these current parameters to using vk::image_params - // to make the API's consistent. - texture(const VkDevice& p_device, - const std::filesystem::path& p_filename, - const texture_params& p_texture_params) - : m_device(p_device) { - // 1. load from file - int w, h; - int channels; - // TODO: Make passing in the filepath an explicit parameter for - // loading in a texture - stbi_uc* image_pixel_data = - stbi_load(p_filename.string().c_str(), - &w, - &h, - &channels, - STBI_rgb_alpha); - m_extent = { - .width = static_cast(w), - .height = static_cast(h), - }; - - const VkFormat texture_format = - static_cast(format::r8g8b8a8_unorm); - int bytes_per_pixel = bytes_per_texture_format(texture_format); - - // Ensuring we get pass in the correct image size - // with bytes per pixel - // uint32_t layer_size_with_bytes = - uint32_t image_layer_sizes_with_bytes = - m_extent.width * m_extent.height * bytes_per_pixel; - - // uint32_t layer_count = 1; - uint32_t layer_count = p_texture_params.layer_count; - uint32_t image_size = - image_layer_sizes_with_bytes * layer_count; - - image_params config_image = { - .extent = m_extent, - .format = texture_format, - .memory_mask = p_texture_params.memory_mask, - .usage = - static_cast(image_usage::transfer_dst_bit) | - static_cast(image_usage::sampled_bit), - .mip_levels = p_texture_params.mip_levels, - .layer_count = p_texture_params.layer_count, - }; - - // Ensures the image data is valid before continuing - // We can check the state of the image if it loaded succesfully - if (!image_pixel_data) { - m_texture_loaded = false; - return; - } - - // Creating Image Handle + Loading Image Pixel Data - m_image = create_texture_with_data( - p_device, - config_image, - std::span(image_pixel_data, image_size)); - - // Proper cleanup of the image data - stbi_image_free(image_pixel_data); - m_texture_loaded = true; - } - texture(const VkDevice& p_device, image* p_image, const texture_params& p_texture_params) : m_device(p_device) { construct(p_image, p_texture_params); } From 7ce4e642dff4ed42991bf1bd8d7fadfaf81d10b2 Mon Sep 17 00:00:00 2001 From: SpinnerX Date: Fri, 22 May 2026 17:29:24 -0700 Subject: [PATCH 04/11] Added support for loading albedo textures and remove automatic dependencies of stbi image dependencies from vk::texture implementation --- .../17-buffer-device-address/application.cpp | 2 + vulkan-cpp/raw_image.cppm | 31 +++ vulkan-cpp/texture.cppm | 210 +++++++----------- 3 files changed, 119 insertions(+), 124 deletions(-) create mode 100644 vulkan-cpp/raw_image.cppm diff --git a/demos/17-buffer-device-address/application.cpp b/demos/17-buffer-device-address/application.cpp index 83a3e11..aa5eb93 100644 --- a/demos/17-buffer-device-address/application.cpp +++ b/demos/17-buffer-device-address/application.cpp @@ -679,6 +679,8 @@ main() { // config_texture); stb_image img = stb_image("asset_samples/viking_room.png", config_texture); vk::texture texture1(logical_device, &img, config_texture); + // std::array color_bytes = {0xFF, 0xFF, 0xFF, 0xFF}; + // vk::texture texture1(logical_device, vk::image_extent{1, 1}, color_bytes, physical_device.memory_properties(vk::memory_property::host_visible_bit | vk::memory_property::host_cached_bit)); // Setting the texture sampler/image view to descriptor resource std::array samplers = { diff --git a/vulkan-cpp/raw_image.cppm b/vulkan-cpp/raw_image.cppm new file mode 100644 index 0000000..d6f8bdb --- /dev/null +++ b/vulkan-cpp/raw_image.cppm @@ -0,0 +1,31 @@ +module; + +#include + +export module vk:raw_image; + +import :types; + +export namespace vk { + inline namespace v1 { + class raw_image { + public: + raw_image() = delete; + + raw_image(const VkDevice& p_device, image_extent p_extent, std::span p_bytes) : m_device(p_device) { + } + + ~raw_image() { + + } + + void construct(image_extent p_extent, std::span p_bytes) {} + + void destruct() { + } + + private: + VkDevice m_device=nullptr; + }; + }; +}; \ No newline at end of file diff --git a/vulkan-cpp/texture.cppm b/vulkan-cpp/texture.cppm index 08110d7..0a91fe0 100644 --- a/vulkan-cpp/texture.cppm +++ b/vulkan-cpp/texture.cppm @@ -5,11 +5,6 @@ module; #include #include -#ifndef STB_IMAGE_IMPLEMENTATION -#define STB_IMAGE_IMPLEMENTATION -#include -#endif - export module vk:texture; import :types; @@ -22,141 +17,108 @@ import :image; export namespace vk { inline namespace v1 { - sample_image create_texture_with_data(const VkDevice& p_device, - const image_params& p_config, - std::span p_data) { - - // 1. loading texture - sample_image texture_image = sample_image(p_device, p_config); - - // 2. transfer data from staging buffer - uint32_t property_flag = memory_property::host_visible_bit | - memory_property::host_cached_bit; - - buffer_parameters staging_buffer_config = { - .memory_mask = p_config.memory_mask, - .property_flags = static_cast(property_flag), - .usage = static_cast(buffer_usage::transfer_src_bit), - }; - buffer_stream staging( - p_device, p_data.size(), staging_buffer_config); - - // 3. write data to the staging buffer with specific size specified - staging.transfer(p_data); - - // 4. start recording to this command buffer - VkImageLayout old_layout = VK_IMAGE_LAYOUT_UNDEFINED; - VkImageLayout new_layout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL; - VkFormat texture_format = p_config.format; - - // 5. Creating temporary command buffer for texture - command_params copy_command_params = { - .levels = command_levels::primary, - .queue_index = 0, - .flags = command_pool_flags::reset, - }; - command_buffer temp_command_buffer = - command_buffer(p_device, copy_command_params); - - temp_command_buffer.begin(command_usage::one_time_submit); - - // 6. transition image layout - // Ensure that we are transferring our image data and correcting the - // format to ensure we do not lose any data in the process - texture_image.memory_barrier( - temp_command_buffer, texture_format, old_layout, new_layout); - - std::array region_copies = { - vk::buffer_image_copy{ - .image_offset = { .width = 0, .height = 0, .depth = 0, }, - .image_extent = { .width = p_config.extent.width, .height = p_config.extent.height, .depth = 1, }, - } - }; - - // staging.copy_to_image(temp_command_buffer, texture_image, - // p_config.extent); - staging.copy_to_image( - temp_command_buffer, texture_image, region_copies); - old_layout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL; - new_layout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; - texture_image.memory_barrier( - temp_command_buffer, texture_format, old_layout, new_layout); - - temp_command_buffer.end(); - - // 8. Getting graphics queue to store the texture data for GPU - // access - // TODO: Extend vk::device_queue to enable perform command - // submission to the GPU - uint32_t queue_family_index = 0; - uint32_t queue_index = 0; - VkQueue temp_graphics_queue; - vkGetDeviceQueue( - p_device, queue_family_index, queue_index, &temp_graphics_queue); - - // 8. now submit that texture data to be stored in GPU memory - const VkCommandBuffer handle = temp_command_buffer; - VkSubmitInfo submit_info = { - .sType = VK_STRUCTURE_TYPE_SUBMIT_INFO, - .commandBufferCount = 1, - .pCommandBuffers = &handle, - }; - - vkQueueSubmit(temp_graphics_queue, 1, &submit_info, nullptr); - vkQueueWaitIdle(temp_graphics_queue); - - temp_command_buffer.destroy(); - staging.destroy(); - - return texture_image; - } - class texture { public: - texture() = default; + texture() = delete; - // TODO: Replace these current parameters to using vk::image_params - // to make the API's consistent. texture(const VkDevice& p_device, const image_extent& p_extent, - uint32_t p_memory_mask) + std::span p_color, + uint32_t p_memory_mask, + uint32_t p_mip_levels=1, + uint32_t p_layer_count=1) : m_device(p_device) , m_extent(p_extent) { - // 1.) Load in extent dimensions - // White pixels for storing texture. - std::array white_color = { 0xFF, 0xFF, 0xFF, 0xFF }; + construct(p_extent, p_color, p_memory_mask, p_mip_levels, p_layer_count); + m_texture_loaded = true; + } - image_params config_image = { - .extent = m_extent, - .format = static_cast(format::r8g8b8a8_unorm), + texture(const VkDevice& p_device, image* p_image, const texture_params& p_texture_params) : m_device(p_device) { + construct(p_image, p_texture_params); + } + + void construct(image_extent p_extent, std::span p_data, uint32_t p_memory_mask, uint32_t p_mip_levels=1, uint32_t p_layer_count=1) { + m_extent = p_extent; + + const VkFormat texture_format = static_cast(format::r8g8b8a8_unorm); + // NOTE To Self: Essentially passed to p_config parameter in create_texture_with_data + image_params img_options = { + .extent = p_extent, + .format = texture_format, .memory_mask = p_memory_mask, .usage = static_cast(image_usage::transfer_dst_bit) | static_cast(image_usage::sampled_bit), + .mip_levels = p_mip_levels, + .layer_count = p_layer_count, }; - int bytes_per_pixel = - bytes_per_texture_format(config_image.format); - - // Ensuring we get pass in the correct image size with bytes per - // pixel - uint32_t layer_size_with_bytes = config_image.extent.width * - config_image.extent.height * - bytes_per_pixel; - uint32_t layer_count = 1; - uint32_t image_size = layer_size_with_bytes * layer_count; - - m_image = create_texture_with_data( - m_device, - config_image, - std::span(white_color.data(), image_size)); - m_texture_loaded = true; - } - texture(const VkDevice& p_device, image* p_image, const texture_params& p_texture_params) : m_device(p_device) { - construct(p_image, p_texture_params); - } + m_image = sample_image(m_device, img_options); + + + // Setup staging buffer + uint32_t property_flag = memory_property::host_visible_bit | + memory_property::host_cached_bit; + + buffer_parameters staging_options = { + .memory_mask = img_options.memory_mask, + .property_flags = static_cast(property_flag), + .usage = static_cast(buffer_usage::transfer_src_bit), + }; + buffer_stream staging(m_device, p_data.size(), staging_options); + + staging.transfer(p_data); + + // 5. Creating temporary command buffer for texture + command_params copy_command_params = { + .levels = command_levels::primary, + .queue_index = 0, + .flags = command_pool_flags::reset, + }; + command_buffer temp_command_buffer = command_buffer(m_device, copy_command_params); + + temp_command_buffer.begin(command_usage::one_time_submit); + + // Performing image layouts + VkImageLayout old_layout = VK_IMAGE_LAYOUT_UNDEFINED; + VkImageLayout new_layout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL; + m_image.memory_barrier(temp_command_buffer, img_options.format, old_layout, new_layout); + + std::array region_copies = { + vk::buffer_image_copy{ + .image_offset = { .width = 0, .height = 0, .depth = 0, }, + .image_extent = { .width = img_options.extent.width, .height = img_options.extent.height, .depth = 1, }, + } + }; + + staging.copy_to_image(temp_command_buffer, m_image, region_copies); + + old_layout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL; + new_layout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; + m_image.memory_barrier(temp_command_buffer, img_options.format, old_layout, new_layout); + temp_command_buffer.end(); + + uint32_t queue_family = 0; + uint32_t queue_index = 0; + VkQueue temp_graphics_queue=nullptr; + vkGetDeviceQueue(m_device, queue_family, queue_index, &temp_graphics_queue); + + const VkCommandBuffer handle = temp_command_buffer; + VkSubmitInfo submit_info = { + .sType = VK_STRUCTURE_TYPE_SUBMIT_INFO, + .commandBufferCount = 1, + .pCommandBuffers = &handle, + }; + + vkQueueSubmit(temp_graphics_queue, 1, &submit_info, nullptr); + vkQueueWaitIdle(temp_graphics_queue); + + + temp_command_buffer.destroy(); + staging.destroy(); + } void construct(image* p_image, const texture_params& p_texture_params) { m_extent = p_image->extent(); From 8beb742c5b6b716161f6447e1219cf83bb790c5e Mon Sep 17 00:00:00 2001 From: SpinnerX Date: Fri, 22 May 2026 17:30:18 -0700 Subject: [PATCH 05/11] Removing outdated comment no longer needed --- vulkan-cpp/texture.cppm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vulkan-cpp/texture.cppm b/vulkan-cpp/texture.cppm index 0a91fe0..f6ca122 100644 --- a/vulkan-cpp/texture.cppm +++ b/vulkan-cpp/texture.cppm @@ -42,7 +42,7 @@ export namespace vk { m_extent = p_extent; const VkFormat texture_format = static_cast(format::r8g8b8a8_unorm); - // NOTE To Self: Essentially passed to p_config parameter in create_texture_with_data + image_params img_options = { .extent = p_extent, .format = texture_format, From e36ad816072c1f4183f8c234c7b662b8c09d0d40 Mon Sep 17 00:00:00 2001 From: SpinnerX Date: Fri, 22 May 2026 17:31:55 -0700 Subject: [PATCH 06/11] Removed unneeded raw_image file as it is redundant --- vulkan-cpp/raw_image.cppm | 31 ------------------------------- 1 file changed, 31 deletions(-) delete mode 100644 vulkan-cpp/raw_image.cppm diff --git a/vulkan-cpp/raw_image.cppm b/vulkan-cpp/raw_image.cppm deleted file mode 100644 index d6f8bdb..0000000 --- a/vulkan-cpp/raw_image.cppm +++ /dev/null @@ -1,31 +0,0 @@ -module; - -#include - -export module vk:raw_image; - -import :types; - -export namespace vk { - inline namespace v1 { - class raw_image { - public: - raw_image() = delete; - - raw_image(const VkDevice& p_device, image_extent p_extent, std::span p_bytes) : m_device(p_device) { - } - - ~raw_image() { - - } - - void construct(image_extent p_extent, std::span p_bytes) {} - - void destruct() { - } - - private: - VkDevice m_device=nullptr; - }; - }; -}; \ No newline at end of file From 10e0786f0dcd870fc31da6e94869eca23fac93d2 Mon Sep 17 00:00:00 2001 From: SpinnerX Date: Fri, 22 May 2026 17:37:33 -0700 Subject: [PATCH 07/11] Added stbi directive to enable for implementations now that it was removed from vk::texture --- demos/17-buffer-device-address/application.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/demos/17-buffer-device-address/application.cpp b/demos/17-buffer-device-address/application.cpp index aa5eb93..0a94e4d 100644 --- a/demos/17-buffer-device-address/application.cpp +++ b/demos/17-buffer-device-address/application.cpp @@ -27,10 +27,10 @@ import vk; #include -// #ifndef STB_IMAGE_IMPLEMENTATION -// #define STB_IMAGE_IMPLEMENTATION +#ifndef STB_IMAGE_IMPLEMENTATION +#define STB_IMAGE_IMPLEMENTATION #include -// #endif +#endif static VKAPI_ATTR VkBool32 VKAPI_CALL debug_callback( From a8614f2cfbfd862f0cf7a728b68fd61cccf46f0f Mon Sep 17 00:00:00 2001 From: SpinnerX Date: Fri, 22 May 2026 17:44:36 -0700 Subject: [PATCH 08/11] Removed old code from demo 17 --- demos/17-buffer-device-address/application.cpp | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/demos/17-buffer-device-address/application.cpp b/demos/17-buffer-device-address/application.cpp index 0a94e4d..aeb75cf 100644 --- a/demos/17-buffer-device-address/application.cpp +++ b/demos/17-buffer-device-address/application.cpp @@ -674,13 +674,9 @@ main() { .memory_mask = physical_device.memory_properties(vk::memory_property::host_visible_bit | vk::memory_property::host_cached_bit), }; - // vk::texture texture1(logical_device, - // std::filesystem::path("asset_samples/viking_room.png"), - // config_texture); + stb_image img = stb_image("asset_samples/viking_room.png", config_texture); vk::texture texture1(logical_device, &img, config_texture); - // std::array color_bytes = {0xFF, 0xFF, 0xFF, 0xFF}; - // vk::texture texture1(logical_device, vk::image_extent{1, 1}, color_bytes, physical_device.memory_properties(vk::memory_property::host_visible_bit | vk::memory_property::host_cached_bit)); // Setting the texture sampler/image view to descriptor resource std::array samplers = { From bedf7a0462de753b49aeac4035ba4263b9e70f72 Mon Sep 17 00:00:00 2001 From: SpinnerX Date: Fri, 22 May 2026 17:49:12 -0700 Subject: [PATCH 09/11] Removed stb_image from vulkan-cpp dependencies --- CMakeLists.txt | 2 -- conanfile.py | 1 - demos/17-buffer-device-address/CMakeLists.txt | 1 + 3 files changed, 1 insertion(+), 3 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index e1728a8..d9655a3 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -16,13 +16,11 @@ static_library( glfw3 Vulkan glm - stb LINK_PACKAGES glfw Vulkan::Vulkan glm::glm - stb::stb ) target_compile_features(${PROJECT_NAME} PUBLIC cxx_std_23) diff --git a/conanfile.py b/conanfile.py index c4fc71e..62eaff1 100644 --- a/conanfile.py +++ b/conanfile.py @@ -27,7 +27,6 @@ def build_requirements(self): def requirements(self): self.requires("glfw/3.4") self.requires("glm/1.0.1") - self.requires("stb/cci.20230920") def layout(self): cmake_layout(self) diff --git a/demos/17-buffer-device-address/CMakeLists.txt b/demos/17-buffer-device-address/CMakeLists.txt index dd8c7ed..b7fefe3 100644 --- a/demos/17-buffer-device-address/CMakeLists.txt +++ b/demos/17-buffer-device-address/CMakeLists.txt @@ -14,6 +14,7 @@ build_application( tinyobjloader LINK_PACKAGES + stb::stb vulkan-cpp tinyobjloader Vulkan::Vulkan From 00798f39dc8610705dbb04e1c6c8e974dc2f6084 Mon Sep 17 00:00:00 2001 From: SpinnerX Date: Fri, 22 May 2026 17:50:52 -0700 Subject: [PATCH 10/11] Minor code cleanup --- demos/17-buffer-device-address/application.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/demos/17-buffer-device-address/application.cpp b/demos/17-buffer-device-address/application.cpp index aeb75cf..baee411 100644 --- a/demos/17-buffer-device-address/application.cpp +++ b/demos/17-buffer-device-address/application.cpp @@ -674,7 +674,7 @@ main() { .memory_mask = physical_device.memory_properties(vk::memory_property::host_visible_bit | vk::memory_property::host_cached_bit), }; - + stb_image img = stb_image("asset_samples/viking_room.png", config_texture); vk::texture texture1(logical_device, &img, config_texture); @@ -694,6 +694,7 @@ main() { } }; + set1_resource.update({}, set1_samples); VkClearValue clear_color = { From eb3eb28265716645d9e749583653fb2848689857 Mon Sep 17 00:00:00 2001 From: SpinnerX Date: Fri, 22 May 2026 17:52:39 -0700 Subject: [PATCH 11/11] Formatted modified changes using clang-format --- .../17-buffer-device-address/application.cpp | 43 ++++---- vulkan-cpp/image.cppm | 15 +-- vulkan-cpp/texture.cppm | 102 ++++++++++++------ 3 files changed, 98 insertions(+), 62 deletions(-) diff --git a/demos/17-buffer-device-address/application.cpp b/demos/17-buffer-device-address/application.cpp index baee411..3da9742 100644 --- a/demos/17-buffer-device-address/application.cpp +++ b/demos/17-buffer-device-address/application.cpp @@ -246,10 +246,9 @@ struct push_constant_data { uint64_t global_ubo_addr = 0; }; - /** * @brief STBI-specific implementation of the vk::image interface -*/ + */ class stb_image : public vk::image { public: stb_image() = delete; @@ -261,18 +260,21 @@ class stb_image : public vk::image { ~stb_image() = default; protected: - bool image_load(std::string_view p_path, vk::texture_params p_params) override { + bool image_load(std::string_view p_path, + vk::texture_params p_params) override { int w = 0; int h = 0; int channels = 0; - stbi_uc* image_pixel_data = stbi_load(p_path.data(), &w, &h, &channels, STBI_rgb_alpha); + stbi_uc* image_pixel_data = + stbi_load(p_path.data(), &w, &h, &channels, STBI_rgb_alpha); - if(!image_pixel_data) { + if (!image_pixel_data) { return false; } - const VkFormat texture_format = static_cast(vk::format::r8g8b8a8_unorm); + const VkFormat texture_format = + static_cast(vk::format::r8g8b8a8_unorm); int bytes_per_pixel = vk::bytes_per_texture_format(texture_format); m_extent = { @@ -280,8 +282,10 @@ class stb_image : public vk::image { .height = static_cast(h), }; - // Retrieving total size of bytes of the dimensions of the image and accounting for pixels of the image - uint32_t size_bytes = m_extent.width * m_extent.height * bytes_per_pixel; + // Retrieving total size of bytes of the dimensions of the image and + // accounting for pixels of the image + uint32_t size_bytes = + m_extent.width * m_extent.height * bytes_per_pixel; // Retrieving total image size to the count of the image layers uint32_t size = size_bytes * p_params.layer_count; @@ -290,15 +294,15 @@ class stb_image : public vk::image { .extent = m_extent, .format = texture_format, .memory_mask = p_params.memory_mask, - .usage = - static_cast(vk::image_usage::transfer_dst_bit) | - static_cast(vk::image_usage::sampled_bit), + .usage = static_cast(vk::image_usage::transfer_dst_bit) | + static_cast(vk::image_usage::sampled_bit), .mip_levels = p_params.mip_levels, .layer_count = p_params.layer_count, }; m_bytes.reserve(size); - std::span bytes_view = std::span(image_pixel_data, size); + std::span bytes_view = + std::span(image_pixel_data, size); m_bytes.assign(bytes_view.begin(), bytes_view.end()); @@ -307,14 +311,9 @@ class stb_image : public vk::image { return true; } - std::span image_read() const override { - return m_bytes; - } - - vk::image_extent image_extent() const override { - return m_extent; - } + std::span image_read() const override { return m_bytes; } + vk::image_extent image_extent() const override { return m_extent; } private: vk::image_extent m_extent{}; @@ -671,8 +670,9 @@ main() { vk::dyn::buffer(logical_device, sizeof(global_uniform), uniform_params); vk::texture_params config_texture = { - .memory_mask = - physical_device.memory_properties(vk::memory_property::host_visible_bit | vk::memory_property::host_cached_bit), + .memory_mask = physical_device.memory_properties( + vk::memory_property::host_visible_bit | + vk::memory_property::host_cached_bit), }; stb_image img = stb_image("asset_samples/viking_room.png", config_texture); @@ -694,7 +694,6 @@ main() { } }; - set1_resource.update({}, set1_samples); VkClearValue clear_color = { diff --git a/vulkan-cpp/image.cppm b/vulkan-cpp/image.cppm index c79458a..b417657 100644 --- a/vulkan-cpp/image.cppm +++ b/vulkan-cpp/image.cppm @@ -20,22 +20,25 @@ export namespace vk { virtual ~image() = default; /** - * @brief Perform loading operations specific to the implementation of this interface - */ + * @brief Perform loading operations specific to the implementation + * of this interface + */ bool load(std::string_view p_path, texture_params p_params) { return image_load(p_path, p_params); } /** - * @brief Read you the bytes read from the specific image loading implementations - */ + * @brief Read you the bytes read from the specific image loading + * implementations + */ [[nodiscard]] std::span read() const { return image_read(); } /** - * @return the extent that contains properties about the image (dimensions, depth, etc) - */ + * @return the extent that contains properties about the image + * (dimensions, depth, etc) + */ [[nodiscard]] image_extent extent() const { return image_extent(); } protected: diff --git a/vulkan-cpp/texture.cppm b/vulkan-cpp/texture.cppm index f6ca122..d7a332b 100644 --- a/vulkan-cpp/texture.cppm +++ b/vulkan-cpp/texture.cppm @@ -25,24 +25,36 @@ export namespace vk { const image_extent& p_extent, std::span p_color, uint32_t p_memory_mask, - uint32_t p_mip_levels=1, - uint32_t p_layer_count=1) + uint32_t p_mip_levels = 1, + uint32_t p_layer_count = 1) : m_device(p_device) , m_extent(p_extent) { - construct(p_extent, p_color, p_memory_mask, p_mip_levels, p_layer_count); + construct(p_extent, + p_color, + p_memory_mask, + p_mip_levels, + p_layer_count); m_texture_loaded = true; } - texture(const VkDevice& p_device, image* p_image, const texture_params& p_texture_params) : m_device(p_device) { + texture(const VkDevice& p_device, + image* p_image, + const texture_params& p_texture_params) + : m_device(p_device) { construct(p_image, p_texture_params); } - void construct(image_extent p_extent, std::span p_data, uint32_t p_memory_mask, uint32_t p_mip_levels=1, uint32_t p_layer_count=1) { + void construct(image_extent p_extent, + std::span p_data, + uint32_t p_memory_mask, + uint32_t p_mip_levels = 1, + uint32_t p_layer_count = 1) { m_extent = p_extent; - const VkFormat texture_format = static_cast(format::r8g8b8a8_unorm); - + const VkFormat texture_format = + static_cast(format::r8g8b8a8_unorm); + image_params img_options = { .extent = p_extent, .format = texture_format, @@ -56,15 +68,16 @@ export namespace vk { m_image = sample_image(m_device, img_options); - // Setup staging buffer uint32_t property_flag = memory_property::host_visible_bit | - memory_property::host_cached_bit; + memory_property::host_cached_bit; buffer_parameters staging_options = { .memory_mask = img_options.memory_mask, - .property_flags = static_cast(property_flag), - .usage = static_cast(buffer_usage::transfer_src_bit), + .property_flags = + static_cast(property_flag), + .usage = + static_cast(buffer_usage::transfer_src_bit), }; buffer_stream staging(m_device, p_data.size(), staging_options); @@ -76,14 +89,18 @@ export namespace vk { .queue_index = 0, .flags = command_pool_flags::reset, }; - command_buffer temp_command_buffer = command_buffer(m_device, copy_command_params); + command_buffer temp_command_buffer = + command_buffer(m_device, copy_command_params); temp_command_buffer.begin(command_usage::one_time_submit); // Performing image layouts VkImageLayout old_layout = VK_IMAGE_LAYOUT_UNDEFINED; VkImageLayout new_layout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL; - m_image.memory_barrier(temp_command_buffer, img_options.format, old_layout, new_layout); + m_image.memory_barrier(temp_command_buffer, + img_options.format, + old_layout, + new_layout); std::array region_copies = { vk::buffer_image_copy{ @@ -92,18 +109,23 @@ export namespace vk { } }; - staging.copy_to_image(temp_command_buffer, m_image, region_copies); + staging.copy_to_image( + temp_command_buffer, m_image, region_copies); old_layout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL; new_layout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; - m_image.memory_barrier(temp_command_buffer, img_options.format, old_layout, new_layout); + m_image.memory_barrier(temp_command_buffer, + img_options.format, + old_layout, + new_layout); temp_command_buffer.end(); uint32_t queue_family = 0; uint32_t queue_index = 0; - VkQueue temp_graphics_queue=nullptr; - vkGetDeviceQueue(m_device, queue_family, queue_index, &temp_graphics_queue); + VkQueue temp_graphics_queue = nullptr; + vkGetDeviceQueue( + m_device, queue_family, queue_index, &temp_graphics_queue); const VkCommandBuffer handle = temp_command_buffer; VkSubmitInfo submit_info = { @@ -115,16 +137,18 @@ export namespace vk { vkQueueSubmit(temp_graphics_queue, 1, &submit_info, nullptr); vkQueueWaitIdle(temp_graphics_queue); - temp_command_buffer.destroy(); staging.destroy(); } - void construct(image* p_image, const texture_params& p_texture_params) { + void construct(image* p_image, + const texture_params& p_texture_params) { m_extent = p_image->extent(); - const VkFormat texture_format = static_cast(format::r8g8b8a8_unorm); - // NOTE To Self: Essentially passed to p_config parameter in create_texture_with_data + const VkFormat texture_format = + static_cast(format::r8g8b8a8_unorm); + // NOTE To Self: Essentially passed to p_config parameter in + // create_texture_with_data image_params img_options = { .extent = p_image->extent(), .format = texture_format, @@ -138,17 +162,19 @@ export namespace vk { m_image = sample_image(m_device, img_options); - // Setup staging buffer uint32_t property_flag = memory_property::host_visible_bit | - memory_property::host_cached_bit; + memory_property::host_cached_bit; buffer_parameters staging_options = { .memory_mask = img_options.memory_mask, - .property_flags = static_cast(property_flag), - .usage = static_cast(buffer_usage::transfer_src_bit), + .property_flags = + static_cast(property_flag), + .usage = + static_cast(buffer_usage::transfer_src_bit), }; - buffer_stream staging(m_device, p_image->read().size(), staging_options); + buffer_stream staging( + m_device, p_image->read().size(), staging_options); staging.transfer(p_image->read()); @@ -158,14 +184,18 @@ export namespace vk { .queue_index = 0, .flags = command_pool_flags::reset, }; - command_buffer temp_command_buffer = command_buffer(m_device, copy_command_params); + command_buffer temp_command_buffer = + command_buffer(m_device, copy_command_params); temp_command_buffer.begin(command_usage::one_time_submit); // Performing image layouts VkImageLayout old_layout = VK_IMAGE_LAYOUT_UNDEFINED; VkImageLayout new_layout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL; - m_image.memory_barrier(temp_command_buffer, img_options.format, old_layout, new_layout); + m_image.memory_barrier(temp_command_buffer, + img_options.format, + old_layout, + new_layout); std::array region_copies = { vk::buffer_image_copy{ @@ -174,18 +204,23 @@ export namespace vk { } }; - staging.copy_to_image(temp_command_buffer, m_image, region_copies); + staging.copy_to_image( + temp_command_buffer, m_image, region_copies); old_layout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL; new_layout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; - m_image.memory_barrier(temp_command_buffer, img_options.format, old_layout, new_layout); + m_image.memory_barrier(temp_command_buffer, + img_options.format, + old_layout, + new_layout); temp_command_buffer.end(); uint32_t queue_family = 0; uint32_t queue_index = 0; - VkQueue temp_graphics_queue=nullptr; - vkGetDeviceQueue(m_device, queue_family, queue_index, &temp_graphics_queue); + VkQueue temp_graphics_queue = nullptr; + vkGetDeviceQueue( + m_device, queue_family, queue_index, &temp_graphics_queue); const VkCommandBuffer handle = temp_command_buffer; VkSubmitInfo submit_info = { @@ -197,7 +232,6 @@ export namespace vk { vkQueueSubmit(temp_graphics_queue, 1, &submit_info, nullptr); vkQueueWaitIdle(temp_graphics_queue); - temp_command_buffer.destroy(); staging.destroy(); } @@ -217,7 +251,7 @@ export namespace vk { bool m_texture_loaded = false; sample_image m_image{}; image_extent m_extent; - class image* m_image_loader=nullptr; + class image* m_image_loader = nullptr; }; }; }; \ No newline at end of file