From bdeae9b8d0c4a9fc2c77bf5fcd8ab57fecf713f1 Mon Sep 17 00:00:00 2001 From: PancakeTAS Date: Mon, 30 Jun 2025 01:10:54 +0200 Subject: [PATCH] host image copy --- include/utils/upload.hpp | 16 +++++++++ src/device.cpp | 14 ++++++-- src/main.cpp | 7 ++-- src/utils/upload.cpp | 74 ++++++++++++++++++++++++++++++++++++++++ 4 files changed, 107 insertions(+), 4 deletions(-) create mode 100644 include/utils/upload.hpp create mode 100644 src/utils/upload.cpp diff --git a/include/utils/upload.hpp b/include/utils/upload.hpp new file mode 100644 index 0000000..c8a9af6 --- /dev/null +++ b/include/utils/upload.hpp @@ -0,0 +1,16 @@ +#ifndef UPLOAD_HPP +#define UPLOAD_HPP + +#include "core/image.hpp" +#include "device.hpp" + +#include + +namespace Upload { + + void upload(const Vulkan::Device& device, + Vulkan::Core::Image& image, const std::string& path); + +} + +#endif // UPLOAD_HPP diff --git a/src/device.cpp b/src/device.cpp index c84cb4c..0ca4622 100644 --- a/src/device.cpp +++ b/src/device.cpp @@ -3,10 +3,13 @@ #include #include -#include using namespace Vulkan; +const std::vector requiredExtensions = { + "VK_EXT_host_image_copy" +}; + Device::Device(const Instance& instance) { // get all physical devices uint32_t deviceCount{}; @@ -50,8 +53,13 @@ Device::Device(const Instance& instance) { // create logical device const float queuePriority{1.0F}; // highest priority + VkPhysicalDeviceHostImageCopyFeaturesEXT hostImageCopyFeatures{ + .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_HOST_IMAGE_COPY_FEATURES_EXT, + .hostImageCopy = VK_TRUE + }; VkPhysicalDeviceVulkan13Features features13{ .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_3_FEATURES, + .pNext = &hostImageCopyFeatures, .synchronization2 = VK_TRUE }; const VkPhysicalDeviceVulkan12Features features12{ @@ -70,7 +78,9 @@ Device::Device(const Instance& instance) { .sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO, .pNext = &features12, .queueCreateInfoCount = 1, - .pQueueCreateInfos = &computeQueueDesc + .pQueueCreateInfos = &computeQueueDesc, + .enabledExtensionCount = static_cast(requiredExtensions.size()), + .ppEnabledExtensionNames = requiredExtensions.data() }; VkDevice deviceHandle{}; res = vkCreateDevice(*physicalDevice, &deviceCreateInfo, nullptr, &deviceHandle); diff --git a/src/main.cpp b/src/main.cpp index cd78557..cc66998 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -7,6 +7,7 @@ #include "instance.hpp" #include "shaderchains/downsample.hpp" #include "utils/global.hpp" +#include "utils/upload.hpp" #include @@ -23,11 +24,13 @@ int main() { Globals::initializeGlobals(device); // create initialization resources - const Core::Image inputImage( + Core::Image inputImage( device, { 2560, 1411 }, VK_FORMAT_R8G8B8A8_UNORM, - VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_STORAGE_BIT, + VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_STORAGE_BIT + | VK_IMAGE_USAGE_HOST_TRANSFER_BIT, // (remove in prod) VK_IMAGE_ASPECT_COLOR_BIT ); + Upload::upload(device, inputImage, "rsc/images/source.dds"); // create the shaderchains Shaderchains::Downsample downsample(device, descriptorPool, inputImage); diff --git a/src/utils/upload.cpp b/src/utils/upload.cpp new file mode 100644 index 0000000..2dae8dd --- /dev/null +++ b/src/utils/upload.cpp @@ -0,0 +1,74 @@ +#include "utils/upload.hpp" +#include "utils/exceptions.hpp" + +#include +#include +#include + +using namespace Upload; + +void Upload::upload(const Vulkan::Device& device, + Vulkan::Core::Image& image, const std::string& path) { + auto vkTransitionImageLayoutEXT = reinterpret_cast( + vkGetDeviceProcAddr(device.handle(), "vkTransitionImageLayoutEXT")); + auto vkCopyMemoryToImageEXT = reinterpret_cast( + vkGetDeviceProcAddr(device.handle(), "vkCopyMemoryToImageEXT")); + + const VkHostImageLayoutTransitionInfoEXT transitionInfo{ + .sType = VK_STRUCTURE_TYPE_HOST_IMAGE_LAYOUT_TRANSITION_INFO_EXT, + .image = image.handle(), + .oldLayout = image.getLayout(), + .newLayout = VK_IMAGE_LAYOUT_GENERAL, + .subresourceRange = { + .aspectMask = image.getAspectFlags(), + .levelCount = 1, + .layerCount = 1 + } + }; + image.setLayout(VK_IMAGE_LAYOUT_GENERAL); + auto res = vkTransitionImageLayoutEXT(device.handle(), 1, &transitionInfo); + if (res != VK_SUCCESS) + throw ls::vulkan_error(res, "Failed to transition image layout for upload"); + + // read shader bytecode + std::ifstream file(path, std::ios::ate | std::ios::binary); + if (!file) + throw std::system_error(errno, std::generic_category(), "Failed to open shader file: " + path); + + std::streamsize size = file.tellg(); + size -= 124 - 4; + std::vector code(static_cast(size)); + + file.seekg(0, std::ios::beg); + if (!file.read(reinterpret_cast(code.data()), size)) + throw std::system_error(errno, std::generic_category(), "Failed to read shader file: " + path); + + file.close(); + + // copy data to image + auto extent = image.getExtent(); + const VkMemoryToImageCopyEXT copyInfo{ + .sType = VK_STRUCTURE_TYPE_MEMORY_TO_IMAGE_COPY_EXT, + .pHostPointer = code.data(), + .imageSubresource = { + .aspectMask = image.getAspectFlags(), + .layerCount = 1 + }, + .imageExtent = { + .width = extent.width, + .height = extent.height, + .depth = 1 + }, + }; + + const VkCopyMemoryToImageInfoEXT operationInfo{ + .sType = VK_STRUCTURE_TYPE_COPY_MEMORY_TO_IMAGE_INFO_EXT, + .dstImage = image.handle(), + .dstImageLayout = image.getLayout(), + .regionCount = 1, + .pRegions = ©Info, + }; + res = vkCopyMemoryToImageEXT(device.handle(), &operationInfo); + if (res != VK_SUCCESS) + throw ls::vulkan_error(res, "Failed to copy memory to image"); +}