@@ -122,6 +122,16 @@ HPPHelloTriangle::~HPPHelloTriangle()
122
122
instance.destroySurfaceKHR (surface);
123
123
}
124
124
125
+ if (vertex_buffer_allocation != VK_NULL_HANDLE)
126
+ {
127
+ vmaDestroyBuffer (vma_allocator, vertex_buffer, vertex_buffer_allocation);
128
+ }
129
+
130
+ if (vma_allocator != VK_NULL_HANDLE)
131
+ {
132
+ vmaDestroyAllocator (vma_allocator);
133
+ }
134
+
125
135
if (device)
126
136
{
127
137
device.destroy ();
@@ -160,6 +170,9 @@ bool HPPHelloTriangle::prepare(const vkb::ApplicationOptions &options)
160
170
// get the (graphics) queue
161
171
queue = device.getQueue (graphics_queue_index, 0 );
162
172
173
+ vma_allocator = create_vma_allocator ();
174
+ std::tie (vertex_buffer, vertex_buffer_allocation) = create_vertex_buffer ();
175
+
163
176
init_swapchain ();
164
177
165
178
// Create the necessary objects for rendering.
@@ -338,11 +351,40 @@ vk::Device HPPHelloTriangle::create_device(const std::vector<const char *> &requ
338
351
vk::Pipeline HPPHelloTriangle::create_graphics_pipeline ()
339
352
{
340
353
// Load our SPIR-V shaders.
354
+
355
+ // Samples support different shading languages, all of which are offline compiled to SPIR-V, the shader format that Vulkan uses.
356
+ // The shading language to load for can be selected via command line
357
+ std::string shader_folder{" " };
358
+ switch (get_shading_language ())
359
+ {
360
+ case vkb::ShadingLanguage::HLSL:
361
+ shader_folder = " hlsl" ;
362
+ break ;
363
+ case vkb::ShadingLanguage::SLANG:
364
+ shader_folder = " slang" ;
365
+ break ;
366
+ default :
367
+ shader_folder = " glsl" ;
368
+ }
369
+
341
370
std::vector<vk::PipelineShaderStageCreateInfo> shader_stages{
342
- {.stage = vk::ShaderStageFlagBits::eVertex, .module = create_shader_module (" triangle.vert.spv" ), .pName = " main" },
343
- {.stage = vk::ShaderStageFlagBits::eFragment, .module = create_shader_module (" triangle.frag.spv" ), .pName = " main" }};
371
+ {.stage = vk::ShaderStageFlagBits::eVertex, .module = create_shader_module (" hello_triangle/" + shader_folder + " /triangle.vert.spv" ), .pName = " main" },
372
+ {.stage = vk::ShaderStageFlagBits::eFragment, .module = create_shader_module (" hello_triangle/" + shader_folder + " /triangle.frag.spv" ), .pName = " main" }};
373
+
374
+ // Define the vertex input binding.
375
+ vk::VertexInputBindingDescription binding_description{.binding = 0 , .stride = sizeof (Vertex), .inputRate = vk::VertexInputRate::eVertex};
344
376
345
- vk::PipelineVertexInputStateCreateInfo vertex_input;
377
+ // Define the vertex input attribute.
378
+ std::array<vk::VertexInputAttributeDescription, 2 > attribute_descriptions{
379
+ {{.location = 0 , .binding = 0 , .format = vk::Format::eR32G32B32Sfloat, .offset = offsetof (Vertex, position)},
380
+ {.location = 1 , .binding = 0 , .format = vk::Format::eR32G32B32Sfloat, .offset = offsetof (Vertex, color)}}};
381
+
382
+ // Define the pipeline vertex input.
383
+ vk::PipelineVertexInputStateCreateInfo vertex_input{
384
+ .vertexBindingDescriptionCount = 1 ,
385
+ .pVertexBindingDescriptions = &binding_description,
386
+ .vertexAttributeDescriptionCount = static_cast <uint32_t >(attribute_descriptions.size ()),
387
+ .pVertexAttributeDescriptions = attribute_descriptions.data ()};
346
388
347
389
// Our attachment will write to all color channels, but no blending is enabled.
348
390
vk::PipelineColorBlendAttachmentState blend_attachment{.colorWriteMask = vk::ColorComponentFlagBits::eR | vk::ColorComponentFlagBits::eG |
@@ -378,8 +420,8 @@ vk::ImageView HPPHelloTriangle::create_image_view(vk::Image image)
378
420
.image = image,
379
421
.viewType = vk::ImageViewType::e2D,
380
422
.format = swapchain_data.format ,
381
- .components = {vk::ComponentSwizzle::eR, vk::ComponentSwizzle::eG, vk::ComponentSwizzle::eB, vk::ComponentSwizzle::eA},
382
- .subresourceRange = {vk::ImageAspectFlagBits::eColor, 0 , 1 , 0 , 1 }};
423
+ .components = {. r = vk::ComponentSwizzle::eR, . g = vk::ComponentSwizzle::eG, . b = vk::ComponentSwizzle::eB, . a = vk::ComponentSwizzle::eA},
424
+ .subresourceRange = {. aspectMask = vk::ImageAspectFlagBits::eColor, . baseMipLevel = 0 , . levelCount = 1 , . baseArrayLayer = 0 , . layerCount = 1 }};
383
425
return device.createImageView (image_view_create_info);
384
426
}
385
427
@@ -498,19 +540,20 @@ vk::Instance HPPHelloTriangle::create_instance(std::vector<const char *> const &
498
540
499
541
vk::RenderPass HPPHelloTriangle::create_render_pass ()
500
542
{
501
- vk::AttachmentDescription attachment{{},
502
- swapchain_data.format , // Backbuffer format
503
- vk::SampleCountFlagBits::e1 , // Not multisampled
504
- vk::AttachmentLoadOp::eClear, // When starting the frame, we want tiles to be cleared
505
- vk::AttachmentStoreOp::eStore, // When ending the frame, we want tiles to be written out
506
- vk::AttachmentLoadOp::eDontCare, // Don't care about stencil since we're not using it
507
- vk::AttachmentStoreOp::eDontCare,
508
- vk::ImageLayout::eUndefined, // The image layout will be undefined when the render pass begins
509
- vk::ImageLayout::ePresentSrcKHR}; // After the render pass is complete, we will transition to ePresentSrcKHR layout
543
+ vk::AttachmentDescription attachment{
544
+ .format = swapchain_data.format , // Backbuffer format.
545
+ .samples = vk::SampleCountFlagBits::e1 , // Not multisampled.
546
+ .loadOp = vk::AttachmentLoadOp::eClear, // When starting the frame, we want tiles to be cleared.
547
+ .storeOp = vk::AttachmentStoreOp::eStore, // When ending the frame, we want tiles to be written out.
548
+ .stencilLoadOp = vk::AttachmentLoadOp::eDontCare, // Don't care about stencil since we're not using it.
549
+ .stencilStoreOp = vk::AttachmentStoreOp::eDontCare, // Don't care about stencil since we're not using it.
550
+ .initialLayout = vk::ImageLayout::eUndefined, // The image layout will be undefined when the render pass begins.
551
+ .finalLayout = vk::ImageLayout::ePresentSrcKHR // After the render pass is complete, we will transition to PRESENT_SRC_KHR layout.
552
+ };
510
553
511
554
// We have one subpass. This subpass has one color attachment.
512
555
// While executing this subpass, the attachment will be in attachment optimal layout.
513
- vk::AttachmentReference color_ref{0 , vk::ImageLayout::eColorAttachmentOptimal};
556
+ vk::AttachmentReference color_ref{. attachment = 0 , . layout = vk::ImageLayout::eColorAttachmentOptimal};
514
557
515
558
// We will end up with two transitions.
516
559
// The first one happens right before we start subpass #0, where
@@ -538,20 +581,17 @@ vk::RenderPass HPPHelloTriangle::create_render_pass()
538
581
}
539
582
540
583
/* *
541
- * @brief Helper function to load a shader module.
584
+ * @brief Helper function to load a shader module from an offline-compiled SPIR-V file .
542
585
* @param path The path for the shader (relative to the assets directory).
543
586
* @returns A vk::ShaderModule handle. Aborts execution if shader creation fails.
544
587
*/
545
- vk::ShaderModule HPPHelloTriangle::create_shader_module (const char * path)
588
+ vk::ShaderModule HPPHelloTriangle::create_shader_module (std::string const & path)
546
589
{
547
590
auto spirv = vkb::fs::read_shader_binary_u32 (path);
548
591
549
- VkShaderModuleCreateInfo module_info{
550
- .sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO,
551
- .codeSize = spirv.size () * sizeof (uint32_t ),
552
- .pCode = spirv.data ()};
592
+ vk::ShaderModuleCreateInfo shader_module_create_info{.codeSize = spirv.size () * sizeof (uint32_t ), .pCode = spirv.data ()};
553
593
554
- return device.createShaderModule ({. codeSize = static_cast < uint32_t >(spirv. size () * sizeof ( uint32_t )), . pCode = spirv. data ()} );
594
+ return device.createShaderModule (shader_module_create_info );
555
595
}
556
596
557
597
vk::SwapchainKHR
@@ -595,25 +635,80 @@ vk::SwapchainKHR
595
635
// FIFO must be supported by all implementations.
596
636
vk::PresentModeKHR swapchain_present_mode = vk::PresentModeKHR::eFifo;
597
637
598
- vk::SwapchainCreateInfoKHR swapchain_create_info;
599
- swapchain_create_info.surface = surface;
600
- swapchain_create_info.minImageCount = desired_swapchain_images;
601
- swapchain_create_info.imageFormat = surface_format.format ;
602
- swapchain_create_info.imageColorSpace = surface_format.colorSpace ;
603
- swapchain_create_info.imageExtent .width = swapchain_extent.width ;
604
- swapchain_create_info.imageExtent .height = swapchain_extent.height ;
605
- swapchain_create_info.imageArrayLayers = 1 ;
606
- swapchain_create_info.imageUsage = vk::ImageUsageFlagBits::eColorAttachment;
607
- swapchain_create_info.imageSharingMode = vk::SharingMode::eExclusive;
608
- swapchain_create_info.preTransform = pre_transform;
609
- swapchain_create_info.compositeAlpha = composite;
610
- swapchain_create_info.presentMode = swapchain_present_mode;
611
- swapchain_create_info.clipped = true ;
612
- swapchain_create_info.oldSwapchain = old_swapchain;
638
+ vk::SwapchainCreateInfoKHR swapchain_create_info{
639
+ .surface = surface,
640
+ .minImageCount = desired_swapchain_images,
641
+ .imageFormat = surface_format.format ,
642
+ .imageColorSpace = surface_format.colorSpace ,
643
+ .imageExtent = swapchain_extent,
644
+ .imageArrayLayers = 1 ,
645
+ .imageUsage = vk::ImageUsageFlagBits::eColorAttachment,
646
+ .imageSharingMode = vk::SharingMode::eExclusive,
647
+ .preTransform = pre_transform,
648
+ .compositeAlpha = composite,
649
+ .presentMode = swapchain_present_mode,
650
+ .clipped = true ,
651
+ .oldSwapchain = old_swapchain};
613
652
614
653
return device.createSwapchainKHR (swapchain_create_info);
615
654
}
616
655
656
+ std::pair<vk::Buffer, VmaAllocation> HPPHelloTriangle::create_vertex_buffer ()
657
+ {
658
+ // Vertex data for a single colored triangle
659
+ const std::vector<Vertex> vertices = {
660
+ {{0 .5f , -0 .5f , 0 .5f }, {1 .0f , 0 .0f , 0 .0f }},
661
+ {{0 .5f , 0 .5f , 0 .5f }, {0 .0f , 1 .0f , 0 .0f }},
662
+ {{-0 .5f , 0 .5f , 0 .5f }, {0 .0f , 0 .0f , 1 .0f }}};
663
+
664
+ const vk::DeviceSize buffer_size = sizeof (vertices[0 ]) * vertices.size ();
665
+
666
+ // Copy Vertex data to a buffer accessible by the device
667
+
668
+ vk::BufferCreateInfo buffer_create_info{.size = buffer_size, .usage = vk::BufferUsageFlagBits::eVertexBuffer};
669
+
670
+ // We use the Vulkan Memory Allocator to find a memory type that can be written and mapped from the host
671
+ // On most setups this will return a memory type that resides in VRAM and is accessible from the host
672
+ VmaAllocationCreateInfo allocation_create_info{
673
+ .flags = VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT | VMA_ALLOCATION_CREATE_MAPPED_BIT,
674
+ .usage = VMA_MEMORY_USAGE_AUTO,
675
+ .requiredFlags = VK_MEMORY_PROPERTY_HOST_COHERENT_BIT};
676
+
677
+ vk::Buffer vertex_buffer;
678
+ VmaAllocation vertex_buffer_allocation;
679
+ VmaAllocationInfo allocation_info{};
680
+ vmaCreateBuffer (vma_allocator, reinterpret_cast <VkBufferCreateInfo *>(&buffer_create_info), &allocation_create_info, reinterpret_cast <VkBuffer *>(&vertex_buffer), &vertex_buffer_allocation, &allocation_info);
681
+ if (allocation_info.pMappedData )
682
+ {
683
+ memcpy (allocation_info.pMappedData , vertices.data (), buffer_size);
684
+ }
685
+ else
686
+ {
687
+ throw std::runtime_error (" Could not map vertex buffer." );
688
+ }
689
+
690
+ return {vertex_buffer, vertex_buffer_allocation};
691
+ }
692
+
693
+ VmaAllocator HPPHelloTriangle::create_vma_allocator ()
694
+ {
695
+ // This sample uses the Vulkan Memory Alloctor (VMA), which needs to be set up
696
+ VmaVulkanFunctions vma_vulkan_functions{
697
+ .vkGetInstanceProcAddr = VULKAN_HPP_DEFAULT_DISPATCHER.vkGetInstanceProcAddr ,
698
+ .vkGetDeviceProcAddr = VULKAN_HPP_DEFAULT_DISPATCHER.vkGetDeviceProcAddr };
699
+
700
+ VmaAllocatorCreateInfo allocator_info{.physicalDevice = gpu, .device = device, .pVulkanFunctions = &vma_vulkan_functions, .instance = instance};
701
+
702
+ VmaAllocator allocator;
703
+ VkResult result = vmaCreateAllocator (&allocator_info, &allocator);
704
+ if (result != VK_SUCCESS)
705
+ {
706
+ throw std::runtime_error (" Could not create allocator for VMA allocator" );
707
+ }
708
+
709
+ return allocator;
710
+ }
711
+
617
712
/* *
618
713
* @brief Initializes the Vulkan framebuffers.
619
714
*/
@@ -732,6 +827,10 @@ void HPPHelloTriangle::render_triangle(uint32_t swapchain_index)
732
827
// Set scissor dynamically
733
828
cmd.setScissor (0 , scissor);
734
829
830
+ // Bind the vertex buffer to source the draw calls from.
831
+ vk::DeviceSize offset = {0 };
832
+ cmd.bindVertexBuffers (0 , vertex_buffer, offset);
833
+
735
834
// Draw three vertices with one instance.
736
835
cmd.draw (3 , 1 , 0 , 0 );
737
836
0 commit comments