Advertisement
Guest User

Untitled

a guest
Dec 31st, 2024
6
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 6.88 KB | None | 0 0
  1. void Texture3D::loadFromBuffer(Device &device, const void *buffer, VkDeviceSize instanceSize, uint32_t width,
  2.                                      uint32_t height, uint32_t channels, uint32_t depth, VkFormat format,
  3.                                      VkImageLayout imageLayout) {
  4.     this->width = width;
  5.     this->height = height;
  6.     this->depth = depth;
  7.     this->channels = channels;
  8.     this->layout = imageLayout;
  9.  
  10.     // Format support check
  11.     // 3D texture support in Vulkan is mandatory so there is no need to check if it is supported
  12.     VkFormatProperties formatProperties;
  13.     vkGetPhysicalDeviceFormatProperties(device.getPhysicalDevice(), format, &formatProperties);
  14.     // Check if format supports transfer
  15.     if (!(formatProperties.optimalTilingFeatures & VK_FORMAT_FEATURE_TRANSFER_DST_BIT)) {
  16.         Logger::log(LOG_LEVEL_ERROR,
  17.                     "Error: Device does not support flag TRANSFER_DST for selected texture format!\n");
  18.         throw std::runtime_error("Error: Device does not support flag TRANSFER_DST for selected!");
  19.     }
  20.     // Check if GPU supports requested 3D texture dimensions
  21.     uint32_t maxImageDimension3D(device.properties.limits.maxImageDimension3D);
  22.     if (width > maxImageDimension3D || height > maxImageDimension3D || depth > maxImageDimension3D) {
  23.         Logger::log(LOG_LEVEL_ERROR,
  24.                     "Error: Requested texture dimensions is greater than supported 3D texture dimension!\n");
  25.         throw std::runtime_error("Error: Requested texture dimensions is greater than supported 3D texture dimension!");
  26.     }
  27.  
  28.     // Calculate aligned dimensions based on device properties
  29.     VkDeviceSize alignedRowPitch = (width * instanceSize +
  30.         device.properties.limits.optimalBufferCopyRowPitchAlignment - 1) &
  31.         ~(device.properties.limits.optimalBufferCopyRowPitchAlignment - 1);
  32.    
  33.     VkDeviceSize alignedSlicePitch = alignedRowPitch * height;
  34.     VkDeviceSize totalSize = alignedSlicePitch * depth;
  35.  
  36.  
  37.     VkImageCreateInfo imageCreateInfo = Init::imageCreateInfo();
  38.     imageCreateInfo.imageType = VK_IMAGE_TYPE_3D;
  39.     imageCreateInfo.format = format;
  40.     imageCreateInfo.mipLevels = this->mipLevels;
  41.     imageCreateInfo.arrayLayers = 1;
  42.     imageCreateInfo.samples = VK_SAMPLE_COUNT_1_BIT;
  43.     imageCreateInfo.tiling = VK_IMAGE_TILING_OPTIMAL;
  44.     imageCreateInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
  45.     imageCreateInfo.extent.width = this->width;
  46.     imageCreateInfo.extent.height = this->height;
  47.     imageCreateInfo.extent.depth = this->depth;
  48.     // Set initial layout of the image to undefined
  49.     imageCreateInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
  50.     imageCreateInfo.usage = VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT;
  51.     checkResult(vkCreateImage(device.device(), &imageCreateInfo, nullptr, &this->image));
  52.  
  53.     // Device local memory to back up image
  54.     VkMemoryAllocateInfo memAllocInfo = Init::memoryAllocateInfo();
  55.     VkMemoryRequirements memReqs = {};
  56.     vkGetImageMemoryRequirements(device.device(), this->image, &memReqs);
  57.     memAllocInfo.allocationSize = memReqs.size;
  58.     memAllocInfo.memoryTypeIndex = device.findMemoryType(memReqs.memoryTypeBits, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
  59.     checkResult(vkAllocateMemory(device.device(), &memAllocInfo, nullptr, &this->memory));
  60.     checkResult(vkBindImageMemory(device.device(), this->image, this->memory, 0));
  61.  
  62.     // Create a host-visible staging buffer that contains the raw image data
  63.     Buffer stagingBuffer{
  64.         device,
  65.         instanceSize, // Size of each element (4 bytes for float)
  66.         totalSize,  // Total size including padding
  67.         VK_BUFFER_USAGE_TRANSFER_SRC_BIT,
  68.         VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT,
  69.     };
  70.  
  71.     stagingBuffer.map();
  72.  
  73.     // Copy data slice by slice with proper alignment
  74.     const float* srcData = static_cast<const float*>(buffer);
  75.     float* dstData = static_cast<float*>(stagingBuffer.getMappedMemory());
  76.  
  77.     // Calculate pitches in bytes
  78.     VkDeviceSize unalignedRowPitch = width * sizeof(float);
  79.     VkDeviceSize unalignedSlicePitch = unalignedRowPitch * height;
  80.  
  81.     // Debug prints
  82.     Logger::log(LOG_LEVEL_DEBUG, "Width: %d, Height: %d, Depth: %d\n", width, height, depth);
  83.     Logger::log(LOG_LEVEL_DEBUG, "Unaligned row pitch: %zu bytes\n", unalignedRowPitch);
  84.     Logger::log(LOG_LEVEL_DEBUG, "Aligned row pitch: %zu bytes\n", alignedRowPitch);
  85.     Logger::log(LOG_LEVEL_DEBUG, "Aligned slice pitch: %zu bytes\n", alignedSlicePitch);
  86.     Logger::log(LOG_LEVEL_DEBUG, "Unligned slice pitch: %zu bytes\n", alignedSlicePitch);
  87.    
  88.     for (uint32_t z = 0; z < depth; z++) {
  89.         for (uint32_t y = 0; y < height; y++) {
  90.             const float* srcRow = srcData + (z * height * width) + (y * width);
  91.             float* dstRow = dstData + (z * alignedSlicePitch / sizeof(float)) +
  92.                                     (y * alignedRowPitch / sizeof(float));
  93.            
  94.             // Copy one row of floats
  95.             memcpy(dstRow, srcRow, unalignedRowPitch);
  96.         }
  97.     }
  98.     stagingBuffer.unmap();
  99.  
  100.     // Setup buffer copy regions with proper alignment
  101.     VkBufferImageCopy copyRegion{};
  102.     copyRegion.bufferOffset = 0;
  103.     copyRegion.bufferRowLength = alignedRowPitch / instanceSize;  // In texels
  104.     copyRegion.bufferImageHeight = height;
  105.     copyRegion.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
  106.     copyRegion.imageSubresource.mipLevel = 0;
  107.     copyRegion.imageSubresource.baseArrayLayer = 0;
  108.     copyRegion.imageSubresource.layerCount = 1;
  109.     copyRegion.imageExtent = {width, height, depth};
  110.  
  111.     // Transition the texture image layout to transfer destination
  112.     device.transitionImageLayout(
  113.         this->image,
  114.         VK_IMAGE_LAYOUT_UNDEFINED,
  115.         VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL
  116.     );
  117.  
  118.     // Copy the data from the staging buffer to the texture image
  119.     VkCommandBuffer cmdBuffer = device.beginSingleTimeCommands();
  120.     vkCmdCopyBufferToImage(
  121.         cmdBuffer,
  122.         stagingBuffer.getBuffer(),
  123.         image,
  124.         VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
  125.         1,
  126.         &copyRegion
  127.     );
  128.     device.endSingleTimeCommands(cmdBuffer);
  129.  
  130.     // Transition the texture image layout to shader read after copying the data
  131.     device.transitionImageLayout(
  132.         this->image,
  133.         VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
  134.         imageLayout
  135.     );
  136.  
  137.     // create image view
  138.     VkImageViewCreateInfo view = Init::imageViewCreateInfo();
  139.     view.image = this->image;
  140.     view.viewType = VK_IMAGE_VIEW_TYPE_3D;
  141.     view.format = format;
  142.     view.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
  143.     view.subresourceRange.baseMipLevel = 0;
  144.     view.subresourceRange.baseArrayLayer = 0;
  145.     view.subresourceRange.layerCount = 1;
  146.     view.subresourceRange.levelCount = 1;
  147.     checkResult(vkCreateImageView(device.device(), &view, nullptr, &this->view));
  148. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement