From e74fe2557205996493ffd177bb6fd73dddb8c3e6 Mon Sep 17 00:00:00 2001 From: SpinnerX Date: Mon, 18 May 2026 23:53:17 -0700 Subject: [PATCH 1/8] Added vk::dyn::buffer for implementing buffer device address APIs --- vulkan-cpp/dyn/buffer.cppm | 174 +++++++++++++++++++++++++++++++++++++ vulkan-cpp/types.cppm | 12 ++- 2 files changed, 185 insertions(+), 1 deletion(-) create mode 100644 vulkan-cpp/dyn/buffer.cppm diff --git a/vulkan-cpp/dyn/buffer.cppm b/vulkan-cpp/dyn/buffer.cppm new file mode 100644 index 0000000..b728182 --- /dev/null +++ b/vulkan-cpp/dyn/buffer.cppm @@ -0,0 +1,174 @@ +module; + +#include +#include +#include +#include + +export module vk:buffer_device_address; + +import :types; +import :utilities; + +export namespace vk::dyn { + + class buffer { + public: + buffer() = delete; + + buffer(const VkDevice& p_device, + uint64_t p_device_size, + const buffer_parameters& p_params) + : m_device(p_device) { + construct(p_device_size, p_params); + } + + // Can be invoked to perform invalidation on this buffer + void construct(uint64_t p_device_size, + const buffer_parameters& p_params) { + + m_size_bytes = p_device_size; + + // Constructs this dyn::buffer + VkBufferCreateInfo buffer_ci = { + .sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, + .pNext = nullptr, + .flags = 0, + .size = p_device_size, // size in bytes + .usage = static_cast(p_params.usage), + .sharingMode = p_params.share_mode, + }; + + vk_check(vkCreateBuffer(m_device, &buffer_ci, nullptr, &m_handle), + "vkCreateBuffer"); + + // Required to ensure the memory allocated is correspondent to the + // shader buffer device address bit + VkMemoryAllocateFlagsInfo allocate_flags_info = { + .sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_FLAGS_INFO, + .pNext = nullptr, + .flags = + static_cast(p_params.allocate_flags), + }; + // retrieving buffer memory requirements + VkMemoryRequirements memory_requirements = {}; + vkGetBufferMemoryRequirements( + m_device, m_handle, &memory_requirements); + uint32_t mapped_memory_requirements = + memory_requirements.memoryTypeBits & p_params.memory_mask; + uint32_t memory_index = + std::countr_zero(mapped_memory_requirements); + + // Required to be set for buffer device addresses + VkMemoryAllocateInfo memory_alloc_info = { + .sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO, + .pNext = &allocate_flags_info, + .allocationSize = memory_requirements.size, + .memoryTypeIndex = memory_index, + }; + + // Allocating for this buffer handle + vk_check(vkAllocateMemory( + m_device, &memory_alloc_info, nullptr, &m_device_memory), + "vkAllocateMemory"); + vk_check(vkBindBufferMemory(m_device, m_handle, m_device_memory, 0), + "vkBindBufferMemory"); + } + + void copy_to_image(const VkCommandBuffer& p_command, + const VkImage& p_image, + std::span p_copies) { + std::vector image_copies(p_copies.size()); + + for (uint32_t i = 0; i < image_copies.size(); i++) { + const buffer_image_copy image_copy = p_copies[i]; + image_copies[i] = { + .bufferOffset = image_copy.offset, + .bufferRowLength = image_copy.row_length, + .bufferImageHeight = image_copy.image_height, + .imageSubresource = { + .aspectMask = static_cast(image_copy.aspect_mask), + .mipLevel = image_copy.mip_level, + .baseArrayLayer = image_copy.base_array_layer, + .layerCount = image_copy.layer_count, + }, + .imageOffset = { + static_cast(image_copy.image_offset.width), + static_cast(image_copy.image_offset.height), + static_cast(image_copy.image_offset.depth), + }, + .imageExtent = { + image_copy.image_extent.width, + image_copy.image_extent.height, + image_copy.image_extent.depth, + }, + }; + } + + vkCmdCopyBufferToImage(p_command, + m_handle, + p_image, + VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, + static_cast(image_copies.size()), + image_copies.data()); + } + + //! @brief Destroys this object + void reset() { + if (m_handle != nullptr) { + vkDestroyBuffer(m_device, m_handle, nullptr); + } + + if (m_device_memory != nullptr) { + vkFreeMemory(m_device, m_device_memory, nullptr); + } + } + + template + void transfer(std::span p_data, uint32_t p_offset = 0) { + void* mapped = nullptr; + vk_check(vkMapMemory(m_device, + m_device_memory, + p_offset, + p_data.size_bytes(), + 0, + &mapped), + "vkMapMemory"); + memcpy(mapped, p_data.data(), p_data.size_bytes()); + vkUnmapMemory(m_device, m_device_memory); + } + + //! @brief Allows to retrieve the address to this particular buffer + //! handle + [[nodiscard("Cannot discard get_device_address()")]] const uint64_t + get_device_address() const { + VkBufferDeviceAddressInfo buffer_address_info = { + .sType = VK_STRUCTURE_TYPE_BUFFER_DEVICE_ADDRESS_INFO, + .buffer = m_handle, + }; + + return static_cast( + vkGetBufferDeviceAddress(m_device, &buffer_address_info)); + } + + [[nodiscard("Cannot discard device_memory()")]] VkDeviceMemory + device_memory() const { + return m_device_memory; + } + + [[nodiscard("cannot discard size_bytes()")]] uint32_t size_bytes() + const { + return m_size_bytes; + } + + operator VkBuffer() { return m_handle; } + + operator VkBuffer() const { return m_handle; } + + private: + uint32_t m_size_bytes = 0; + VkDevice m_device = nullptr; + VkBuffer m_handle = nullptr; + VkDeviceMemory m_device_memory; + }; +}; \ No newline at end of file diff --git a/vulkan-cpp/types.cppm b/vulkan-cpp/types.cppm index efa8e93..1c8351f 100644 --- a/vulkan-cpp/types.cppm +++ b/vulkan-cpp/types.cppm @@ -1413,6 +1413,16 @@ export namespace vk { flag_bits_max_enum = VK_MEMORY_PROPERTY_FLAG_BITS_MAX_ENUM }; + enum memory_allocate_flags : uint64_t { + device_mask_bit = VK_MEMORY_ALLOCATE_DEVICE_MASK_BIT, + device_address_bit = VK_MEMORY_ALLOCATE_DEVICE_ADDRESS_BIT, + device_address_capture_replay_bit = VK_MEMORY_ALLOCATE_DEVICE_ADDRESS_CAPTURE_REPLAY_BIT, + zero_initialize_bit = VK_MEMORY_ALLOCATE_ZERO_INITIALIZE_BIT_EXT, + device_mask_bit_khr = VK_MEMORY_ALLOCATE_DEVICE_MASK_BIT_KHR, + device_address_bit_khr = VK_MEMORY_ALLOCATE_DEVICE_ADDRESS_BIT, + device_address_capture_replay_bit_khr = VK_MEMORY_ALLOCATE_DEVICE_ADDRESS_CAPTURE_REPLAY_BIT + }; + enum class shader_stage { vertex = VK_SHADER_STAGE_VERTEX_BIT, fragment = VK_SHADER_STAGE_FRAGMENT_BIT, @@ -1607,8 +1617,8 @@ export namespace vk { struct buffer_parameters { uint32_t memory_mask = 0; memory_property property_flags; - // VkBufferUsageFlags usage; uint32_t usage; + memory_allocate_flags allocate_flags; VkSharingMode share_mode = VK_SHARING_MODE_EXCLUSIVE; const char* debug_name = nullptr; PFN_vkSetDebugUtilsObjectNameEXT vkSetDebugUtilsObjectNameEXT = From 288c5fe5ddbba137e1a59f63b7d99c58487804ba Mon Sep 17 00:00:00 2001 From: SpinnerX Date: Mon, 18 May 2026 23:56:59 -0700 Subject: [PATCH 2/8] Added demo 17 for testing buffer device addresses --- demos/17-buffer-device-address/CMakeLists.txt | 20 + demos/17-buffer-device-address/README.md | 1 + .../17-buffer-device-address/application.cpp | 899 ++++++++++++++++++ demos/17-buffer-device-address/conanfile.py | 35 + 4 files changed, 955 insertions(+) create mode 100644 demos/17-buffer-device-address/CMakeLists.txt create mode 100644 demos/17-buffer-device-address/README.md create mode 100644 demos/17-buffer-device-address/application.cpp create mode 100644 demos/17-buffer-device-address/conanfile.py diff --git a/demos/17-buffer-device-address/CMakeLists.txt b/demos/17-buffer-device-address/CMakeLists.txt new file mode 100644 index 0000000..dd8c7ed --- /dev/null +++ b/demos/17-buffer-device-address/CMakeLists.txt @@ -0,0 +1,20 @@ +cmake_minimum_required(VERSION 4.0) +project(buffer-device-address CXX) + +build_application( + SOURCES + application.cpp + + PACKAGES + vulkan-cpp + Vulkan + glfw3 + glm + stb + tinyobjloader + + LINK_PACKAGES + vulkan-cpp + tinyobjloader + Vulkan::Vulkan +) \ No newline at end of file diff --git a/demos/17-buffer-device-address/README.md b/demos/17-buffer-device-address/README.md new file mode 100644 index 0000000..8d9d84f --- /dev/null +++ b/demos/17-buffer-device-address/README.md @@ -0,0 +1 @@ +# Demo 16: Buffer Device Address \ No newline at end of file diff --git a/demos/17-buffer-device-address/application.cpp b/demos/17-buffer-device-address/application.cpp new file mode 100644 index 0000000..77809b9 --- /dev/null +++ b/demos/17-buffer-device-address/application.cpp @@ -0,0 +1,899 @@ +#define GLFW_INCLUDE_VULKAN +#if _WIN32 +#define VK_USE_PLATFORM_WIN32_KHR +#include +#define GLFW_EXPOSE_NATIVE_WIN32 +#include +#include +#else +#include +#include +#endif + +#include +#include +#include +#include +import vk; + +#include +#define GLM_FORCE_RADIANS +#include +#include +#define GLM_ENABLE_EXPERIMENTAL +#include + +#include + +#include + +namespace vk { + using buffer_device_address = feature_trait; +}; + +static VKAPI_ATTR VkBool32 VKAPI_CALL +debug_callback( + [[maybe_unused]] VkDebugUtilsMessageSeverityFlagBitsEXT p_message_severity, + [[maybe_unused]] VkDebugUtilsMessageTypeFlagsEXT p_message_type, + const VkDebugUtilsMessengerCallbackDataEXT* p_callback_data, + [[maybe_unused]] void* p_user_data) { + + std::print("validation layer:\t\t{}\n\n", p_callback_data->pMessage); + // std::print(core_dump_file, "Validation Layer:\t\t{}\n\n", p_callback_data->pMessage); + return false; +} + +struct global_uniform { + glm::mat4 model; + glm::mat4 view; + glm::mat4 proj; +}; + +template +void +hash_combine(size_t& seed, const T& v, const Rest&... rest) { + seed ^= std::hash()(v) + 0x9e3779b9 + (seed << 6) + (seed << 2); + (hash_combine(seed, rest), ...); +} + +namespace std { + + template<> + struct hash { + size_t operator()(const vk::vertex_input& vertex) const { + size_t seed = 0; + hash_combine( + seed, vertex.position, vertex.color, vertex.normals, vertex.uv); + return seed; + } + }; +} + +// Part of this demo for loading a 3D .obj model +class obj_model { +public: + obj_model() = default; + obj_model(const std::filesystem::path& p_filename, + const VkDevice& p_device, + const vk::physical_device& p_physical) { + tinyobj::attrib_t attrib; + std::vector shapes; + std::vector materials; + std::string warn, err; + + //! @note If we return the constructor then we can check if the mesh + //! loaded successfully + //! @note We also receive hints if the loading is successful! + //! @note Return default constructor automatically returns false means + //! that mesh will return the boolean as false because it wasnt + //! successful + if (!tinyobj::LoadObj(&attrib, + &shapes, + &materials, + &warn, + &err, + p_filename.string().c_str())) { + std::println("Could not load model from path {}", + p_filename.string()); + m_is_loaded = false; + return; + } + + std::vector vertices; + std::vector indices; + std::unordered_map unique_vertices{}; + + for (const auto& shape : shapes) { + for (const auto& index : shape.mesh.indices) { + vk::vertex_input vertex{}; + + // vertices.push_back(vertex); + if (!unique_vertices.contains(vertex)) { + unique_vertices[vertex] = + static_cast(vertices.size()); + vertices.push_back(vertex); + } + + if (index.vertex_index >= 0) { + vertex.position = { + attrib.vertices[3 * index.vertex_index + 0], + attrib.vertices[3 * index.vertex_index + 1], + attrib.vertices[3 * index.vertex_index + 2] + }; + + vertex.color = { + attrib.colors[3 * index.vertex_index + 0], + attrib.colors[3 * index.vertex_index + 1], + attrib.colors[3 * index.vertex_index + 2] + }; + } + + if (index.normal_index >= 0) { + vertex.normals = { + attrib.normals[3 * index.normal_index + 0], + attrib.normals[3 * index.normal_index + 1], + attrib.normals[3 * index.normal_index + 2] + }; + } + + if (index.texcoord_index >= 0) { + vertex.uv = { + attrib.texcoords[2 * index.texcoord_index + 0], + 1.0f - attrib.texcoords[2 * index.texcoord_index + 1] + }; + } + + if (!unique_vertices.contains(vertex)) { + unique_vertices[vertex] = + static_cast(vertices.size()); + vertices.push_back(vertex); + } + + indices.push_back(unique_vertices[vertex]); + } + } + + m_has_indices = (indices.size() > 0) ? true : false; + + if (m_has_indices) { + m_indices_size = indices.size(); + } + m_indices_size = vertices.size(); + m_indices_size = indices.size(); + + //! @brief Creating vertex/index buffers with host visibility flags + const auto property_flags = static_cast( + vk::memory_property::host_visible_bit | + vk::memory_property::host_cached_bit); + + vk::buffer_parameters vertex_params = { + .memory_mask = p_physical.memory_properties(property_flags), + .property_flags = vk::memory_property::device_local_bit, + .usage = static_cast(vk::buffer_usage::transfer_dst_bit) | + static_cast(vk::buffer_usage::vertex_buffer_bit), + }; + + vk::buffer_parameters index_params = { + .memory_mask = p_physical.memory_properties(property_flags), + .property_flags = static_cast( + vk::memory_property::host_visible_bit | + vk::memory_property::host_cached_bit), + .usage = static_cast(vk::buffer_usage::index_buffer_bit), + }; + + m_vertex_buffer = vk::vertex_buffer(p_device, vertices, vertex_params); + m_index_buffer = vk::index_buffer(p_device, indices, index_params); + m_is_loaded = true; + } + + [[nodiscard]] bool loaded() const { return m_is_loaded; } + + [[nodiscard]] VkBuffer vertex_handle() const { return m_vertex_buffer; } + + [[nodiscard]] VkBuffer index_handle() const { return m_index_buffer; } + + [[nodiscard]] bool has_indices() const { return m_has_indices; } + + [[nodiscard]] uint32_t indices_size() const { return m_indices_size; } + + void draw(const VkCommandBuffer& p_command) { + if (m_has_indices) { + vkCmdDrawIndexed(p_command, m_indices_size, 1, 0, 0, 0); + } + else { + vkCmdDraw(p_command, m_indices_size, 1, 0, 0); + } + } + + void destroy() { + m_vertex_buffer.destroy(); + m_index_buffer.destroy(); + } + +private: + bool m_is_loaded = false; + bool m_has_indices = false; + uint32_t m_indices_size = 0; + vk::vertex_buffer m_vertex_buffer{}; + vk::index_buffer m_index_buffer{}; +}; + +std::vector +get_instance_extensions() { + std::vector extension_names; + uint32_t extension_count = 0; + const char** required_extensions = + glfwGetRequiredInstanceExtensions(&extension_count); + + for (uint32_t i = 0; i < extension_count; i++) { + std::println("Required Extension = {}", required_extensions[i]); + extension_names.emplace_back(required_extensions[i]); + } + + extension_names.emplace_back(VK_EXT_DEBUG_UTILS_EXTENSION_NAME); + +#if defined(__APPLE__) + extension_names.emplace_back(VK_KHR_PORTABILITY_ENUMERATION_EXTENSION_NAME); + extension_names.emplace_back( + VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME); +#endif + + return extension_names; +} + +struct push_constant_data { + uint32_t texture_index = 0; +}; + +int +main() { + //! @note Just added the some test code to test the conan-starter setup code + if (!glfwInit()) { + std::print("glfwInit could not be initialized!\n"); + return -1; + } + + if (!glfwVulkanSupported()) { + std::print("GLFW: Vulkan is not supported!"); + return -1; + } + + glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API); + glfwWindowHint(GLFW_RESIZABLE, GLFW_TRUE); + + int width = 800; + int height = 600; + std::string title = "Hello Window"; + GLFWwindow* window = + glfwCreateWindow(width, height, title.c_str(), nullptr, nullptr); + + glfwMakeContextCurrent(window); + + std::array validation_layers = { + "VK_LAYER_KHRONOS_validation", + }; + + // setting up extensions + std::vector global_extensions = get_instance_extensions(); + + vk::debug_message_utility debug_callback_info = { + // .severity essentially takes in vk::message::verbose, + // vk::message::warning, vk::message::error + .severity = + vk::message::verbose | vk::message::warning | vk::message::error, + // .message_type essentially takes in vk::debug. Like: + // vk::debug::general, vk::debug::validation, vk::debug::performance + .message_type = + vk::debug::general | vk::debug::validation | vk::debug::performance, + .callback = debug_callback + }; + + vk::application_params config = { + .name = "vulkan instance", + .version = vk::api_version::vk_1_3, // specify to using vulkan 1.3 + .validations = + validation_layers, // .validation takes in a std::span + .extensions = + global_extensions // .extensions also takes in std::span + }; + + // 1. Setting up vk instance + vk::instance api_instance(config, debug_callback_info); + + if (api_instance.alive()) { + std::println("\napi_instance alive and initiated!!!"); + } + + std::span properties = + api_instance.validation(); + for (vk::layer_properties property : properties) { + std::println("Validation Layer Name:\t\t{}", property.name); + std::println("Validation Layer Description: {}", property.description); + } + + // setting up physical device + vk::physical_enumeration enumerate_devices{ + .device_type = vk::physical_gpu::integrated, + }; + vk::physical_device physical_device(api_instance, enumerate_devices); + + vk::queue_indices queue_indices = physical_device.family_indices(); + + // setting up logical device + std::array priorities = { 0.f }; + +#if defined(__APPLE__) + std::array extensions = { + VK_KHR_SWAPCHAIN_EXTENSION_NAME, + "VK_KHR_portability_subset", + }; +#else + std::array extensions = { + VK_KHR_SWAPCHAIN_EXTENSION_NAME, + }; +#endif + + std::array format_support = { + vk::format::d32_sfloat, + vk::format::d32_sfloat_s8_uint, + vk::format::d24_unorm_s8_uint + }; + + // We provide a selection of format support that we want to check is + // supported on current hardware device. + VkFormat depth_format = + physical_device.request_depth_format(format_support); + + vk::device_features device_features{ + vk::dynamic_rendering_feature{ { + .dynamicRendering = true, + } }, + vk::descriptor_indexing_feature{ { + .shaderSampledImageArrayNonUniformIndexing = true, + .descriptorBindingSampledImageUpdateAfterBind = true, + .descriptorBindingPartiallyBound = true, + .descriptorBindingVariableDescriptorCount = true, + .runtimeDescriptorArray = true, + } }, + vk::buffer_device_address{ { + .bufferDeviceAddress = true, + } }, + }; + + vk::device_params logical_device_params = { + .features = device_features.data(), + .queue_priorities = priorities, + .extensions = extensions, + .queue_family_index = queue_indices.graphics, + }; + + + vk::device logical_device(physical_device, logical_device_params); + + vk::surface window_surface(api_instance, window); + + vk::surface_params surface_properties = + physical_device.request_surface(window_surface); + + VkBool32 presentation_supported = false; + vkGetPhysicalDeviceSurfaceSupportKHR(physical_device, 0, window_surface, &presentation_supported); + + VkPhysicalDeviceProperties device_properties; + vkGetPhysicalDeviceProperties(physical_device, &device_properties); + + VkPhysicalDeviceType currently_selected_physical_gpu = device_properties.deviceType; + + std::println("External Monitor Physical Device Type: VK_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU "); + std::println("External Monitor Physical Device Type (take 2): VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU "); + std::println("Selected Physical GPU: {}", static_cast(currently_selected_physical_gpu)); + + // m_surface_params.format.format, + // .imageColorSpace = m_surface_params.format.colorSpace + + std::println("Laptop VkFormat = VK_FORMAT_B8G8R8A8_SRGB , VkColorSpaceKHR = VK_COLOR_SPACE_SRGB_NONLINEAR_KHR "); + std::println("VkFormat = {}\nColor Space = {}", static_cast(surface_properties.format.format), static_cast(surface_properties.format.colorSpace)); + + // if (presentation_supported] == VK_TRUE) { + // // The surface is presentable by this queue family + // } + + std::println("Presentation Supported = {}", static_cast(presentation_supported)); + + vk::swapchain_params enumerate_swapchain_settings = { + .width = static_cast(width), + .height = static_cast(height), + .present_index = + physical_device.family_indices() + .graphics, // presentation index just uses the graphics index + }; + + std::println("Surface Extent (w, h) = ({}, {})", surface_properties.capabilities.currentExtent.width, surface_properties.capabilities.currentExtent.height); + + std::println("Presentation Index: {}", + physical_device.family_indices().graphics); + + // m_surface_params.capabilities.currentExtent + + vk::swapchain main_swapchain(logical_device, + window_surface, + enumerate_swapchain_settings, + surface_properties); + + + if(!main_swapchain.alive()) { + std::println("main_swapchain is nullptr!!!"); + return -1; + } + + // querying presentable images + std::span images = main_swapchain.get_images(); + + std::println("span::size() = {}", images.size()); + uint32_t image_count = static_cast(images.size()); + + // Creating Images + std::vector swapchain_images(image_count); + std::vector swapchain_depth_images(image_count); + + VkExtent2D swapchain_extent = surface_properties.capabilities.currentExtent; + + // Setting up the images + uint32_t layer_count = 1; + uint32_t mip_levels = 1; + for (uint32_t i = 0; i < swapchain_images.size(); i++) { + vk::image_params swapchain_image_config = { + .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, + }; + + swapchain_images[i] = + vk::sample_image(logical_device, images[i], swapchain_image_config); + + vk::image_params image_config = { + .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, + }; + swapchain_depth_images[i] = + vk::sample_image(logical_device, image_config); + } + + // setting up command buffers + std::vector swapchain_command_buffers(image_count); + for (size_t i = 0; i < swapchain_command_buffers.size(); i++) { + vk::command_params settings = { + .levels = vk::command_levels::primary, + .queue_index = enumerate_swapchain_settings.present_index, + .flags = vk::command_pool_flags::reset, + }; + + swapchain_command_buffers[i] = + vk::command_buffer(logical_device, settings); + } + + // setting up presentation queue to display commands to the screen + vk::queue_params enumerate_present_queue{ + .family = 0, + .index = 0, + }; + vk::device_present_queue presentation_queue( + logical_device, main_swapchain, enumerate_present_queue); + + // gets set with the renderpass + std::array color = { 0.f, 0.5f, 0.5f, 1.f }; + + // Loading graphics pipeline + std::array shader_sources = { + vk::shader_source{ + .filename = + "shader_samples/sample9-buffer-device-address/test.vert.spv", + .stage = vk::shader_stage::vertex, + }, + vk::shader_source{ + .filename = + "shader_samples/sample9-buffer-device-address/test.frag.spv", + .stage = vk::shader_stage::fragment, + }, + }; + + // To render triangle, we do not need to set any vertex attributes + vk::shader_resource_info shader_info = { + .sources = shader_sources, + .vertex_attributes = {} // this is to explicitly set to none, but also + // dont need to set this at all regardless + }; + vk::shader_resource geometry_resource(logical_device, shader_info); + + // Setting up vertex attributes in the test shaders + std::array attribute_entries = { + vk::vertex_attribute_entry{ + .location = 0, + .format = vk::format::rgb32_sfloat, + .stride = offsetof(vk::vertex_input, position), + }, + vk::vertex_attribute_entry{ + .location = 1, + .format = vk::format::rgb32_sfloat, + .stride = offsetof(vk::vertex_input, color), + }, + vk::vertex_attribute_entry{ + .location = 2, + .format = vk::format::rg32_sfloat, + .stride = offsetof(vk::vertex_input, uv), + }, + vk::vertex_attribute_entry{ + .location = 3, + .format = vk::format::rgb32_sfloat, + .stride = offsetof(vk::vertex_input, normals), + } + }; + + std::array attributes = { + vk::vertex_attribute{ + // layout (set = 0, binding = 0) + .binding = 0, + .entries = attribute_entries, + .stride = sizeof(vk::vertex_input), + .input_rate = vk::input_rate::vertex, + }, + }; + geometry_resource.vertex_attributes(attributes); + + // Set 0: For Uniform BUffers (or global scene data) + std::vector entries = { + vk::descriptor_entry{ + // specifies "layout (set = 0, binding = 0) uniform GlobalUbo" + .type = vk::buffer::uniform, + .binding_point = { + .binding = 0, + .stage = vk::shader_stage::vertex, + }, + .descriptor_count = 1, + }, + }; + vk::descriptor_layout set0_layout = { + .slot = 0, // indicate specific descriptor slot 0 + .max_sets = image_count, // max descriptors to allocate + .entries = entries, // descriptor layout entries description + }; + vk::descriptor_resource set0_resource(logical_device, set0_layout); + + // Set 1 = For Textures + std::vector entries_set1 = { + vk::descriptor_entry{ + // layout (set = 1, binding = 0) uniform sampler2D textures[]; + .type = vk::buffer::combined_image_sampler, + .binding_point = { + .binding = 0, + .stage = vk::shader_stage::fragment, + }, + .descriptor_count = 1, + .flags = vk::descriptor_bind_flags::partially_bound_bit | + vk::descriptor_bind_flags::variable_descriptor_count_bit | + vk::descriptor_bind_flags::update_after_bind, + } + }; + + uint32_t max_descriptor = 1; + vk::descriptor_layout set1_layout = { + .slot = 1, // indicate specific descriptor slot 0 + .max_sets = image_count, // max descriptors to allocate + .entries = entries_set1, // descriptor layout entries description + .descriptor_counts = std::span(&max_descriptor, 1), + }; + + vk::descriptor_resource set1_resource( + logical_device, + set1_layout, + vk::descriptor_layout_flags::update_after_bind_pool); + + std::array layouts = { + set0_resource.layout(), + set1_resource.layout(), + }; + + std::array color_blend_attachments = { + vk::color_blend_attachment_state{}, + }; + + std::array dynamic_states = { + vk::dynamic_state::viewport, vk::dynamic_state::scissor + }; + + uint32_t format = static_cast(surface_properties.format.format); + uint32_t vertex_mask = static_cast(vk::shader_stage::vertex); + uint32_t fragment_mask = static_cast(vk::shader_stage::fragment); + uint32_t stage_mask = vertex_mask | fragment_mask; + vk::shader_stage stage = static_cast(stage_mask); + vk::push_constant_range range = { + .stage = stage, + .offset = 0, + .range = sizeof(push_constant_data), + }; + vk::pipeline_params pipeline_configuration = { + .use_render_pipeline = true, + .color_attachment_formats = std::span(&format, 1), + .depth_format = static_cast(depth_format), + .stencil_format = static_cast(depth_format), + .renderpass = nullptr, + .shader_modules = geometry_resource.handles(), + .vertex_attributes = geometry_resource.vertex_attributes(), + .vertex_bind_attributes = geometry_resource.vertex_bind_attributes(), + .descriptor_layouts = layouts, + .color_blend = { + .attachments = color_blend_attachments, + }, + .depth_stencil_enabled = true, + .dynamic_states = dynamic_states, + .push_constants = std::span(&range, 1), + }; + vk::pipeline main_graphics_pipeline(logical_device, pipeline_configuration); + + obj_model test_model(std::filesystem::path("asset_samples/viking_room.obj"), + logical_device, + physical_device); + + vk::buffer_parameters uniform_params = { + .memory_mask = + physical_device.memory_properties(static_cast( + vk::memory_property::host_visible_bit | + vk::memory_property::host_cached_bit)), + .usage = static_cast(vk::buffer_usage::uniform_buffer_bit | vk::buffer_usage::shader_device_address_bit), + .allocate_flags = vk::memory_allocate_flags::device_address_bit_khr, + }; + vk::dyn::buffer test_ubo = vk::dyn::buffer( + logical_device, sizeof(global_uniform), uniform_params); + + std::array uniforms0 = { + vk::write_buffer{ + .buffer = test_ubo, + .offset = 0, + .range = static_cast(test_ubo.size_bytes()), + }, + }; + std::array uniforms = { + vk::write_buffer_descriptor{ + .dst_binding = 0, + .uniforms = uniforms0, + }, + }; + + 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)), + }; + vk::texture texture1(logical_device, + std::filesystem::path("asset_samples/viking_room.png"), + config_texture); + + std::array samplers = { + vk::write_image{ + .sampler = texture1.image().sampler(), + .view = texture1.image().image_view(), + .layout = vk::image_layout::shader_read_only_optimal, + }, + }; + + // Specify image descriptor images/samplers to the descriptor + std::array set1_samples = { + vk::write_image_descriptor{ + .dst_binding = 0, + .sample_images = samplers, + } + }; + set0_resource.update(uniforms); + + set1_resource.update({}, set1_samples); + + VkClearValue clear_color = { + { 0.f, 0.5f, 0.5f, 1.f }, + }; + + VkClearValue depth_value = { + .depthStencil = { .depth = 1.f, .stencil = 0 }, + }; + + while (!glfwWindowShouldClose(window)) { + glfwPollEvents(); + + uint32_t current_frame = presentation_queue.acquire_next_image(); + vk::command_buffer current = swapchain_command_buffers[current_frame]; + + current.begin(vk::command_usage::simulatneous_use_bit); + + swapchain_images[current_frame].memory_barrier( + current, + surface_properties.format.format, + VK_IMAGE_LAYOUT_UNDEFINED, + VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL); + + // Because dynamic rendering does not automatically handle layout + // transitions These memory barriers set the color and depth images for + // the output + swapchain_depth_images[current_frame].memory_barrier( + current, + depth_format, + VK_IMAGE_LAYOUT_UNDEFINED, + VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, + VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT); + + vk::rendering_attachment color_render_attachment = { + .image_view = swapchain_images[current_frame].image_view(), + .layout = vk::image_layout::color_optimal, + .resolve_mode = vk::resolved_mode_flags::none, + .resolve_image_view = nullptr, + .resolve_image_layout = vk::image_layout::undefined, + .load = vk::attachment_load::clear, + .store = vk::attachment_store::store, + .clear_values = clear_color + }; + + vk::rendering_attachment depth_stencil_attachment = { + .image_view = swapchain_depth_images[current_frame].image_view(), + .layout = vk::image_layout::depth_stencil_optimal, + .resolve_mode = vk::resolved_mode_flags::none, + .resolve_image_view = nullptr, + .resolve_image_layout = vk::image_layout::undefined, + .load = vk::attachment_load::clear, + .store = vk::attachment_store::store, + .depth_values = depth_value + }; + + vk::rendering_begin_parameters begin_params = { + .render_area = { { 0, 0 }, + { + swapchain_extent.width, + swapchain_extent.height, + }, }, + .layer_count = 1, + .color_attachments = std::span( + &color_render_attachment, 1), + .depth_attachment = depth_stencil_attachment, + .stencil_attachment = depth_stencil_attachment, + }; + + vk::viewport_params viewport = { + .x = 0.0f, + .y = 0.0f, + .width = static_cast(swapchain_extent.width), + .height = static_cast(swapchain_extent.height), + .min_depth = 0.0f, + .max_depth = 1.0f, + }; + current.set_viewport( + 0, 1, std::span(&viewport, 1)); + + vk::scissor_params scissor = { + .offset = { 0, 0 }, + .extent = swapchain_extent, + }; + + current.set_scissor( + 0, 1, std::span(&scissor, 1)); + + current.begin_rendering(begin_params); + + main_graphics_pipeline.bind(current); + + const VkBuffer vertex = test_model.vertex_handle(); + uint64_t offset = 0; + current.bind_vertex_buffers(std::span(&vertex, 1), + std::span(&offset, 1)); + + if (test_model.has_indices()) { + current.bind_index_buffers32(test_model.index_handle()); + } + + static auto start_time = std::chrono::high_resolution_clock::now(); + + auto current_time = std::chrono::high_resolution_clock::now(); + float time = std::chrono::duration( + current_time - start_time) + .count(); + + push_constant_data push = { + .texture_index = 0, + }; + main_graphics_pipeline.push_constant( + current, push, stage, 0, sizeof(push_constant_data)); + + // We set the uniforms and then we offload that to the GPU + global_uniform ubo = { + .model = glm::rotate(glm::mat4(1.0f), + time * glm::radians(90.0f), + glm::vec3(0.0f, 0.0f, 1.0f)), + .view = glm::lookAt(glm::vec3(2.0f, 2.0f, 2.0f), + glm::vec3(0.0f, 0.0f, 0.0f), + glm::vec3(0.0f, 0.0f, 1.0f)), + .proj = glm::perspective(glm::radians(45.0f), + (float)swapchain_extent.width / + (float)swapchain_extent.height, + 0.1f, + 10.0f) + }; + ubo.proj[1][1] *= -1; + + test_ubo.transfer( + std::span(&ubo, 1)); + + std::array descriptors = { + set0_resource, + set1_resource, + }; + + current.bind_descriptors(main_graphics_pipeline.layout(), + VK_PIPELINE_BIND_POINT_GRAPHICS, + descriptors); + + // Drawing-call to render actual triangle to the screen + // vkCmdDrawIndexed(current, static_cast(indices.size()), 1, + // 0, 0, 0); + test_model.draw(current); + + // vkCmdDraw(current, 3, 1, 0, 0); + + current.end_rendering(); + + swapchain_images[current_frame].memory_barrier( + current, + surface_properties.format.format, + VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, + VK_IMAGE_LAYOUT_PRESENT_SRC_KHR); + + current.end(); + + // Submitting and then presenting to the screen + std::array commands = { current }; + presentation_queue.submit_async(commands); + presentation_queue.present_frame(current_frame); + } + + logical_device.wait(); + main_swapchain.destroy(); + + texture1.destroy(); + set0_resource.destroy(); + set1_resource.destroy(); + test_ubo.reset(); + test_model.destroy(); + + geometry_resource.destroy(); + main_graphics_pipeline.destroy(); + + for (auto& command : swapchain_command_buffers) { + command.destroy(); + } + + for (auto& image : swapchain_images) { + image.destroy(); + } + + for (auto& image : swapchain_depth_images) { + image.destroy(); + } + + presentation_queue.destroy(); + + logical_device.destroy(); + window_surface.destroy(); + glfwDestroyWindow(window); + api_instance.destroy(); + return 0; +} diff --git a/demos/17-buffer-device-address/conanfile.py b/demos/17-buffer-device-address/conanfile.py new file mode 100644 index 0000000..5d2a70c --- /dev/null +++ b/demos/17-buffer-device-address/conanfile.py @@ -0,0 +1,35 @@ +from conan import ConanFile +from conan.tools.cmake import CMake, cmake_layout + +class Demo(ConanFile): + name = "game-demo" + version = "1.0" + settings = "os", "compiler", "build_type", "arch" + generators = "CMakeDeps", "CMakeToolchain" + export_source = "CMakeLists.txt", "application.cpp" + + # Putting all of your build-related dependencies here + def build_requirements(self): + self.tool_requires("cmake/[^4.0.0]") + self.tool_requires("ninja/[^1.3.0]") + self.tool_requires("engine3d-cmake-utils/4.0") + + # Setting demo dependencies + def requirements(self): + self.requires("glfw/3.4") + self.requires("glm/1.0.1") + self.requires("stb/cci.20230920") + self.requires("tinyobjloader/2.0.0-rc10") + self.requires("vulkan-cpp/6.0") + + def build(self): + cmake = CMake(self) + cmake.configure() + cmake.build() + + def package(self): + cmake = CMake(self) + cmake.install() + + def layout(self): + cmake_layout(self) \ No newline at end of file From 598b8f80a6714613f36ee5551b4c2e2ab4c1ca95 Mon Sep 17 00:00:00 2001 From: SpinnerX Date: Tue, 19 May 2026 17:37:29 -0700 Subject: [PATCH 3/8] Actually working buffer device address demo code --- .../17-buffer-device-address/application.cpp | 122 +++++++++--------- .../sample9-buffer-device-address/test.frag | 17 +++ .../test.frag.spv | Bin 0 -> 1092 bytes .../sample9-buffer-device-address/test.vert | 38 ++++++ .../test.vert.spv | Bin 0 -> 2596 bytes 5 files changed, 113 insertions(+), 64 deletions(-) create mode 100644 shader_samples/sample9-buffer-device-address/test.frag create mode 100644 shader_samples/sample9-buffer-device-address/test.frag.spv create mode 100644 shader_samples/sample9-buffer-device-address/test.vert create mode 100644 shader_samples/sample9-buffer-device-address/test.vert.spv diff --git a/demos/17-buffer-device-address/application.cpp b/demos/17-buffer-device-address/application.cpp index 77809b9..bf2bc3f 100644 --- a/demos/17-buffer-device-address/application.cpp +++ b/demos/17-buffer-device-address/application.cpp @@ -28,6 +28,8 @@ import vk; #include namespace vk { + // REQUIRED + using physical_device_features2 = feature_trait; using buffer_device_address = feature_trait; }; @@ -243,6 +245,7 @@ get_instance_extensions() { struct push_constant_data { uint32_t texture_index = 0; + uint64_t global_ubo_addr=0; }; int @@ -304,12 +307,12 @@ main() { std::println("\napi_instance alive and initiated!!!"); } - std::span properties = - api_instance.validation(); - for (vk::layer_properties property : properties) { - std::println("Validation Layer Name:\t\t{}", property.name); - std::println("Validation Layer Description: {}", property.description); - } + // std::span properties = + // api_instance.validation(); + // for (vk::layer_properties property : properties) { + // std::println("Layer Name:\t\t{}", property.name); + // std::println("Layer Description: {}", property.description); + // } // setting up physical device vk::physical_enumeration enumerate_devices{ @@ -383,19 +386,12 @@ main() { VkPhysicalDeviceType currently_selected_physical_gpu = device_properties.deviceType; - std::println("External Monitor Physical Device Type: VK_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU "); - std::println("External Monitor Physical Device Type (take 2): VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU "); - std::println("Selected Physical GPU: {}", static_cast(currently_selected_physical_gpu)); - - // m_surface_params.format.format, - // .imageColorSpace = m_surface_params.format.colorSpace - - std::println("Laptop VkFormat = VK_FORMAT_B8G8R8A8_SRGB , VkColorSpaceKHR = VK_COLOR_SPACE_SRGB_NONLINEAR_KHR "); - std::println("VkFormat = {}\nColor Space = {}", static_cast(surface_properties.format.format), static_cast(surface_properties.format.colorSpace)); + // std::println("External Monitor Physical Device Type: VK_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU "); + // std::println("External Monitor Physical Device Type (take 2): VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU "); + // std::println("Selected Physical GPU: {}", static_cast(currently_selected_physical_gpu)); - // if (presentation_supported] == VK_TRUE) { - // // The surface is presentable by this queue family - // } + // std::println("Laptop VkFormat = VK_FORMAT_B8G8R8A8_SRGB , VkColorSpaceKHR = VK_COLOR_SPACE_SRGB_NONLINEAR_KHR "); + // std::println("VkFormat = {}\nColor Space = {}", static_cast(surface_properties.format.format), static_cast(surface_properties.format.colorSpace)); std::println("Presentation Supported = {}", static_cast(presentation_supported)); @@ -555,31 +551,31 @@ main() { geometry_resource.vertex_attributes(attributes); // Set 0: For Uniform BUffers (or global scene data) - std::vector entries = { - vk::descriptor_entry{ - // specifies "layout (set = 0, binding = 0) uniform GlobalUbo" - .type = vk::buffer::uniform, - .binding_point = { - .binding = 0, - .stage = vk::shader_stage::vertex, - }, - .descriptor_count = 1, - }, - }; - vk::descriptor_layout set0_layout = { - .slot = 0, // indicate specific descriptor slot 0 - .max_sets = image_count, // max descriptors to allocate - .entries = entries, // descriptor layout entries description - }; - vk::descriptor_resource set0_resource(logical_device, set0_layout); + // std::vector entries = { + // vk::descriptor_entry{ + // // specifies "layout (set = 0, binding = 0) uniform GlobalUbo" + // .type = vk::buffer::uniform, + // .binding_point = { + // .binding = 0, + // .stage = vk::shader_stage::vertex, + // }, + // .descriptor_count = 1, + // }, + // }; + // vk::descriptor_layout set0_layout = { + // .slot = 0, // indicate specific descriptor slot 0 + // .max_sets = image_count, // max descriptors to allocate + // .entries = entries, // descriptor layout entries description + // }; + // vk::descriptor_resource set0_resource(logical_device, set0_layout); // Set 1 = For Textures std::vector entries_set1 = { vk::descriptor_entry{ - // layout (set = 1, binding = 0) uniform sampler2D textures[]; + // layout (set = 0, binding = 1) uniform sampler2D textures[]; .type = vk::buffer::combined_image_sampler, .binding_point = { - .binding = 0, + .binding = 1, .stage = vk::shader_stage::fragment, }, .descriptor_count = 1, @@ -591,7 +587,7 @@ main() { uint32_t max_descriptor = 1; vk::descriptor_layout set1_layout = { - .slot = 1, // indicate specific descriptor slot 0 + .slot = 0, // indicate specific descriptor slot 0 .max_sets = image_count, // max descriptors to allocate .entries = entries_set1, // descriptor layout entries description .descriptor_counts = std::span(&max_descriptor, 1), @@ -602,8 +598,7 @@ main() { set1_layout, vk::descriptor_layout_flags::update_after_bind_pool); - std::array layouts = { - set0_resource.layout(), + std::array layouts = { set1_resource.layout(), }; @@ -659,19 +654,19 @@ main() { vk::dyn::buffer test_ubo = vk::dyn::buffer( logical_device, sizeof(global_uniform), uniform_params); - std::array uniforms0 = { - vk::write_buffer{ - .buffer = test_ubo, - .offset = 0, - .range = static_cast(test_ubo.size_bytes()), - }, - }; - std::array uniforms = { - vk::write_buffer_descriptor{ - .dst_binding = 0, - .uniforms = uniforms0, - }, - }; + // std::array uniforms0 = { + // vk::write_buffer{ + // .buffer = test_ubo, + // .offset = 0, + // .range = static_cast(test_ubo.size_bytes()), + // }, + // }; + // std::array uniforms = { + // vk::write_buffer_descriptor{ + // .dst_binding = 0, + // .uniforms = uniforms0, + // }, + // }; vk::texture_params config_texture = { .memory_mask = @@ -694,11 +689,11 @@ main() { // Specify image descriptor images/samplers to the descriptor std::array set1_samples = { vk::write_image_descriptor{ - .dst_binding = 0, + .dst_binding = 1, .sample_images = samplers, } }; - set0_resource.update(uniforms); + // set0_resource.update(uniforms); set1_resource.update({}, set1_samples); @@ -808,12 +803,6 @@ main() { current_time - start_time) .count(); - push_constant_data push = { - .texture_index = 0, - }; - main_graphics_pipeline.push_constant( - current, push, stage, 0, sizeof(push_constant_data)); - // We set the uniforms and then we offload that to the GPU global_uniform ubo = { .model = glm::rotate(glm::mat4(1.0f), @@ -833,8 +822,14 @@ main() { test_ubo.transfer( std::span(&ubo, 1)); - std::array descriptors = { - set0_resource, + const uint64_t ubo_address = test_ubo.get_device_address(); + push_constant_data push = { + .texture_index = 0, + .global_ubo_addr = ubo_address, + }; + main_graphics_pipeline.push_constant( + current, push, stage, 0, sizeof(push_constant_data)); + std::array descriptors = { set1_resource, }; @@ -869,7 +864,6 @@ main() { main_swapchain.destroy(); texture1.destroy(); - set0_resource.destroy(); set1_resource.destroy(); test_ubo.reset(); test_model.destroy(); diff --git a/shader_samples/sample9-buffer-device-address/test.frag b/shader_samples/sample9-buffer-device-address/test.frag new file mode 100644 index 0000000..0a98c20 --- /dev/null +++ b/shader_samples/sample9-buffer-device-address/test.frag @@ -0,0 +1,17 @@ +#version 450 + +#extension GL_EXT_nonuniform_qualifier : require + +layout(location = 0) in vec3 fragColor; +layout(location = 1) in vec2 fragTexCoords; +layout(location = 2) in vec3 fragNormals; +layout(location = 3) in flat int fragTexIndex; + +layout(location = 0) out vec4 outColor; + +layout(set = 0, binding = 1) uniform sampler2D textures[]; + +void main() { + + outColor = texture(textures[nonuniformEXT(fragTexIndex)], fragTexCoords); +} \ No newline at end of file diff --git a/shader_samples/sample9-buffer-device-address/test.frag.spv b/shader_samples/sample9-buffer-device-address/test.frag.spv new file mode 100644 index 0000000000000000000000000000000000000000..7cc26048ac6f92c159ea5b7e814883401c1fc658 GIT binary patch literal 1092 zcmYk4U2D`(5QfL@hjnXhYi(<-)vewaFH{6kkWzxMSYeBL7naT0av)9Ce8~F0)En>o zRo)1`Pc~U{U@|lBd1uaiq_g()rr8bKuuU7<^6c1}5Hs}8drSSR*1x3(wr=B(pThGm zmto}cY3AoenuR`z+`=bU%GIypgVA_&nitXO^B2#^e8)P~1LWRPmaa5%J@E+_wHxVrddP)Ip`U@Nespez&@zGNt|1tYM2vT4nA+6NSJHm zKatG|G&5!jhdXRy*#vjH(m%9Q?7fz~zp}fleKh%rZ@*8C`0Qp^U-XIc@doz3tiJS6 za-bU6B|dW<>bout7yNbY(<9iSx*bTv=l%9+{39_pbOG;J_HAi=a&Jm=z{riyEI51e zx1@&>a>3uOZE*Pb%&fWBsH#JLdO47$Hu@y~zBF8L;_=z{66@MS+3@KN{&9T=4j-Rc z!f$-$i~myp1Me_54mth`=}Es4O3imA)H|+y_6zn-ENW-R^bbx9eXwhAeCmE6q2|wu VVJAltIN)#fD!T#ur>b5_{sU2AWo`ff literal 0 HcmV?d00001 diff --git a/shader_samples/sample9-buffer-device-address/test.vert b/shader_samples/sample9-buffer-device-address/test.vert new file mode 100644 index 0000000..df3dd0c --- /dev/null +++ b/shader_samples/sample9-buffer-device-address/test.vert @@ -0,0 +1,38 @@ +#version 450 + +#extension GL_EXT_buffer_reference : require + +layout(location = 0) in vec3 inPosition; +layout(location = 1) in vec3 inColor; +layout(location = 2) in vec2 inTexCoords; +layout(location = 3) in vec3 inNormals; + +layout(location = 0) out vec3 fragColor; +layout(location = 1) out vec2 fragTexCoords; +layout(location = 2) out vec3 fragNormals; +layout(location = 3) out flat int fragTexIndex; + +layout(buffer_reference, std140) buffer readonly UniformBufferObject { + mat4 model; + mat4 view; + mat4 proj; +}; + +layout(push_constant) uniform Constants { + int texture_index; + UniformBufferObject global_ubo_address; +} push_const; + + + +void main() { + + // UniformBufferObject ubo = UniformBufferObject(push_const.global_ubo_address); + UniformBufferObject ubo = push_const.global_ubo_address; + + gl_Position = ubo.proj * ubo.view * ubo.model * vec4(inPosition, 1.0); + fragColor = inColor; + fragTexCoords = inTexCoords; + fragNormals = inNormals; + fragTexIndex = push_const.texture_index; +} \ No newline at end of file diff --git a/shader_samples/sample9-buffer-device-address/test.vert.spv b/shader_samples/sample9-buffer-device-address/test.vert.spv new file mode 100644 index 0000000000000000000000000000000000000000..fcb1ab4b15ed456555fd788575ba4a2a73abd882 GIT binary patch literal 2596 zcmZ9MZ*vqy5XOgGE`%T=B7am2fvBK?01Aje;NS=s%an-*DBo>e?j~WV&FUGRa2r-8J?~ja` zF^9~?`m^N6m0yz4^H-%C^wXrQ@}j?Olg;tgmMs)N@?DHC()Y<0@?Lo0j=U z9Pk~L#+sDu^j*gJ6Ul<)rsO-x9m$g9zN91RN?Q7x(EgW5Ce1<9TTPaKebQu33ak7! z8(7(9u=Uo~daKLHU^G&ZuTq<&F0;wd6?Ra$mllrc$j@bibUch5+VY5NY%AxC@;}Yo zR$lBp^fzAHd?7yFy6tT;o1J`UQ|$rc&M%$)4O_st$Ee6(fVFk6_q2~UbDi71JKa1h ztA19M!l#tC?wB!^-L1xjOcLXk0!|29SbH znbY1sS+~VATZmMu&>H8wohIvf=_;3JK0p3-4&g4VHr(&(U|kzF?xUD)>PC+ol@IJ* zT&uB-({#_qoq2N>HS+c@+e_&&W?@Ui)y>nq@P3niHe6OC+=Ds6=ZW3z=6NxsU+^(I zE_;W9F-!RVq{r*0rT6Q2zkt-eVb&VXADTAnn`rs><(?~k!gSDTOIGyDT(I;J`F_Vf z^e6V2$5AWz(ASs;eLoLa%!3Y3M-q6bE#^Vr&jS|opu_W8!X25zH~LOFGjrIfJu|k!9x!6S*n=N=z*-T;8H{hRr{4wbvl13M^AYR(-#~{KJF^k% z%mg~Qurm*_-f495a{sP&?u{>Je6bxD103h1p>w{V)0Fmq)w`2A)Au>aDaFzobnbCl zzlXGgq0g#M%nn$PIavZ1Hgx&`2lxr;M?7BNbyhlcf?>!1sCM|k?=(992f!AZ_+vWL zEBrrfY=QrT$MvIyKl(`t{%540(oQ{Kv&zc5hI?W|;Qd%TJ;F{M=zRBJp^i^=W(EB- zo#`p@^qihjH@*ByJ9&x6{&*>b;o|g_*=dNStrGtmqKa~g0&n0sb?1AqKonyW)rGqg~ zp_U6egYW0NC=5>Q@bUhaB+Smw%1MtF8%*0CcBR1%MA+2^BgeWTnXPLQ;_=7M4E`Zr zY~M)8j}LuhCa+8QE~uTpqvIE9yQMR8h>iI~$HrXU^XJ;e?A3aGrw7tI9&7nILnkM5 avn=6#>VDP#Qyw=sd6+Zw|22)bByRz?YudB` literal 0 HcmV?d00001 From 761cbacc5cb0ff875c43d3c4e71cbe900e533e46 Mon Sep 17 00:00:00 2001 From: SpinnerX Date: Tue, 19 May 2026 17:42:07 -0700 Subject: [PATCH 4/8] Fix some of the swapchain params --- vulkan-cpp/dyn/shader_objects.cppm | 150 +++++++++++++++++++++++++++++ vulkan-cpp/swapchain.cppm | 22 +++-- vulkan-cpp/vk.cppm | 1 + 3 files changed, 165 insertions(+), 8 deletions(-) create mode 100644 vulkan-cpp/dyn/shader_objects.cppm diff --git a/vulkan-cpp/dyn/shader_objects.cppm b/vulkan-cpp/dyn/shader_objects.cppm new file mode 100644 index 0000000..346e336 --- /dev/null +++ b/vulkan-cpp/dyn/shader_objects.cppm @@ -0,0 +1,150 @@ +module; + +#include +#include +#include +#include +#include + +export module vk:shader_objects; + +import :types; +import :utilities; + +export namespace vk::dyn { + inline namespace v1 { + struct shader_ext_params { + shader_stage stage; + shader_stage next_stage; + shader_code_type code_type; + std::span code_binary{}; + std::string_view name = ""; + std::span descriptor_layouts; + std::span push_constants{}; + }; + + // When querying the binary from the shaders + // If the pData is null, then we can retrieve both either the error to + // check if succeeded or the bytes needed when queried + struct shader_ext_error { + VkResult error; + uint32_t bytes = 0; + }; + + class shader_ext { + public: + shader_ext(const VkDevice& p_device, + const shader_ext_params& p_params) + : m_device(p_device) { + + vkCreateShadersEXT = reinterpret_cast(vkGetDeviceProcAddr(m_device, "vkCreateShadersEXT")); + + std::println("ShadersEXT = {}", (vkCreateShadersEXT == nullptr)); + + vkDestroyShaderEXT = reinterpret_cast(vkGetDeviceProcAddr(m_device, "vkDestroyShaderEXT")); + vkCmdBindShadersEXT = reinterpret_cast(vkGetDeviceProcAddr(m_device, "vkCmdBindShadersEXT")); + vkGetShaderBinaryDataEXT = reinterpret_cast(vkGetDeviceProcAddr(m_device, "vkGetShaderBinaryDataEXT")); + + vkCmdSetAlphaToCoverageEnableEXT = reinterpret_cast(vkGetDeviceProcAddr(m_device, "vkCmdSetAlphaToCoverageEnableEXT")); + vkCmdSetColorBlendEnableEXT = reinterpret_cast(vkGetDeviceProcAddr(m_device, "vkCmdSetColorBlendEnableEXT")); + vkCmdSetColorWriteMaskEXT = reinterpret_cast(vkGetDeviceProcAddr(m_device, "vkCmdSetColorWriteMaskEXT")); + vkCmdSetCullModeEXT = reinterpret_cast(vkGetDeviceProcAddr(m_device, "vkCmdSetCullModeEXT")); + vkCmdSetDepthBiasEnableEXT = reinterpret_cast(vkGetDeviceProcAddr(m_device, "vkCmdSetDepthBiasEnableEXT")); + vkCmdSetDepthCompareOpEXT = reinterpret_cast(vkGetDeviceProcAddr(m_device, "vkCmdSetDepthCompareOpEXT")); + vkCmdSetDepthTestEnableEXT = reinterpret_cast(vkGetDeviceProcAddr(m_device, "vkCmdSetDepthTestEnableEXT")); + vkCmdSetDepthWriteEnableEXT = reinterpret_cast(vkGetDeviceProcAddr(m_device, "vkCmdSetDepthWriteEnableEXT")); + vkCmdSetFrontFaceEXT = reinterpret_cast(vkGetDeviceProcAddr(m_device, "vkCmdSetFrontFaceEXT")); + vkCmdSetPolygonModeEXT = reinterpret_cast(vkGetDeviceProcAddr(m_device, "vkCmdSetPolygonModeEXT")); + vkCmdSetPrimitiveRestartEnableEXT = reinterpret_cast(vkGetDeviceProcAddr(m_device, "vkCmdSetPrimitiveRestartEnableEXT")); + vkCmdSetPrimitiveTopologyEXT = reinterpret_cast(vkGetDeviceProcAddr(m_device, "vkCmdSetPrimitiveTopologyEXT")); + vkCmdSetRasterizationSamplesEXT = reinterpret_cast(vkGetDeviceProcAddr(m_device, "vkCmdSetRasterizationSamplesEXT")); + vkCmdSetRasterizerDiscardEnableEXT = reinterpret_cast(vkGetDeviceProcAddr(m_device, "vkCmdSetRasterizerDiscardEnableEXT")); + vkCmdSetSampleMaskEXT = reinterpret_cast(vkGetDeviceProcAddr(m_device, "vkCmdSetSampleMaskEXT")); + vkCmdSetScissorWithCountEXT = reinterpret_cast(vkGetDeviceProcAddr(m_device, "vkCmdSetScissorWithCountEXT")); + vkCmdSetStencilTestEnableEXT = reinterpret_cast(vkGetDeviceProcAddr(m_device, "vkCmdSetStencilTestEnableEXT")); + vkCmdSetVertexInputEXT = reinterpret_cast(vkGetDeviceProcAddr(m_device, "vkCmdSetVertexInputEXT")); + vkCmdSetViewportWithCountEXT = reinterpret_cast(vkGetDeviceProcAddr(m_device, "vkCmdSetViewportWithCountEXT"));; + + + std::vector push_constants( + p_params.push_constants.size()); + + for (uint32_t i = 0; i < push_constants.size(); i++) { + const push_constant_range data = p_params.push_constants[i]; + push_constants[i] = { + .stageFlags = + static_cast(data.stage), + .offset = data.offset, + .size = data.range, + }; + } + + VkShaderCreateInfoEXT shader_info_ci = { + .sType = VK_STRUCTURE_TYPE_SHADER_CREATE_INFO_EXT, + .pNext = nullptr, + .flags = 0, + .stage = static_cast(p_params.stage), + .nextStage = + static_cast(p_params.next_stage), + .codeType = + static_cast(p_params.code_type), + .codeSize = + static_cast(p_params.code_binary.size()), + .pCode = p_params.code_binary.data(), + .pName = p_params.name.data(), + .setLayoutCount = + static_cast(p_params.descriptor_layouts.size()), + .pSetLayouts = p_params.descriptor_layouts.data(), + .pushConstantRangeCount = + static_cast(push_constants.size()), + .pPushConstantRanges = push_constants.data(), + }; + + vk_check( + vkCreateShadersEXT( + m_device, 1, &shader_info_ci, nullptr, &m_shader_handle), + "vkCreateShadersEXT"); + } + + + void bind(const VkCommandBuffer& p_command, uint32_t p_stage_count, std::span p_stages) { + vkCmdBindShadersEXT(p_command, p_stage_count, reinterpret_cast(p_stages.data()), &m_shader_handle); } + + void destroy() { + vkDestroyShaderEXT(m_device, m_shader_handle, nullptr); + } + + private: + VkDevice m_device = nullptr; + VkShaderEXT m_shader_handle = nullptr; + + PFN_vkCreateShadersEXT vkCreateShadersEXT{ nullptr }; + PFN_vkDestroyShaderEXT vkDestroyShaderEXT{ nullptr }; + PFN_vkCmdBindShadersEXT vkCmdBindShadersEXT{ nullptr }; + PFN_vkGetShaderBinaryDataEXT vkGetShaderBinaryDataEXT{ nullptr }; + + // With VK_EXT_shader_object pipeline state must be set at command buffer creation using these functions + PFN_vkCmdSetAlphaToCoverageEnableEXT vkCmdSetAlphaToCoverageEnableEXT{ nullptr }; + PFN_vkCmdSetColorBlendEnableEXT vkCmdSetColorBlendEnableEXT{ nullptr }; + PFN_vkCmdSetColorWriteMaskEXT vkCmdSetColorWriteMaskEXT{ nullptr }; + PFN_vkCmdSetCullModeEXT vkCmdSetCullModeEXT{ nullptr }; + PFN_vkCmdSetDepthBiasEnableEXT vkCmdSetDepthBiasEnableEXT{ nullptr }; + PFN_vkCmdSetDepthCompareOpEXT vkCmdSetDepthCompareOpEXT{ nullptr }; + PFN_vkCmdSetDepthTestEnableEXT vkCmdSetDepthTestEnableEXT{ nullptr }; + PFN_vkCmdSetDepthWriteEnableEXT vkCmdSetDepthWriteEnableEXT{ nullptr }; + PFN_vkCmdSetFrontFaceEXT vkCmdSetFrontFaceEXT{ nullptr }; + PFN_vkCmdSetPolygonModeEXT vkCmdSetPolygonModeEXT{ nullptr }; + PFN_vkCmdSetPrimitiveRestartEnableEXT vkCmdSetPrimitiveRestartEnableEXT{ nullptr }; + PFN_vkCmdSetPrimitiveTopologyEXT vkCmdSetPrimitiveTopologyEXT{ nullptr }; + PFN_vkCmdSetRasterizationSamplesEXT vkCmdSetRasterizationSamplesEXT{ nullptr }; + PFN_vkCmdSetRasterizerDiscardEnableEXT vkCmdSetRasterizerDiscardEnableEXT{ nullptr }; + PFN_vkCmdSetSampleMaskEXT vkCmdSetSampleMaskEXT{ nullptr }; + PFN_vkCmdSetScissorWithCountEXT vkCmdSetScissorWithCountEXT{ nullptr }; + PFN_vkCmdSetStencilTestEnableEXT vkCmdSetStencilTestEnableEXT{ nullptr }; + PFN_vkCmdSetViewportWithCountEXT vkCmdSetViewportWithCountEXT{ nullptr }; + + // VK_EXT_vertex_input_dynamic_state + PFN_vkCmdSetVertexInputEXT vkCmdSetVertexInputEXT{ nullptr }; + }; + }; +}; \ No newline at end of file diff --git a/vulkan-cpp/swapchain.cppm b/vulkan-cpp/swapchain.cppm index a8329a6..74d8c15 100644 --- a/vulkan-cpp/swapchain.cppm +++ b/vulkan-cpp/swapchain.cppm @@ -4,6 +4,7 @@ module; #include #include #include +#include export module vk:swapchain; @@ -30,8 +31,10 @@ export namespace vk { } void create(const swapchain_params& p_settings) { + VkSwapchainCreateInfoKHR swapchain_ci = { .sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR, + .pNext = nullptr, .surface = m_surface_handler, .minImageCount = m_image_size, .imageFormat = m_surface_params.format.format, @@ -40,10 +43,11 @@ export namespace vk { // formats in vulkan .imageExtent = m_surface_params.capabilities.currentExtent, .imageArrayLayers = 1, - .imageUsage = (VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | - VK_IMAGE_USAGE_TRANSFER_DST_BIT), - .queueFamilyIndexCount = 1, - .pQueueFamilyIndices = &p_settings.present_index, + + // Remove COLOR_ATTACHMENT flag because its not needed + .imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT, + .queueFamilyIndexCount = 0, + .pQueueFamilyIndices = nullptr, .preTransform = m_surface_params.capabilities.currentTransform, .compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR, @@ -51,11 +55,11 @@ export namespace vk { static_cast(p_settings.present_mode), .clipped = p_settings.clipped, }; + VkResult res = vkCreateSwapchainKHR( + m_device, &swapchain_ci, nullptr, &m_swapchain_handler); - vk_check( - vkCreateSwapchainKHR( - m_device, &swapchain_ci, nullptr, &m_swapchain_handler), - "vkCreateSwapchainKHR"); + std::println("VkResult = {}", static_cast(res)); + vk_check(res, "vkCreateSwapchainKHR"); } /** @@ -89,6 +93,8 @@ export namespace vk { vkDestroySwapchainKHR(m_device, m_swapchain_handler, nullptr); } + [[nodiscard]] bool alive() const { return m_swapchain_handler; } + operator VkSwapchainKHR() const { return m_swapchain_handler; } operator VkSwapchainKHR() { return m_swapchain_handler; } diff --git a/vulkan-cpp/vk.cppm b/vulkan-cpp/vk.cppm index 4262616..5a5e7b9 100644 --- a/vulkan-cpp/vk.cppm +++ b/vulkan-cpp/vk.cppm @@ -22,6 +22,7 @@ export import :index_buffer; export import :uniform_buffer; export import :descriptor_resource; export import :texture; +export import :buffer_device_address; namespace vk { inline namespace v1 {}; From c2eb1904f5103a5f3d28258c74ada6709f9589f5 Mon Sep 17 00:00:00 2001 From: SpinnerX Date: Tue, 19 May 2026 17:45:08 -0700 Subject: [PATCH 5/8] Updated CMakeLists.txt --- CMakeLists.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index 13afa8c..fee275c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -56,6 +56,7 @@ target_sources(${PROJECT_NAME} PUBLIC vulkan-cpp/uniform_buffer.cppm vulkan-cpp/descriptor_resource.cppm vulkan-cpp/texture.cppm + vulkan-cpp/dyn/buffer.cppm ) install( From fc4b8087e3e04f460d6d62a8e756b47849248f14 Mon Sep 17 00:00:00 2001 From: SpinnerX Date: Tue, 19 May 2026 21:45:41 -0700 Subject: [PATCH 6/8] Updated demo 17 README instructions and did some cleanup removing debugging statements --- demos/17-buffer-device-address/README.md | 166 +++++++++++++++++- .../17-buffer-device-address/application.cpp | 102 ++--------- .../sample9-buffer-device-address/test.vert | 2 - vulkan-cpp/feature_extensions.cppm | 7 + 4 files changed, 183 insertions(+), 94 deletions(-) diff --git a/demos/17-buffer-device-address/README.md b/demos/17-buffer-device-address/README.md index 8d9d84f..ba87653 100644 --- a/demos/17-buffer-device-address/README.md +++ b/demos/17-buffer-device-address/README.md @@ -1 +1,165 @@ -# Demo 16: Buffer Device Address \ No newline at end of file +# Demo 16: Buffer Device Address + + +In this demo 17, will show how to get buffer device addresses working using vulkan-cpp APIs. + +## Enabling Buffer Device Addresses + +To enable buffer device addresses, add onto the `vk::device_features` initialization here: + +```C++ +vk::device_features device_features{ + vk::dynamic_rendering_feature{ { + .dynamicRendering = true, + } }, + vk::descriptor_indexing_feature{ { + .shaderSampledImageArrayNonUniformIndexing = true, + .descriptorBindingSampledImageUpdateAfterBind = true, + .descriptorBindingPartiallyBound = true, + .descriptorBindingVariableDescriptorCount = true, + .runtimeDescriptorArray = true, + } }, + + // NEW: Add buffer device address feature here + vk::buffer_device_address{ { + .bufferDeviceAddress = true, + } }, +}; +``` + +## Replacing `vk::uniform_buffer` with `vk::dyn::buffer` + +The `vk::dyn::buffer` is meant to be a buffer abstraction similar to `vk::buffer` with an additional API to getting the buffers device address from the buffer. + +Which also does performs an automated configuration to for buffer device address. + +The initialization for the test_ubo variable is quite similar. + +```C++ + +vk::buffer_parameters uniform_params = { + .memory_mask = + physical_device.memory_properties(static_cast( + vk::memory_property::host_visible_bit | + vk::memory_property::host_cached_bit)), + .usage = + static_cast(vk::buffer_usage::uniform_buffer_bit | + vk::buffer_usage::shader_device_address_bit), + .allocate_flags = vk::memory_allocate_flags::device_address_bit_khr, +}; + +// NEW: Change this from vk::uniform_buffer to vk::dyn::buffer +vk::dyn::buffer test_ubo = + vk::dyn::buffer(logical_device, sizeof(global_uniform), uniform_params); +``` + +## Getting the Device Address + +In the mainloop, you can retrieve the buffer device address through the `.get_device_address` API. + + +When getting the `ubo_addr`, you pass this into the push constant to send in the address to retrieve that specific buffer to access. + +```C++ + +while (!glfwWindowShouldClose(window)) { + // ... + // Performing some operation + global_uniform ubo = { + .model = glm::rotate(glm::mat4(1.0f), + time * glm::radians(90.0f), + glm::vec3(0.0f, 0.0f, 1.0f)), + .view = glm::lookAt(glm::vec3(2.0f, 2.0f, 2.0f), + glm::vec3(0.0f, 0.0f, 0.0f), + glm::vec3(0.0f, 0.0f, 1.0f)), + .proj = glm::perspective(glm::radians(45.0f), + (float)swapchain_extent.width / + (float)swapchain_extent.height, + 0.1f, + 10.0f) + }; + ubo.proj[1][1] *= -1; + + test_ubo.transfer(std::span(&ubo, 1)); + + // NEW: ADD THIS LINE + const uint64_t ubo_addr = test_ubo.get_device_address(); + + push_constant_data push = { + .texture_index = 0, + + // NEW: Set device address here + .global_ubo_addr = ubo_addr, + }; + main_graphics_pipeline.push_constant( + current, push, stage, 0, sizeof(push_constant_data)); + + // ... +} + +``` + +## Changes to the shader + +### `vertex` shader + +In the vertex shader, we originally had used `layout(set = 0, binding = 0)` to contain a descriptor set that allows us to write our buffer. + +Now, that we are using a buffer device address, we can change that layout to being `layout(buffer_reference, std140)`. + +Here is what `layout(buffer_reference, std140)`: + +- `buffer_reference`: is to tell the resource lookup that the layout of this uniform is not going to be lookedup as a descriptor binding rather as a reference to this buffer. +- `std140`: Just set what the alignment rules are in how these uniform data can be aligned. + +```C++ +#version 450 + +#extension GL_EXT_buffer_reference : require + +layout(location = 0) in vec3 inPosition; +layout(location = 1) in vec3 inColor; +layout(location = 2) in vec2 inTexCoords; +layout(location = 3) in vec3 inNormals; + +layout(location = 0) out vec3 fragColor; +layout(location = 1) out vec2 fragTexCoords; +layout(location = 2) out vec3 fragNormals; +layout(location = 3) out flat int fragTexIndex; + +// NEW: Replace layout(set=0, binding=1) +layout(buffer_reference, std140) buffer readonly UniformBufferObject { + mat4 model; + mat4 view; + mat4 proj; +}; + +layout(push_constant) uniform Constants { + int texture_index; + + // NEW: Pass uint64_t from the push_constant_data and this + // specifies what piece of data to access from buffer device address previously stored + UniformBufferObject global_ubo_address; +} push_const; + + + +void main() { + + // NEW: Add this here to retrieve the global uniform buffer data + UniformBufferObject ubo = push_const.global_ubo_address; + + gl_Position = ubo.proj * ubo.view * ubo.model * vec4(inPosition, 1.0); + fragColor = inColor; + fragTexCoords = inTexCoords; + fragNormals = inNormals; + fragTexIndex = push_const.texture_index; +} +``` + +## That is it! + +Configuring buffer device address and using this Vulkan feature to access your uniform buffers are now much easier through the use of buffer device address. + +This will reduce the need to have to manage an entire descriptor sets for specifically buffers, and to just provide the address for the shader to directly access the buffer already stored in memory the GPU already has access. + diff --git a/demos/17-buffer-device-address/application.cpp b/demos/17-buffer-device-address/application.cpp index bf2bc3f..ee72113 100644 --- a/demos/17-buffer-device-address/application.cpp +++ b/demos/17-buffer-device-address/application.cpp @@ -27,12 +27,6 @@ import vk; #include -namespace vk { - // REQUIRED - using physical_device_features2 = feature_trait; - using buffer_device_address = feature_trait; -}; - static VKAPI_ATTR VkBool32 VKAPI_CALL debug_callback( [[maybe_unused]] VkDebugUtilsMessageSeverityFlagBitsEXT p_message_severity, @@ -41,7 +35,6 @@ debug_callback( [[maybe_unused]] void* p_user_data) { std::print("validation layer:\t\t{}\n\n", p_callback_data->pMessage); - // std::print(core_dump_file, "Validation Layer:\t\t{}\n\n", p_callback_data->pMessage); return false; } @@ -245,7 +238,7 @@ get_instance_extensions() { struct push_constant_data { uint32_t texture_index = 0; - uint64_t global_ubo_addr=0; + uint64_t global_ubo_addr = 0; }; int @@ -307,13 +300,6 @@ main() { std::println("\napi_instance alive and initiated!!!"); } - // std::span properties = - // api_instance.validation(); - // for (vk::layer_properties property : properties) { - // std::println("Layer Name:\t\t{}", property.name); - // std::println("Layer Description: {}", property.description); - // } - // setting up physical device vk::physical_enumeration enumerate_devices{ .device_type = vk::physical_gpu::integrated, @@ -359,7 +345,7 @@ main() { .runtimeDescriptorArray = true, } }, vk::buffer_device_address{ { - .bufferDeviceAddress = true, + .bufferDeviceAddress = true, } }, }; @@ -370,7 +356,6 @@ main() { .queue_family_index = queue_indices.graphics, }; - vk::device logical_device(physical_device, logical_device_params); vk::surface window_surface(api_instance, window); @@ -378,23 +363,6 @@ main() { vk::surface_params surface_properties = physical_device.request_surface(window_surface); - VkBool32 presentation_supported = false; - vkGetPhysicalDeviceSurfaceSupportKHR(physical_device, 0, window_surface, &presentation_supported); - - VkPhysicalDeviceProperties device_properties; - vkGetPhysicalDeviceProperties(physical_device, &device_properties); - - VkPhysicalDeviceType currently_selected_physical_gpu = device_properties.deviceType; - - // std::println("External Monitor Physical Device Type: VK_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU "); - // std::println("External Monitor Physical Device Type (take 2): VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU "); - // std::println("Selected Physical GPU: {}", static_cast(currently_selected_physical_gpu)); - - // std::println("Laptop VkFormat = VK_FORMAT_B8G8R8A8_SRGB , VkColorSpaceKHR = VK_COLOR_SPACE_SRGB_NONLINEAR_KHR "); - // std::println("VkFormat = {}\nColor Space = {}", static_cast(surface_properties.format.format), static_cast(surface_properties.format.colorSpace)); - - std::println("Presentation Supported = {}", static_cast(presentation_supported)); - vk::swapchain_params enumerate_swapchain_settings = { .width = static_cast(width), .height = static_cast(height), @@ -403,20 +371,13 @@ main() { .graphics, // presentation index just uses the graphics index }; - std::println("Surface Extent (w, h) = ({}, {})", surface_properties.capabilities.currentExtent.width, surface_properties.capabilities.currentExtent.height); - - std::println("Presentation Index: {}", - physical_device.family_indices().graphics); - // m_surface_params.capabilities.currentExtent - vk::swapchain main_swapchain(logical_device, window_surface, enumerate_swapchain_settings, surface_properties); - - if(!main_swapchain.alive()) { + if (!main_swapchain.alive()) { std::println("main_swapchain is nullptr!!!"); return -1; } @@ -541,7 +502,6 @@ main() { std::array attributes = { vk::vertex_attribute{ - // layout (set = 0, binding = 0) .binding = 0, .entries = attribute_entries, .stride = sizeof(vk::vertex_input), @@ -550,26 +510,6 @@ main() { }; geometry_resource.vertex_attributes(attributes); - // Set 0: For Uniform BUffers (or global scene data) - // std::vector entries = { - // vk::descriptor_entry{ - // // specifies "layout (set = 0, binding = 0) uniform GlobalUbo" - // .type = vk::buffer::uniform, - // .binding_point = { - // .binding = 0, - // .stage = vk::shader_stage::vertex, - // }, - // .descriptor_count = 1, - // }, - // }; - // vk::descriptor_layout set0_layout = { - // .slot = 0, // indicate specific descriptor slot 0 - // .max_sets = image_count, // max descriptors to allocate - // .entries = entries, // descriptor layout entries description - // }; - // vk::descriptor_resource set0_resource(logical_device, set0_layout); - - // Set 1 = For Textures std::vector entries_set1 = { vk::descriptor_entry{ // layout (set = 0, binding = 1) uniform sampler2D textures[]; @@ -648,25 +588,13 @@ main() { physical_device.memory_properties(static_cast( vk::memory_property::host_visible_bit | vk::memory_property::host_cached_bit)), - .usage = static_cast(vk::buffer_usage::uniform_buffer_bit | vk::buffer_usage::shader_device_address_bit), + .usage = + static_cast(vk::buffer_usage::uniform_buffer_bit | + vk::buffer_usage::shader_device_address_bit), .allocate_flags = vk::memory_allocate_flags::device_address_bit_khr, }; - vk::dyn::buffer test_ubo = vk::dyn::buffer( - logical_device, sizeof(global_uniform), uniform_params); - - // std::array uniforms0 = { - // vk::write_buffer{ - // .buffer = test_ubo, - // .offset = 0, - // .range = static_cast(test_ubo.size_bytes()), - // }, - // }; - // std::array uniforms = { - // vk::write_buffer_descriptor{ - // .dst_binding = 0, - // .uniforms = uniforms0, - // }, - // }; + vk::dyn::buffer test_ubo = + vk::dyn::buffer(logical_device, sizeof(global_uniform), uniform_params); vk::texture_params config_texture = { .memory_mask = @@ -678,6 +606,7 @@ main() { std::filesystem::path("asset_samples/viking_room.png"), config_texture); + // Setting the texture sampler/image view to descriptor resource std::array samplers = { vk::write_image{ .sampler = texture1.image().sampler(), @@ -686,14 +615,12 @@ main() { }, }; - // Specify image descriptor images/samplers to the descriptor std::array set1_samples = { vk::write_image_descriptor{ .dst_binding = 1, .sample_images = samplers, } }; - // set0_resource.update(uniforms); set1_resource.update({}, set1_samples); @@ -829,21 +756,14 @@ main() { }; main_graphics_pipeline.push_constant( current, push, stage, 0, sizeof(push_constant_data)); - std::array descriptors = { - set1_resource, - }; + const VkDescriptorSet set1 = set1_resource; current.bind_descriptors(main_graphics_pipeline.layout(), VK_PIPELINE_BIND_POINT_GRAPHICS, - descriptors); + std::span(&set1, 1)); - // Drawing-call to render actual triangle to the screen - // vkCmdDrawIndexed(current, static_cast(indices.size()), 1, - // 0, 0, 0); test_model.draw(current); - // vkCmdDraw(current, 3, 1, 0, 0); - current.end_rendering(); swapchain_images[current_frame].memory_barrier( diff --git a/shader_samples/sample9-buffer-device-address/test.vert b/shader_samples/sample9-buffer-device-address/test.vert index df3dd0c..c270eec 100644 --- a/shader_samples/sample9-buffer-device-address/test.vert +++ b/shader_samples/sample9-buffer-device-address/test.vert @@ -26,8 +26,6 @@ layout(push_constant) uniform Constants { void main() { - - // UniformBufferObject ubo = UniformBufferObject(push_const.global_ubo_address); UniformBufferObject ubo = push_const.global_ubo_address; gl_Position = ubo.proj * ubo.view * ubo.model * vec4(inPosition, 1.0); diff --git a/vulkan-cpp/feature_extensions.cppm b/vulkan-cpp/feature_extensions.cppm index f3999c5..e5d4140 100644 --- a/vulkan-cpp/feature_extensions.cppm +++ b/vulkan-cpp/feature_extensions.cppm @@ -64,6 +64,13 @@ export namespace vk { } }; + using physical_device_features2 = + feature_trait; + using buffer_device_address = feature_trait< + VkPhysicalDeviceBufferDeviceAddressFeatures, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_BUFFER_DEVICE_ADDRESS_FEATURES>; + // Descriptor indexing to access unbounded array of a given uniform using descriptor_indexing_feature = feature_trait< VkPhysicalDeviceDescriptorIndexingFeatures, From ac712c79df9bb27e6a4855b74a8c9f1e8dcffa02 Mon Sep 17 00:00:00 2001 From: SpinnerX Date: Tue, 19 May 2026 21:48:45 -0700 Subject: [PATCH 7/8] Changed demo number in README to 17 --- demos/17-buffer-device-address/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/demos/17-buffer-device-address/README.md b/demos/17-buffer-device-address/README.md index ba87653..bf8e784 100644 --- a/demos/17-buffer-device-address/README.md +++ b/demos/17-buffer-device-address/README.md @@ -1,4 +1,4 @@ -# Demo 16: Buffer Device Address +# Demo 17: Buffer Device Address In this demo 17, will show how to get buffer device addresses working using vulkan-cpp APIs. From d6e1b15f6500ae17c197b9d91abbe009d398c578 Mon Sep 17 00:00:00 2001 From: SpinnerX Date: Tue, 19 May 2026 23:09:26 -0700 Subject: [PATCH 8/8] Formatted code using clang-format --- .../17-buffer-device-address/application.cpp | 1 - vulkan-cpp/dyn/shader_objects.cppm | 174 +++++++++++++----- vulkan-cpp/types.cppm | 6 +- 3 files changed, 133 insertions(+), 48 deletions(-) diff --git a/demos/17-buffer-device-address/application.cpp b/demos/17-buffer-device-address/application.cpp index ee72113..4ddc950 100644 --- a/demos/17-buffer-device-address/application.cpp +++ b/demos/17-buffer-device-address/application.cpp @@ -371,7 +371,6 @@ main() { .graphics, // presentation index just uses the graphics index }; - vk::swapchain main_swapchain(logical_device, window_surface, enumerate_swapchain_settings, diff --git a/vulkan-cpp/dyn/shader_objects.cppm b/vulkan-cpp/dyn/shader_objects.cppm index 346e336..c300481 100644 --- a/vulkan-cpp/dyn/shader_objects.cppm +++ b/vulkan-cpp/dyn/shader_objects.cppm @@ -11,7 +11,7 @@ export module vk:shader_objects; import :types; import :utilities; -export namespace vk::dyn { +export namespace vk::dyn::experimental { inline namespace v1 { struct shader_ext_params { shader_stage stage; @@ -37,34 +37,89 @@ export namespace vk::dyn { const shader_ext_params& p_params) : m_device(p_device) { - vkCreateShadersEXT = reinterpret_cast(vkGetDeviceProcAddr(m_device, "vkCreateShadersEXT")); - - std::println("ShadersEXT = {}", (vkCreateShadersEXT == nullptr)); - - vkDestroyShaderEXT = reinterpret_cast(vkGetDeviceProcAddr(m_device, "vkDestroyShaderEXT")); - vkCmdBindShadersEXT = reinterpret_cast(vkGetDeviceProcAddr(m_device, "vkCmdBindShadersEXT")); - vkGetShaderBinaryDataEXT = reinterpret_cast(vkGetDeviceProcAddr(m_device, "vkGetShaderBinaryDataEXT")); - - vkCmdSetAlphaToCoverageEnableEXT = reinterpret_cast(vkGetDeviceProcAddr(m_device, "vkCmdSetAlphaToCoverageEnableEXT")); - vkCmdSetColorBlendEnableEXT = reinterpret_cast(vkGetDeviceProcAddr(m_device, "vkCmdSetColorBlendEnableEXT")); - vkCmdSetColorWriteMaskEXT = reinterpret_cast(vkGetDeviceProcAddr(m_device, "vkCmdSetColorWriteMaskEXT")); - vkCmdSetCullModeEXT = reinterpret_cast(vkGetDeviceProcAddr(m_device, "vkCmdSetCullModeEXT")); - vkCmdSetDepthBiasEnableEXT = reinterpret_cast(vkGetDeviceProcAddr(m_device, "vkCmdSetDepthBiasEnableEXT")); - vkCmdSetDepthCompareOpEXT = reinterpret_cast(vkGetDeviceProcAddr(m_device, "vkCmdSetDepthCompareOpEXT")); - vkCmdSetDepthTestEnableEXT = reinterpret_cast(vkGetDeviceProcAddr(m_device, "vkCmdSetDepthTestEnableEXT")); - vkCmdSetDepthWriteEnableEXT = reinterpret_cast(vkGetDeviceProcAddr(m_device, "vkCmdSetDepthWriteEnableEXT")); - vkCmdSetFrontFaceEXT = reinterpret_cast(vkGetDeviceProcAddr(m_device, "vkCmdSetFrontFaceEXT")); - vkCmdSetPolygonModeEXT = reinterpret_cast(vkGetDeviceProcAddr(m_device, "vkCmdSetPolygonModeEXT")); - vkCmdSetPrimitiveRestartEnableEXT = reinterpret_cast(vkGetDeviceProcAddr(m_device, "vkCmdSetPrimitiveRestartEnableEXT")); - vkCmdSetPrimitiveTopologyEXT = reinterpret_cast(vkGetDeviceProcAddr(m_device, "vkCmdSetPrimitiveTopologyEXT")); - vkCmdSetRasterizationSamplesEXT = reinterpret_cast(vkGetDeviceProcAddr(m_device, "vkCmdSetRasterizationSamplesEXT")); - vkCmdSetRasterizerDiscardEnableEXT = reinterpret_cast(vkGetDeviceProcAddr(m_device, "vkCmdSetRasterizerDiscardEnableEXT")); - vkCmdSetSampleMaskEXT = reinterpret_cast(vkGetDeviceProcAddr(m_device, "vkCmdSetSampleMaskEXT")); - vkCmdSetScissorWithCountEXT = reinterpret_cast(vkGetDeviceProcAddr(m_device, "vkCmdSetScissorWithCountEXT")); - vkCmdSetStencilTestEnableEXT = reinterpret_cast(vkGetDeviceProcAddr(m_device, "vkCmdSetStencilTestEnableEXT")); - vkCmdSetVertexInputEXT = reinterpret_cast(vkGetDeviceProcAddr(m_device, "vkCmdSetVertexInputEXT")); - vkCmdSetViewportWithCountEXT = reinterpret_cast(vkGetDeviceProcAddr(m_device, "vkCmdSetViewportWithCountEXT"));; - + vkCreateShadersEXT = reinterpret_cast( + vkGetDeviceProcAddr(m_device, "vkCreateShadersEXT")); + + std::println("ShadersEXT = {}", + (vkCreateShadersEXT == nullptr)); + + vkDestroyShaderEXT = reinterpret_cast( + vkGetDeviceProcAddr(m_device, "vkDestroyShaderEXT")); + vkCmdBindShadersEXT = reinterpret_cast( + vkGetDeviceProcAddr(m_device, "vkCmdBindShadersEXT")); + vkGetShaderBinaryDataEXT = + reinterpret_cast( + vkGetDeviceProcAddr(m_device, "vkGetShaderBinaryDataEXT")); + + vkCmdSetAlphaToCoverageEnableEXT = + reinterpret_cast( + vkGetDeviceProcAddr(m_device, + "vkCmdSetAlphaToCoverageEnableEXT")); + vkCmdSetColorBlendEnableEXT = + reinterpret_cast( + vkGetDeviceProcAddr(m_device, + "vkCmdSetColorBlendEnableEXT")); + vkCmdSetColorWriteMaskEXT = + reinterpret_cast( + vkGetDeviceProcAddr(m_device, "vkCmdSetColorWriteMaskEXT")); + vkCmdSetCullModeEXT = reinterpret_cast( + vkGetDeviceProcAddr(m_device, "vkCmdSetCullModeEXT")); + vkCmdSetDepthBiasEnableEXT = + reinterpret_cast( + vkGetDeviceProcAddr(m_device, + "vkCmdSetDepthBiasEnableEXT")); + vkCmdSetDepthCompareOpEXT = + reinterpret_cast( + vkGetDeviceProcAddr(m_device, "vkCmdSetDepthCompareOpEXT")); + vkCmdSetDepthTestEnableEXT = + reinterpret_cast( + vkGetDeviceProcAddr(m_device, + "vkCmdSetDepthTestEnableEXT")); + vkCmdSetDepthWriteEnableEXT = + reinterpret_cast( + vkGetDeviceProcAddr(m_device, + "vkCmdSetDepthWriteEnableEXT")); + vkCmdSetFrontFaceEXT = + reinterpret_cast( + vkGetDeviceProcAddr(m_device, "vkCmdSetFrontFaceEXT")); + vkCmdSetPolygonModeEXT = + reinterpret_cast( + vkGetDeviceProcAddr(m_device, "vkCmdSetPolygonModeEXT")); + vkCmdSetPrimitiveRestartEnableEXT = + reinterpret_cast( + vkGetDeviceProcAddr(m_device, + "vkCmdSetPrimitiveRestartEnableEXT")); + vkCmdSetPrimitiveTopologyEXT = + reinterpret_cast( + vkGetDeviceProcAddr(m_device, + "vkCmdSetPrimitiveTopologyEXT")); + vkCmdSetRasterizationSamplesEXT = + reinterpret_cast( + vkGetDeviceProcAddr(m_device, + "vkCmdSetRasterizationSamplesEXT")); + vkCmdSetRasterizerDiscardEnableEXT = + reinterpret_cast( + vkGetDeviceProcAddr(m_device, + "vkCmdSetRasterizerDiscardEnableEXT")); + vkCmdSetSampleMaskEXT = + reinterpret_cast( + vkGetDeviceProcAddr(m_device, "vkCmdSetSampleMaskEXT")); + vkCmdSetScissorWithCountEXT = + reinterpret_cast( + vkGetDeviceProcAddr(m_device, + "vkCmdSetScissorWithCountEXT")); + vkCmdSetStencilTestEnableEXT = + reinterpret_cast( + vkGetDeviceProcAddr(m_device, + "vkCmdSetStencilTestEnableEXT")); + vkCmdSetVertexInputEXT = + reinterpret_cast( + vkGetDeviceProcAddr(m_device, "vkCmdSetVertexInputEXT")); + vkCmdSetViewportWithCountEXT = + reinterpret_cast( + vkGetDeviceProcAddr(m_device, + "vkCmdSetViewportWithCountEXT")); + ; std::vector push_constants( p_params.push_constants.size()); @@ -106,9 +161,16 @@ export namespace vk::dyn { "vkCreateShadersEXT"); } - - void bind(const VkCommandBuffer& p_command, uint32_t p_stage_count, std::span p_stages) { - vkCmdBindShadersEXT(p_command, p_stage_count, reinterpret_cast(p_stages.data()), &m_shader_handle); } + void bind(const VkCommandBuffer& p_command, + uint32_t p_stage_count, + std::span p_stages) { + vkCmdBindShadersEXT( + p_command, + p_stage_count, + reinterpret_cast( + p_stages.data()), + &m_shader_handle); + } void destroy() { vkDestroyShaderEXT(m_device, m_shader_handle, nullptr); @@ -123,25 +185,47 @@ export namespace vk::dyn { PFN_vkCmdBindShadersEXT vkCmdBindShadersEXT{ nullptr }; PFN_vkGetShaderBinaryDataEXT vkGetShaderBinaryDataEXT{ nullptr }; - // With VK_EXT_shader_object pipeline state must be set at command buffer creation using these functions - PFN_vkCmdSetAlphaToCoverageEnableEXT vkCmdSetAlphaToCoverageEnableEXT{ nullptr }; - PFN_vkCmdSetColorBlendEnableEXT vkCmdSetColorBlendEnableEXT{ nullptr }; + // With VK_EXT_shader_object pipeline state must be set at command + // buffer creation using these functions + PFN_vkCmdSetAlphaToCoverageEnableEXT + vkCmdSetAlphaToCoverageEnableEXT{ nullptr }; + PFN_vkCmdSetColorBlendEnableEXT vkCmdSetColorBlendEnableEXT{ + nullptr + }; PFN_vkCmdSetColorWriteMaskEXT vkCmdSetColorWriteMaskEXT{ nullptr }; PFN_vkCmdSetCullModeEXT vkCmdSetCullModeEXT{ nullptr }; - PFN_vkCmdSetDepthBiasEnableEXT vkCmdSetDepthBiasEnableEXT{ nullptr }; + PFN_vkCmdSetDepthBiasEnableEXT vkCmdSetDepthBiasEnableEXT{ + nullptr + }; PFN_vkCmdSetDepthCompareOpEXT vkCmdSetDepthCompareOpEXT{ nullptr }; - PFN_vkCmdSetDepthTestEnableEXT vkCmdSetDepthTestEnableEXT{ nullptr }; - PFN_vkCmdSetDepthWriteEnableEXT vkCmdSetDepthWriteEnableEXT{ nullptr }; + PFN_vkCmdSetDepthTestEnableEXT vkCmdSetDepthTestEnableEXT{ + nullptr + }; + PFN_vkCmdSetDepthWriteEnableEXT vkCmdSetDepthWriteEnableEXT{ + nullptr + }; PFN_vkCmdSetFrontFaceEXT vkCmdSetFrontFaceEXT{ nullptr }; PFN_vkCmdSetPolygonModeEXT vkCmdSetPolygonModeEXT{ nullptr }; - PFN_vkCmdSetPrimitiveRestartEnableEXT vkCmdSetPrimitiveRestartEnableEXT{ nullptr }; - PFN_vkCmdSetPrimitiveTopologyEXT vkCmdSetPrimitiveTopologyEXT{ nullptr }; - PFN_vkCmdSetRasterizationSamplesEXT vkCmdSetRasterizationSamplesEXT{ nullptr }; - PFN_vkCmdSetRasterizerDiscardEnableEXT vkCmdSetRasterizerDiscardEnableEXT{ nullptr }; + PFN_vkCmdSetPrimitiveRestartEnableEXT + vkCmdSetPrimitiveRestartEnableEXT{ nullptr }; + PFN_vkCmdSetPrimitiveTopologyEXT vkCmdSetPrimitiveTopologyEXT{ + nullptr + }; + PFN_vkCmdSetRasterizationSamplesEXT vkCmdSetRasterizationSamplesEXT{ + nullptr + }; + PFN_vkCmdSetRasterizerDiscardEnableEXT + vkCmdSetRasterizerDiscardEnableEXT{ nullptr }; PFN_vkCmdSetSampleMaskEXT vkCmdSetSampleMaskEXT{ nullptr }; - PFN_vkCmdSetScissorWithCountEXT vkCmdSetScissorWithCountEXT{ nullptr }; - PFN_vkCmdSetStencilTestEnableEXT vkCmdSetStencilTestEnableEXT{ nullptr }; - PFN_vkCmdSetViewportWithCountEXT vkCmdSetViewportWithCountEXT{ nullptr }; + PFN_vkCmdSetScissorWithCountEXT vkCmdSetScissorWithCountEXT{ + nullptr + }; + PFN_vkCmdSetStencilTestEnableEXT vkCmdSetStencilTestEnableEXT{ + nullptr + }; + PFN_vkCmdSetViewportWithCountEXT vkCmdSetViewportWithCountEXT{ + nullptr + }; // VK_EXT_vertex_input_dynamic_state PFN_vkCmdSetVertexInputEXT vkCmdSetVertexInputEXT{ nullptr }; diff --git a/vulkan-cpp/types.cppm b/vulkan-cpp/types.cppm index 1c8351f..65681f0 100644 --- a/vulkan-cpp/types.cppm +++ b/vulkan-cpp/types.cppm @@ -1416,11 +1416,13 @@ export namespace vk { enum memory_allocate_flags : uint64_t { device_mask_bit = VK_MEMORY_ALLOCATE_DEVICE_MASK_BIT, device_address_bit = VK_MEMORY_ALLOCATE_DEVICE_ADDRESS_BIT, - device_address_capture_replay_bit = VK_MEMORY_ALLOCATE_DEVICE_ADDRESS_CAPTURE_REPLAY_BIT, + device_address_capture_replay_bit = + VK_MEMORY_ALLOCATE_DEVICE_ADDRESS_CAPTURE_REPLAY_BIT, zero_initialize_bit = VK_MEMORY_ALLOCATE_ZERO_INITIALIZE_BIT_EXT, device_mask_bit_khr = VK_MEMORY_ALLOCATE_DEVICE_MASK_BIT_KHR, device_address_bit_khr = VK_MEMORY_ALLOCATE_DEVICE_ADDRESS_BIT, - device_address_capture_replay_bit_khr = VK_MEMORY_ALLOCATE_DEVICE_ADDRESS_CAPTURE_REPLAY_BIT + device_address_capture_replay_bit_khr = + VK_MEMORY_ALLOCATE_DEVICE_ADDRESS_CAPTURE_REPLAY_BIT }; enum class shader_stage {