103 lines
3.1 KiB
C++
103 lines
3.1 KiB
C++
#include <cassert>
|
|
#include <limits>
|
|
#include <stdexcept>
|
|
#include <destrum/Graphics/ImmediateExecuter.h>
|
|
|
|
#include <volk.h>
|
|
|
|
#include <destrum/Graphics/Init.h>
|
|
#include <destrum/Graphics/Util.h>
|
|
|
|
|
|
namespace
|
|
{
|
|
constexpr auto NO_TIMEOUT = std::numeric_limits<std::uint64_t>::max();
|
|
}
|
|
|
|
void VulkanImmediateExecutor::init(
|
|
VkDevice deviceHandle,
|
|
std::uint32_t graphicsQueueFamily,
|
|
VkQueue graphicsQueueHandle)
|
|
{
|
|
if (initialized) {
|
|
throw std::logic_error("VulkanImmediateExecutor::init called twice");
|
|
}
|
|
|
|
this->device = deviceHandle;
|
|
this->graphicsQueue = graphicsQueueHandle;
|
|
|
|
try {
|
|
const auto poolCreateInfo = vkinit::
|
|
commandPoolCreateInfo(VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, graphicsQueueFamily);
|
|
VK_CHECK(vkCreateCommandPool(deviceHandle, &poolCreateInfo, nullptr, &immCommandPool));
|
|
|
|
const auto cmdAllocInfo = vkinit::commandBufferAllocateInfo(immCommandPool, 1);
|
|
VK_CHECK(vkAllocateCommandBuffers(deviceHandle, &cmdAllocInfo, &immCommandBuffer));
|
|
|
|
constexpr auto fenceCreateInfo = VkFenceCreateInfo{
|
|
.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO,
|
|
.flags = VK_FENCE_CREATE_SIGNALED_BIT,
|
|
};
|
|
VK_CHECK(vkCreateFence(deviceHandle, &fenceCreateInfo, nullptr, &immFence));
|
|
|
|
vkutil::addDebugLabel(deviceHandle, immCommandPool, "immediate command pool");
|
|
vkutil::addDebugLabel(deviceHandle, immCommandBuffer, "immediate command buffer");
|
|
vkutil::addDebugLabel(deviceHandle, immFence, "immediate fence");
|
|
|
|
initialized = true;
|
|
} catch (...) {
|
|
cleanup(deviceHandle);
|
|
throw;
|
|
}
|
|
}
|
|
|
|
void VulkanImmediateExecutor::cleanup(VkDevice deviceHandle)
|
|
{
|
|
if (deviceHandle == VK_NULL_HANDLE && device != VK_NULL_HANDLE) {
|
|
deviceHandle = device;
|
|
}
|
|
|
|
if (deviceHandle == VK_NULL_HANDLE) {
|
|
return;
|
|
}
|
|
|
|
if (immCommandPool != VK_NULL_HANDLE) {
|
|
vkDestroyCommandPool(deviceHandle, immCommandPool, nullptr);
|
|
}
|
|
if (immFence != VK_NULL_HANDLE) {
|
|
vkDestroyFence(deviceHandle, immFence, nullptr);
|
|
}
|
|
|
|
immCommandPool = VK_NULL_HANDLE;
|
|
immCommandBuffer = VK_NULL_HANDLE;
|
|
immFence = VK_NULL_HANDLE;
|
|
this->device = VK_NULL_HANDLE;
|
|
graphicsQueue = VK_NULL_HANDLE;
|
|
initialized = false;
|
|
}
|
|
|
|
void VulkanImmediateExecutor::immediateSubmit(
|
|
std::function<void(VkCommandBuffer cmd)>&& function) const
|
|
{
|
|
assert(initialized);
|
|
VK_CHECK(vkResetFences(device, 1, &immFence));
|
|
VK_CHECK(vkResetCommandBuffer(immCommandBuffer, 0));
|
|
|
|
auto cmd = immCommandBuffer;
|
|
const auto cmdBeginInfo = VkCommandBufferBeginInfo{
|
|
.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO,
|
|
.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT,
|
|
};
|
|
|
|
VK_CHECK(vkBeginCommandBuffer(cmd, &cmdBeginInfo));
|
|
function(cmd);
|
|
VK_CHECK(vkEndCommandBuffer(cmd));
|
|
|
|
const auto cmdinfo = vkinit::commandBufferSubmitInfo(cmd);
|
|
const auto submit = vkinit::submitInfo(&cmdinfo, nullptr, nullptr);
|
|
|
|
VK_CHECK(vkQueueSubmit2(graphicsQueue, 1, &submit, immFence));
|
|
|
|
VK_CHECK(vkWaitForFences(device, 1, &immFence, true, NO_TIMEOUT));
|
|
}
|