Files
Seele/src/Engine/Graphics/Vulkan/Command.cpp
T

595 lines
23 KiB
C++
Raw Normal View History

2023-11-15 17:42:57 +01:00
#include "Command.h"
2024-06-09 12:20:04 +02:00
#include "Descriptor.h"
2023-10-26 18:37:29 +02:00
#include "Enums.h"
#include "Framebuffer.h"
2024-06-09 12:20:04 +02:00
#include "Graphics.h"
2023-10-26 18:37:29 +02:00
#include "Pipeline.h"
2024-07-10 21:07:10 +02:00
#include "RayTracing.h"
2024-06-09 12:20:04 +02:00
#include "RenderPass.h"
2023-11-16 22:58:47 +01:00
#include "Window.h"
2020-03-24 21:05:32 +01:00
using namespace Seele;
using namespace Seele::Vulkan;
2024-06-15 21:47:20 +02:00
Command::Command(PGraphics graphics, PCommandPool pool) : graphics(graphics), pool(pool), statisticsFlags(0) {
2023-11-15 00:06:00 +01:00
VkCommandBufferAllocateInfo allocInfo = {
.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO,
.pNext = nullptr,
2024-04-10 08:43:56 +02:00
.commandPool = pool->getHandle(),
2023-11-15 00:06:00 +01:00
.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY,
.commandBufferCount = 1,
};
2020-03-24 21:05:32 +01:00
VK_CHECK(vkAllocateCommandBuffers(graphics->getDevice(), &allocInfo, &handle))
2020-04-12 15:47:19 +02:00
fence = new Fence(graphics);
signalSemaphore = new Semaphore(graphics);
2023-11-15 00:06:00 +01:00
state = State::Init;
2024-06-09 12:20:04 +02:00
// std::cout << "Cmd " << handle << " semaphore " << signalSemaphore->getHandle() << std::endl;
2020-03-24 21:05:32 +01:00
}
2024-06-09 12:20:04 +02:00
Command::~Command() {
2024-04-10 08:43:56 +02:00
vkFreeCommandBuffers(graphics->getDevice(), pool->getHandle(), 1, &handle);
2020-04-12 15:47:19 +02:00
waitSemaphores.clear();
2020-03-24 21:05:32 +01:00
}
2024-06-09 12:20:04 +02:00
void Command::begin() {
2023-11-15 00:06:00 +01:00
VkCommandBufferBeginInfo beginInfo = {
.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO,
.pNext = nullptr,
.flags = 0,
.pInheritanceInfo = nullptr,
};
2020-03-24 21:05:32 +01:00
VK_CHECK(vkBeginCommandBuffer(handle, &beginInfo));
2023-11-15 00:06:00 +01:00
state = State::Begin;
2020-03-24 21:05:32 +01:00
}
2024-06-09 12:20:04 +02:00
void Command::end() {
2020-03-24 21:05:32 +01:00
VK_CHECK(vkEndCommandBuffer(handle));
2025-03-07 21:48:27 +01:00
signalSemaphore->rotateSemaphore();
2023-11-15 00:06:00 +01:00
state = State::End;
2020-03-24 21:05:32 +01:00
}
2024-06-09 12:20:04 +02:00
void Command::beginRenderPass(PRenderPass renderPass, PFramebuffer framebuffer) {
2023-11-15 00:06:00 +01:00
assert(state == State::Begin);
2023-11-16 22:58:47 +01:00
boundRenderPass = renderPass;
boundFramebuffer = framebuffer;
2023-11-15 00:06:00 +01:00
VkRenderPassBeginInfo beginInfo = {
.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO,
.pNext = nullptr,
.renderPass = renderPass->getHandle(),
.framebuffer = framebuffer->getHandle(),
2025-04-11 21:02:52 +02:00
.renderArea = framebuffer->getRenderArea(),
2023-11-15 00:06:00 +01:00
.clearValueCount = (uint32)renderPass->getClearValueCount(),
.pClearValues = renderPass->getClearValues(),
};
2020-03-24 21:05:32 +01:00
vkCmdBeginRenderPass(handle, &beginInfo, renderPass->getSubpassContents());
2023-11-15 00:06:00 +01:00
state = State::RenderPass;
2020-03-24 21:05:32 +01:00
}
2024-06-09 12:20:04 +02:00
void Command::endRenderPass() {
boundRenderPass->endRenderPass();
2023-11-16 22:58:47 +01:00
boundRenderPass = nullptr;
boundFramebuffer = nullptr;
2020-03-24 21:05:32 +01:00
vkCmdEndRenderPass(handle);
2023-11-15 00:06:00 +01:00
state = State::Begin;
2020-04-12 15:47:19 +02:00
}
2024-06-09 12:20:04 +02:00
void Command::executeCommands(Array<Gfx::ORenderCommand> commands) {
if (commands.size() == 0) {
// std::cout << "No commands provided" << std::endl;
2021-12-02 13:00:03 +01:00
return;
}
2020-04-12 15:47:19 +02:00
Array<VkCommandBuffer> cmdBuffers(commands.size());
2024-06-09 12:20:04 +02:00
for (uint32 i = 0; i < commands.size(); ++i) {
2024-04-10 10:23:06 +02:00
auto command = Gfx::PRenderCommand(commands[i]).cast<RenderCommand>();
command->end();
2024-06-09 12:20:04 +02:00
for (auto& descriptor : command->boundResources) {
2024-05-15 15:27:13 +02:00
boundResources.add(descriptor);
2024-06-09 12:20:04 +02:00
// std::cout << "Cmd " << handle << " bound descriptor " << descriptor->getHandle() << std::endl;
}
2021-05-10 23:57:55 +02:00
cmdBuffers[i] = command->getHandle();
2024-04-12 09:27:30 +02:00
executingRenders.add(std::move(commands[i]));
2021-05-10 23:57:55 +02:00
}
vkCmdExecuteCommands(handle, (uint32)cmdBuffers.size(), cmdBuffers.data());
}
2024-06-09 12:20:04 +02:00
void Command::executeCommands(Array<Gfx::OComputeCommand> commands) {
if (commands.size() == 0) {
2021-12-02 13:00:03 +01:00
return;
}
2021-05-10 23:57:55 +02:00
Array<VkCommandBuffer> cmdBuffers(commands.size());
2024-06-09 12:20:04 +02:00
for (uint32 i = 0; i < commands.size(); ++i) {
2024-04-10 10:23:06 +02:00
auto command = Gfx::PComputeCommand(commands[i]).cast<ComputeCommand>();
2021-05-10 23:57:55 +02:00
command->end();
2024-06-09 12:20:04 +02:00
for (auto& descriptor : command->boundResources) {
2024-05-15 15:27:13 +02:00
boundResources.add(descriptor);
2024-06-09 12:20:04 +02:00
// std::cout << "Cmd " << handle << " bound descriptor " << descriptor->getHandle() << std::endl;
}
cmdBuffers[i] = command->getHandle();
2024-04-12 09:27:30 +02:00
executingComputes.add(std::move(commands[i]));
2020-04-12 15:47:19 +02:00
}
2021-03-31 12:18:16 +02:00
vkCmdExecuteCommands(handle, (uint32)cmdBuffers.size(), cmdBuffers.data());
2020-04-12 15:47:19 +02:00
}
2024-06-09 12:20:04 +02:00
void Command::waitForSemaphore(VkPipelineStageFlags flags, PSemaphore semaphore) {
2025-03-07 21:48:27 +01:00
bindResource(semaphore->getCurrentSemaphore());
2020-04-12 15:47:19 +02:00
waitSemaphores.add(semaphore);
waitFlags.add(flags);
}
2024-06-09 12:20:04 +02:00
void Command::checkFence() {
2023-11-15 00:06:00 +01:00
assert(state == State::Submit || !fence->isSignaled());
2024-06-09 12:20:04 +02:00
if (fence->isSignaled()) {
2023-11-15 00:06:00 +01:00
vkResetCommandBuffer(handle, VK_COMMAND_BUFFER_RESET_RELEASE_RESOURCES_BIT);
fence->reset();
2024-06-09 12:20:04 +02:00
for (auto& command : executingComputes) {
2023-11-15 00:06:00 +01:00
command->reset();
2020-04-12 15:47:19 +02:00
}
2024-06-07 14:56:42 +02:00
pool->cacheCommands(std::move(executingComputes));
2024-06-09 12:20:04 +02:00
for (auto& command : executingRenders) {
2023-11-15 00:06:00 +01:00
command->reset();
}
2024-06-07 14:56:42 +02:00
pool->cacheCommands(std::move(executingRenders));
2024-06-09 12:20:04 +02:00
for (auto& descriptor : boundResources) {
2023-11-15 00:06:00 +01:00
descriptor->unbind();
}
2025-03-07 21:48:27 +01:00
signalSemaphore->resolveSignal();
2024-05-15 15:27:13 +02:00
boundResources.clear();
graphics->getDestructionManager()->notifyCommandComplete();
2023-11-15 00:06:00 +01:00
state = State::Init;
2020-04-12 15:47:19 +02:00
}
2020-03-24 21:05:32 +01:00
}
2024-06-09 12:20:04 +02:00
void Command::waitForCommand(uint32 timeout) {
if (state == State::Begin) {
2023-02-13 14:56:13 +01:00
// is already done
return;
}
2021-05-10 23:57:55 +02:00
fence->wait(timeout);
2023-11-15 00:06:00 +01:00
checkFence();
2021-05-10 23:57:55 +02:00
}
2024-06-20 21:57:26 +02:00
void Command::setPipelineStatisticsFlags(VkQueryPipelineStatisticFlags flags) { statisticsFlags = flags; }
2024-06-15 21:47:20 +02:00
2024-06-09 12:20:04 +02:00
void Command::bindResource(PCommandBoundResource resource) {
2024-05-15 15:27:13 +02:00
resource->bind();
boundResources.add(resource);
}
2024-06-09 12:20:04 +02:00
PFence Command::getFence() { return fence; }
2020-05-05 01:51:13 +02:00
2024-06-09 12:20:04 +02:00
PCommandPool Command::getPool() { return pool; }
2020-09-19 14:36:50 +02:00
2024-06-09 12:20:04 +02:00
RenderCommand::RenderCommand(PGraphics graphics, VkCommandPool cmdPool) : graphics(graphics), owner(cmdPool) {
2023-11-15 00:06:00 +01:00
VkCommandBufferAllocateInfo allocInfo = {
.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO,
.pNext = nullptr,
.commandPool = owner,
.level = VK_COMMAND_BUFFER_LEVEL_SECONDARY,
.commandBufferCount = 1,
};
2020-03-24 21:05:32 +01:00
VK_CHECK(vkAllocateCommandBuffers(graphics->getDevice(), &allocInfo, &handle));
}
2024-06-09 12:20:04 +02:00
RenderCommand::~RenderCommand() { vkFreeCommandBuffers(graphics->getDevice(), owner, 1, &handle); }
2021-05-10 23:57:55 +02:00
2024-06-15 21:47:20 +02:00
void RenderCommand::begin(PRenderPass renderPass, PFramebuffer framebuffer, VkQueryPipelineStatisticFlags pipelineFlags) {
threadId = std::this_thread::get_id();
2024-12-25 14:59:08 +01:00
pipeline = nullptr;
rtPipeline = nullptr;
2021-05-10 23:57:55 +02:00
ready = false;
2023-11-15 17:42:57 +01:00
VkCommandBufferInheritanceInfo inheritanceInfo = {
.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_INFO,
.subpass = 0,
2024-06-15 21:47:20 +02:00
.occlusionQueryEnable = 0,
.queryFlags = 0,
.pipelineStatistics = pipelineFlags,
2023-11-15 17:42:57 +01:00
};
VkCommandBufferBeginInfo beginInfo = {
.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO,
.pNext = nullptr,
.pInheritanceInfo = &inheritanceInfo,
};
2024-07-10 21:07:10 +02:00
if (renderPass != nullptr || framebuffer != nullptr) {
inheritanceInfo.renderPass = renderPass->getHandle();
inheritanceInfo.framebuffer = framebuffer->getHandle();
beginInfo.flags = VK_COMMAND_BUFFER_USAGE_RENDER_PASS_CONTINUE_BIT;
}
2021-05-10 23:57:55 +02:00
VK_CHECK(vkBeginCommandBuffer(handle, &beginInfo));
2024-08-17 15:11:57 +02:00
VkDebugUtilsObjectNameInfoEXT nameInfo = {
.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_OBJECT_NAME_INFO_EXT,
.pNext = nullptr,
.objectType = VK_OBJECT_TYPE_COMMAND_BUFFER,
.objectHandle = (uint64)handle,
.pObjectName = name.c_str(),
};
vkSetDebugUtilsObjectNameEXT(graphics->getDevice(), &nameInfo);
2021-05-10 23:57:55 +02:00
}
2024-06-09 12:20:04 +02:00
void RenderCommand::end() { VK_CHECK(vkEndCommandBuffer(handle)); }
2024-06-09 12:20:04 +02:00
void RenderCommand::reset() {
vkResetCommandBuffer(handle, VK_COMMAND_BUFFER_RESET_RELEASE_RESOURCES_BIT);
2024-05-15 15:27:13 +02:00
boundResources.clear();
ready = true;
}
2021-05-10 23:57:55 +02:00
2024-06-09 12:20:04 +02:00
bool RenderCommand::isReady() { return ready; }
2024-06-09 12:20:04 +02:00
void RenderCommand::setViewport(Gfx::PViewport viewport) {
assert(threadId == std::this_thread::get_id());
2020-10-03 11:00:10 +02:00
VkViewport vp = viewport.cast<Viewport>()->getHandle();
2023-11-15 17:42:57 +01:00
VkRect2D scissors = {
2024-06-09 12:20:04 +02:00
.offset =
{
.x = (int32)viewport->getOffsetX(),
.y = (int32)viewport->getOffsetY(),
},
.extent =
{
.width = viewport->getWidth(),
.height = viewport->getHeight(),
},
2023-11-15 17:42:57 +01:00
};
2020-10-03 11:00:10 +02:00
vkCmdSetViewport(handle, 0, 1, &vp);
vkCmdSetScissor(handle, 0, 1, &scissors);
}
2024-06-09 12:20:04 +02:00
void RenderCommand::bindPipeline(Gfx::PGraphicsPipeline gfxPipeline) {
assert(threadId == std::this_thread::get_id());
2020-05-05 01:51:13 +02:00
pipeline = gfxPipeline.cast<GraphicsPipeline>();
pipeline->bind(handle);
}
2024-06-18 09:48:00 +02:00
2024-07-10 21:07:10 +02:00
void RenderCommand::bindPipeline(Gfx::PRayTracingPipeline gfxPipeline) {
assert(threadId == std::this_thread::get_id());
rtPipeline = gfxPipeline.cast<RayTracingPipeline>();
rtPipeline->bind(handle);
2024-07-16 15:32:51 +02:00
boundResources.add(PBufferAllocation(rtPipeline->rayGen));
boundResources.add(PBufferAllocation(rtPipeline->hit));
boundResources.add(PBufferAllocation(rtPipeline->miss));
2024-07-10 21:07:10 +02:00
}
2024-09-27 15:57:37 +02:00
void RenderCommand::bindDescriptor(Gfx::PDescriptorSet descriptor) {
assert(threadId == std::this_thread::get_id());
2024-09-27 15:57:37 +02:00
auto descriptorSet = descriptor.cast<DescriptorSet>();
assert(descriptorSet->writeDescriptors.size() == 0);
descriptorSet->bind();
boundResources.add(descriptorSet);
for (auto& binding : descriptorSet->boundResources) {
for (auto& res : binding) {
// partially bound descriptors can include nulls
if (res != nullptr) {
res->bind();
boundResources.add(res);
}
}
}
2021-09-23 10:10:39 +02:00
2024-09-27 15:57:37 +02:00
VkDescriptorSet setHandle = descriptorSet->getHandle();
2024-07-10 21:07:10 +02:00
Gfx::PPipelineLayout layout = pipeline != nullptr ? pipeline->getPipelineLayout() : rtPipeline->getPipelineLayout();
2024-07-12 13:33:52 +02:00
vkCmdBindDescriptorSets(handle, pipeline != nullptr ? VK_PIPELINE_BIND_POINT_GRAPHICS : VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR,
2025-04-13 14:41:42 +02:00
pipeline->getLayout(), layout->findParameter(descriptorSet->getName()), 1, &setHandle, 0, nullptr);
2020-05-05 01:51:13 +02:00
}
2024-05-15 15:27:13 +02:00
2024-09-26 17:09:53 +02:00
void RenderCommand::bindDescriptor(const Array<Gfx::PDescriptorSet>& descriptorSets) {
assert(threadId == std::this_thread::get_id());
2020-10-03 11:00:10 +02:00
VkDescriptorSet* sets = new VkDescriptorSet[descriptorSets.size()];
2024-06-11 14:15:29 +02:00
std::memset(sets, 0, sizeof(VkDescriptorSet) * descriptorSets.size());
2024-07-10 21:07:10 +02:00
Gfx::PPipelineLayout layout = pipeline != nullptr ? pipeline->getPipelineLayout() : rtPipeline->getPipelineLayout();
2024-06-09 12:20:04 +02:00
for (uint32 i = 0; i < descriptorSets.size(); ++i) {
2020-10-03 11:00:10 +02:00
auto descriptorSet = descriptorSets[i].cast<DescriptorSet>();
2022-04-15 23:45:44 +02:00
assert(descriptorSet->writeDescriptors.size() == 0);
descriptorSet->bind();
2024-07-18 11:45:56 +02:00
boundResources.add(descriptorSet);
2024-09-27 15:57:37 +02:00
for (auto& binding : descriptorSet->boundResources) {
for (auto& res : binding) {
2025-04-13 14:41:42 +02:00
// partially bound descriptors can include nulls
2024-09-27 15:57:37 +02:00
if (res != nullptr) {
2025-04-13 14:41:42 +02:00
res->bind();
2024-09-27 15:57:37 +02:00
boundResources.add(res);
}
2024-06-20 21:57:26 +02:00
}
}
2024-07-10 21:07:10 +02:00
sets[layout->findParameter(descriptorSet->getName())] = descriptorSet->getHandle();
2020-10-03 11:00:10 +02:00
}
2024-07-12 13:33:52 +02:00
vkCmdBindDescriptorSets(handle, pipeline != nullptr ? VK_PIPELINE_BIND_POINT_GRAPHICS : VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR,
pipeline != nullptr ? pipeline->getLayout() : rtPipeline->getLayout(), 0, (uint32)descriptorSets.size(), sets,
2024-09-26 17:09:53 +02:00
0, nullptr);
2020-10-03 11:00:10 +02:00
delete[] sets;
}
2024-06-18 09:48:00 +02:00
2024-06-09 12:20:04 +02:00
void RenderCommand::bindVertexBuffer(const Array<Gfx::PVertexBuffer>& streams) {
assert(threadId == std::this_thread::get_id());
2020-06-08 01:44:47 +02:00
Array<VkBuffer> buffers(streams.size());
Array<VkDeviceSize> offsets(streams.size());
2024-06-09 12:20:04 +02:00
for (uint32 i = 0; i < streams.size(); ++i) {
2023-11-01 23:12:30 +01:00
PVertexBuffer buf = streams[i].cast<VertexBuffer>();
2020-06-08 01:44:47 +02:00
buffers[i] = buf->getHandle();
2023-11-01 23:12:30 +01:00
offsets[i] = 0;
2024-05-15 15:27:13 +02:00
buf->getAlloc()->bind();
boundResources.add(buf->getAlloc());
2020-06-08 01:44:47 +02:00
};
2021-03-31 12:18:16 +02:00
vkCmdBindVertexBuffers(handle, 0, (uint32)streams.size(), buffers.data(), offsets.data());
2020-05-05 01:51:13 +02:00
}
2024-06-18 09:48:00 +02:00
2024-06-09 12:20:04 +02:00
void RenderCommand::bindIndexBuffer(Gfx::PIndexBuffer indexBuffer) {
assert(threadId == std::this_thread::get_id());
2020-05-05 01:51:13 +02:00
PIndexBuffer buf = indexBuffer.cast<IndexBuffer>();
2024-05-15 15:27:13 +02:00
buf->getAlloc()->bind();
boundResources.add(buf->getAlloc());
2020-10-23 01:47:56 +02:00
vkCmdBindIndexBuffer(handle, buf->getHandle(), 0, cast(buf->getIndexType()));
2020-05-05 01:51:13 +02:00
}
2022-04-15 11:19:30 +02:00
2024-06-09 12:20:04 +02:00
void RenderCommand::pushConstants(Gfx::SeShaderStageFlags stage, uint32 offset, uint32 size, const void* data) {
2022-04-15 11:19:30 +02:00
assert(threadId == std::this_thread::get_id());
2024-12-25 14:59:08 +01:00
vkCmdPushConstants(handle, pipeline == nullptr ? rtPipeline->getLayout() : pipeline->getLayout(), stage, offset, size, data);
2022-04-15 11:19:30 +02:00
}
2024-06-09 12:20:04 +02:00
void RenderCommand::draw(uint32 vertexCount, uint32 instanceCount, int32 firstVertex, uint32 firstInstance) {
assert(threadId == std::this_thread::get_id());
2021-09-23 10:10:39 +02:00
vkCmdDraw(handle, vertexCount, instanceCount, firstVertex, firstInstance);
}
2024-10-07 20:14:00 +02:00
void RenderCommand::drawIndirect(Gfx::PShaderBuffer buffer, uint64 offset, uint32 drawCount, uint32 stride) {
assert(threadId == std::this_thread::get_id());
vkCmdDrawIndirect(handle, buffer.cast<ShaderBuffer>()->getHandle(), offset, drawCount, stride);
}
2024-06-09 12:20:04 +02:00
void RenderCommand::drawIndexed(uint32 indexCount, uint32 instanceCount, int32 firstIndex, uint32 vertexOffset, uint32 firstInstance) {
assert(threadId == std::this_thread::get_id());
2023-11-11 13:56:12 +01:00
vkCmdDrawIndexed(handle, indexCount, instanceCount, firstIndex, vertexOffset, firstInstance);
}
2024-06-09 12:20:04 +02:00
void RenderCommand::drawMesh(uint32 groupX, uint32 groupY, uint32 groupZ) {
2023-10-24 15:01:09 +02:00
assert(threadId == std::this_thread::get_id());
if (groupX * groupY * groupZ == 0) // any dimension is 0
return;
2024-06-13 15:43:03 +02:00
vkCmdDrawMeshTasksEXT(handle, groupX, groupY, groupZ);
2023-10-24 15:01:09 +02:00
}
2024-06-09 12:20:04 +02:00
void RenderCommand::drawMeshIndirect(Gfx::PShaderBuffer buffer, uint64 offset, uint32 drawCount, uint32 stride) {
2024-05-09 08:41:46 +02:00
assert(threadId == std::this_thread::get_id());
2024-06-13 15:43:03 +02:00
vkCmdDrawMeshTasksIndirectEXT(handle, buffer.cast<ShaderBuffer>()->getHandle(), offset, drawCount, stride);
2024-05-09 08:41:46 +02:00
}
2024-07-10 21:07:10 +02:00
void RenderCommand::traceRays(uint32 width, uint32 height, uint32 depth) {
VkStridedDeviceAddressRegionKHR rayGenRef = rtPipeline->getRayGenRegion();
VkStridedDeviceAddressRegionKHR hitRef = rtPipeline->getHitRegion();
VkStridedDeviceAddressRegionKHR missRef = rtPipeline->getMissRegion();
2024-07-12 13:33:52 +02:00
VkStridedDeviceAddressRegionKHR callableRef = rtPipeline->getCallableRegion();
vkCmdTraceRaysKHR(handle, &rayGenRef, &missRef, &hitRef, &callableRef, width, height, depth);
2024-07-10 21:07:10 +02:00
}
2024-06-18 09:48:00 +02:00
2024-06-09 12:20:04 +02:00
ComputeCommand::ComputeCommand(PGraphics graphics, VkCommandPool cmdPool) : graphics(graphics), owner(cmdPool) {
2023-11-15 17:42:57 +01:00
VkCommandBufferAllocateInfo allocInfo = {
.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO,
.pNext = nullptr,
.commandPool = owner,
.level = VK_COMMAND_BUFFER_LEVEL_SECONDARY,
.commandBufferCount = 1,
};
VK_CHECK(vkAllocateCommandBuffers(graphics->getDevice(), &allocInfo, &handle));
2021-05-10 23:57:55 +02:00
}
2024-06-09 12:20:04 +02:00
ComputeCommand::~ComputeCommand() { vkFreeCommandBuffers(graphics->getDevice(), owner, 1, &handle); }
2024-06-15 21:47:20 +02:00
void ComputeCommand::begin(VkQueryPipelineStatisticFlags pipelineFlags) {
threadId = std::this_thread::get_id();
2021-05-10 23:57:55 +02:00
ready = false;
2023-11-15 17:42:57 +01:00
VkCommandBufferInheritanceInfo inheritanceInfo = {
.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_INFO,
.renderPass = VK_NULL_HANDLE,
.subpass = 0,
.framebuffer = VK_NULL_HANDLE,
.occlusionQueryEnable = 0,
.queryFlags = 0,
2024-06-15 21:47:20 +02:00
.pipelineStatistics = pipelineFlags,
2023-11-15 17:42:57 +01:00
};
VkCommandBufferBeginInfo beginInfo = {
.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO,
.pNext = nullptr,
.flags = 0,
.pInheritanceInfo = &inheritanceInfo,
};
2021-05-10 23:57:55 +02:00
VK_CHECK(vkBeginCommandBuffer(handle, &beginInfo));
2024-08-17 15:11:57 +02:00
VkDebugUtilsObjectNameInfoEXT nameInfo = {
.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_OBJECT_NAME_INFO_EXT,
.pNext = nullptr,
.objectType = VK_OBJECT_TYPE_COMMAND_BUFFER,
.objectHandle = (uint64)handle,
.pObjectName = name.c_str(),
};
vkSetDebugUtilsObjectNameEXT(graphics->getDevice(), &nameInfo);
2021-05-10 23:57:55 +02:00
}
2024-06-09 12:20:04 +02:00
void ComputeCommand::end() {
assert(threadId == std::this_thread::get_id());
VK_CHECK(vkEndCommandBuffer(handle));
}
2024-06-09 12:20:04 +02:00
void ComputeCommand::reset() {
assert(threadId == std::this_thread::get_id());
vkResetCommandBuffer(handle, VK_COMMAND_BUFFER_RESET_RELEASE_RESOURCES_BIT);
2024-05-15 15:27:13 +02:00
boundResources.clear();
ready = true;
}
2024-06-09 12:20:04 +02:00
bool ComputeCommand::isReady() { return ready; }
2021-05-10 23:57:55 +02:00
2024-06-09 12:20:04 +02:00
void ComputeCommand::bindPipeline(Gfx::PComputePipeline computePipeline) {
assert(threadId == std::this_thread::get_id());
2021-05-10 23:57:55 +02:00
pipeline = computePipeline.cast<ComputePipeline>();
pipeline->bind(handle);
}
2024-09-27 15:57:37 +02:00
void ComputeCommand::bindDescriptor(Gfx::PDescriptorSet descriptor) {
assert(threadId == std::this_thread::get_id());
2024-09-27 15:57:37 +02:00
auto descriptorSet = descriptor.cast<DescriptorSet>();
assert(descriptorSet->writeDescriptors.size() == 0);
descriptorSet->bind();
boundResources.add(descriptorSet.getHandle());
2024-09-27 15:57:37 +02:00
for (auto& binding : descriptorSet->boundResources) {
for (auto& res : binding) {
// partially bound descriptors can include nulls
if (res != nullptr) {
res->bind();
boundResources.add(res);
}
}
}
2024-06-09 12:20:04 +02:00
2024-09-27 15:57:37 +02:00
VkDescriptorSet setHandle = descriptorSet->getHandle();
2024-06-09 12:20:04 +02:00
vkCmdBindDescriptorSets(handle, VK_PIPELINE_BIND_POINT_COMPUTE, pipeline->getLayout(),
2025-04-13 14:41:42 +02:00
pipeline->getPipelineLayout()->findParameter(descriptorSet->getName()), 1, &setHandle, 0, nullptr);
2021-05-10 23:57:55 +02:00
}
2024-09-26 17:09:53 +02:00
void ComputeCommand::bindDescriptor(const Array<Gfx::PDescriptorSet>& descriptorSets) {
assert(threadId == std::this_thread::get_id());
2021-05-10 23:57:55 +02:00
VkDescriptorSet* sets = new VkDescriptorSet[descriptorSets.size()];
2024-06-09 12:20:04 +02:00
for (uint32 i = 0; i < descriptorSets.size(); ++i) {
2021-05-10 23:57:55 +02:00
auto descriptorSet = descriptorSets[i].cast<DescriptorSet>();
2022-04-15 23:45:44 +02:00
assert(descriptorSet->writeDescriptors.size() == 0);
descriptorSet->bind();
boundResources.add(descriptorSet.getHandle());
2024-09-27 15:57:37 +02:00
for (auto& binding : descriptorSet->boundResources) {
for (auto& res : binding) {
// partially bound descriptors can include nulls
if (res != nullptr) {
res->bind();
boundResources.add(res);
}
}
}
2024-04-23 08:11:44 +02:00
sets[pipeline->getPipelineLayout()->findParameter(descriptorSet->getName())] = descriptorSet->getHandle();
2021-05-10 23:57:55 +02:00
}
2025-04-13 14:41:42 +02:00
vkCmdBindDescriptorSets(handle, VK_PIPELINE_BIND_POINT_COMPUTE, pipeline->getLayout(), 0, (uint32)descriptorSets.size(), sets, 0,
nullptr);
2021-05-10 23:57:55 +02:00
delete[] sets;
}
2024-06-09 12:20:04 +02:00
void ComputeCommand::pushConstants(Gfx::SeShaderStageFlags stage, uint32 offset, uint32 size, const void* data) {
2022-04-15 11:19:30 +02:00
assert(threadId == std::this_thread::get_id());
2024-05-12 19:36:32 +02:00
vkCmdPushConstants(handle, pipeline->getLayout(), stage, offset, size, data);
2022-04-15 11:19:30 +02:00
}
2024-06-09 12:20:04 +02:00
void ComputeCommand::dispatch(uint32 threadX, uint32 threadY, uint32 threadZ) {
assert(threadId == std::this_thread::get_id());
2021-05-10 23:57:55 +02:00
vkCmdDispatch(handle, threadX, threadY, threadZ);
}
2024-10-07 20:14:00 +02:00
void ComputeCommand::dispatchIndirect(Gfx::PShaderBuffer buffer, uint32 offset) {
assert(threadId == std::this_thread::get_id());
vkCmdDispatchIndirect(handle, buffer.cast<ShaderBuffer>()->getHandle(), offset);
}
2021-05-10 23:57:55 +02:00
2024-06-09 12:20:04 +02:00
CommandPool::CommandPool(PGraphics graphics, PQueue queue) : graphics(graphics), queue(queue), queueFamilyIndex(queue->getFamilyIndex()) {
2023-11-15 17:42:57 +01:00
VkCommandPoolCreateInfo info = {
.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO,
.pNext = nullptr,
.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT,
.queueFamilyIndex = queue->getFamilyIndex(),
};
2020-03-24 21:05:32 +01:00
VK_CHECK(vkCreateCommandPool(graphics->getDevice(), &info, nullptr, &commandPool));
2024-01-26 23:19:18 +01:00
// TODO: dont reset individual commands, reset pool instead
2024-04-10 08:43:56 +02:00
allocatedBuffers.add(new Command(graphics, this));
2024-06-09 12:20:04 +02:00
2023-11-15 00:06:00 +01:00
command = allocatedBuffers.back();
command->begin();
2020-03-24 21:05:32 +01:00
}
2024-06-09 12:20:04 +02:00
CommandPool::~CommandPool() {
2024-08-07 21:19:33 +02:00
submitCommands();
2023-11-26 12:47:48 +01:00
vkDeviceWaitIdle(graphics->getDevice());
2024-06-09 12:20:04 +02:00
for (auto& cmd : allocatedBuffers) {
2024-04-23 08:11:44 +02:00
cmd->checkFence();
2023-12-02 10:55:00 +01:00
}
2023-11-17 22:31:26 +01:00
allocatedRenderCommands.clear();
allocatedComputeCommands.clear();
allocatedBuffers.clear();
2020-03-24 21:05:32 +01:00
vkDestroyCommandPool(graphics->getDevice(), commandPool, nullptr);
2020-04-12 15:47:19 +02:00
graphics = nullptr;
queue = nullptr;
2020-03-24 21:05:32 +01:00
}
2024-06-09 12:20:04 +02:00
PCommand CommandPool::getCommands() { return command; }
2024-06-15 21:47:20 +02:00
2024-06-09 12:20:04 +02:00
void CommandPool::cacheCommands(Array<ORenderCommand> commands) {
for (auto&& cmd : commands) {
allocatedRenderCommands.add(std::move(cmd));
}
2024-04-10 10:23:06 +02:00
}
2020-03-24 21:05:32 +01:00
2024-06-09 12:20:04 +02:00
void CommandPool::cacheCommands(Array<OComputeCommand> commands) {
for (auto&& cmd : commands) {
allocatedComputeCommands.add(std::move(cmd));
}
2024-04-10 10:23:06 +02:00
}
2024-06-09 12:20:04 +02:00
ORenderCommand CommandPool::createRenderCommand(const std::string& name) {
for (uint32 i = 0; i < allocatedRenderCommands.size(); ++i) {
if (allocatedRenderCommands[i]->isReady()) {
2024-04-10 10:23:06 +02:00
ORenderCommand cmdBuffer = std::move(allocatedRenderCommands[i]);
allocatedRenderCommands.removeAt(i, false);
2021-10-19 23:04:38 +02:00
cmdBuffer->name = name;
2024-06-15 21:47:20 +02:00
cmdBuffer->begin(command->boundRenderPass, command->boundFramebuffer, command->statisticsFlags);
2021-04-13 23:09:16 +02:00
return cmdBuffer;
}
}
2024-04-10 10:23:06 +02:00
ORenderCommand result = new RenderCommand(graphics, commandPool);
2021-05-10 23:57:55 +02:00
result->name = name;
2024-06-15 21:47:20 +02:00
result->begin(command->boundRenderPass, command->boundFramebuffer, command->statisticsFlags);
2021-05-10 23:57:55 +02:00
return result;
}
2024-06-09 12:20:04 +02:00
OComputeCommand CommandPool::createComputeCommand(const std::string& name) {
for (uint32 i = 0; i < allocatedComputeCommands.size(); ++i) {
if (allocatedComputeCommands[i]->isReady()) {
2024-04-10 10:23:06 +02:00
OComputeCommand cmdBuffer = std::move(allocatedComputeCommands[i]);
allocatedComputeCommands.removeAt(i, false);
2021-10-19 23:04:38 +02:00
cmdBuffer->name = name;
2024-06-15 21:47:20 +02:00
cmdBuffer->begin(command->statisticsFlags);
2021-05-10 23:57:55 +02:00
return cmdBuffer;
}
}
2024-04-10 10:23:06 +02:00
OComputeCommand result = new ComputeCommand(graphics, commandPool);
2021-05-10 23:57:55 +02:00
result->name = name;
2024-06-15 21:47:20 +02:00
result->begin(command->statisticsFlags);
2021-04-13 23:09:16 +02:00
return result;
2020-03-24 21:05:32 +01:00
}
2024-06-09 12:20:04 +02:00
void CommandPool::submitCommands(PSemaphore signalSemaphore) {
2023-11-15 17:42:57 +01:00
assert(command->state == Command::State::Begin); // Not in a renderpass
command->end();
2024-06-09 12:20:04 +02:00
Array<VkSemaphore> semaphores = {command->signalSemaphore->getHandle()};
2025-03-07 21:48:27 +01:00
command->signalSemaphore->encodeSignal();
2024-06-09 12:20:04 +02:00
if (signalSemaphore != nullptr) {
semaphores.add(signalSemaphore->getHandle());
2025-03-07 21:48:27 +01:00
signalSemaphore->encodeSignal();
2020-04-01 02:17:49 +02:00
}
queue->submitCommandBuffer(command, semaphores);
PSemaphore waitSemaphore = command->signalSemaphore;
2024-06-09 12:20:04 +02:00
for (uint32 i = 0; i < allocatedBuffers.size(); ++i) {
2023-11-15 17:42:57 +01:00
PCommand cmdBuffer = allocatedBuffers[i];
2023-11-15 00:06:00 +01:00
cmdBuffer->checkFence();
2024-06-09 12:20:04 +02:00
if (cmdBuffer->state == Command::State::Init) {
2023-11-15 00:06:00 +01:00
command = cmdBuffer;
command->begin();
command->waitForSemaphore(VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, waitSemaphore);
2020-04-01 02:17:49 +02:00
return;
2024-06-09 12:20:04 +02:00
} else {
2023-11-15 00:06:00 +01:00
assert(cmdBuffer->state == Command::State::Submit);
2020-04-01 02:17:49 +02:00
}
}
2024-04-10 08:43:56 +02:00
allocatedBuffers.add(new Command(graphics, this));
2023-11-15 00:06:00 +01:00
command = allocatedBuffers.back();
command->begin();
command->waitForSemaphore(VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, waitSemaphore);
2023-11-11 13:56:12 +01:00
}
2024-07-18 11:45:56 +02:00
void CommandPool::refreshCommands() {
2025-03-07 21:48:27 +01:00
for (uint32 i = 0; i < allocatedBuffers.size(); ++i) {
2024-07-18 11:45:56 +02:00
allocatedBuffers[i]->checkFence();
}
}