SpiecsEngine
 
Loading...
Searching...
No Matches
VulkanImage.cpp
Go to the documentation of this file.
1/**
2* @file VulkanImage.cpp.
3* @brief The VulkanImage Class Implementation.
4* @author Spices.
5*/
6
7#include "Pchheader.h"
8#include "VulkanImage.h"
9
10#include "VulkanBuffer.h"
13#include "Render/Vulkan/VulkanRenderBackend.h"
14
15namespace Spices {
16
18 VulkanState& vulkanState ,
19 const std::string& name ,
20 VkImageType type ,
21 uint32_t width ,
22 uint32_t height ,
23 uint32_t layers ,
24 VkSampleCountFlagBits numSamples ,
25 VkFormat format ,
26 VkImageTiling tiling ,
27 VkImageUsageFlags usage ,
28 VkImageCreateFlags flags ,
29 VkMemoryPropertyFlags properties ,
30 uint32_t mipLevels
31 )
32 : VulkanObject(vulkanState)
33 , m_Width(static_cast<int>(width))
34 , m_Height(static_cast<int>(height))
35 , m_Layers(layers)
38 {
40
41 /**
42 * @brief Create Image.
43 */
44 CreateImage(
45 vulkanState,
46 name,
47 type,
48 width,
49 height,
50 layers,
51 numSamples,
52 format,
53 tiling,
54 usage,
55 flags,
56 properties,
57 mipLevels
58 );
59 }
60
62 {
64
65 /**
66 * @brief Destroy DescriptorSet.
67 */
69
70 /**
71 * @brief Destroy reltative object.
72 */
73 vkDestroySampler(m_VulkanState.m_Device, m_TextureSampler, nullptr);
74
75 for (int i = 0; i < m_ImageViews.size(); i++)
76 {
77 vkDestroyImageView(m_VulkanState.m_Device, m_ImageViews[i], nullptr);
78 }
79
81
82 /**
83 * @brief Destroy VkImage.
84 */
85 vmaDestroyImage(m_VulkanState.m_VmaAllocator, m_Image, m_Alloc);
86
87#else
88
89 /**
90 * @brief Destroy VkImage.
91 */
92 vkDestroyImage(m_VulkanState.m_Device, m_Image, nullptr);
93 vkFreeMemory(m_VulkanState.m_Device, m_ImageMemory, nullptr);
94
95#endif
96
97 }
98
100 {
102
103 m_ImageInfo.imageLayout = imageLayout;
104 m_ImageInfo.imageView = m_ImageViews[mipLevel];
105 m_ImageInfo.sampler = m_TextureSampler;
106
107 return &m_ImageInfo;
108 }
109
111 VkFormat format ,
112 VkImageLayout oldLayout ,
113 VkImageLayout newLayout
114 )
115 {
117
118 VkPipelineStageFlags sourceStage;
119 VkPipelineStageFlags destinationStage;
120
121 /**
122 * @brief Instance a VkImageMemoryBarrier.
123 */
124 VkImageMemoryBarrier barrier{};
125 barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
126 barrier.oldLayout = oldLayout;
127 barrier.newLayout = newLayout;
128 barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
129 barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
130 barrier.image = m_Image;
131 barrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
132 barrier.subresourceRange.baseMipLevel = 0;
133 barrier.subresourceRange.levelCount = m_MipLevels;
134 barrier.subresourceRange.baseArrayLayer = 0;
135 barrier.subresourceRange.layerCount = m_Layers;
136 barrier.srcAccessMask = 0;
137 barrier.dstAccessMask = 0;
138
139 /**
140 * @breif transform imagelayout from undefined to transferdst.
141 * Used during CopyBuffertoImage.
142 */
143 if (oldLayout == VK_IMAGE_LAYOUT_UNDEFINED && newLayout == VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL)
144 {
145 barrier.srcAccessMask = 0;
146 barrier.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
147
148 // Don't care what stage the pipeline is in at the start.
149 sourceStage = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
150
151 // Used for copying
152 destinationStage = VK_PIPELINE_STAGE_TRANSFER_BIT;
153 }
154
155 /**
156 * @breif transform imagelayout from undefined to transfersrc.
157 * Used during CopyImagetoBuffer.
158 */
159 else if (oldLayout == VK_IMAGE_LAYOUT_UNDEFINED && newLayout == VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL)
160 {
161 barrier.srcAccessMask = 0;
162 barrier.dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT;
163
164 // Don't care what stage the pipeline is in at the start.
165 sourceStage = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
166
167 // Used for copying
168 destinationStage = VK_PIPELINE_STAGE_TRANSFER_BIT;
169 }
170
171 /**
172 * @breif transform imagelayout from undefined to shaderread.
173 * Used during CopyImagetoBuffer.
174 */
175 else if (oldLayout == VK_IMAGE_LAYOUT_UNDEFINED && newLayout == VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL)
176 {
177 barrier.srcAccessMask = 0;
178 barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT;
179
180 // Don't care what stage the pipeline is in at the start.
181 sourceStage = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
182
183 // Used for sampling.
184 destinationStage = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
185 }
186
187 /**
188 * @breif transform imagelayout from transferdst to shaderread.
189 * Used combine with CopyBuffertoImage.
190 */
191 else if (oldLayout == VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL && newLayout == VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL)
192 {
193 barrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
194 barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT;
195
196 // From a copying stage to...
197 sourceStage = VK_PIPELINE_STAGE_TRANSFER_BIT;
198
199 // The fragment stage.
200 destinationStage = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
201 }
202
203 /**
204 * @brief transform imagelayout from transfersrc to shaderread.
205 * Used combine with CopyImagetoBuffer.
206 */
207 else if (oldLayout == VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL && newLayout == VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL)
208 {
209 barrier.srcAccessMask = VK_ACCESS_TRANSFER_READ_BIT;
210 barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT;
211
212 // From a copying stage to...
213 sourceStage = VK_PIPELINE_STAGE_TRANSFER_BIT;
214
215 // The fragment stage.
216 destinationStage = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
217 }
218
219 /**
220 * @brief transfer imagelayout from undefined to depthattachment.
221 * Used during Creating depth renderresource.
222 */
223 else if (oldLayout == VK_IMAGE_LAYOUT_UNDEFINED && newLayout == VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL)
224 {
225 barrier.srcAccessMask = 0;
226 barrier.dstAccessMask = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT;
227
228 sourceStage = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
229 destinationStage = VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT;
230 }
231
232 /**
233 * @brief transfer imagelayout from undefined to depthattachment.
234 * Used during Creating depth renderresource.
235 */
236 else if (oldLayout == VK_IMAGE_LAYOUT_UNDEFINED && newLayout == VK_IMAGE_LAYOUT_GENERAL)
237 {
238 barrier.srcAccessMask = 0;
239 barrier.dstAccessMask = VK_IMAGE_ASPECT_NONE;
240
241 sourceStage = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
242 destinationStage = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
243 }
244 else
245 {
246 SPICES_CORE_WARN("Unsupported layout transition!");
247 }
248
249 if (newLayout == VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL)
250 {
251 barrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT;
252
253 if (format == VK_FORMAT_D32_SFLOAT_S8_UINT || format == VK_FORMAT_D24_UNORM_S8_UINT)
254 {
255 barrier.subresourceRange.aspectMask |= VK_IMAGE_ASPECT_STENCIL_BIT;
256 }
257 }
258 else
259 {
260 barrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
261 }
262
263 /**
264 * @brief Use Custom Cmd.
265 */
266 VulkanCommandBuffer::CustomGraphicCmd(m_VulkanState, [&](auto& commandBuffer) {
267 vkCmdPipelineBarrier(
268 commandBuffer,
269 sourceStage,
270 destinationStage,
271 0,
272 0,
273 nullptr,
274 0,
275 nullptr,
276 1,
277 &barrier
278 );
279 });
280 }
281
283 VkCommandBuffer commandBuffer ,
284 VkAccessFlags srcAccessMask ,
285 VkAccessFlags dstAccessMask ,
286 VkPipelineStageFlags srcStageMask ,
287 VkPipelineStageFlags dstStageMask ,
288 uint32_t srcQueueFamilyIndex ,
289 uint32_t dstQueueFamilyIndex
290 ) const
291 {
293
294 VkImageSubresourceRange range{};
295 range.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
296 range.baseMipLevel = 0;
297 range.levelCount = m_MipLevels;
298 range.baseArrayLayer = 0;
299 range.layerCount = m_Layers;
300
301 VkImageMemoryBarrier imageBarrier {};
302 imageBarrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
303 imageBarrier.srcAccessMask = srcAccessMask;
304 imageBarrier.dstAccessMask = dstAccessMask;
305 imageBarrier.srcQueueFamilyIndex = srcQueueFamilyIndex; // Fetch From Graphic to Compute.
306 imageBarrier.dstQueueFamilyIndex = dstQueueFamilyIndex;
307 imageBarrier.image = m_Image;
308 imageBarrier.subresourceRange = range;
309
310 vkCmdPipelineBarrier(
311 commandBuffer,
312 srcStageMask,
313 dstStageMask,
314 0,
315 0, nullptr,
316 0, nullptr,
317 1, &imageBarrier
318 );
319 }
320
322 VkBuffer buffer ,
323 VkImage image ,
324 uint32_t width ,
325 uint32_t height
326 )
327 const
328 {
330
331 /**
332 * @brief Instance a VkBufferImageCopy.
333 */
334 VkBufferImageCopy region{};
335 region.bufferOffset = 0;
336 region.bufferRowLength = 0;
337 region.bufferImageHeight = 0;
338
339 region.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
340 region.imageSubresource.mipLevel = 0;
341 region.imageSubresource.baseArrayLayer = 0;
342 region.imageSubresource.layerCount = m_Layers;
343
344 region.imageOffset = { 0, 0, 0 };
345 region.imageExtent = { width, height, 1 };
346
347 /**
348 * @brief Use Custom Cmd.
349 */
350 VulkanCommandBuffer::CustomGraphicCmd(m_VulkanState, [&](const VkCommandBuffer& commandBuffer) {
351 vkCmdCopyBufferToImage(
352 commandBuffer,
353 buffer,
354 image,
355 VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
356 1,
357 &region
358 );
359 });
360 }
361
363 VkBuffer buffer ,
364 VkImage image ,
365 uint32_t width ,
366 uint32_t height ,
367 const std::vector<VkBufferImageCopy>& regions
368 )
369 const
370 {
372
373 /**
374 * @brief Use Custom Cmd.
375 */
376 VulkanCommandBuffer::CustomGraphicCmd(m_VulkanState, [&](const VkCommandBuffer& commandBuffer) {
377 vkCmdCopyBufferToImage(
378 commandBuffer,
379 buffer,
380 image,
381 VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
382 static_cast<uint32_t>(regions.size()),
383 regions.data()
384 );
385 });
386 }
387
388 void VulkanImage::CopyMemoryToImageHost(const std::vector<VkMemoryToImageCopyEXT>& copies) const
389 {
391
392 /**
393 * @brief Issue the copy.
394 */
395 VkCopyMemoryToImageInfoEXT copyInfo{};
396 copyInfo.sType = VK_STRUCTURE_TYPE_COPY_MEMORY_TO_IMAGE_INFO_EXT;
397 copyInfo.dstImage = m_Image;
398 copyInfo.dstImageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
399 copyInfo.regionCount = static_cast<uint32_t>(copies.size());
400 copyInfo.pRegions = copies.data();
401
402 m_VulkanState.m_VkFunc.vkCopyMemoryToImageEXT(m_VulkanState.m_Device, &copyInfo);
403 }
404
405 void VulkanImage::CopyMemoryToImageHost(const void* data) const
406 {
408
409 /**
410 * @brief Instance a VkMemoryToImageCopyEXT.
411 */
412 VkMemoryToImageCopyEXT memoryCopy{};
413 memoryCopy.sType = VK_STRUCTURE_TYPE_MEMORY_TO_IMAGE_COPY_EXT;
414 memoryCopy.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
415 memoryCopy.imageSubresource.mipLevel = 0;
416 memoryCopy.imageSubresource.baseArrayLayer = 0;
417 memoryCopy.imageSubresource.layerCount = 1;
418 memoryCopy.imageExtent.width = m_Width;
419 memoryCopy.imageExtent.height = m_Height;
420 memoryCopy.imageExtent.depth = m_Layers;
421 memoryCopy.pHostPointer = data;
422
423 /**
424 * @brief Issue the copy.
425 */
426 VkCopyMemoryToImageInfoEXT copyInfo{};
427 copyInfo.sType = VK_STRUCTURE_TYPE_COPY_MEMORY_TO_IMAGE_INFO_EXT;
428 copyInfo.dstImage = m_Image;
429 copyInfo.dstImageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
430 copyInfo.regionCount = 1;
431 copyInfo.pRegions = &memoryCopy;
432
433 m_VulkanState.m_VkFunc.vkCopyMemoryToImageEXT(m_VulkanState.m_Device, &copyInfo);
434 }
435
436 void VulkanImage::CopyImageTexelToBuffer(uint32_t x, uint32_t y, void* out_rgba)
437 {
439
440 uint32_t channelize = 4;
441
442 /**
443 * @todo Support all type;
444 */
445 switch (m_Format)
446 {
447 case VK_FORMAT_B8G8R8A8_UNORM: // 4 bytes.
448 channelize = 4;
449 break;
450 case VK_FORMAT_R32_SFLOAT: // 4 bytes.
451 channelize = 4;
452 break;
453 case VK_FORMAT_R32G32B32A32_SFLOAT: // 16 bytes.
454 channelize = 16;
455 break;
456 default:
457 break;
458 }
459
460 /**
461 * @brief The temp buffer image date copy to.
462 */
463 VulkanBuffer stagingBuffer(
464 m_VulkanState,
465 "StagingBuffer",
466 channelize,
467 VK_BUFFER_USAGE_TRANSFER_DST_BIT,
468 VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT
469 );
470
471 /*
472 * @brief Transfer image layout from whatever to transfer src.
473 */
474 TransitionImageLayout(
475 m_Format,
476 VK_IMAGE_LAYOUT_UNDEFINED,
477 VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL
478 );
479
480 /**
481 * @brief Instance a VkBufferImageCopy.
482 */
483 VkBufferImageCopy region{};
484 region.bufferOffset = 0;
485 region.bufferRowLength = 0;
486 region.bufferImageHeight = 0;
487
488 region.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
489 region.imageSubresource.mipLevel = 0;
490 region.imageSubresource.baseArrayLayer = 0;
491 region.imageSubresource.layerCount = m_Layers;
492
493 region.imageOffset.x = static_cast<int32_t>(x);
494 region.imageOffset.y = static_cast<int32_t>(y);
495 region.imageExtent = { 1, 1, 1 };
496
497 /**
498 * @brief Use Custom Cmd.
499 */
500 VulkanCommandBuffer::CustomGraphicCmd(m_VulkanState, [&](const VkCommandBuffer& commandBuffer) {
501 vkCmdCopyImageToBuffer(commandBuffer, m_Image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, stagingBuffer.Get(), 1, &region);
502 });
503
504 /*
505 * @brief Transfer image layout from transfer src to shader read.
506 * means only can get data from a shader read layout image.
507 * @note In SpicesEngine, we need transform layout to shader read in scene compose renderer first,
508 * and after that, you can do this here.
509 */
510 TransitionImageLayout(
511 m_Format,
512 VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
513 VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL
514 );
515
516 /**
517 * @brief Write data to stagingbuffer.
518 */
519 stagingBuffer.WriteFromBuffer(out_rgba);
520 }
521
522 void VulkanImage::CopyImageToBuffer(VkBuffer dstBuffer, const std::vector<VkBufferImageCopy>& regions)
523 {
525
526 /*
527 * @brief Transfer image layout from whatever to transfer src.
528 */
529 TransitionImageLayout(
530 m_Format,
531 VK_IMAGE_LAYOUT_UNDEFINED,
532 VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL
533 );
534
535 /**
536 * @brief Use Custom Cmd.
537 */
538 VulkanCommandBuffer::CustomGraphicCmd(m_VulkanState, [&](const VkCommandBuffer& commandBuffer) {
539 vkCmdCopyImageToBuffer(commandBuffer, m_Image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, dstBuffer, regions.size(), regions.data());
540 });
541
542 /*
543 * @brief Transfer image layout from transfer src to shader read.
544 * means only can get data from a shader read layout image.
545 * @note In SpicesEngine, we need transform layout to shader read in scene compose renderer first,
546 * and after that, you can do this here.
547 */
548 TransitionImageLayout(
549 m_Format,
550 VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
551 VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL
552 );
553 }
554
555 void VulkanImage::CopyImageToMemoryHost(void* data) const
556 {
558
559 VkImageToMemoryCopyEXT memoryCopy{};
560 memoryCopy.sType = VK_STRUCTURE_TYPE_IMAGE_TO_MEMORY_COPY_EXT;
561 memoryCopy.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
562 memoryCopy.imageSubresource.mipLevel = 0;
563 memoryCopy.imageSubresource.baseArrayLayer = 0;
564 memoryCopy.imageSubresource.layerCount = 1;
565 memoryCopy.imageOffset = { 0, 0, 0 };
566 memoryCopy.imageExtent.width = m_Width;
567 memoryCopy.imageExtent.height = m_Height;
568 memoryCopy.imageExtent.depth = m_Layers;
569 memoryCopy.pHostPointer = data;
570
571 /**
572 * @brief Instance a VkCopyImageToMemoryInfoEXT.
573 */
574 VkCopyImageToMemoryInfoEXT copyInfo{};
575 copyInfo.sType = VK_STRUCTURE_TYPE_COPY_IMAGE_TO_MEMORY_INFO_EXT;
576 copyInfo.srcImage = m_Image;
577 copyInfo.srcImageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
578 copyInfo.regionCount = 1;
579 copyInfo.pRegions = &memoryCopy;
580
581 m_VulkanState.m_VkFunc.vkCopyImageToMemoryEXT(m_VulkanState.m_Device, &copyInfo);
582 }
583
584 void VulkanImage::CopyImageToMemoryHost(const std::vector<VkImageToMemoryCopyEXT>& copies) const
585 {
587
588 /**
589 * @brief Instance a VkCopyImageToMemoryInfoEXT.
590 */
591 VkCopyImageToMemoryInfoEXT copyInfo{};
592 copyInfo.sType = VK_STRUCTURE_TYPE_COPY_IMAGE_TO_MEMORY_INFO_EXT;
593 copyInfo.srcImage = m_Image;
594 copyInfo.srcImageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
595 copyInfo.regionCount = static_cast<uint32_t>(copies.size());
596 copyInfo.pRegions = copies.data();
597
598 m_VulkanState.m_VkFunc.vkCopyImageToMemoryEXT(m_VulkanState.m_Device, &copyInfo);
599 }
600
601 void VulkanImage::GenerateMipmaps(VkFormat imageFormat, int32_t texWidth, int32_t texHeight) const
602 {
604
605 /**
606 * @brief Get video memory properties.
607 */
608 VkFormatProperties formatProperties;
609 vkGetPhysicalDeviceFormatProperties(m_VulkanState.m_PhysicalDevice, imageFormat, &formatProperties);
610
611 /**
612 * @brief Must require VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT.
613 */
614 if (!(formatProperties.optimalTilingFeatures & VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT) &&
615 (formatProperties.optimalTilingFeatures & VK_FORMAT_FEATURE_BLIT_SRC_BIT) &&
616 (formatProperties.optimalTilingFeatures & VK_FORMAT_FEATURE_BLIT_DST_BIT))
617 {
618 SPICES_CORE_ERROR("texture image format does not support linear blitting!")
619 }
620
621 /**
622 * @brief Instance a VkImageMemoryBarrier.
623 */
624 VkImageMemoryBarrier barrier{};
625 barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
626 barrier.image = m_Image;
627 barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
628 barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
629 barrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
630 barrier.subresourceRange.baseArrayLayer = 0;
631 barrier.subresourceRange.layerCount = m_Layers;
632 barrier.subresourceRange.levelCount = 1;
633
634 /**
635 * @brief Use Custom Cmd.
636 */
637 VulkanCommandBuffer::CustomGraphicCmd(m_VulkanState, [&](const VkCommandBuffer& commandBuffer) {
638
639 /**
640 * @brief Iter all mips.
641 */
642 for (uint32_t i = 1; i < m_MipLevels; i++)
643 {
644 const int pw = std::max(1, (m_Width >> (i - 1)));
645 const int ph = std::max(1, (m_Height >> (i - 1)));
646
647 const int w = std::max(1, m_Width >> i);
648 const int h = std::max(1, m_Height >> i);
649
650 barrier.subresourceRange.baseMipLevel = i - 1;
651 barrier.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
652 barrier.newLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL;
653 barrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
654 barrier.dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT;
655
656 /**
657 * @breif Pipeline Barrier.
658 */
659 vkCmdPipelineBarrier(commandBuffer,
660 VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0,
661 0, nullptr,
662 0, nullptr,
663 1, &barrier
664 );
665
666 /**
667 * @brief Instance a VkImageBlit.
668 */
669 VkImageBlit blit{};
670 blit.srcOffsets[0] = { 0, 0, 0 };
671 blit.srcOffsets[1] = { pw, ph, 1 };
672 blit.srcSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
673 blit.srcSubresource.mipLevel = i - 1;
674 blit.srcSubresource.baseArrayLayer = 0;
675 blit.srcSubresource.layerCount = m_Layers;
676 blit.dstOffsets[0] = { 0, 0, 0 };
677 blit.dstOffsets[1] = { w, h, 1 };
678 blit.dstSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
679 blit.dstSubresource.mipLevel = i;
680 blit.dstSubresource.baseArrayLayer = 0;
681 blit.dstSubresource.layerCount = m_Layers;
682
683 /**
684 * @brief BitlImage.
685 */
686 vkCmdBlitImage(commandBuffer,
687 m_Image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
688 m_Image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
689 1, &blit,
690 VK_FILTER_LINEAR
691 );
692
693 barrier.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL;
694 barrier.newLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
695 barrier.srcAccessMask = VK_ACCESS_TRANSFER_READ_BIT;
696 barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT;
697
698 /**
699 * @brief Pipeline Barrier.
700 */
701 vkCmdPipelineBarrier(commandBuffer,
702 VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, 0,
703 0, nullptr,
704 0, nullptr,
705 1, &barrier
706 );
707 }
708
709 barrier.subresourceRange.baseMipLevel = m_MipLevels - 1;
710 barrier.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
711 barrier.newLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
712 barrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
713 barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT;
714
715 /**
716 * @brief Pipeline Barrier.
717 */
718 vkCmdPipelineBarrier(commandBuffer,
719 VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, 0,
720 0, nullptr,
721 0, nullptr,
722 1, &barrier
723 );
724 });
725 }
726
727 void VulkanImage::CreateImageView(VkFormat format, VkImageViewType viewType, VkImageAspectFlags aspectFlags, bool isCreateMipmapView)
728 {
730
731 uint32_t count = isCreateMipmapView ? m_MipLevels : 1;
732
733 m_ImageViews.resize(count);
734 for(int i = 0; i < count; i++)
735 {
736 /**
737 * @brief Instance a VkImageViewCreateInfo.
738 */
739 VkImageViewCreateInfo viewInfo{};
740 viewInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
741 viewInfo.image = m_Image;
742 viewInfo.viewType = viewType;
743 viewInfo.format = format;
744 viewInfo.subresourceRange.aspectMask = aspectFlags;
745 viewInfo.subresourceRange.baseMipLevel = i;
746 viewInfo.subresourceRange.levelCount = isCreateMipmapView ? 1 : m_MipLevels; // mipmaps num.
747 viewInfo.subresourceRange.baseArrayLayer = 0; // layer index.(access given index layer of texture array/texture cube)
748 viewInfo.subresourceRange.layerCount = m_Layers; // layer num.
749
750 /**
751 * @brief Create ImageView.
752 */
753 VK_CHECK(vkCreateImageView(m_VulkanState.m_Device, &viewInfo, nullptr, &m_ImageViews[i]))
754 DEBUGUTILS_SETOBJECTNAME(VK_OBJECT_TYPE_IMAGE_VIEW, reinterpret_cast<uint64_t>(m_ImageViews[i]), m_VulkanState.m_Device, "ImageView")
755 }
756 }
757
759 {
761
762 /**
763 * @brief Instance a VkSamplerCreateInfo.
764 */
765 VkSamplerCreateInfo samplerInfo{};
766 samplerInfo.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO;
767 samplerInfo.magFilter = VK_FILTER_LINEAR;
768 samplerInfo.minFilter = VK_FILTER_LINEAR;
769 samplerInfo.addressModeU = VK_SAMPLER_ADDRESS_MODE_REPEAT;
770 samplerInfo.addressModeV = VK_SAMPLER_ADDRESS_MODE_REPEAT;
771 samplerInfo.addressModeW = VK_SAMPLER_ADDRESS_MODE_REPEAT;
772 samplerInfo.anisotropyEnable = VK_TRUE;
773
774 /**
775 * @brief Get VkPhysicalDeviceProperties.
776 */
777 VkPhysicalDeviceProperties properties{};
778 vkGetPhysicalDeviceProperties(m_VulkanState.m_PhysicalDevice, &properties);
779
780 samplerInfo.maxAnisotropy = properties.limits.maxSamplerAnisotropy;
781 samplerInfo.borderColor = VK_BORDER_COLOR_INT_OPAQUE_BLACK;
782 samplerInfo.unnormalizedCoordinates = VK_FALSE;
783 samplerInfo.compareEnable = VK_FALSE;
784 samplerInfo.compareOp = VK_COMPARE_OP_ALWAYS;
785
786 samplerInfo.mipmapMode = VK_SAMPLER_MIPMAP_MODE_LINEAR;
787 samplerInfo.mipLodBias = 0.0f;
788 samplerInfo.minLod = 0;
789 samplerInfo.maxLod = static_cast<float>(m_MipLevels);
790
791 /**
792 * @brief Create Sampler.
793 */
794 VK_CHECK(vkCreateSampler(m_VulkanState.m_Device, &samplerInfo, nullptr, &m_TextureSampler))
795 DEBUGUTILS_SETOBJECTNAME(VK_OBJECT_TYPE_SAMPLER, reinterpret_cast<uint64_t>(m_TextureSampler), m_VulkanState.m_Device, "ImageSampler")
796 }
797
799 VulkanState& vulkanState ,
800 const std::string& name ,
801 VkImageType type ,
802 uint32_t width ,
803 uint32_t height ,
804 uint32_t layers ,
805 VkSampleCountFlagBits numSamples ,
806 VkFormat format ,
807 VkImageTiling tiling ,
808 VkImageUsageFlags usage ,
809 VkImageCreateFlags flags ,
810 VkMemoryPropertyFlags properties ,
811 uint32_t mipLevels
812 )
813 {
815
816 m_Width = static_cast<int>(width);
817 m_Height = static_cast<int>(height);
818 m_Layers = layers;
819 m_ImageType = type;
820 m_Format = format;
821 m_MipLevels = mipLevels;
822
823 /**
824 * @brief Instance a VkImageCreateInfo.
825 */
826 VkImageCreateInfo imageInfo{};
827 imageInfo.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
828 imageInfo.imageType = type;
829 imageInfo.extent.width = width;
830 imageInfo.extent.height = height;
831 imageInfo.extent.depth = 1;
832 imageInfo.mipLevels = mipLevels;
833 imageInfo.arrayLayers = layers;
834 imageInfo.format = format;
835 imageInfo.tiling = tiling;
836 imageInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
837 imageInfo.usage = usage;
838 imageInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
839 imageInfo.samples = numSamples;
840 imageInfo.flags = flags;
841
843
844 /**
845 * @brief Instance a VmaAllocationCreateInfo.
846 */
847 VmaAllocationCreateInfo createInfo{};
848 createInfo.usage = VMA_MEMORY_USAGE_AUTO;
849
850 /**
851 * @brief Create Image.
852 */
853 VK_CHECK(vmaCreateImage(vulkanState.m_VmaAllocator, &imageInfo, &createInfo, &m_Image, &m_Alloc, nullptr))
854 DEBUGUTILS_SETOBJECTNAME(VK_OBJECT_TYPE_IMAGE, reinterpret_cast<uint64_t>(m_Image), m_VulkanState.m_Device, name)
855
856#else
857
858 /**
859 * @brief Create Image.
860 */
861 VK_CHECK(vkCreateImage(vulkanState.m_Device, &imageInfo, nullptr, &m_Image));
862 DEBUGUTILS_SETOBJECTNAME(VK_OBJECT_TYPE_IMAGE, (uint64_t)m_Image, m_VulkanState.m_Device, name)
863
864 /**
865 * @brief Get VkMemoryRequirements.
866 */
867 VkMemoryRequirements memRequirements;
868 vkGetImageMemoryRequirements(vulkanState.m_Device, m_Image, &memRequirements);
869
870 /**
871 * @brief Instance a VkMemoryAllocateInfo.
872 */
873 VkMemoryAllocateInfo allocInfo{};
874 allocInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
875 allocInfo.allocationSize = memRequirements.size;
876
877 /**
878 * @brief Get VkPhysicalDeviceMemoryProperties.
879 */
880 VkPhysicalDeviceMemoryProperties memProperties;
881 vkGetPhysicalDeviceMemoryProperties(vulkanState.m_PhysicalDevice, &memProperties);
882
883 /**
884 * @brief Get suitable video memory index.
885 */
886 allocInfo.memoryTypeIndex = 0;
887 for (uint32_t i = 0; i < memProperties.memoryTypeCount; i++)
888 {
889 if (memRequirements.memoryTypeBits & (1 << i) && (memProperties.memoryTypes[i].propertyFlags & properties) == properties)
890 {
891 allocInfo.memoryTypeIndex = i;
892 }
893 }
894
895 /**
896 * @brief Allocate video memory.
897 */
898 VK_CHECK(vkAllocateMemory(vulkanState.m_Device, &allocInfo, nullptr, &m_ImageMemory))
899
900 /**
901 * @brief Bind video memory.
902 */
903 vkBindImageMemory(vulkanState.m_Device, m_Image, m_ImageMemory, 0);
904
905#endif
906
907 }
908
909 void VulkanImage::CreateDescriptorSet(uint32_t binding)
910 {
912
913 /**
914 * @brief Destroy old DescriptorSetLayout.
915 */
917
918 m_IsCreateSet = true;
919
920 /**
921 * @brief Instance a VkDescriptorSetLayoutBinding.
922 */
923 VkDescriptorSetLayoutBinding samplerLayoutBinding{};
924 samplerLayoutBinding.binding = binding;
925 samplerLayoutBinding.descriptorCount = 1;
926 samplerLayoutBinding.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
927 samplerLayoutBinding.pImmutableSamplers = nullptr;
928 samplerLayoutBinding.stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT;
929
930 VkDescriptorBindingFlags setBindingFlags;
931 setBindingFlags = VK_DESCRIPTOR_BINDING_PARTIALLY_BOUND_BIT | VK_DESCRIPTOR_BINDING_UPDATE_AFTER_BIND_BIT;
932
933 /**
934 * @breif Instance a VkDescriptorSetLayoutBindingFlagsCreateInfo.
935 */
936 VkDescriptorSetLayoutBindingFlagsCreateInfo bindingFlags{};
937 bindingFlags.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_BINDING_FLAGS_CREATE_INFO;
938 bindingFlags.pNext = nullptr;
939 bindingFlags.pBindingFlags = &setBindingFlags;
940 bindingFlags.bindingCount = 1;
941
942 /**
943 * @brief Instance a VkDescriptorSetLayoutCreateInfo.
944 */
945 VkDescriptorSetLayoutCreateInfo layoutInfo{};
946 layoutInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO;
947 layoutInfo.bindingCount = 1;
948 layoutInfo.pBindings = &samplerLayoutBinding;
949 layoutInfo.flags = VK_DESCRIPTOR_SET_LAYOUT_CREATE_UPDATE_AFTER_BIND_POOL_BIT;
950 layoutInfo.pNext = &bindingFlags;
951
952 /**
953 * @brief Create DescriptorSetLayout.
954 */
955 VK_CHECK(vkCreateDescriptorSetLayout(m_VulkanState.m_Device, &layoutInfo, nullptr, &m_DescriptorSetLayout))
956 DEBUGUTILS_SETOBJECTNAME(VK_OBJECT_TYPE_DESCRIPTOR_SET_LAYOUT, reinterpret_cast<uint64_t>(m_DescriptorSetLayout), m_VulkanState.m_Device, "DescriptorSetLayoutImage")
957
958 /**
959 * @brief Instance a VkDescriptorSetAllocateInfo.
960 */
961 VkDescriptorSetAllocateInfo allocInfo{};
962 allocInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO;
963 allocInfo.descriptorPool = VulkanRenderBackend::GetDescriptorPool()->GetPool();
964 allocInfo.descriptorSetCount = 1;
965 allocInfo.pSetLayouts = &m_DescriptorSetLayout;
966
967 /**
968 * @brief Allocate DescriptorSets.
969 */
970 VK_CHECK(vkAllocateDescriptorSets(m_VulkanState.m_Device, &allocInfo, &m_DescriptorSet))
971 DEBUGUTILS_SETOBJECTNAME(VK_OBJECT_TYPE_DESCRIPTOR_SET, reinterpret_cast<uint64_t>(m_DescriptorSet), m_VulkanState.m_Device, "DescriptorSetImage")
972
973 /**
974 * @brief Instance a VkDescriptorImageInfo.
975 */
976 VkDescriptorImageInfo imageInfo{};
977 imageInfo.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
978 imageInfo.imageView = m_ImageViews[0];
979 imageInfo.sampler = m_TextureSampler;
980
981 /**
982 * @brief Instance a VkWriteDescriptorSet.
983 */
984 VkWriteDescriptorSet descriptorWrite{};
985 descriptorWrite.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
986 descriptorWrite.dstSet = m_DescriptorSet;
987 descriptorWrite.dstBinding = binding;
988 descriptorWrite.dstArrayElement = 0;
989 descriptorWrite.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
990 descriptorWrite.descriptorCount = 1;
991 descriptorWrite.pImageInfo = &imageInfo;
992
993 /**
994 * @brief Update DecriptorSet.
995 */
996 vkUpdateDescriptorSets(m_VulkanState.m_Device, 1, &descriptorWrite, 0, nullptr);
997 }
998
1000 {
1002
1003 /**
1004 * @brief Instance a VkFormatProperties3.
1005 */
1006 VkFormatProperties3 formatProperties3{};
1007 formatProperties3.sType = VK_STRUCTURE_TYPE_FORMAT_PROPERTIES_3_KHR;
1008
1009 /**
1010 * @brief Properties3 need to be chained into Properties2.
1011 */
1012 VkFormatProperties2 formatProperties2{};
1013 formatProperties2.sType = VK_STRUCTURE_TYPE_FORMAT_PROPERTIES_2;
1014 formatProperties2.pNext = &formatProperties3;
1015
1016 /**
1017 * @brief Get format properties for the select image format.
1018 */
1019 vkGetPhysicalDeviceFormatProperties2(m_VulkanState.m_PhysicalDevice, m_Format, &formatProperties2);
1020
1021 return formatProperties3.optimalTilingFeatures & VK_FORMAT_FEATURE_2_HOST_IMAGE_TRANSFER_BIT_EXT && VKImageHostOperation;
1022 }
1023
1024 bool VulkanImage::IsHostCopyable(VulkanState& state, VkFormat format)
1025 {
1027
1028 /**
1029 * @brief Instance a VkFormatProperties3.
1030 */
1031 VkFormatProperties3 formatProperties3{};
1032 formatProperties3.sType = VK_STRUCTURE_TYPE_FORMAT_PROPERTIES_3_KHR;
1033
1034 /**
1035 * @brief Properties3 need to be chained into Properties2.
1036 */
1037 VkFormatProperties2 formatProperties2{};
1038 formatProperties2.sType = VK_STRUCTURE_TYPE_FORMAT_PROPERTIES_2;
1039 formatProperties2.pNext = &formatProperties3;
1040
1041 /**
1042 * @brief Get format properties for the select image format.
1043 */
1044 vkGetPhysicalDeviceFormatProperties2(state.m_PhysicalDevice, format, &formatProperties2);
1045
1046 return formatProperties3.optimalTilingFeatures & VK_FORMAT_FEATURE_2_HOST_IMAGE_TRANSFER_BIT_EXT && VKImageHostOperation;
1047 }
1048
1050 {
1052
1053 if (m_IsCreateSet)
1054 {
1055 /**
1056 * @brief Destroy DescriptorSetLayout.
1057 */
1058 vkDestroyDescriptorSetLayout(m_VulkanState.m_Device, m_DescriptorSetLayout, nullptr);
1059 }
1060 }
1061}
#define SPICES_PROFILE_ZONE
#define VMA_ALLOCATOR
Use VMA for memory allocate.
Definition VulkanUtils.h:27
#define VK_CHECK(expr)
Vulkan Check macro. Verify Vulkan API Effectiveness.
Definition VulkanUtils.h:68
#define VKImageHostOperation
Disable Host Image copy for host memory heap is too smaller.
Definition VulkanUtils.h:32
This Class is a Wrapper of VulkanBuffer.
VulkanCommandBuffer Class. This class defines the VulkanCommandBuffer behaves. This class is just a w...
void CopyImageToMemoryHost(const std::vector< VkImageToMemoryCopyEXT > &copies) const
int m_Width
Image width.
bool IsHostCopyable() const
Check if this image format can copy from host to gpu directly.
void CreateDescriptorSet(uint32_t binding)
Create DescriptorSet with single image.
void CopyImageToMemoryHost(void *data) const
VkDescriptorImageInfo * GetImageInfo(VkImageLayout imageLayout=VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, uint32_t mipLevel=0)
void CopyMemoryToImageHost(const void *data) const
Copy the Memory's data to this VkImage.
void CreateSampler()
Create a Sampler.
void CopyImageToBuffer(VkBuffer dstBuffer, const std::vector< VkBufferImageCopy > &regions)
void CopyImageTexelToBuffer(uint32_t x, uint32_t y, void *out_rgba)
void CreateImage(VulkanState &vulkanState, const std::string &name, VkImageType type, uint32_t width, uint32_t height, uint32_t layers, VkSampleCountFlagBits numSamples, VkFormat format, VkImageTiling tiling, VkImageUsageFlags usage, VkImageCreateFlags flags, VkMemoryPropertyFlags properties, uint32_t mipLevels)
void DestroyDescriptorSetLayout() const
Destroy the DescriptorSetLayout if Created a DescriptorSet.
void CopyBufferToImage(VkBuffer buffer, VkImage image, uint32_t width, uint32_t height, const std::vector< VkBufferImageCopy > &regions) const
Copy the Buffer's data to this VkImage. Used to create image data (include mipmaps),...
void CopyMemoryToImageHost(const std::vector< VkMemoryToImageCopyEXT > &copies) const
Copy the Memory's data to this VkImage. Used to create image data (include mipmaps),...
bool m_IsCreateSet
True if Called Create DescriptorSet.
virtual ~VulkanImage() override
Destructor Function.
VulkanImage(VulkanState &vulkanState, const std::string &name, VkImageType type, uint32_t width, uint32_t height, uint32_t layers, VkSampleCountFlagBits numSamples, VkFormat format, VkImageTiling tiling, VkImageUsageFlags usage, VkImageCreateFlags flags, VkMemoryPropertyFlags properties, uint32_t mipLevels)
uint32_t m_MipLevels
Image mipmaps num.
void CreateImageView(VkFormat format, VkImageViewType viewType, VkImageAspectFlags aspectFlags, bool isCreateMipmapView=false)
Create Image View.
int m_Height
Image height.
void Barrier(VkCommandBuffer commandBuffer, VkAccessFlags srcAccessMask, VkAccessFlags dstAccessMask, VkPipelineStageFlags srcStageMask, VkPipelineStageFlags dstStageMask, uint32_t srcQueueFamilyIndex, uint32_t dstQueueFamilyIndex) const
Wrapper of Call vkCmdImageBarrier.
void TransitionImageLayout(VkFormat format, VkImageLayout oldLayout, VkImageLayout newLayout)
void CopyBufferToImage(VkBuffer buffer, VkImage image, uint32_t width, uint32_t height) const
Copy the Buffer's data to this VkImage.
uint32_t m_Layers
Image layer(texture cube: 6).
void GenerateMipmaps(VkFormat imageFormat, int32_t texWidth, int32_t texHeight) const
Generate mipmaps with the VkImage.
VulkanState & m_VulkanState
The global VulkanState Referenced from VulkanRenderBackend.
VulkanObject(VulkanState &vulkanState)
Constructor Function. Init member variables.
VulkanObject Class. This class defines the basic behaves of VulkanObject. When we create an new Vulka...
This struct contains all Vulkan object in used global.
Definition VulkanUtils.h:74