vulkan: fix video rendering

This commit is contained in:
niki
2022-07-30 00:26:49 +02:00
parent 1096b76054
commit 94c58e1599
5 changed files with 52 additions and 13 deletions
+30 -8
View File
@@ -142,6 +142,9 @@ namespace love {
}
imagesInFlight[imageIndex] = inFlightFences[currentFrame];
// all data transfers should happen before any draw calls.
std::vector<VkCommandBuffer> submitCommandbuffers = { dataTransferCommandBuffers.at(currentFrame), commandBuffers.at(imageIndex) };
VkSubmitInfo submitInfo{};
submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
@@ -151,8 +154,8 @@ namespace love {
submitInfo.pWaitSemaphores = waitSemaphores;
submitInfo.pWaitDstStageMask = waitStages;
submitInfo.commandBufferCount = 1;
submitInfo.pCommandBuffers = &commandBuffers[imageIndex];
submitInfo.commandBufferCount = static_cast<uint32_t>(submitCommandbuffers.size());
submitInfo.pCommandBuffers = submitCommandbuffers.data();
VkSemaphore signalSemaphores[] = { renderFinishedSemaphores.at(currentFrame) };
submitInfo.signalSemaphoreCount = 1;
@@ -213,10 +216,10 @@ namespace love {
initCapabilities();
createSwapChain();
createImageViews();
createDefaultShaders();
createCommandPool();
createCommandBuffers();
createDefaultTexture();
createDefaultShaders();
createQuadIndexBuffer();
createSyncObjects();
startRecordingGraphicsCommands();
@@ -510,6 +513,9 @@ namespace love {
if (vkBeginCommandBuffer(commandBuffers.at(imageIndex), &beginInfo) != VK_SUCCESS) {
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");
}
Vulkan::cmdTransitionImageLayout(commandBuffers.at(imageIndex), swapChainImages[imageIndex], VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL);
@@ -519,8 +525,6 @@ namespace love {
}
void Graphics::endRecordingGraphicsCommands() {
const auto& commandBuffer = commandBuffers.at(imageIndex);
endRenderPass();
Vulkan::cmdTransitionImageLayout(commandBuffers.at(imageIndex), swapChainImages[imageIndex], VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, VK_IMAGE_LAYOUT_PRESENT_SRC_KHR);
@@ -528,6 +532,9 @@ namespace love {
if (vkEndCommandBuffer(commandBuffers.at(imageIndex)) != VK_SUCCESS) {
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");
}
}
void Graphics::updatedBatchedDrawBuffers() {
@@ -547,12 +554,16 @@ namespace love {
return minUniformBufferOffsetAlignment;
}
graphics::Texture* Graphics::getDefaultTexture() const {
return dynamic_cast<graphics::Texture*>(standardTexture.get());
}
const PFN_vkCmdPushDescriptorSetKHR Graphics::getVkCmdPushDescriptorSetKHRFunctionPointer() const {
return vkCmdPushDescriptorSet;
}
void Graphics::executeCommand(std::function<void(VkCommandBuffer)> command, std::function<void()> cleanUp) {
command(commandBuffers.at(imageIndex));
void Graphics::queueDatatransfer(std::function<void(VkCommandBuffer)> command, std::function<void()> cleanUp) {
command(dataTransferCommandBuffers.at(currentFrame));
cleanUpFunctions.at(currentFrame).push_back(std::move(cleanUp));
}
@@ -1207,7 +1218,6 @@ namespace love {
else {
configuration.shader->setMainTex(texture);
}
configuration.shader->setVideoTextures(standardTexture.get(), standardTexture.get(), standardTexture.get());
ensureGraphicsPipelineConfiguration(configuration);
@@ -1416,6 +1426,7 @@ namespace love {
void Graphics::createCommandBuffers() {
commandBuffers.resize(swapChainImages.size());
dataTransferCommandBuffers.resize(MAX_FRAMES_IN_FLIGHT);
VkCommandBufferAllocateInfo allocInfo{};
allocInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
@@ -1426,6 +1437,16 @@ namespace love {
if (vkAllocateCommandBuffers(device, &allocInfo, commandBuffers.data()) != VK_SUCCESS) {
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 = (uint32_t)MAX_FRAMES_IN_FLIGHT;
if (vkAllocateCommandBuffers(device, &dataTransferAllocInfo, dataTransferCommandBuffers.data()) != VK_SUCCESS) {
throw love::Exception("failed to allocate data transfer command buffers");
}
}
void Graphics::createSyncObjects() {
@@ -1565,6 +1586,7 @@ namespace love {
void Graphics::cleanupSwapChain() {
vkDestroyDescriptorPool(device, descriptorPool, nullptr);
vkFreeCommandBuffers(device, commandPool, static_cast<uint32_t>(commandBuffers.size()), commandBuffers.data());
vkFreeCommandBuffers(device, commandPool, MAX_FRAMES_IN_FLIGHT, dataTransferCommandBuffers.data());
for (auto const& p : graphicsPipelines) {
vkDestroyPipeline(device, p.second, nullptr);
}
+3 -2
View File
@@ -114,8 +114,7 @@ namespace love {
GraphicsReadback* newReadbackInternal(ReadbackMethod method, love::graphics::Buffer* buffer, size_t offset, size_t size, data::ByteData* dest, size_t destoffset) override { return nullptr; };
GraphicsReadback* newReadbackInternal(ReadbackMethod method, love::graphics::Texture* texture, int slice, int mipmap, const Rect& rect, image::ImageData* dest, int destx, int desty) { return nullptr; }
// fixme: better naming for these two functions?
void executeCommand(std::function<void(VkCommandBuffer)> command, std::function<void()> cleanUp);
void queueDatatransfer(std::function<void(VkCommandBuffer)> command, std::function<void()> cleanUp);
void queueCleanUp(std::function<void()> cleanUp);
VkCommandBuffer beginSingleTimeCommands();
@@ -124,6 +123,7 @@ namespace love {
uint32_t getNumImagesInFlight() const;
const PFN_vkCmdPushDescriptorSetKHR getVkCmdPushDescriptorSetKHRFunctionPointer() const;
const VkDeviceSize getMinUniformBufferOffsetAlignment() const;
graphics::Texture* getDefaultTexture() const;
protected:
graphics::ShaderStage* newShaderStageInternal(ShaderStageType stage, const std::string& cachekey, const std::string& source, bool gles) override {
@@ -190,6 +190,7 @@ namespace love {
std::vector<std::pair<GraphicsPipelineConfiguration, VkPipeline>> graphicsPipelines; // FIXME improve performance by using a hash map
VkCommandPool commandPool = VK_NULL_HANDLE;
std::vector<VkCommandBuffer> commandBuffers;
std::vector<VkCommandBuffer> dataTransferCommandBuffers;
VkDescriptorPool descriptorPool = VK_NULL_HANDLE;
std::vector<VkSemaphore> imageAvailableSemaphores;
std::vector<VkSemaphore> renderFinishedSemaphores;
+5
View File
@@ -311,6 +311,11 @@ namespace love {
auto vgfx = (Graphics*)gfx;
device = vgfx->getDevice();
mainTex = vgfx->getDefaultTexture();
ytexture = vgfx->getDefaultTexture();
crtexture = vgfx->getDefaultTexture();
cbtexture = vgfx->getDefaultTexture();
for (int i = 0; i < SHADERSTAGE_MAX_ENUM; i++) {
if (!stages[i])
continue;
+7 -3
View File
@@ -43,6 +43,7 @@ namespace love {
if (vmaCreateImage(allocator, &imageInfo, &imageAllocationCreateInfo, &textureImage, &textureImageAllocation, nullptr) != VK_SUCCESS) {
throw love::Exception("failed to create image");
}
// fixme: we should use VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL as the default image layout instead of VK_IMAGE_LAYOUT_GENERAL.
transitionImageLayout(textureImage, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_GENERAL);
if (data) {
@@ -253,22 +254,25 @@ namespace love {
static_cast<uint32_t>(r.h), 1
};
// fixme: use VK_IMAGE_LAYOUT_DST_OPTIMAL
Vulkan::cmdTransitionImageLayout(commandBuffer, image, VK_IMAGE_LAYOUT_GENERAL, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL);
vkCmdCopyBufferToImage(
commandBuffer,
buffer,
image,
VK_IMAGE_LAYOUT_GENERAL,
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
1,
&region
);
Vulkan::cmdTransitionImageLayout(commandBuffer, image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_GENERAL);
};
auto cleanUp = [allocator = allocator, stagingBuffer, vmaAllocation]() {
vmaDestroyBuffer(allocator, stagingBuffer, vmaAllocation);
};
vgfx->executeCommand(command, cleanUp);
vgfx->queueDatatransfer(command, cleanUp);
}
}
}
+7
View File
@@ -491,6 +491,13 @@ namespace love {
sourceStage = VK_PIPELINE_STAGE_TRANSFER_BIT;
destinationStage = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
}
else if (oldLayout == VK_IMAGE_LAYOUT_GENERAL && newLayout == VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL) {
barrier.srcAccessMask = VK_ACCESS_SHADER_READ_BIT;
barrier.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
sourceStage = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
destinationStage = VK_PIPELINE_STAGE_TRANSFER_BIT;
}
else if (oldLayout == VK_IMAGE_LAYOUT_UNDEFINED && newLayout == VK_IMAGE_LAYOUT_GENERAL) {
barrier.srcAccessMask = 0;
barrier.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT | VK_ACCESS_SHADER_READ_BIT;