### Install Git LFS Filter (Windows CMD) Source: https://github.com/saschawillems/howtovulkan/blob/main/source/external/ktx/README.md Installs the smudge & clean filter for $Date$ keyword expansion on Windows using the Command Prompt. Requires Git for Windows and git.exe in PATH. ```cmd install-gitconfig.bat del TODO.md include/ktx.h tools/toktx/toktx.cpp git checkout TODO.md include/ktx.h tools/toktx/toktx.cpp ``` -------------------------------- ### SDL Initialization Example Source: https://github.com/saschawillems/howtovulkan/blob/main/_autodocs/utilities.md Demonstrates using the generic boolean `chk` function to verify the success of SDL initialization and Vulkan library loading. ```cpp chk(SDL_Init(SDL_INIT_VIDEO)); chk(SDL_Vulkan_LoadLibrary(NULL)); ``` -------------------------------- ### Swapchain Operation Example Source: https://github.com/saschawillems/howtovulkan/blob/main/_autodocs/utilities.md Example of using `chkSwapchain` to validate the result of acquiring the next swapchain image. ```cpp chkSwapchain(vkAcquireNextImageKHR(device, swapchain, UINT64_MAX, imageAcquiredSemaphores[frameIndex], VK_NULL_HANDLE, &imageIndex)); ``` -------------------------------- ### Logging Selected Device Name Source: https://github.com/saschawillems/howtovulkan/blob/main/_autodocs/utilities.md Example of logging the selected Vulkan physical device's name to standard output. ```cpp std::cout << "Selected device: " << deviceProperties.properties.deviceName << "\n"; ``` -------------------------------- ### Begin Command Buffer Recording Source: https://github.com/saschawillems/howtovulkan/blob/main/tutorial/docs/index.md Starts recording commands to a command buffer. Uses VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT for optimization hints. ```cpp VkCommandBufferBeginInfo cbBI { .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO, .flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT }; chk(vkBeginCommandBuffer(cb, &cbBI)); ``` -------------------------------- ### Install Git LFS Filter (Unix/Git Bash) Source: https://github.com/saschawillems/howtovulkan/blob/main/source/external/ktx/README.md Installs the smudge & clean filter for $Date$ keyword expansion on Unix-like systems. Requires Git LFS to be installed. ```bash ./install-gitconfig.sh rm TODO.md include/ktx.h tools/toktx/toktx.cpp git checkout TODO.md include/ktx.h tools/toktx/toktx.cpp ``` -------------------------------- ### Begin Dynamic Rendering Pass Source: https://github.com/saschawillems/howtovulkan/blob/main/tutorial/docs/index.md Starts a dynamic render pass instance using the provided VkRenderingInfo, which includes attachment configurations and render area. Ensure attachments are in the correct layout before calling. ```cpp VkRenderingInfo renderingInfo{ .sType = VK_STRUCTURE_TYPE_RENDERING_INFO, .renderArea{.extent{.width = static_cast(windowSize.x), .height = static_cast(windowSize.y) }}, .layerCount = 1, .colorAttachmentCount = 1, .pColorAttachments = &colorAttachmentInfo, .pDepthAttachment = &depthAttachmentInfo }; vkCmdBeginRendering(cb, &renderingInfo); ``` -------------------------------- ### Build Instructions for How to Vulkan Source: https://github.com/saschawillems/howtovulkan/blob/main/_autodocs/README.md These commands outline the process for building the How to Vulkan project using CMake. Ensure you have a C++20 compiler, Vulkan SDK 1.3+, and CMake 3.20+ installed. ```bash cd source cmake -B build -G "Visual Studio 17 2022" # or your CMake generator cd build cmake --build . --config Release ``` -------------------------------- ### Vulkan Function Call Example Source: https://github.com/saschawillems/howtovulkan/blob/main/_autodocs/utilities.md Example of using the `chk` utility function to check the result of `vkCreateInstance`. ```cpp chk(vkCreateInstance(&instanceCI, nullptr, &instance)); ``` -------------------------------- ### Get Platform-Specific Instance Extensions with SDL Source: https://github.com/saschawillems/howtovulkan/blob/main/tutorial/docs/index.md Retrieves the necessary instance extensions for the current platform using SDL, avoiding manual platform-specific code. ```cpp uint32_t instanceExtensionsCount{ 0 }; char const* const* instanceExtensions{ SDL_Vulkan_GetInstanceExtensions(&instanceExtensionsCount) }; ``` -------------------------------- ### Enable Vulkan 1.0 Device Features Source: https://github.com/saschawillems/howtovulkan/blob/main/_autodocs/configuration.md Enables basic Vulkan 1.0 device features. This example specifically enables sampler anisotropy for improved texture filtering. ```cpp VkPhysicalDeviceFeatures enabledVk10Features{ .samplerAnisotropy = VK_TRUE }; ``` -------------------------------- ### Enable Vulkan 1.3 Device Features Source: https://github.com/saschawillems/howtovulkan/blob/main/_autodocs/configuration.md Enables specific Vulkan 1.3 features, chaining them with Vulkan 1.2 features. This example enables synchronization2 and dynamic rendering. ```cpp VkPhysicalDeviceVulkan13Features enabledVk13Features{ .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_3_FEATURES, .pNext = &enabledVk12Features, .synchronization2 = true, .dynamicRendering = true }; ``` -------------------------------- ### Get Vulkan Surface Capabilities Source: https://github.com/saschawillems/howtovulkan/blob/main/tutorial/docs/index.md Queries and stores the surface capabilities for the given Vulkan physical device and surface. This information is crucial for configuring the swapchain. ```cpp VkSurfaceCapabilitiesKHR surfaceCaps{}; chk(vkGetPhysicalDeviceSurfaceCapabilitiesKHR(devices[deviceIndex], surface, &surfaceCaps)); ``` -------------------------------- ### Get and Display Physical Device Properties Source: https://github.com/saschawillems/howtovulkan/blob/main/tutorial/docs/index.md Fetches the properties of the selected Vulkan physical device, including its name, and prints it to the console. Uses the `VkPhysicalDeviceProperties2` structure and `vkGetPhysicalDeviceProperties2` function. ```cpp VkPhysicalDeviceProperties2 deviceProperties{ .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2 }; vkGetPhysicalDeviceProperties2(devices[deviceIndex], &deviceProperties); std::cout << "Selected device: " << deviceProperties.properties.deviceName << "\n"; ``` -------------------------------- ### Set Vulkan API Version Source: https://github.com/saschawillems/howtovulkan/blob/main/_autodocs/configuration.md Specifies the target Vulkan API version for the application. This example targets Vulkan 1.3, enabling features like dynamic rendering and buffer device address. ```cpp VkApplicationInfo appInfo{ .sType = VK_STRUCTURE_TYPE_APPLICATION_INFO, .pApplicationName = "How to Vulkan", .apiVersion = VK_API_VERSION_1_3 }; ``` -------------------------------- ### Setup Vulkan Memory Allocator Source: https://github.com/saschawillems/howtovulkan/blob/main/_autodocs/initialization.md Initializes the Vulkan Memory Allocator (VMA) with necessary Vulkan function pointers and physical device information. This allocator is crucial for managing Vulkan memory efficiently, especially with buffer device address support enabled. ```cpp VmaVulkanFunctions vkFunctions{ .vkGetInstanceProcAddr = vkGetInstanceProcAddr, .vkGetDeviceProcAddr = vkGetDeviceProcAddr, .vkCreateImage = vkCreateImage }; VmaAllocatorCreateInfo allocatorCI{ .flags = VMA_ALLOCATOR_CREATE_BUFFER_DEVICE_ADDRESS_BIT, .physicalDevice = devices[deviceIndex], .device = device, .pVulkanFunctions = &vkFunctions, .instance = instance }; chk(vmaCreateAllocator(&allocatorCI, &allocator)); ``` -------------------------------- ### Configure Color and Depth Attachments for Dynamic Rendering Source: https://github.com/saschawillems/howtovulkan/blob/main/tutorial/docs/index.md Sets up VkRenderingAttachmentInfo for color and depth attachments. Use VK_ATTACHMENT_LOAD_OP_CLEAR to clear attachments at the start of a render pass. Store color attachment contents for presentation, but discard depth information. ```cpp VkRenderingAttachmentInfo colorAttachmentInfo{ .sType = VK_STRUCTURE_TYPE_RENDERING_ATTACHMENT_INFO, .imageView = swapchainImageViews[imageIndex], .imageLayout = VK_IMAGE_LAYOUT_ATTACHMENT_OPTIMAL, .loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR, .storeOp = VK_ATTACHMENT_STORE_OP_STORE, .clearValue{.color{ 0.0f, 0.0f, 0.2f, 1.0f }} }; VkRenderingAttachmentInfo depthAttachmentInfo{ .sType = VK_STRUCTURE_TYPE_RENDERING_ATTACHMENT_INFO, .imageView = depthImageView, .imageLayout = VK_IMAGE_LAYOUT_ATTACHMENT_OPTIMAL, .loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR, .storeOp = VK_ATTACHMENT_STORE_OP_DONT_CARE, .clearValue = {.depthStencil = {1.0f, 0}} }; ``` -------------------------------- ### Build and Run HowToVulkan Source: https://github.com/saschawillems/howtovulkan/blob/main/_autodocs/INDEX.md Instructions for building the project using CMake and running the executable. You can specify a device index to run on a particular GPU. ```bash cd source cmake -B build -G "Visual Studio 17 2022" # or appropriate generator cd build cmake --build . --config Release cd ../.. ./build/bin/HowToVulkan # Run default device ./build/bin/HowToVulkan 1 # Run device 1 ``` -------------------------------- ### Load and Initialize Textures Source: https://github.com/saschawillems/howtovulkan/blob/main/_autodocs/initialization.md Loads textures from KTX files, creates Vulkan images and samplers, and prepares descriptor image infos. Assumes textures are stored in 'assets/' and named sequentially. ```cpp std::vector textureDescriptors{}; for (auto i = 0; i < textures.size(); i++) { ktxTexture* ktxTexture{ nullptr }; std::string filename = "assets/suzanne" + std::to_string(i) + ".ktx"; ktxTexture_CreateFromNamedFile(filename.c_str(), KTX_TEXTURE_CREATE_LOAD_IMAGE_DATA_BIT, &ktxTexture); VkImageCreateInfo texImgCI{ .sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, .imageType = VK_IMAGE_TYPE_2D, .format = ktxTexture_GetVkFormat(ktxTexture), .extent = {.width = ktxTexture->baseWidth, .height = ktxTexture->baseHeight, .depth = 1 }, .mipLevels = ktxTexture->numLevels, .arrayLayers = 1, .samples = VK_SAMPLE_COUNT_1_BIT, .tiling = VK_IMAGE_TILING_OPTIMAL, .usage = VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT, .initialLayout = VK_IMAGE_LAYOUT_UNDEFINED }; VmaAllocationCreateInfo texImageAllocCI{ .usage = VMA_MEMORY_USAGE_AUTO }; chk(vmaCreateImage(allocator, &texImgCI, &texImageAllocCI, &textures[i].image, &textures[i].allocation, nullptr)); // ... image view and upload ... VkSamplerCreateInfo samplerCI{ .sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO, .magFilter = VK_FILTER_LINEAR, .minFilter = VK_FILTER_LINEAR, .mipmapMode = VK_SAMPLER_MIPMAP_MODE_LINEAR, .anisotropyEnable = VK_TRUE, .maxAnisotropy = 8.0f, .maxLod = (float)ktxTexture->numLevels, }; chk(vkCreateSampler(device, &samplerCI, nullptr, &textures[i].sampler)); ktxTexture_Destroy(ktxTexture); } ``` -------------------------------- ### Running the How to Vulkan Application Source: https://github.com/saschawillems/howtovulkan/blob/main/_autodocs/README.md Instructions for executing the compiled How to Vulkan application. You can specify a GPU device index as an argument. The application requires the 'assets/' folder in the current working directory and a Vulkan-capable GPU with 1.3 support. ```bash cd ../.. ./build/bin/HowToVulkan # Use default GPU device ./build/bin/HowToVulkan 1 # Use GPU device index 1 ``` -------------------------------- ### Get Swapchain Images Source: https://github.com/saschawillems/howtovulkan/blob/main/tutorial/docs/index.md Retrieves the images that are part of the created swapchain. These images are owned by the swapchain and will be used for rendering. ```cpp uint32_t imageCount{ 0 }; chk(vkGetSwapchainImagesKHR(device, swapchain, &imageCount, nullptr)); swapchainImages.resize(imageCount); chk(vkGetSwapchainImagesKHR(device, swapchain, &imageCount, swapchainImages.data())); swapchainImageViews.resize(imageCount); ``` -------------------------------- ### Initialize Vulkan Memory Allocator (VMA) Source: https://github.com/saschawillems/howtovulkan/blob/main/tutorial/docs/index.md Sets up the VMA allocator by providing Vulkan function pointers, the instance, and the physical/logical devices. Enables buffer device address support via flags. ```cpp VmaVulkanFunctions vkFunctions{ .vkGetInstanceProcAddr = vkGetInstanceProcAddr, .vkGetDeviceProcAddr = vkGetDeviceProcAddr, .vkCreateImage = vkCreateImage }; VmaAllocatorCreateInfo allocatorCI{ .flags = VMA_ALLOCATOR_CREATE_BUFFER_DEVICE_ADDRESS_BIT, .physicalDevice = devices[deviceIndex], .device = device, .pVulkanFunctions = &vkFunctions, .instance = instance }; chk(vmaCreateAllocator(&allocatorCI, &allocator)); ``` -------------------------------- ### Compile Slang Shader to SPIR-V and Create Vulkan Shader Module Source: https://github.com/saschawillems/howtovulkan/blob/main/_autodocs/initialization.md This snippet demonstrates how to initialize Slang, create a Vulkan-compatible SPIR-V target, load a Slang shader source file, compile it, and then create a VkShaderModule from the resulting SPIR-V code. Ensure that `slangGlobalSession` is initialized and `device` is a valid VkDevice. ```cpp slang::createGlobalSession(slangGlobalSession.writeRef()); auto slangTargets{ std::to_array({ {.format{SLANG_SPIRV}, .profile{slangGlobalSession->findProfile("spirv_1_4")} } }) }; auto slangOptions{ std::to_array({ { slang::CompilerOptionName::EmitSpirvDirectly, {slang::CompilerOptionValueKind::Int, 1} } }) }; slang::SessionDesc slangSessionDesc{ .targets{slangTargets.data()}, .targetCount{SlangInt(slangTargets.size())}, .defaultMatrixLayoutMode = SLANG_MATRIX_LAYOUT_COLUMN_MAJOR, .compilerOptionEntries{slangOptions.data()}, .compilerOptionEntryCount{uint32_t(slangOptions.size())} }; Slang::ComPtr slangSession; slangGlobalSession->createSession(slangSessionDesc, slangSession.writeRef()); Slang::ComPtr slangModule{ slangSession->loadModuleFromSource("triangle", "assets/shader.slang", nullptr, nullptr) }; Slang::ComPtr spirv; slangModule->getTargetCode(0, spirv.writeRef()); VkShaderModuleCreateInfo shaderModuleCI{ .sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO, .codeSize = spirv->getBufferSize(), .pCode = (uint32_t*)spirv->getBufferPointer() }; VkShaderModule shaderModule{}; chk(vkCreateShaderModule(device, &shaderModuleCI, nullptr, &shaderModule)); ``` -------------------------------- ### Get Device Queue Source: https://github.com/saschawillems/howtovulkan/blob/main/tutorial/docs/index.md Retrieves a handle to a specific queue from the newly created logical device. This queue will be used for submitting commands. ```cpp vkGetDeviceQueue(device, queueFamily, 0, &queue); ``` -------------------------------- ### Get Device Queue Source: https://github.com/saschawillems/howtovulkan/blob/main/_autodocs/vulkan-objects.md Retrieves a queue from the logical device for submitting commands. The queue family must support graphics operations. ```cpp vkGetDeviceQueue(device, queueFamily, 0, &queue) ``` -------------------------------- ### Create SDL Window with Vulkan Support Source: https://github.com/saschawillems/howtovulkan/blob/main/tutorial/docs/index.md Creates an SDL window with Vulkan support and resizable properties. This is the first step in setting up a rendering surface. ```cpp SDL_Window* window = SDL_CreateWindow("How to Vulkan", 1280u, 720u, SDL_WINDOW_VULKAN | SDL_WINDOW_RESIZABLE); ``` -------------------------------- ### Configure Color Blend Attachment Source: https://github.com/saschawillems/howtovulkan/blob/main/_autodocs/configuration.md Defines color blending behavior for a single pipeline attachment. This example enables all color channel writes. ```cpp VkPipelineColorBlendAttachmentState blendAttachment{ .colorWriteMask = 0xF }; ``` -------------------------------- ### Vulkan Instance Creation Source: https://github.com/saschawillems/howtovulkan/blob/main/_autodocs/initialization.md Creates a Vulkan instance with application information and necessary extensions. Loads instance-level function pointers afterwards. ```cpp VkApplicationInfo appInfo{ .sType = VK_STRUCTURE_TYPE_APPLICATION_INFO, .pApplicationName = "How to Vulkan", .apiVersion = VK_API_VERSION_1_3 }; uint32_t instanceExtensionsCount{ 0 }; char const* const* instanceExtensions{ SDL_Vulkan_GetInstanceExtensions(&instanceExtensionsCount) }; VkInstanceCreateInfo instanceCI{ .sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO, .pApplicationInfo = &appInfo, .enabledExtensionCount = instanceExtensionsCount, .ppEnabledExtensionNames = instanceExtensions, }; chk(vkCreateInstance(&instanceCI, nullptr, &instance)); volkLoadInstance(instance); ``` -------------------------------- ### Bind Descriptor Sets Source: https://github.com/saschawillems/howtovulkan/blob/main/_autodocs/render-loop.md Binds descriptor sets to the command buffer. This example binds the texture descriptor set (set 0) to the pipeline layout. ```cpp vkCmdBindDescriptorSets(cb, VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineLayout, 0, 1, &descriptorSetTex, 0, nullptr); ``` -------------------------------- ### Create Vulkan Instance Source: https://github.com/saschawillems/howtovulkan/blob/main/tutorial/docs/index.md Creates the Vulkan instance using the application info and retrieved platform-specific extensions. Assumes a 'chk' function for error checking. ```cpp VkInstanceCreateInfo instanceCI{ .sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO, .pApplicationInfo = &appInfo, .enabledExtensionCount = instanceExtensionsCount, .ppEnabledExtensionNames = instanceExtensions, }; chk(vkCreateInstance(&instanceCI, nullptr, &instance)); ``` -------------------------------- ### Application Entry Point Source: https://github.com/saschawillems/howtovulkan/blob/main/_autodocs/initialization.md Defines the main function of the application, accepting command-line arguments. ```cpp int main(int argc, char* argv[]) ``` -------------------------------- ### Create SDL Window and Vulkan Surface Source: https://github.com/saschawillems/howtovulkan/blob/main/_autodocs/initialization.md Creates an SDL window with Vulkan support and resizability, then creates a Vulkan surface associated with this window. This step is essential for rendering to the window. ```cpp SDL_Window* window = SDL_CreateWindow( "How to Vulkan", 1280u, 720u, SDL_WINDOW_VULKAN | SDL_WINDOW_RESIZABLE ); assert(window); chk(SDL_Vulkan_CreateSurface(window, instance, nullptr, &surface)); chk(SDL_GetWindowSize(window, &windowSize.x, &windowSize.y)); ``` -------------------------------- ### Create Vulkan Window Source: https://github.com/saschawillems/howtovulkan/blob/main/_autodocs/configuration.md Initializes an SDL window with Vulkan support and resizable properties. Sets the window title and dimensions. ```cpp SDL_Window* window = SDL_CreateWindow( "How to Vulkan", 1280u, 720u, SDL_WINDOW_VULKAN | SDL_WINDOW_RESIZABLE ); ``` -------------------------------- ### Push Constants for Shader Data Source: https://github.com/saschawillems/howtovulkan/blob/main/_autodocs/render-loop.md Pushes constant data to the vertex shader. This example pushes the device address of a shader data buffer, likely containing per-instance data. ```cpp vkCmdPushConstants(cb, pipelineLayout, VK_SHADER_STAGE_VERTEX_BIT, 0, sizeof(VkDeviceAddress), &shaderDataBuffers[frameIndex].deviceAddress); ``` -------------------------------- ### Begin Dynamic Rendering Pass Source: https://github.com/saschawillems/howtovulkan/blob/main/_autodocs/render-loop.md Initializes a dynamic rendering pass with specified color and depth attachments. The color attachment is cleared to black and stored, while the depth attachment is cleared and discarded. ```cpp VkRenderingAttachmentInfo colorAttachmentInfo{ .sType = VK_STRUCTURE_STRUCTURE_TYPE_RENDERING_ATTACHMENT_INFO, .imageView = swapchainImageViews[imageIndex], .imageLayout = VK_IMAGE_LAYOUT_ATTACHMENT_OPTIMAL, .loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR, .storeOp = VK_ATTACHMENT_STORE_OP_STORE, .clearValue{.color{ 0.0f, 0.0f, 0.0f, 1.0f }} }; VkRenderingAttachmentInfo depthAttachmentInfo{ .sType = VK_STRUCTURE_TYPE_RENDERING_ATTACHMENT_INFO, .imageView = depthImageView, .imageLayout = VK_IMAGE_LAYOUT_ATTACHMENT_OPTIMAL, .loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR, .storeOp = VK_ATTACHMENT_STORE_OP_DONT_CARE, .clearValue = {.depthStencil = {1.0f, 0}} }; VkRenderingInfo renderingInfo{ .sType = VK_STRUCTURE_TYPE_RENDERING_INFO, .renderArea{.extent{.width = static_cast(windowSize.x), .height = static_cast(windowSize.y) }}, .layerCount = 1, .colorAttachmentCount = 1, .pColorAttachments = &colorAttachmentInfo, .pDepthAttachment = &depthAttachmentInfo }; vkCmdBeginRendering(cb, &renderingInfo); ``` -------------------------------- ### Configure Swapchain Source: https://github.com/saschawillems/howtovulkan/blob/main/_autodocs/configuration.md Sets up the swapchain creation information, defining image format, color space, extent, usage, and presentation mode. This configuration is crucial for rendering to the window surface. ```cpp const VkFormat imageFormat{ VK_FORMAT_B8G8R8A8_SRGB }; VkSwapchainCreateInfoKHR swapchainCI{ .sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR, .surface = surface, .minImageCount = surfaceCaps.minImageCount, .imageFormat = imageFormat, .imageColorSpace = VK_COLORSPACE_SRGB_NONLINEAR_KHR, .imageExtent{.width = swapchainExtent.width, .height = swapchainExtent.height}, .imageArrayLayers = 1, .imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT, .preTransform = VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR, .compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR, .presentMode = VK_PRESENT_MODE_FIFO_KHR }; ``` -------------------------------- ### Create Vulkan Instance Source: https://github.com/saschawillems/howtovulkan/blob/main/_autodocs/vulkan-objects.md Creates a connection to the Vulkan driver. This is a fundamental step required before any other Vulkan operations. ```cpp vkCreateInstance(&instanceCI, nullptr, &instance) ``` -------------------------------- ### Create Device Queue Create Info Source: https://github.com/saschawillems/howtovulkan/blob/main/tutorial/docs/index.md Sets up the VkDeviceQueueCreateInfo structure to request a single graphics queue from the identified queue family with a priority of 1.0. ```cpp const float qfpriorities{ 1.0f }; VkDeviceQueueCreateInfo queueCI{ .sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO, .queueFamilyIndex = queueFamily, .queueCount = 1, .pQueuePriorities = &qfpriorities }; ``` -------------------------------- ### Define Descriptor Set Layout Binding Flags Source: https://github.com/saschawillems/howtovulkan/blob/main/tutorial/docs/index.md Configures descriptor binding flags for a descriptor set layout, enabling variable descriptor counts which is essential for bindless texture setups using descriptor indexing. ```cpp VkDescriptorBindingFlags descVariableFlag{ VK_DESCRIPTOR_BINDING_VARIABLE_DESCRIPTOR_COUNT_BIT }; VkDescriptorSetLayoutBindingFlagsCreateInfo descBindingFlags{ .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_BINDING_FLAGS_CREATE_INFO, .bindingCount = 1, .pBindingFlags = &descVariableFlag }; ``` -------------------------------- ### Get Shader Data Buffer Device Address Source: https://github.com/saschawillems/howtovulkan/blob/main/tutorial/docs/index.md Retrieves the device address for a created shader data buffer, which is necessary for accessing it directly in shaders using Vulkan 1.3's buffer device address feature. ```cpp VkBufferDeviceAddressInfo uBufferBdaInfo{ .sType = VK_STRUCTURE_TYPE_BUFFER_DEVICE_ADDRESS_INFO, .buffer = shaderDataBuffers[i].buffer }; shaderDataBuffers[i].deviceAddress = vkGetBufferDeviceAddress(device, &uBufferBdaInfo); } ``` -------------------------------- ### Loading .obj File with tinyobjloader Source: https://github.com/saschawillems/howtovulkan/blob/main/tutorial/docs/index.md Uses the tinyobjloader library to parse a Wavefront .obj file. Ensure the 'assets/suzanne.obj' file exists. ```cpp // Mesh data tinyobj::attrib_t attrib; std::vector shapes; std::vector materials; chk(tinyobj::LoadObj(&attrib, &shapes, &materials, nullptr, nullptr, "assets/suzanne.obj")); ``` -------------------------------- ### Viewport and Dynamic State Configuration Source: https://github.com/saschawillems/howtovulkan/blob/main/tutorial/docs/index.md Sets up the viewport and scissor rectangles, and configures them as dynamic states. This allows changes without pipeline recreation, essential for window resizing. ```cpp VkPipelineViewportStateCreateInfo viewportState{ .sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO, .viewportCount = 1, .scissorCount = 1 }; std::vector dynamicStates{ VK_DYNAMIC_STATE_VIEWPORT, VK_DYNAMIC_STATE_SCISSOR }; VkPipelineDynamicStateCreateInfo dynamicState{ .sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO, .dynamicStateCount = 2, .pDynamicStates = dynamicStates.data() }; ``` -------------------------------- ### Scale Input Actions with Elapsed Time Source: https://github.com/saschawillems/howtovulkan/blob/main/_autodocs/input-and-events.md Applies the calculated elapsed time to input events like mouse motion and wheel scroll to ensure consistent speed regardless of frame rate. For example, rotation speed is halved at 30fps compared to 60fps. ```cpp // Rotation scaling objectRotations[shaderData.selected].x -= (float)event.motion.yrel * elapsedTime; // Camera zoom scaling camPos.z += (float)event.wheel.y * elapsedTime * 10.0f; ``` -------------------------------- ### Volk Initialization Source: https://github.com/saschawillems/howtovulkan/blob/main/_autodocs/initialization.md Initializes the Volk meta-loader for runtime Vulkan function pointer loading. ```cpp volkInitialize(); ``` -------------------------------- ### Configure Frame Fence Source: https://github.com/saschawillems/howtovulkan/blob/main/_autodocs/configuration.md Creates a Vulkan fence and initializes it in a signaled state. This allows the first frame to proceed without waiting. ```cpp VkFenceCreateInfo fenceCI{ .sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO, .flags = VK_FENCE_CREATE_SIGNALED_BIT }; ``` -------------------------------- ### Create Vulkan Graphics Pipeline Source: https://github.com/saschawillems/howtovulkan/blob/main/_autodocs/initialization.md This snippet shows the complete process of creating a Vulkan graphics pipeline. It configures various states including shader stages, vertex input, input assembly, viewport, rasterization, multisampling, depth stencil, color blending, and dynamic states. Ensure all prerequisite objects like the device, descriptor set layout, and shader modules are created beforehand. ```cpp VkPushConstantRange pushConstantRange{ .stageFlags = VK_SHADER_STAGE_VERTEX_BIT, .size = sizeof(VkDeviceAddress) }; VkPipelineLayoutCreateInfo pipelineLayoutCI{ .sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO, .setLayoutCount = 1, .pSetLayouts = &descriptorSetLayoutTex, .pushConstantRangeCount = 1, .pPushConstantRanges = &pushConstantRange }; chk(vkCreatePipelineLayout(device, &pipelineLayoutCI, nullptr, &pipelineLayout)); std::vector shaderStages{ { .sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, .stage = VK_SHADER_STAGE_VERTEX_BIT, .module = shaderModule, .pName = "main"}, { .sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, .stage = VK_SHADER_STAGE_FRAGMENT_BIT, .module = shaderModule, .pName = "main" } }; VkVertexInputBindingDescription vertexBinding{ .binding = 0, .stride = sizeof(Vertex), .inputRate = VK_VERTEX_INPUT_RATE_VERTEX }; std::vector vertexAttributes{ { .location = 0, .binding = 0, .format = VK_FORMAT_R32G32B32_SFLOAT }, { .location = 1, .binding = 0, .format = VK_FORMAT_R32G32B32_SFLOAT, .offset = offsetof(Vertex, normal) }, { .location = 2, .binding = 0, .format = VK_FORMAT_R32G32_SFLOAT, .offset = offsetof(Vertex, uv) }, }; VkPipelineVertexInputStateCreateInfo vertexInputState{ .sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO, .vertexBindingDescriptionCount = 1, .pVertexBindingDescriptions = &vertexBinding, .vertexAttributeDescriptionCount = static_cast(vertexAttributes.size()), .pVertexAttributeDescriptions = vertexAttributes.data(), }; VkPipelineInputAssemblyStateCreateInfo inputAssemblyState{ .sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO, .topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST }; std::vector dynamicStates{ VK_DYNAMIC_STATE_VIEWPORT, VK_DYNAMIC_STATE_SCISSOR }; VkPipelineDynamicStateCreateInfo dynamicState{ .sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO, .dynamicStateCount = 2, .pDynamicStates = dynamicStates.data() }; VkPipelineViewportStateCreateInfo viewportState{ .sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO, .viewportCount = 1, .scissorCount = 1 }; VkPipelineRasterizationStateCreateInfo rasterizationState{ .sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO, .lineWidth = 1.0f }; VkPipelineMultisampleStateCreateInfo multisampleState{ .sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO, .rasterizationSamples = VK_SAMPLE_COUNT_1_BIT }; VkPipelineDepthStencilStateCreateInfo depthStencilState{ .sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO, .depthTestEnable = VK_TRUE, .depthWriteEnable = VK_TRUE, .depthCompareOp = VK_COMPARE_OP_LESS_OR_EQUAL }; VkPipelineColorBlendAttachmentState blendAttachment{ .colorWriteMask = 0xF }; VkPipelineColorBlendStateCreateInfo colorBlendState{ .sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO, .attachmentCount = 1, .pAttachments = &blendAttachment }; VkPipelineRenderingCreateInfo renderingCI{ .sType = VK_STRUCTURE_TYPE_PIPELINE_RENDERING_CREATE_INFO, .colorAttachmentCount = 1, .pColorAttachmentFormats = &imageFormat, .depthAttachmentFormat = depthFormat }; VkGraphicsPipelineCreateInfo pipelineCI{ .sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO, .pNext = &renderingCI, .stageCount = 2, .pStages = shaderStages.data(), .pVertexInputState = &vertexInputState, .pInputAssemblyState = &inputAssemblyState, .pViewportState = &viewportState, .pRasterizationState = &rasterizationState, .pMultisampleState = &multisampleState, .pDepthStencilState = &depthStencilState, .pColorBlendState = &colorBlendState, .pDynamicState = &dynamicState, .layout = pipelineLayout }; chk(vkCreateGraphicsPipelines(device, VK_NULL_HANDLE, 1, &pipelineCI, nullptr, &pipeline)); ``` -------------------------------- ### Check Presentation Support Source: https://github.com/saschawillems/howtovulkan/blob/main/tutorial/docs/index.md Verifies if the found graphics queue family also supports presentation to the screen using SDL. ```cpp chk(SDL_Vulkan_GetPresentationSupport(instance, devices[deviceIndex], queueFamily)); ``` -------------------------------- ### Create Fence and Command Buffer for Texture Loading Source: https://github.com/saschawillems/howtovulkan/blob/main/tutorial/docs/index.md Initializes a fence for synchronizing command buffer execution and allocates a command buffer for one-time submission. This is a prerequisite for recording copy and barrier commands. ```cpp VkFenceCreateInfo fenceOneTimeCI{ .sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO }; VkFence fenceOneTime{}; chk(vkCreateFence(device, &fenceOneTimeCI, nullptr, &fenceOneTime)); VkCommandBuffer cbOneTime{}; VkCommandBufferAllocateInfo cbOneTimeAI{ .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO, .commandPool = commandPool, .commandBufferCount = 1 }; chk(vkAllocateCommandBuffers(device, &cbOneTimeAI, &cbOneTime)); ``` -------------------------------- ### Load and Compile Slang Shader to SPIR-V Source: https://github.com/saschawillems/howtovulkan/blob/main/tutorial/docs/index.md Loads a Slang shader from a file and compiles it to SPIR-V using the created Slang session. This SPIR-V blob can then be used to create a Vulkan shader module. ```cpp Slang::ComPtr slangModule{ slangSession->loadModuleFromSource("triangle", "assets/shader.slang", nullptr, nullptr) }; Slang::ComPtr spirv; slangModule->getTargetCode(0, spirv.writeRef()); ``` -------------------------------- ### Configure VMA Allocator Source: https://github.com/saschawillems/howtovulkan/blob/main/_autodocs/configuration.md Initializes the Vulkan Memory Allocator (VMA) with settings for buffer device address tracking. Requires Vulkan instance and device handles. ```cpp VmaVulkanFunctions vkFunctions{ .vkGetInstanceProcAddr = vkGetInstanceProcAddr, .vkGetDeviceProcAddr = vkGetDeviceProcAddr, .vkCreateImage = vkCreateImage }; VmaAllocatorCreateInfo allocatorCI{ .flags = VMA_ALLOCATOR_CREATE_BUFFER_DEVICE_ADDRESS_BIT, .physicalDevice = devices[deviceIndex], .device = device, .pVulkanFunctions = &vkFunctions, .instance = instance }; ``` -------------------------------- ### Transition Swapchain Image for Presentation Source: https://github.com/saschawillems/howtovulkan/blob/main/tutorial/docs/index.md Transitions the swapchain image layout from optimal for rendering to the layout required for presentation. This ensures the image can be displayed correctly. ```cpp VkImageMemoryBarrier2 barrierPresent{ .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER_2, .srcStageMask = VK_PIPELINE_STAGE_2_COLOR_ATTACHMENT_OUTPUT_BIT, .srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, .dstStageMask = VK_PIPELINE_STAGE_2_COLOR_ATTACHMENT_OUTPUT_BIT, .dstAccessMask = 0, .oldLayout = VK_IMAGE_LAYOUT_ATTACHMENT_OPTIMAL, .newLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR, .image = swapchainImages[imageIndex], .subresourceRange{.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT, .levelCount = 1, .layerCount = 1 } }; VkDependencyInfo barrierPresentDependencyInfo{ .sType = VK_STRUCTURE_TYPE_DEPENDENCY_INFO, .imageMemoryBarrierCount = 1, .pImageMemoryBarriers = &barrierPresent }; vkCmdPipelineBarrier2(cb, &barrierPresentDependencyInfo); ``` -------------------------------- ### Create Vulkan Surface Source: https://github.com/saschawillems/howtovulkan/blob/main/_autodocs/vulkan-objects.md Creates a Vulkan surface associated with an SDL window, enabling presentation of rendered content. Requires a valid Vulkan instance and SDL window. ```cpp SDL_Vulkan_CreateSurface(window, instance, nullptr, &surface) ``` -------------------------------- ### Image Layout Transitions with Pipeline Barrier Source: https://github.com/saschawillems/howtovulkan/blob/main/tutorial/docs/index.md Issues layout transitions for swapchain and depth images using vkCmdPipelineBarrier2. Ensures images are in the optimal layout for rendering. ```cpp std::array outputBarriers{ VkImageMemoryBarrier2{ .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER_2, .srcStageMask = VK_PIPELINE_STAGE_2_COLOR_ATTACHMENT_OUTPUT_BIT, .srcAccessMask = 0, .dstStageMask = VK_PIPELINE_STAGE_2_COLOR_ATTACHMENT_OUTPUT_BIT, .dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, .oldLayout = VK_IMAGE_LAYOUT_UNDEFINED, .newLayout = VK_IMAGE_LAYOUT_ATTACHMENT_OPTIMAL, .image = swapchainImages[imageIndex], subresourceRange{.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT, .levelCount = 1, .layerCount = 1 } }, VkImageMemoryBarrier2{ .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER_2, .srcStageMask = VK_PIPELINE_STAGE_2_LATE_FRAGMENT_TESTS_BIT, .srcAccessMask = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT, .dstStageMask = VK_PIPELINE_STAGE_2_EARLY_FRAGMENT_TESTS_BIT, .dstAccessMask = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT, .oldLayout = VK_IMAGE_LAYOUT_UNDEFINED, .newLayout = VK_IMAGE_LAYOUT_ATTACHMENT_OPTIMAL, .image = depthImage, subresourceRange{.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT, .levelCount = 1, .layerCount = 1 } } }; VkDependencyInfo barrierDependencyInfo{ .sType = VK_STRUCTURE_TYPE_DEPENDENCY_INFO, .imageMemoryBarrierCount = 2, .pImageMemoryBarriers = outputBarriers.data() }; vkCmdPipelineBarrier2(cb, &barrierDependencyInfo); ``` -------------------------------- ### Image Layout Transitions for Rendering Source: https://github.com/saschawillems/howtovulkan/blob/main/_autodocs/render-loop.md Applies pipeline barriers to transition image layouts for rendering. It transitions the swapchain image to `VK_IMAGE_LAYOUT_ATTACHMENT_OPTIMAL` for color output and the depth image for depth/stencil operations, using the Synchronization2 features. ```cpp std::array outputBarriers{ VkImageMemoryBarrier2{ .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER_2, .srcStageMask = VK_PIPELINE_STAGE_2_COLOR_ATTACHMENT_OUTPUT_BIT, .srcAccessMask = 0, .dstStageMask = VK_PIPELINE_STAGE_2_COLOR_ATTACHMENT_OUTPUT_BIT, .dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, .oldLayout = VK_IMAGE_LAYOUT_UNDEFINED, .newLayout = VK_IMAGE_LAYOUT_ATTACHMENT_OPTIMAL, .image = swapchainImages[imageIndex], .subresourceRange{.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT, .levelCount = 1, .layerCount = 1 } }, VkImageMemoryBarrier2{ .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER_2, .srcStageMask = VK_PIPELINE_STAGE_2_LATE_FRAGMENT_TESTS_BIT, .srcAccessMask = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT, .dstStageMask = VK_PIPELINE_STAGE_2_EARLY_FRAGMENT_TESTS_BIT, .dstAccessMask = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT, .oldLayout = VK_IMAGE_LAYOUT_UNDEFINED, .newLayout = VK_IMAGE_LAYOUT_ATTACHMENT_OPTIMAL, .image = depthImage, .subresourceRange{.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT, .levelCount = 1, .layerCount = 1 } } }; VkDependencyInfo barrierDependencyInfo{ .sType = VK_STRUCTURE_TYPE_DEPENDENCY_INFO, .imageMemoryBarrierCount = 2, .pImageMemoryBarriers = outputBarriers.data() }; vkCmdPipelineBarrier2(cb, &barrierDependencyInfo); ``` -------------------------------- ### Configure SPIR-V Shader Compilation Source: https://github.com/saschawillems/howtovulkan/blob/main/_autodocs/configuration.md Sets up Slang compiler to emit SPIR-V bytecode directly for Vulkan. Ensures compatibility with SPIR-V 1.4. ```cpp auto slangTargets{ std::to_array({ {.format{SLANG_SPIRV}, .profile{slangGlobalSession->findProfile("spirv_1_4")} } }) }; auto slangOptions{ std::to_array({ { slang::CompilerOptionName::EmitSpirvDirectly, {slang::CompilerOptionValueKind::Int, 1} } }) }; ``` -------------------------------- ### Create Vulkan Swapchain Source: https://github.com/saschawillems/howtovulkan/blob/main/_autodocs/initialization.md Creates the Vulkan swapchain, which manages the images that will be presented to the screen. It's configured with a specific format, extent, and presentation mode, typically VK_PRESENT_MODE_FIFO_KHR for vsync. ```cpp const VkFormat imageFormat{ VK_FORMAT_B8G8R8A8_SRGB }; VkSwapchainCreateInfoKHR swapchainCI{ .sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR, .surface = surface, .minImageCount = surfaceCaps.minImageCount, .imageFormat = imageFormat, .imageColorSpace = VK_COLORSPACE_SRGB_NONLINEAR_KHR, .imageExtent{.width = swapchainExtent.width, .height = swapchainExtent.height}, .imageArrayLayers = 1, .imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT, .preTransform = VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR, .compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR, .presentMode = VK_PRESENT_MODE_FIFO_KHR }; chk(vkCreateSwapchainKHR(device, &swapchainCI, nullptr, &swapchain)); ``` -------------------------------- ### Configure Vertex/Index Buffer Allocation Source: https://github.com/saschawillems/howtovulkan/blob/main/_autodocs/configuration.md Sets up allocation parameters for vertex and index buffers. Enables host-side writing and mapping for efficient data transfer. ```cpp VmaAllocationCreateInfo vBufferAllocCI{ .flags = VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT | VMA_ALLOCATION_CREATE_HOST_ACCESS_ALLOW_TRANSFER_INSTEAD_BIT | VMA_ALLOCATION_CREATE_MAPPED_BIT, .usage = VMA_MEMORY_USAGE_AUTO }; ``` -------------------------------- ### Input Assembly State for Triangle List Source: https://github.com/saschawillems/howtovulkan/blob/main/tutorial/docs/index.md Configures how primitives are assembled. Use VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST for rendering separate triangles. ```cpp VkPipelineInputAssemblyStateCreateInfo inputAssemblyState{ .sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO, topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST }; ``` -------------------------------- ### Select Device by Index Source: https://github.com/saschawillems/howtovulkan/blob/main/tutorial/docs/index.md Allows selection of a specific Vulkan device based on its index, which can be provided as a command-line argument. Asserts that the selected index is within the valid range of available devices. ```cpp uint32_t deviceIndex{ 0 }; if (argc > 1) { deviceIndex = std::stoi(argv[1]); assert(deviceIndex < deviceCount); } ``` -------------------------------- ### Application Information Structure Source: https://github.com/saschawillems/howtovulkan/blob/main/tutorial/docs/index.md Defines basic application details like name and Vulkan API version. ```cpp VkApplicationInfo appInfo{ .sType = VK_STRUCTURE_TYPE_APPLICATION_INFO, .pApplicationName = "How to Vulkan", .apiVersion = VK_API_VERSION_1_3 }; ``` -------------------------------- ### Include Directories for Vulkan Project Source: https://github.com/saschawillems/howtovulkan/blob/main/_autodocs/configuration.md Specifies include directories for the Vulkan SDK, and external libraries like tinyobj and ktx. The SYSTEM prefix is used for Vulkan SDK headers to suppress warnings. ```cmake include_directories(SYSTEM $ENV{VULKAN_SDK}/include) include_directories(external/tinyobj) include_directories(external/ktx/include) include_directories(external/ktx/other_include) ``` -------------------------------- ### Physical Device Selection Source: https://github.com/saschawillems/howtovulkan/blob/main/_autodocs/initialization.md Selects a physical device, defaulting to the first one or using a command-line argument for override. Logs the selected device's name. ```cpp uint32_t deviceIndex{ 0 }; if (argc > 1) { deviceIndex = std::stoi(argv[1]); assert(deviceIndex < deviceCount); } VkPhysicalDeviceProperties2 deviceProperties{ .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2 }; vkGetPhysicalDeviceProperties2(devices[deviceIndex], &deviceProperties); std::cout << "Selected device: " << deviceProperties.properties.deviceName << "\n"; ``` -------------------------------- ### Render Loop Entry Point Source: https://github.com/saschawillems/howtovulkan/blob/main/_autodocs/render-loop.md The main loop that iterates each frame. It continues until the 'quit' flag is set, typically by a quit event. ```cpp uint64_t lastTime{ SDL_GetTicks() }; bool quit{ false }; while (!quit) { // ... per-frame operations ... } ``` -------------------------------- ### Recreate Vulkan Swapchain Source: https://github.com/saschawillems/howtovulkan/blob/main/_autodocs/render-loop.md This code snippet handles the recreation of the Vulkan swapchain and associated resources when a window resize event occurs or when VK_ERROR_OUT_OF_DATE_KHR is encountered. It ensures that the swapchain, image views, semaphores, and depth image are updated to match the new window dimensions. ```cpp if (updateSwapchain) { chk(SDL_GetWindowSize(window, &windowSize.x, &windowSize.y)); updateSwapchain = false; chk(vkDeviceWaitIdle(device)); chk(vkGetPhysicalDeviceSurfaceCapabilitiesKHR(devices[deviceIndex], surface, &surfaceCaps)); swapchainCI.oldSwapchain = swapchain; swapchainCI.imageExtent = { .width = static_cast(windowSize.x), .height = static_cast(windowSize.y)}; chk(vkCreateSwapchainKHR(device, &swapchainCI, nullptr, &swapchain)); // Recreate image views for (auto i = 0; i < imageCount; i++) { vkDestroyImageView(device, swapchainImageViews[i], nullptr); } chk(vkGetSwapchainImagesKHR(device, swapchain, &imageCount, nullptr)); swapchainImages.resize(imageCount); chk(vkGetSwapchainImagesKHR(device, swapchain, &imageCount, swapchainImages.data())); swapchainImageViews.resize(imageCount); for (auto i = 0; i < imageCount; i++) { VkImageViewCreateInfo viewCI{ .sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO, .image = swapchainImages[i], .viewType = VK_IMAGE_VIEW_TYPE_2D, .format = imageFormat, .subresourceRange = {.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT, .levelCount = 1, .layerCount = 1} }; chk(vkCreateImageView(device, &viewCI, nullptr, &swapchainImageViews[i])); } // Recreate semaphores for (auto& semaphore : renderCompleteSemaphores) { vkDestroySemaphore(device, semaphore, nullptr); } renderCompleteSemaphores.resize(imageCount); for (auto& semaphore : renderCompleteSemaphores) { chk(vkCreateSemaphore(device, &semaphoreCI, nullptr, &semaphore)); } vkDestroySwapchainKHR(device, swapchainCI.oldSwapchain, nullptr); // Recreate depth image vmaDestroyImage(allocator, depthImage, depthImageAllocation); vkDestroyImageView(device, depthImageView, nullptr); depthImageCI.extent = { .width = static_cast(windowSize.x), .height = static_cast(windowSize.y), .depth = 1 }; VmaAllocationCreateInfo allocCI{ .flags = VMA_ALLOCATION_CREATE_DEDICATED_MEMORY_BIT, .usage = VMA_MEMORY_USAGE_AUTO }; chk(vmaCreateImage(allocator, &depthImageCI, &allocCI, &depthImage, &depthImageAllocation, nullptr)); VkImageViewCreateInfo viewCI{ .sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO, .image = depthImage, .viewType = VK_IMAGE_VIEW_TYPE_2D, .format = depthFormat, .subresourceRange = {.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT, .levelCount = 1, .layerCount = 1} }; chk(vkCreateImageView(device, &viewCI, nullptr, &depthImageView)); } ``` -------------------------------- ### Vulkan Project File Structure Source: https://github.com/saschawillems/howtovulkan/blob/main/_autodocs/INDEX.md Outlines the directory layout for the How Vulkan project. It shows the organization of source files, assets, external libraries, and documentation. ```text howtovulkan/ ├── source/ │ ├── main.cpp (700 lines) │ ├── CMakeLists.txt │ ├── assets/ │ │ ├── shader.slang │ │ ├── suzanne.obj │ │ ├── suzanne0.ktx │ │ ├── suzanne1.ktx │ │ └── suzanne2.ktx │ └── external/ │ ├── ktx/ │ └── tinyobj/ ├── tutorial/ │ └── docs/ │ └── index.md (tutorial) └── README.md ``` -------------------------------- ### Create Logical Device Source: https://github.com/saschawillems/howtovulkan/blob/main/_autodocs/vulkan-objects.md Creates a logical interface to a selected physical device, enabling command submission and resource allocation. Requires device extensions and enabled features. ```cpp vkCreateDevice(devices[deviceIndex], &deviceCI, nullptr, &device) ``` -------------------------------- ### Retrieve Swapchain Images and Create Image Views Source: https://github.com/saschawillems/howtovulkan/blob/main/_autodocs/initialization.md Fetches swapchain images and creates corresponding VkImageView objects. This is a crucial step for rendering to the swapchain. ```cpp uint32_t imageCount{ 0 }; chk(vkGetSwapchainImagesKHR(device, swapchain, &imageCount, nullptr)); swapchainImages.resize(imageCount); chk(vkGetSwapchainImagesKHR(device, swapchain, &imageCount, swapchainImages.data())); swapchainImageViews.resize(imageCount); for (auto i = 0; i < imageCount; i++) { VkImageViewCreateInfo viewCI{ .sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO, .image = swapchainImages[i], .viewType = VK_IMAGE_VIEW_TYPE_2D, .format = imageFormat, .subresourceRange{.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT, .levelCount = 1, .layerCount = 1} }; chk(vkCreateImageView(device, &viewCI, nullptr, &swapchainImageViews[i])); } ```