#include "mini/image.hpp" #include "lsfg.hpp" #include #include using namespace Mini; Image::Image(VkDevice device, VkPhysicalDevice physicalDevice, VkExtent2D extent, VkFormat format, VkImageUsageFlags usage, VkImageAspectFlags aspectFlags, int* fd) : extent(extent), format(format), aspectFlags(aspectFlags) { // create image const VkExternalMemoryImageCreateInfo externalInfo{ .sType = VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_IMAGE_CREATE_INFO, .handleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT_KHR }; const VkImageCreateInfo desc{ .sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, .pNext = &externalInfo, .imageType = VK_IMAGE_TYPE_2D, .format = format, .extent = { .width = extent.width, .height = extent.height, .depth = 1 }, .mipLevels = 1, .arrayLayers = 1, .samples = VK_SAMPLE_COUNT_1_BIT, .usage = usage, .sharingMode = VK_SHARING_MODE_EXCLUSIVE }; VkImage imageHandle{}; auto res = vkCreateImage(device, &desc, nullptr, &imageHandle); if (res != VK_SUCCESS || imageHandle == VK_NULL_HANDLE) throw LSFG::vulkan_error(res, "Failed to create Vulkan image"); // find memory type VkPhysicalDeviceMemoryProperties memProps; vkGetPhysicalDeviceMemoryProperties(physicalDevice, &memProps); VkMemoryRequirements memReqs; vkGetImageMemoryRequirements(device, imageHandle, &memReqs); #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wunsafe-buffer-usage" std::optional memType{}; for (uint32_t i = 0; i < memProps.memoryTypeCount; ++i) { if ((memReqs.memoryTypeBits & (1 << i)) && // NOLINTBEGIN (memProps.memoryTypes[i].propertyFlags & VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT)) { memType.emplace(i); break; } // NOLINTEND } if (!memType.has_value()) throw LSFG::vulkan_error(VK_ERROR_UNKNOWN, "Unable to find memory type for image"); #pragma clang diagnostic pop // allocate and bind memory const VkMemoryDedicatedAllocateInfoKHR dedicatedInfo{ .sType = VK_STRUCTURE_TYPE_MEMORY_DEDICATED_ALLOCATE_INFO_KHR, .image = imageHandle, }; const VkExportMemoryAllocateInfo exportInfo{ .sType = VK_STRUCTURE_TYPE_EXPORT_MEMORY_ALLOCATE_INFO, .pNext = &dedicatedInfo, .handleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT_KHR }; const VkMemoryAllocateInfo allocInfo{ .sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO, .pNext = &exportInfo, .allocationSize = memReqs.size, .memoryTypeIndex = memType.value() }; VkDeviceMemory memoryHandle{}; res = vkAllocateMemory(device, &allocInfo, nullptr, &memoryHandle); if (res != VK_SUCCESS || memoryHandle == VK_NULL_HANDLE) throw LSFG::vulkan_error(res, "Failed to allocate memory for Vulkan image"); res = vkBindImageMemory(device, imageHandle, memoryHandle, 0); if (res != VK_SUCCESS) throw LSFG::vulkan_error(res, "Failed to bind memory to Vulkan image"); // create image view const VkImageViewCreateInfo viewDesc{ .sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO, .image = imageHandle, .viewType = VK_IMAGE_VIEW_TYPE_2D, .format = format, .components = { .r = VK_COMPONENT_SWIZZLE_IDENTITY, .g = VK_COMPONENT_SWIZZLE_IDENTITY, .b = VK_COMPONENT_SWIZZLE_IDENTITY, .a = VK_COMPONENT_SWIZZLE_IDENTITY }, .subresourceRange = { .aspectMask = aspectFlags, .levelCount = 1, .layerCount = 1 } }; VkImageView viewHandle{}; res = vkCreateImageView(device, &viewDesc, nullptr, &viewHandle); if (res != VK_SUCCESS || viewHandle == VK_NULL_HANDLE) throw LSFG::vulkan_error(res, "Failed to create image view"); // obtain the sharing fd auto vkGetMemoryFdKHR = reinterpret_cast(vkGetDeviceProcAddr(device, "vkGetMemoryFdKHR")); const VkMemoryGetFdInfoKHR fdInfo{ .sType = VK_STRUCTURE_TYPE_MEMORY_GET_FD_INFO_KHR, .memory = memoryHandle, .handleType = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT_KHR, }; res = vkGetMemoryFdKHR(device, &fdInfo, fd); if (res != VK_SUCCESS || *fd < 0) throw LSFG::vulkan_error(res, "Failed to obtain sharing fd for Vulkan image"); // store objects in shared ptr this->layout = std::make_shared(VK_IMAGE_LAYOUT_UNDEFINED); this->image = std::shared_ptr( new VkImage(imageHandle), [dev = device](VkImage* img) { vkDestroyImage(dev, *img, nullptr); } ); this->memory = std::shared_ptr( new VkDeviceMemory(memoryHandle), [dev = device](VkDeviceMemory* mem) { vkFreeMemory(dev, *mem, nullptr); } ); this->view = std::shared_ptr( new VkImageView(viewHandle), [dev = device](VkImageView* imgView) { vkDestroyImageView(dev, *imgView, nullptr); } ); }