diff --git a/include/core/buffer.hpp b/include/core/buffer.hpp index e0a1bc9..ebe1889 100644 --- a/include/core/buffer.hpp +++ b/include/core/buffer.hpp @@ -33,6 +33,21 @@ namespace Vulkan::Core { construct(device, reinterpret_cast(&data), usage); } + /// + /// Create the buffer. + /// + /// @param device Vulkan device + /// @param data Initial data for the buffer + /// @param size Size of the buffer in bytes + /// @param usage Usage flags for the buffer + /// + /// @throws ls::vulkan_error if object creation fails. + /// + Buffer(const Device& device, const void* data, size_t size, VkBufferUsageFlags usage) + : size(size) { + construct(device, data, usage); + } + /// Get the Vulkan handle. [[nodiscard]] auto handle() const { return *this->buffer; } /// Get the size of the buffer. diff --git a/include/utils/upload.hpp b/include/utils/upload.hpp index c8a9af6..b00967e 100644 --- a/include/utils/upload.hpp +++ b/include/utils/upload.hpp @@ -1,6 +1,7 @@ #ifndef UPLOAD_HPP #define UPLOAD_HPP +#include "core/commandpool.hpp" #include "core/image.hpp" #include "device.hpp" @@ -8,8 +9,19 @@ namespace Upload { - void upload(const Vulkan::Device& device, - Vulkan::Core::Image& image, const std::string& path); + /// + /// Upload a DDS file to a Vulkan image. + /// + /// @param device The Vulkan device + /// @param commandPool The command pool + /// @param image The Vulkan image to upload to + /// @param path The path to the DDS file. + /// + /// @throws std::system_error If the file cannot be opened or read. + /// @throws ls:vulkan_error If the Vulkan image cannot be created or updated. + /// + void upload(const Vulkan::Device& device, const Vulkan::Core::CommandPool& commandPool, + Vulkan::Core::Image& image, const std::string& path); } diff --git a/src/device.cpp b/src/device.cpp index 0ca4622..97c0208 100644 --- a/src/device.cpp +++ b/src/device.cpp @@ -7,7 +7,7 @@ using namespace Vulkan; const std::vector requiredExtensions = { - "VK_EXT_host_image_copy" + "VK_KHR_external_memory_fd" }; Device::Device(const Instance& instance) { @@ -53,13 +53,8 @@ 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{ diff --git a/src/main.cpp b/src/main.cpp index cc66998..e2f6c83 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -11,9 +11,28 @@ #include +#include +#include +#include +#include + using namespace Vulkan; int main() { + // attempt to load renderdoc + RENDERDOC_API_1_6_0* rdoc = nullptr; + if (void* mod_renderdoc = dlopen("/usr/lib/librenderdoc.so", RTLD_NOLOAD | RTLD_NOW)) { + std::cerr << "Found RenderDoc library, setting up frame capture." << '\n'; + + auto GetAPI = reinterpret_cast(dlsym(mod_renderdoc, "RENDERDOC_GetAPI")); + const int ret = GetAPI(eRENDERDOC_API_Version_1_6_0, reinterpret_cast(&rdoc)); + if (ret == 0) { + std::cerr << "Unable to initialize RenderDoc API. Is your RenderDoc up to date?" << '\n'; + rdoc = nullptr; + } + usleep(1000 * 100); // give renderdoc time to load + } + // initialize application const Instance instance; const Device device(instance); @@ -26,16 +45,18 @@ int main() { // create initialization resources Core::Image inputImage( device, { 2560, 1411 }, VK_FORMAT_R8G8B8A8_UNORM, - VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_STORAGE_BIT - | VK_IMAGE_USAGE_HOST_TRANSFER_BIT, // (remove in prod) + VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_STORAGE_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT, VK_IMAGE_ASPECT_COLOR_BIT ); - Upload::upload(device, inputImage, "rsc/images/source.dds"); + Upload::upload(device, commandPool, inputImage, "rsc/images/source.dds"); // create the shaderchains Shaderchains::Downsample downsample(device, descriptorPool, inputImage); // start the rendering pipeline + if (rdoc) + rdoc->StartFrameCapture(nullptr, nullptr); + Core::CommandBuffer commandBuffer(device, commandPool); commandBuffer.begin(); @@ -52,6 +73,11 @@ int main() { return 1; } + if (rdoc) + rdoc->EndFrameCapture(nullptr, nullptr); + + usleep(1000 * 100); // give renderdoc time to capture + Globals::uninitializeGlobals(); std::cerr << "Application finished" << '\n'; diff --git a/src/utils/upload.cpp b/src/utils/upload.cpp index 2dae8dd..95b239a 100644 --- a/src/utils/upload.cpp +++ b/src/utils/upload.cpp @@ -1,4 +1,6 @@ #include "utils/upload.hpp" +#include "core/buffer.hpp" +#include "core/commandbuffer.hpp" #include "utils/exceptions.hpp" #include @@ -6,34 +8,14 @@ #include using namespace Upload; +using namespace Vulkan; -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 +void Upload::upload(const Device& device, const Core::CommandPool& commandPool, + Core::Image& image, const std::string& path) { + // read iamge 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); + throw std::system_error(errno, std::generic_category(), "Failed to open image: " + path); std::streamsize size = file.tellg(); size -= 124 - 4; @@ -41,34 +23,60 @@ void Upload::upload(const Vulkan::Device& device, 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); + throw std::system_error(errno, std::generic_category(), "Failed to read image: " + path); file.close(); - // copy data to image + // copy data to buffer + const Vulkan::Core::Buffer stagingBuffer( + device, code.data(), static_cast(code.size()), + VK_BUFFER_USAGE_TRANSFER_SRC_BIT + ); + + // perform the upload + Core::CommandBuffer commandBuffer(device, commandPool); + commandBuffer.begin(); + + const VkImageMemoryBarrier barrier{ + .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, + .srcAccessMask = VK_ACCESS_NONE, + .dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT, + .oldLayout = image.getLayout(), + .newLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, + .image = image.handle(), + .subresourceRange = { + .aspectMask = image.getAspectFlags(), + .levelCount = 1, + .layerCount = 1 + } + }; + image.setLayout(VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL); + vkCmdPipelineBarrier( + commandBuffer.handle(), + VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, + 0, 0, nullptr, 0, nullptr, 1, &barrier + ); + auto extent = image.getExtent(); - const VkMemoryToImageCopyEXT copyInfo{ - .sType = VK_STRUCTURE_TYPE_MEMORY_TO_IMAGE_COPY_EXT, - .pHostPointer = code.data(), + const VkBufferImageCopy region{ + .bufferImageHeight = 0, .imageSubresource = { .aspectMask = image.getAspectFlags(), .layerCount = 1 }, - .imageExtent = { - .width = extent.width, - .height = extent.height, - .depth = 1 - }, + .imageExtent = { extent.width, extent.height, 1 } }; + vkCmdCopyBufferToImage( + commandBuffer.handle(), + stagingBuffer.handle(), image.handle(), + VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, ®ion + ); - 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"); + commandBuffer.end(); + + Core::Fence fence(device); + commandBuffer.submit(device.getComputeQueue(), fence); + + if (!fence.wait(device)) + throw ls::vulkan_error(VK_TIMEOUT, "Upload operation timed out"); }