mirror of
https://github.com/PancakeTAS/lsfg-vk.git
synced 2025-12-02 14:12:20 +00:00
host image copyless host image copy
This commit is contained in:
parent
bdeae9b8d0
commit
10ac493312
5 changed files with 112 additions and 56 deletions
|
|
@ -33,6 +33,21 @@ namespace Vulkan::Core {
|
|||
construct(device, reinterpret_cast<const void*>(&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.
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@
|
|||
using namespace Vulkan;
|
||||
|
||||
const std::vector<const char*> 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{
|
||||
|
|
|
|||
32
src/main.cpp
32
src/main.cpp
|
|
@ -11,9 +11,28 @@
|
|||
|
||||
#include <iostream>
|
||||
|
||||
#include <renderdoc_app.h>
|
||||
#include <dlfcn.h>
|
||||
#include <unistd.h>
|
||||
#include <vulkan/vulkan_core.h>
|
||||
|
||||
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<pRENDERDOC_GetAPI>(dlsym(mod_renderdoc, "RENDERDOC_GetAPI"));
|
||||
const int ret = GetAPI(eRENDERDOC_API_Version_1_6_0, reinterpret_cast<void**>(&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';
|
||||
|
|
|
|||
|
|
@ -1,4 +1,6 @@
|
|||
#include "utils/upload.hpp"
|
||||
#include "core/buffer.hpp"
|
||||
#include "core/commandbuffer.hpp"
|
||||
#include "utils/exceptions.hpp"
|
||||
|
||||
#include <fstream>
|
||||
|
|
@ -6,34 +8,14 @@
|
|||
#include <vulkan/vulkan_core.h>
|
||||
|
||||
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<PFN_vkTransitionImageLayoutEXT>(
|
||||
vkGetDeviceProcAddr(device.handle(), "vkTransitionImageLayoutEXT"));
|
||||
auto vkCopyMemoryToImageEXT = reinterpret_cast<PFN_vkCopyMemoryToImageEXT>(
|
||||
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<char*>(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<uint32_t>(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");
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue