vulkan: correctly order gpu commands

This commit is contained in:
niki
2022-09-10 19:21:31 +02:00
parent a93d153792
commit 816e3f01a2
4 changed files with 133 additions and 211 deletions
+1 -1
View File
@@ -114,7 +114,7 @@ void Buffer::unmap(size_t usedoffset, size_t usedsize)
void Buffer::copyTo(love::graphics::Buffer *dest, size_t sourceoffset, size_t destoffset, size_t size) void Buffer::copyTo(love::graphics::Buffer *dest, size_t sourceoffset, size_t destoffset, size_t size)
{ {
auto commandBuffer = vgfx->getReadbackCommandBuffer(); auto commandBuffer = vgfx->getCommandBufferForDataTransfer();
VkBufferCopy bufferCopy{}; VkBufferCopy bufferCopy{};
bufferCopy.srcOffset = sourceoffset; bufferCopy.srcOffset = sourceoffset;
+104 -179
View File
@@ -89,6 +89,9 @@ love::graphics::Buffer *Graphics::newBuffer(const love::graphics::Buffer::Settin
void Graphics::clear(OptionalColorD color, OptionalInt stencil, OptionalDouble depth) void Graphics::clear(OptionalColorD color, OptionalInt stencil, OptionalDouble depth)
{ {
if (!renderPassState.active)
startRenderPass();
VkClearAttachment attachment{}; VkClearAttachment attachment{};
if (color.hasValue) if (color.hasValue)
@@ -120,8 +123,8 @@ void Graphics::clear(OptionalColorD color, OptionalInt stencil, OptionalDouble d
VkClearRect rect{}; VkClearRect rect{};
rect.layerCount = 1; rect.layerCount = 1;
rect.rect.extent.width = static_cast<uint32_t>(currentViewportWidth); rect.rect.extent.width = static_cast<uint32_t>(renderPassState.width);
rect.rect.extent.height = static_cast<uint32_t>(currentViewportHeight); rect.rect.extent.height = static_cast<uint32_t>(renderPassState.height);
vkCmdClearAttachments( vkCmdClearAttachments(
commandBuffers[currentFrame], commandBuffers[currentFrame],
@@ -131,6 +134,9 @@ void Graphics::clear(OptionalColorD color, OptionalInt stencil, OptionalDouble d
void Graphics::clear(const std::vector<OptionalColorD> &colors, OptionalInt stencil, OptionalDouble depth) void Graphics::clear(const std::vector<OptionalColorD> &colors, OptionalInt stencil, OptionalDouble depth)
{ {
if (!renderPassState.active)
startRenderPass();
std::vector<VkClearAttachment> attachments; std::vector<VkClearAttachment> attachments;
for (const auto &color : colors) for (const auto &color : colors)
{ {
@@ -163,8 +169,8 @@ void Graphics::clear(const std::vector<OptionalColorD> &colors, OptionalInt sten
VkClearRect rect{}; VkClearRect rect{};
rect.layerCount = 1; rect.layerCount = 1;
rect.rect.extent.width = static_cast<uint32_t>(currentViewportWidth); rect.rect.extent.width = static_cast<uint32_t>(renderPassState.width);
rect.rect.extent.height = static_cast<uint32_t>(currentViewportHeight); rect.rect.extent.height = static_cast<uint32_t>(renderPassState.height);
vkCmdClearAttachments(commandBuffers[currentFrame], static_cast<uint32_t>(attachments.size()), attachments.data(), 1, &rect); vkCmdClearAttachments(commandBuffers[currentFrame], static_cast<uint32_t>(attachments.size()), attachments.data(), 1, &rect);
} }
@@ -179,11 +185,7 @@ void Graphics::submitGpuCommands(bool present)
vkWaitForFences(device, 1, &imagesInFlight.at(imageIndex), VK_TRUE, UINT64_MAX); vkWaitForFences(device, 1, &imagesInFlight.at(imageIndex), VK_TRUE, UINT64_MAX);
imagesInFlight[imageIndex] = inFlightFences[currentFrame]; imagesInFlight[imageIndex] = inFlightFences[currentFrame];
std::vector<VkCommandBuffer> submitCommandbuffers = { std::array<VkCommandBuffer, 1> submitCommandbuffers = { commandBuffers.at(currentFrame) };
dataTransferCommandBuffers.at(currentFrame),
computeCommandBuffers.at(currentFrame),
commandBuffers.at(currentFrame),
readbackCommandBuffers.at(currentFrame)};
VkSubmitInfo submitInfo{}; VkSubmitInfo submitInfo{};
submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
@@ -339,8 +341,6 @@ bool Graphics::setMode(void *context, int width, int height, int pixelwidth, int
restoreState(states.back()); restoreState(states.back());
setViewportSize(width, height, pixelwidth, pixelheight); setViewportSize(width, height, pixelwidth, pixelheight);
currentViewportWidth = 1.0f;
currentViewportHeight = 1.0f;
Vulkan::resetShaderSwitches(); Vulkan::resetShaderSwitches();
@@ -715,11 +715,14 @@ graphics::StreamBuffer *Graphics::newStreamBuffer(BufferUsage type, size_t size)
bool Graphics::dispatch(int x, int y, int z) bool Graphics::dispatch(int x, int y, int z)
{ {
vkCmdBindPipeline(computeCommandBuffers.at(currentFrame), VK_PIPELINE_BIND_POINT_COMPUTE, computeShader->getComputePipeline()); if (renderPassState.active)
endRenderPass();
computeShader->cmdPushDescriptorSets(computeCommandBuffers.at(currentFrame), currentFrame, VK_PIPELINE_BIND_POINT_COMPUTE); vkCmdBindPipeline(commandBuffers.at(currentFrame), VK_PIPELINE_BIND_POINT_COMPUTE, computeShader->getComputePipeline());
vkCmdDispatch(computeCommandBuffers.at(currentFrame), static_cast<uint32_t>(x), static_cast<uint32_t>(y), static_cast<uint32_t>(z)); computeShader->cmdPushDescriptorSets(commandBuffers.at(currentFrame), currentFrame, VK_PIPELINE_BIND_POINT_COMPUTE);
vkCmdDispatch(commandBuffers.at(currentFrame), static_cast<uint32_t>(x), static_cast<uint32_t>(y), static_cast<uint32_t>(z));
return true; return true;
} }
@@ -732,13 +735,14 @@ Matrix4 Graphics::computeDeviceProjection(const Matrix4 &projection, bool render
void Graphics::setRenderTargetsInternal(const RenderTargets &rts, int pixelw, int pixelh, bool hasSRGBtexture) void Graphics::setRenderTargetsInternal(const RenderTargets &rts, int pixelw, int pixelh, bool hasSRGBtexture)
{ {
endRenderPass(); if (renderPassState.active)
endRenderPass();
bool isWindow = rts.getFirstTarget().texture == nullptr; bool isWindow = rts.getFirstTarget().texture == nullptr;
if (isWindow) if (isWindow)
startDefaultRenderPass(); setDefaultRenderPass();
else else
startRenderPass(rts, pixelw, pixelh, hasSRGBtexture); setRenderPass(rts, pixelw, pixelh, hasSRGBtexture);
} }
// END IMPLEMENTATION OVERRIDDEN FUNCTIONS // END IMPLEMENTATION OVERRIDDEN FUNCTIONS
@@ -753,8 +757,8 @@ void Graphics::initDynamicState()
VkViewport viewport{}; VkViewport viewport{};
viewport.x = 0.0f; viewport.x = 0.0f;
viewport.y = 0.0f; viewport.y = 0.0f;
viewport.width = swapChainExtent.width; viewport.width = static_cast<float>(swapChainExtent.width);
viewport.height = swapChainExtent.height; viewport.height = static_cast<float>(swapChainExtent.height);
viewport.minDepth = 0.0f; viewport.minDepth = 0.0f;
viewport.maxDepth = 1.0f; viewport.maxDepth = 1.0f;
@@ -790,7 +794,8 @@ void Graphics::beginFrame()
while (true) while (true)
{ {
VkResult result = vkAcquireNextImageKHR(device, swapChain, UINT64_MAX, imageAvailableSemaphores[currentFrame], VK_NULL_HANDLE, &imageIndex); VkResult result = vkAcquireNextImageKHR(device, swapChain, UINT64_MAX, imageAvailableSemaphores[currentFrame], VK_NULL_HANDLE, &imageIndex);
if (result == VK_ERROR_OUT_OF_DATE_KHR) { if (result == VK_ERROR_OUT_OF_DATE_KHR)
{
recreateSwapChain(); recreateSwapChain();
continue; continue;
} }
@@ -802,16 +807,22 @@ void Graphics::beginFrame()
imageRequested = true; imageRequested = true;
for (auto& readbackCallback : readbackCallbacks.at(currentFrame)) for (auto &readbackCallback : readbackCallbacks.at(currentFrame))
readbackCallback(); readbackCallback();
readbackCallbacks.at(currentFrame).clear(); readbackCallbacks.at(currentFrame).clear();
for (auto& cleanUpFn : cleanUpFunctions.at(currentFrame)) for (auto &cleanUpFn : cleanUpFunctions.at(currentFrame))
cleanUpFn(); cleanUpFn();
cleanUpFunctions.at(currentFrame).clear(); cleanUpFunctions.at(currentFrame).clear();
startRecordingGraphicsCommands(true); startRecordingGraphicsCommands(true);
Vulkan::cmdTransitionImageLayout(
commandBuffers.at(currentFrame),
swapChainImages[imageIndex],
VK_IMAGE_LAYOUT_UNDEFINED,
VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL);
Vulkan::resetShaderSwitches(); Vulkan::resetShaderSwitches();
} }
@@ -824,35 +835,25 @@ void Graphics::startRecordingGraphicsCommands(bool newFrame)
if (vkBeginCommandBuffer(commandBuffers.at(currentFrame), &beginInfo) != VK_SUCCESS) if (vkBeginCommandBuffer(commandBuffers.at(currentFrame), &beginInfo) != VK_SUCCESS)
throw love::Exception("failed to begin recording command buffer"); throw love::Exception("failed to begin recording command buffer");
if (vkBeginCommandBuffer(dataTransferCommandBuffers.at(currentFrame), &beginInfo) != VK_SUCCESS)
throw love::Exception("failed to begin recording data transfer command buffer");
if (vkBeginCommandBuffer(readbackCommandBuffers.at(currentFrame), &beginInfo) != VK_SUCCESS)
throw love::Exception("failed to begin recording readback command buffer");
if (vkBeginCommandBuffer(computeCommandBuffers.at(currentFrame), &beginInfo) != VK_SUCCESS)
throw love::Exception("failed to begin recording compute command buffer");
initDynamicState(); initDynamicState();
if (newFrame) setDefaultRenderPass();
Vulkan::cmdTransitionImageLayout(commandBuffers.at(currentFrame), swapChainImages[imageIndex], VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL);
startDefaultRenderPass();
} }
void Graphics::endRecordingGraphicsCommands(bool present) { void Graphics::endRecordingGraphicsCommands(bool present) {
endRenderPass(); if (renderPassState.active)
endRenderPass();
if (present) if (present)
Vulkan::cmdTransitionImageLayout(commandBuffers.at(currentFrame), swapChainImages[imageIndex], VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, VK_IMAGE_LAYOUT_PRESENT_SRC_KHR); Vulkan::cmdTransitionImageLayout(
commandBuffers.at(currentFrame),
swapChainImages[imageIndex],
VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
VK_IMAGE_LAYOUT_PRESENT_SRC_KHR);
if (vkEndCommandBuffer(commandBuffers.at(currentFrame)) != VK_SUCCESS) if (vkEndCommandBuffer(commandBuffers.at(currentFrame)) != VK_SUCCESS)
throw love::Exception("failed to record command buffer"); throw love::Exception("failed to record command buffer");
if (vkEndCommandBuffer(dataTransferCommandBuffers.at(currentFrame)) != VK_SUCCESS)
throw love::Exception("failed to record data transfer command buffer");
if (vkEndCommandBuffer(readbackCommandBuffers.at(currentFrame)) != VK_SUCCESS)
throw love::Exception("failed to record read back command buffer");
if (vkEndCommandBuffer(computeCommandBuffers.at(currentFrame)) != VK_SUCCESS)
throw love::Exception("failed to record compute command buffer");
} }
void Graphics::updatedBatchedDrawBuffers() void Graphics::updatedBatchedDrawBuffers()
@@ -880,52 +881,12 @@ graphics::Texture *Graphics::getDefaultTexture() const
return dynamic_cast<graphics::Texture*>(standardTexture.get()); return dynamic_cast<graphics::Texture*>(standardTexture.get());
} }
VkCommandBuffer Graphics::getDataTransferCommandBuffer() VkCommandBuffer Graphics::getCommandBufferForDataTransfer()
{ {
return dataTransferCommandBuffers.at(currentFrame); if (renderPassState.active)
} endRenderPass();
VkCommandBuffer Graphics::getReadbackCommandBuffer() return commandBuffers.at(currentFrame);
{
return readbackCommandBuffers.at(currentFrame);
}
void Graphics::oneTimeCommand(std::function<void(VkCommandBuffer)> cmd)
{
VkCommandBufferAllocateInfo allocInfo{};
allocInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
allocInfo.commandPool = commandPool;
allocInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
allocInfo.commandBufferCount = 1;
VkCommandBuffer commandBuffer;
if (vkAllocateCommandBuffers(device, &allocInfo, &commandBuffer) != VK_SUCCESS)
throw love::Exception("failed to allocate one time command buffer");
VkCommandBufferBeginInfo beginInfo{};
beginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
beginInfo.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;
if (vkBeginCommandBuffer(commandBuffer, &beginInfo) != VK_SUCCESS)
throw love::Exception("failed to start recording one time command buffer");
cmd(commandBuffer);
if (vkEndCommandBuffer(commandBuffer) != VK_SUCCESS)
throw love::Exception("failed to end recording one time command buffer");
VkSubmitInfo submitInfo{};
submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
submitInfo.commandBufferCount = 1;
submitInfo.pCommandBuffers = &commandBuffer;
if (vkQueueSubmit(graphicsQueue, 1, &submitInfo, VK_NULL_HANDLE) != VK_SUCCESS)
throw love::Exception("failed to submit to queue");
if (vkQueueWaitIdle(graphicsQueue) != VK_SUCCESS)
throw love::Exception("failed to wait for queue idle");
vkFreeCommandBuffers(device, commandPool, 1, &commandBuffer);
} }
void Graphics::queueCleanUp(std::function<void()> cleanUp) void Graphics::queueCleanUp(std::function<void()> cleanUp)
@@ -1381,7 +1342,7 @@ void Graphics::initVMA()
void Graphics::createSurface() void Graphics::createSurface()
{ {
auto window = Module::getInstance<love::window::Window>(M_WINDOW); auto window = Module::getInstance<love::window::Window>(M_WINDOW);
const void* handle = window->getHandle(); const void *handle = window->getHandle();
if (SDL_Vulkan_CreateSurface((SDL_Window*)handle, instance, &surface) != SDL_TRUE) if (SDL_Vulkan_CreateSurface((SDL_Window*)handle, instance, &surface) != SDL_TRUE)
throw love::Exception("failed to create window surface"); throw love::Exception("failed to create window surface");
} }
@@ -1606,7 +1567,6 @@ void Graphics::createDefaultRenderPass()
{ {
RenderPassConfiguration renderPassConfiguration{}; RenderPassConfiguration renderPassConfiguration{};
renderPassConfiguration.colorFormats.push_back(swapChainImageFormat); renderPassConfiguration.colorFormats.push_back(swapChainImageFormat);
renderPassConfiguration.staticData.initialColorImageLayout = VK_IMAGE_LAYOUT_UNDEFINED;
renderPassConfiguration.staticData.msaaSamples = msaaSamples; renderPassConfiguration.staticData.msaaSamples = msaaSamples;
renderPassConfiguration.staticData.depthFormat = findDepthFormat(); renderPassConfiguration.staticData.depthFormat = findDepthFormat();
if (msaaSamples & VK_SAMPLE_COUNT_1_BIT) if (msaaSamples & VK_SAMPLE_COUNT_1_BIT)
@@ -1704,7 +1664,7 @@ VkRenderPass Graphics::createRenderPass(RenderPassConfiguration &configuration)
std::vector<VkAttachmentReference> colorAttachmentRefs; std::vector<VkAttachmentReference> colorAttachmentRefs;
uint32_t attachment = 0; uint32_t attachment = 0;
for (const auto& colorFormat : configuration.colorFormats) for (const auto &colorFormat : configuration.colorFormats)
{ {
VkAttachmentReference reference{}; VkAttachmentReference reference{};
reference.attachment = attachment++; reference.attachment = attachment++;
@@ -1714,14 +1674,11 @@ VkRenderPass Graphics::createRenderPass(RenderPassConfiguration &configuration)
VkAttachmentDescription colorDescription{}; VkAttachmentDescription colorDescription{};
colorDescription.format = colorFormat; colorDescription.format = colorFormat;
colorDescription.samples = configuration.staticData.msaaSamples; colorDescription.samples = configuration.staticData.msaaSamples;
if (configuration.staticData.initialColorImageLayout != VK_IMAGE_LAYOUT_UNDEFINED) colorDescription.loadOp = VK_ATTACHMENT_LOAD_OP_LOAD;
colorDescription.loadOp = VK_ATTACHMENT_LOAD_OP_LOAD;
else
colorDescription.loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
colorDescription.storeOp = VK_ATTACHMENT_STORE_OP_STORE; colorDescription.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
colorDescription.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; colorDescription.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
colorDescription.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; colorDescription.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
colorDescription.initialLayout = configuration.staticData.initialColorImageLayout; colorDescription.initialLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
colorDescription.finalLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; colorDescription.finalLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
attachments.push_back(colorDescription); attachments.push_back(colorDescription);
} }
@@ -1880,16 +1837,19 @@ void Graphics::createVulkanVertexFormat(
void Graphics::prepareDraw(const VertexAttributes &attributes, const BufferBindings &buffers, graphics::Texture *texture, PrimitiveType primitiveType, CullMode cullmode) void Graphics::prepareDraw(const VertexAttributes &attributes, const BufferBindings &buffers, graphics::Texture *texture, PrimitiveType primitiveType, CullMode cullmode)
{ {
if (!renderPassState.active)
startRenderPass();
GraphicsPipelineConfiguration configuration{}; GraphicsPipelineConfiguration configuration{};
configuration.renderPass = currentRenderPass; configuration.renderPass = renderPassState.renderPass;
configuration.vertexAttributes = attributes; configuration.vertexAttributes = attributes;
configuration.shader = (Shader*)Shader::current; configuration.shader = (Shader*)Shader::current;
configuration.wireFrame = states.back().wireframe; configuration.wireFrame = states.back().wireframe;
configuration.blendState = states.back().blend; configuration.blendState = states.back().blend;
configuration.colorChannelMask = states.back().colorMask; configuration.colorChannelMask = states.back().colorMask;
configuration.msaaSamples = currentMsaaSamples; configuration.msaaSamples = renderPassState.msaa;
configuration.numColorAttachments = currentNumColorAttachments; configuration.numColorAttachments = renderPassState.numColorAttachments;
configuration.primitiveType = primitiveType; configuration.primitiveType = primitiveType;
if (optionalDeviceFeatures.extendedDynamicState) if (optionalDeviceFeatures.extendedDynamicState)
@@ -1933,37 +1893,35 @@ void Graphics::prepareDraw(const VertexAttributes &attributes, const BufferBindi
vkCmdBindVertexBuffers(commandBuffers.at(currentFrame), 0, static_cast<uint32_t>(bufferVector.size()), bufferVector.data(), offsets.data()); vkCmdBindVertexBuffers(commandBuffers.at(currentFrame), 0, static_cast<uint32_t>(bufferVector.size()), bufferVector.data(), offsets.data());
} }
void Graphics::startDefaultRenderPass() void Graphics::setDefaultRenderPass()
{ {
VkRenderPassBeginInfo renderPassInfo{}; renderPassState.beginInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
renderPassInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO; renderPassState.beginInfo.renderPass = defaultRenderPass;
renderPassInfo.renderPass = defaultRenderPass; renderPassState.beginInfo.framebuffer = defaultFramebuffers[imageIndex];
renderPassInfo.framebuffer = defaultFramebuffers[imageIndex]; renderPassState.beginInfo.renderArea.offset = { 0, 0 };
renderPassInfo.renderArea.offset = { 0, 0 }; renderPassState.beginInfo.renderArea.extent = swapChainExtent;
renderPassInfo.renderArea.extent = swapChainExtent; renderPassState.beginInfo.clearValueCount = 0;
vkCmdBeginRenderPass(commandBuffers.at(currentFrame), &renderPassInfo, VK_SUBPASS_CONTENTS_INLINE); renderPassState.renderPass = defaultRenderPass;
renderPassState.pipeline = VK_NULL_HANDLE;
currentRenderPass = defaultRenderPass; renderPassState.width = static_cast<float>(swapChainExtent.width);
currentGraphicsPipeline = VK_NULL_HANDLE; renderPassState.height = static_cast<float>(swapChainExtent.height);
postRenderPass = std::nullopt; renderPassState.msaa = msaaSamples;
currentViewportWidth = (float)swapChainExtent.width; renderPassState.numColorAttachments = 1;
currentViewportHeight = (float)swapChainExtent.height; renderPassState.transitionImages.clear();
currentMsaaSamples = msaaSamples;
currentNumColorAttachments = 1;
VkViewport viewport{}; VkViewport viewport{};
viewport.x = 0.0f; viewport.x = 0.0f;
viewport.y = 0.0f; viewport.y = 0.0f;
viewport.width = currentViewportWidth; viewport.width = renderPassState.width;
viewport.height = currentViewportHeight; viewport.height = renderPassState.height;
viewport.minDepth = 0.0f; viewport.minDepth = 0.0f;
viewport.maxDepth = 1.0f; viewport.maxDepth = 1.0f;
vkCmdSetViewport(commandBuffers.at(currentFrame), 0, 1, &viewport); vkCmdSetViewport(commandBuffers.at(currentFrame), 0, 1, &viewport);
} }
void Graphics::startRenderPass(const RenderTargets &rts, int pixelw, int pixelh, bool hasSRGBtexture) void Graphics::setRenderPass(const RenderTargets &rts, int pixelw, int pixelh, bool hasSRGBtexture)
{ {
VkViewport viewport{}; VkViewport viewport{};
viewport.x = 0.0f; viewport.x = 0.0f;
@@ -1980,7 +1938,6 @@ void Graphics::startRenderPass(const RenderTargets &rts, int pixelw, int pixelh,
// fixme: hasSRGBtexture // fixme: hasSRGBtexture
// fixme: msaaSamples // fixme: msaaSamples
RenderPassConfiguration renderPassConfiguration{}; RenderPassConfiguration renderPassConfiguration{};
renderPassConfiguration.staticData.initialColorImageLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
for (const auto &color : rts.colors) for (const auto &color : rts.colors)
{ {
// fixme: use mipmap and slice. // fixme: use mipmap and slice.
@@ -2009,13 +1966,12 @@ void Graphics::startRenderPass(const RenderTargets &rts, int pixelw, int pixelh,
FramebufferConfiguration configuration{}; FramebufferConfiguration configuration{};
std::vector<VkImage> transitionBackImages; std::vector<VkImage> transitionImages;
for (const auto& color : rts.colors) for (const auto& color : rts.colors)
{ {
configuration.colorViews.push_back((VkImageView)color.texture->getRenderTargetHandle()); configuration.colorViews.push_back((VkImageView)color.texture->getRenderTargetHandle());
Vulkan::cmdTransitionImageLayout(currentCommandBuffer, (VkImage)color.texture->getHandle(), VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL); transitionImages.push_back((VkImage) color.texture->getHandle());
transitionBackImages.push_back((VkImage) color.texture->getHandle());
} }
if (rts.depthStencil.texture != nullptr) if (rts.depthStencil.texture != nullptr)
// fixme: layout transition of depth stencil image? // fixme: layout transition of depth stencil image?
@@ -2026,39 +1982,41 @@ void Graphics::startRenderPass(const RenderTargets &rts, int pixelw, int pixelh,
configuration.staticData.height = static_cast<uint32_t>(pixelh); configuration.staticData.height = static_cast<uint32_t>(pixelh);
VkFramebuffer framebuffer = getFramebuffer(configuration); VkFramebuffer framebuffer = getFramebuffer(configuration);
VkRenderPassBeginInfo renderPassInfo{}; renderPassState.beginInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
renderPassInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO; renderPassState.beginInfo.renderPass = renderPass;
renderPassInfo.renderPass = renderPass; renderPassState.beginInfo.framebuffer = framebuffer;
renderPassInfo.framebuffer = framebuffer; renderPassState.beginInfo.renderArea.offset = {0, 0};
renderPassInfo.renderArea.offset = {0, 0}; renderPassState.beginInfo.renderArea.extent.width = static_cast<uint32_t>(pixelw);
renderPassInfo.renderArea.extent.width = static_cast<uint32_t>(pixelw); renderPassState.beginInfo.renderArea.extent.height = static_cast<uint32_t>(pixelh);
renderPassInfo.renderArea.extent.height = static_cast<uint32_t>(pixelh); renderPassState.beginInfo.clearValueCount = 0;
vkCmdBeginRenderPass(currentCommandBuffer, &renderPassInfo, VK_SUBPASS_CONTENTS_INLINE); renderPassState.renderPass = renderPass;
renderPassState.pipeline = VK_NULL_HANDLE;
renderPassState.width = static_cast<float>(pixelw);
renderPassState.height = static_cast<float>(pixelh);
renderPassState.msaa = VK_SAMPLE_COUNT_1_BIT;
renderPassState.numColorAttachments = static_cast<uint32_t>(rts.colors.size());
renderPassState.transitionImages = std::move(transitionImages);
}
currentRenderPass = renderPass; void Graphics::startRenderPass()
currentGraphicsPipeline = VK_NULL_HANDLE; {
currentViewportWidth = (float)pixelw; renderPassState.active = true;
currentViewportHeight = (float)pixelh;
currentMsaaSamples = VK_SAMPLE_COUNT_1_BIT;
currentNumColorAttachments = static_cast<uint32_t>(rts.colors.size());
postRenderPass = [=]() { for (const auto& image : renderPassState.transitionImages)
for (const auto& image : transitionBackImages) Vulkan::cmdTransitionImageLayout(commandBuffers.at(currentFrame), image, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL);
Vulkan::cmdTransitionImageLayout(currentCommandBuffer, image, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
}; vkCmdBeginRenderPass(commandBuffers.at(currentFrame), &renderPassState.beginInfo, VK_SUBPASS_CONTENTS_INLINE);
} }
void Graphics::endRenderPass() void Graphics::endRenderPass()
{ {
vkCmdEndRenderPass(commandBuffers.at(currentFrame)); renderPassState.active = false;
currentRenderPass = VK_NULL_HANDLE;
if (postRenderPass) vkCmdEndRenderPass(commandBuffers.at(currentFrame));
{
postRenderPass.value()(); for (const auto &image : renderPassState.transitionImages)
postRenderPass = std::nullopt; Vulkan::cmdTransitionImageLayout(commandBuffers.at(currentFrame), image, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
}
} }
VkSampler Graphics::createSampler(const SamplerState &samplerState) VkSampler Graphics::createSampler(const SamplerState &samplerState)
@@ -2287,10 +2245,10 @@ void Graphics::ensureGraphicsPipelineConfiguration(GraphicsPipelineConfiguration
auto it = graphicsPipelines.find(configuration); auto it = graphicsPipelines.find(configuration);
if (it != graphicsPipelines.end()) if (it != graphicsPipelines.end())
{ {
if (it->second != currentGraphicsPipeline) if (it->second != renderPassState.pipeline)
{ {
vkCmdBindPipeline(commandBuffers.at(currentFrame), VK_PIPELINE_BIND_POINT_GRAPHICS, it->second); vkCmdBindPipeline(commandBuffers.at(currentFrame), VK_PIPELINE_BIND_POINT_GRAPHICS, it->second);
currentGraphicsPipeline = it->second; renderPassState.pipeline = it->second;
} }
} }
else else
@@ -2298,7 +2256,7 @@ void Graphics::ensureGraphicsPipelineConfiguration(GraphicsPipelineConfiguration
VkPipeline pipeline = createGraphicsPipeline(configuration); VkPipeline pipeline = createGraphicsPipeline(configuration);
graphicsPipelines.insert({configuration, pipeline}); graphicsPipelines.insert({configuration, pipeline});
vkCmdBindPipeline(commandBuffers.at(currentFrame), VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline); vkCmdBindPipeline(commandBuffers.at(currentFrame), VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline);
currentGraphicsPipeline = pipeline; renderPassState.pipeline = pipeline;
} }
} }
@@ -2459,9 +2417,6 @@ void Graphics::createCommandPool()
void Graphics::createCommandBuffers() void Graphics::createCommandBuffers()
{ {
commandBuffers.resize(MAX_FRAMES_IN_FLIGHT); commandBuffers.resize(MAX_FRAMES_IN_FLIGHT);
dataTransferCommandBuffers.resize(MAX_FRAMES_IN_FLIGHT);
readbackCommandBuffers.resize(MAX_FRAMES_IN_FLIGHT);
computeCommandBuffers.resize(MAX_FRAMES_IN_FLIGHT);
VkCommandBufferAllocateInfo allocInfo{}; VkCommandBufferAllocateInfo allocInfo{};
allocInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO; allocInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
@@ -2471,33 +2426,6 @@ void Graphics::createCommandBuffers()
if (vkAllocateCommandBuffers(device, &allocInfo, commandBuffers.data()) != VK_SUCCESS) if (vkAllocateCommandBuffers(device, &allocInfo, commandBuffers.data()) != VK_SUCCESS)
throw love::Exception("failed to allocate command buffers"); throw love::Exception("failed to allocate command buffers");
VkCommandBufferAllocateInfo dataTransferAllocInfo{};
dataTransferAllocInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
dataTransferAllocInfo.commandPool = commandPool;
dataTransferAllocInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
dataTransferAllocInfo.commandBufferCount = static_cast<uint32_t>(MAX_FRAMES_IN_FLIGHT);
if (vkAllocateCommandBuffers(device, &dataTransferAllocInfo, dataTransferCommandBuffers.data()) != VK_SUCCESS)
throw love::Exception("failed to allocate data transfer command buffers");
VkCommandBufferAllocateInfo readbackAllocInfo{};
readbackAllocInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
readbackAllocInfo.commandPool = commandPool;
readbackAllocInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
readbackAllocInfo.commandBufferCount = static_cast<uint32_t>(MAX_FRAMES_IN_FLIGHT);
if (vkAllocateCommandBuffers(device, &readbackAllocInfo, readbackCommandBuffers.data()) != VK_SUCCESS)
throw love::Exception("failed to allocate readback command buffers");
VkCommandBufferAllocateInfo commandAllocInfo{};
commandAllocInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
commandAllocInfo.commandPool = commandPool;
commandAllocInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
commandAllocInfo.commandBufferCount = static_cast<uint32_t>(MAX_FRAMES_IN_FLIGHT);
if (vkAllocateCommandBuffers(device, &commandAllocInfo, computeCommandBuffers.data()) != VK_SUCCESS)
throw love::Exception("failed to allocate compute command buffers");
} }
void Graphics::createSyncObjects() void Graphics::createSyncObjects()
@@ -2548,9 +2476,6 @@ void Graphics::cleanup()
} }
vkFreeCommandBuffers(device, commandPool, MAX_FRAMES_IN_FLIGHT, commandBuffers.data()); vkFreeCommandBuffers(device, commandPool, MAX_FRAMES_IN_FLIGHT, commandBuffers.data());
vkFreeCommandBuffers(device, commandPool, MAX_FRAMES_IN_FLIGHT, dataTransferCommandBuffers.data());
vkFreeCommandBuffers(device, commandPool, MAX_FRAMES_IN_FLIGHT, readbackCommandBuffers.data());
vkFreeCommandBuffers(device, commandPool, MAX_FRAMES_IN_FLIGHT, computeCommandBuffers.data());
for (auto const &p : samplers) for (auto const &p : samplers)
vkDestroySampler(device, p.second, nullptr); vkDestroySampler(device, p.second, nullptr);
+18 -19
View File
@@ -32,7 +32,6 @@ struct RenderPassConfiguration
struct StaticRenderPassConfiguration struct StaticRenderPassConfiguration
{ {
VkImageLayout initialColorImageLayout = VK_IMAGE_LAYOUT_UNDEFINED;
VkSampleCountFlagBits msaaSamples = VK_SAMPLE_COUNT_1_BIT; VkSampleCountFlagBits msaaSamples = VK_SAMPLE_COUNT_1_BIT;
VkFormat depthFormat = VK_FORMAT_UNDEFINED; VkFormat depthFormat = VK_FORMAT_UNDEFINED;
bool resolve = false; bool resolve = false;
@@ -204,6 +203,19 @@ struct SwapChainSupportDetails
std::vector<VkPresentModeKHR> presentModes; std::vector<VkPresentModeKHR> presentModes;
}; };
struct RenderpassState
{
bool active = false;
VkRenderPassBeginInfo beginInfo{};
VkRenderPass renderPass = VK_NULL_HANDLE;
VkPipeline pipeline = VK_NULL_HANDLE;
std::vector<VkImage> transitionImages;
uint32_t numColorAttachments = 0;
float width = 0.0f;
float height = 0.0f;
VkSampleCountFlagBits msaa = VK_SAMPLE_COUNT_1_BIT;
};
class Graphics final : public love::graphics::Graphics class Graphics final : public love::graphics::Graphics
{ {
public: public:
@@ -261,10 +273,7 @@ public:
graphics::GraphicsReadback *newReadbackInternal(ReadbackMethod method, love::graphics::Buffer *buffer, size_t offset, size_t size, data::ByteData *dest, size_t destoffset) override; graphics::GraphicsReadback *newReadbackInternal(ReadbackMethod method, love::graphics::Buffer *buffer, size_t offset, size_t size, data::ByteData *dest, size_t destoffset) override;
graphics::GraphicsReadback *newReadbackInternal(ReadbackMethod method, love::graphics::Texture *texture, int slice, int mipmap, const Rect &rect, image::ImageData *dest, int destx, int desty) override; graphics::GraphicsReadback *newReadbackInternal(ReadbackMethod method, love::graphics::Texture *texture, int slice, int mipmap, const Rect &rect, image::ImageData *dest, int destx, int desty) override;
VkCommandBuffer getDataTransferCommandBuffer(); VkCommandBuffer getCommandBufferForDataTransfer();
VkCommandBuffer getReadbackCommandBuffer();
void oneTimeCommand(std::function<void(VkCommandBuffer)> cmd);
void queueCleanUp(std::function<void()> cleanUp); void queueCleanUp(std::function<void()> cleanUp);
void addReadbackCallback(std::function<void()> callback); void addReadbackCallback(std::function<void()> callback);
@@ -339,8 +348,9 @@ private:
std::vector<VkVertexInputBindingDescription> &bindingDescriptions, std::vector<VkVertexInputBindingDescription> &bindingDescriptions,
std::vector<VkVertexInputAttributeDescription> &attributeDescriptions); std::vector<VkVertexInputAttributeDescription> &attributeDescriptions);
void prepareDraw(const VertexAttributes &attributes, const BufferBindings &buffers, graphics::Texture *texture, PrimitiveType, CullMode); void prepareDraw(const VertexAttributes &attributes, const BufferBindings &buffers, graphics::Texture *texture, PrimitiveType, CullMode);
void startRenderPass(const RenderTargets &rts, int pixelw, int pixelh, bool hasSRGBtexture); void setRenderPass(const RenderTargets &rts, int pixelw, int pixelh, bool hasSRGBtexture);
void startDefaultRenderPass(); void setDefaultRenderPass();
void startRenderPass();
void endRenderPass(); void endRenderPass();
VkSampler createSampler(const SamplerState&); VkSampler createSampler(const SamplerState&);
@@ -361,8 +371,6 @@ private:
VkFormat swapChainImageFormat = VK_FORMAT_UNDEFINED; VkFormat swapChainImageFormat = VK_FORMAT_UNDEFINED;
VkExtent2D swapChainExtent = VkExtent2D(); VkExtent2D swapChainExtent = VkExtent2D();
std::vector<VkImageView> swapChainImageViews; std::vector<VkImageView> swapChainImageViews;
VkPipeline currentGraphicsPipeline = VK_NULL_HANDLE;
VkRenderPass currentRenderPass = VK_NULL_HANDLE;
VkSampleCountFlagBits msaaSamples = VK_SAMPLE_COUNT_1_BIT; VkSampleCountFlagBits msaaSamples = VK_SAMPLE_COUNT_1_BIT;
VkImage colorImage = VK_NULL_HANDLE; VkImage colorImage = VK_NULL_HANDLE;
VkImageView colorImageView = VK_NULL_HANDLE; VkImageView colorImageView = VK_NULL_HANDLE;
@@ -377,10 +385,7 @@ private:
std::unordered_map<GraphicsPipelineConfiguration, VkPipeline, GraphicsPipelineConfigurationHasher> graphicsPipelines; std::unordered_map<GraphicsPipelineConfiguration, VkPipeline, GraphicsPipelineConfigurationHasher> graphicsPipelines;
std::unordered_map<SamplerState, VkSampler, SamplerStateHasher> samplers; std::unordered_map<SamplerState, VkSampler, SamplerStateHasher> samplers;
VkCommandPool commandPool = VK_NULL_HANDLE; VkCommandPool commandPool = VK_NULL_HANDLE;
std::vector<VkCommandBuffer> dataTransferCommandBuffers;
std::vector<VkCommandBuffer> computeCommandBuffers;
std::vector<VkCommandBuffer> commandBuffers; std::vector<VkCommandBuffer> commandBuffers;
std::vector<VkCommandBuffer> readbackCommandBuffers;
Shader* computeShader = nullptr; Shader* computeShader = nullptr;
std::vector<VkSemaphore> imageAvailableSemaphores; std::vector<VkSemaphore> imageAvailableSemaphores;
std::vector<VkSemaphore> renderFinishedSemaphores; std::vector<VkSemaphore> renderFinishedSemaphores;
@@ -400,13 +405,7 @@ private:
// just like batchedDrawBuffers we need a vector for each frame in flight. // just like batchedDrawBuffers we need a vector for each frame in flight.
std::vector<std::vector<std::function<void()>>> cleanUpFunctions; std::vector<std::vector<std::function<void()>>> cleanUpFunctions;
std::vector<std::vector<std::function<void()>>> readbackCallbacks; std::vector<std::vector<std::function<void()>>> readbackCallbacks;
RenderpassState renderPassState;
// render pass variables.
std::optional<std::function<void()>> postRenderPass;
uint32_t currentNumColorAttachments = 0;
float currentViewportWidth = 0;
float currentViewportHeight = 0;
VkSampleCountFlagBits currentMsaaSamples = VK_SAMPLE_COUNT_1_BIT;
}; };
} // vulkan } // vulkan
+10 -12
View File
@@ -77,19 +77,17 @@ bool Texture::loadVolatile()
if (vmaCreateImage(allocator, &imageInfo, &imageAllocationCreateInfo, &textureImage, &textureImageAllocation, nullptr) != VK_SUCCESS) if (vmaCreateImage(allocator, &imageInfo, &imageAllocationCreateInfo, &textureImage, &textureImageAllocation, nullptr) != VK_SUCCESS)
throw love::Exception("failed to create image"); throw love::Exception("failed to create image");
auto commandBuffer = vgfx->getDataTransferCommandBuffer(); auto commandBuffer = vgfx->getCommandBufferForDataTransfer();
if (computeWrite) if (computeWrite)
imageLayout = VK_IMAGE_LAYOUT_GENERAL; imageLayout = VK_IMAGE_LAYOUT_GENERAL;
else else
imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
vgfx->oneTimeCommand([=](VkCommandBuffer commandBuffer) { Vulkan::cmdTransitionImageLayout(commandBuffer, textureImage,
Vulkan::cmdTransitionImageLayout(commandBuffer, textureImage, VK_IMAGE_LAYOUT_UNDEFINED, imageLayout,
VK_IMAGE_LAYOUT_UNDEFINED, imageLayout, 0, VK_REMAINING_MIP_LEVELS,
0, VK_REMAINING_MIP_LEVELS, 0, VK_REMAINING_ARRAY_LAYERS);
0, VK_REMAINING_ARRAY_LAYERS);
});
bool hasdata = slices.get(0, 0) != nullptr; bool hasdata = slices.get(0, 0) != nullptr;
@@ -200,7 +198,7 @@ void Texture::createTextureImageView()
void Texture::clear() void Texture::clear()
{ {
auto commandBuffer = vgfx->getDataTransferCommandBuffer(); auto commandBuffer = vgfx->getCommandBufferForDataTransfer();
auto clearColor = getClearValue(); auto clearColor = getClearValue();
@@ -258,7 +256,7 @@ VkClearColorValue Texture::getClearValue()
void Texture::generateMipmapsInternal() void Texture::generateMipmapsInternal()
{ {
auto commandBuffer = vgfx->getDataTransferCommandBuffer(); auto commandBuffer = vgfx->getCommandBufferForDataTransfer();
if (imageLayout != VK_IMAGE_LAYOUT_GENERAL) if (imageLayout != VK_IMAGE_LAYOUT_GENERAL)
Vulkan::cmdTransitionImageLayout(commandBuffer, textureImage, Vulkan::cmdTransitionImageLayout(commandBuffer, textureImage,
@@ -374,7 +372,7 @@ void Texture::uploadByteData(PixelFormat pixelformat, const void *data, size_t s
static_cast<uint32_t>(r.h), 1 static_cast<uint32_t>(r.h), 1
}; };
auto commandBuffer = vgfx->getDataTransferCommandBuffer(); auto commandBuffer = vgfx->getCommandBufferForDataTransfer();
if (imageLayout != VK_IMAGE_LAYOUT_GENERAL) if (imageLayout != VK_IMAGE_LAYOUT_GENERAL)
@@ -414,7 +412,7 @@ void Texture::uploadByteData(PixelFormat pixelformat, const void *data, size_t s
void Texture::copyFromBuffer(graphics::Buffer *source, size_t sourceoffset, int sourcewidth, size_t size, int slice, int mipmap, const Rect &rect) void Texture::copyFromBuffer(graphics::Buffer *source, size_t sourceoffset, int sourcewidth, size_t size, int slice, int mipmap, const Rect &rect)
{ {
auto commandBuffer = vgfx->getDataTransferCommandBuffer(); auto commandBuffer = vgfx->getCommandBufferForDataTransfer();
VkImageSubresourceLayers layers{}; VkImageSubresourceLayers layers{};
layers.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; layers.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
@@ -444,7 +442,7 @@ void Texture::copyFromBuffer(graphics::Buffer *source, size_t sourceoffset, int
void Texture::copyToBuffer(graphics::Buffer *dest, int slice, int mipmap, const Rect &rect, size_t destoffset, int destwidth, size_t size) void Texture::copyToBuffer(graphics::Buffer *dest, int slice, int mipmap, const Rect &rect, size_t destoffset, int destwidth, size_t size)
{ {
auto commandBuffer = vgfx->getReadbackCommandBuffer(); auto commandBuffer = vgfx->getCommandBufferForDataTransfer();
VkImageSubresourceLayers layers{}; VkImageSubresourceLayers layers{};
layers.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; layers.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;