From 466046688754652839fb574a3ba655aa7a440f12 Mon Sep 17 00:00:00 2001 From: niki Date: Sat, 20 Aug 2022 15:49:09 +0200 Subject: [PATCH] vulkan: don't use dynamic rendering --- src/modules/graphics/vulkan/Graphics.cpp | 174 ++++++++++++++++------- src/modules/graphics/vulkan/Graphics.h | 23 ++- 2 files changed, 147 insertions(+), 50 deletions(-) diff --git a/src/modules/graphics/vulkan/Graphics.cpp b/src/modules/graphics/vulkan/Graphics.cpp index 9f5ec9632..a34eff406 100644 --- a/src/modules/graphics/vulkan/Graphics.cpp +++ b/src/modules/graphics/vulkan/Graphics.cpp @@ -65,7 +65,7 @@ const VmaAllocator Graphics::getVmaAllocator() const { } Graphics::~Graphics() { - // We already cleaned those up by clearing out batchedDrawBuffers. + // We already cleaned those up by clearing out batchedDrawBuffers. // We set them to nullptr here so the base class doesn't crash // when it tries to free this. batchedDrawState.vb[0] = nullptr; @@ -146,7 +146,7 @@ void Graphics::present(void* screenshotCallbackdata) { submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; VkSemaphore waitSemaphores[] = { imageAvailableSemaphores.at(currentFrame) }; - VkPipelineStageFlags waitStages[] = { VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT }; + VkPipelineStageFlags waitStages[] = { VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT }; submitInfo.waitSemaphoreCount = 1; submitInfo.pWaitSemaphores = waitSemaphores; submitInfo.pWaitDstStageMask = waitStages; @@ -185,7 +185,7 @@ void Graphics::present(void* screenshotCallbackdata) { else if (result != VK_SUCCESS) { throw love::Exception("failed to present swap chain image"); } - + currentFrame = (currentFrame + 1) % MAX_FRAMES_IN_FLIGHT; updatedBatchedDrawBuffers(); @@ -248,7 +248,7 @@ bool Graphics::setMode(void* context, int width, int height, int pixelwidth, int Shader::current = Shader::standardShaders[graphics::Shader::StandardShader::STANDARD_DEFAULT]; restoreState(states.back()); - + setViewportSize(width, height, pixelwidth, pixelheight); renderTargetTexture = nullptr; currentViewportWidth = 0.0f; @@ -410,7 +410,7 @@ void Graphics::setColor(Colorf c) { void Graphics::setScissor(const Rect& rect) { flushBatchedDraws(); - + states.back().scissor = true; states.back().scissorRect = rect; } @@ -427,7 +427,7 @@ void Graphics::setWireframe(bool enable) { states.back().wireframe = enable; } -PixelFormat Graphics::getSizedFormat(PixelFormat format, bool rendertarget, bool readable) const { +PixelFormat Graphics::getSizedFormat(PixelFormat format, bool rendertarget, bool readable) const { switch (format) { case PIXELFORMAT_NORMAL: if (isGammaCorrect()) { @@ -443,7 +443,7 @@ PixelFormat Graphics::getSizedFormat(PixelFormat format, bool rendertarget, bool } } -bool Graphics::isPixelFormatSupported(PixelFormat format, uint32 usage, bool sRGB) { +bool Graphics::isPixelFormatSupported(PixelFormat format, uint32 usage, bool sRGB) { return true; } @@ -455,7 +455,7 @@ graphics::StreamBuffer* Graphics::newStreamBuffer(BufferUsage type, size_t size) return new StreamBuffer(this, type, size); } -Matrix4 Graphics::computeDeviceProjection(const Matrix4& projection, bool rendertotexture) const { +Matrix4 Graphics::computeDeviceProjection(const Matrix4& projection, bool rendertotexture) const { uint32 flags = DEVICE_PROJECTION_DEFAULT; return calculateDeviceProjection(projection, flags); } @@ -530,7 +530,7 @@ void Graphics::endRecordingGraphicsCommands() { void Graphics::updatedBatchedDrawBuffers() { batchedDrawState.vb[0] = batchedDrawBuffers[currentFrame].vertexBuffer1; batchedDrawState.vb[0]->nextFrame(); - batchedDrawState.vb[1] = batchedDrawBuffers[currentFrame].vertexBuffer2; + batchedDrawState.vb[1] = batchedDrawBuffers[currentFrame].vertexBuffer2; batchedDrawState.vb[1]->nextFrame(); batchedDrawState.indexBuffer = batchedDrawBuffers[currentFrame].indexBuffer; batchedDrawState.indexBuffer->nextFrame(); @@ -641,8 +641,8 @@ void Graphics::createVulkanInstance() { } if (vkCreateInstance( - &createInfo, - nullptr, + &createInfo, + nullptr, &instance) != VK_SUCCESS) { throw love::Exception("couldn't create vulkan instance"); } @@ -730,7 +730,7 @@ int Graphics::rateDeviceSuitability(VkPhysicalDevice device) { int score = 1; - // optional + // optional if (deviceProperties.deviceType == VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU) { score += 1000; @@ -823,7 +823,7 @@ void Graphics::createLogicalDevice() { VkPhysicalDeviceDynamicRenderingFeatures dynamicRenderingFeature{}; dynamicRenderingFeature.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DYNAMIC_RENDERING_FEATURES; - dynamicRenderingFeature.dynamicRendering = VK_TRUE; + dynamicRenderingFeature.dynamicRendering = VK_FALSE; VkPhysicalDeviceFeatures deviceFeatures{}; deviceFeatures.samplerAnisotropy = VK_TRUE; @@ -1047,6 +1047,43 @@ void Graphics::createImageViews() { } } +std::vector Graphics::createSwapChainFramebuffers(VkRenderPass renderPass) { + std::vector swapChainFramebuffers; + swapChainFramebuffers.resize(swapChainImageViews.size()); + + for (size_t i = 0; i < swapChainImageViews.size(); i++) { + VkImageView attachments[] = { + swapChainImageViews[i] + }; + + VkFramebufferCreateInfo createInfo{}; + createInfo.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO; + createInfo.renderPass = renderPass; + createInfo.attachmentCount = 1; + createInfo.pAttachments = attachments; + createInfo.width = swapChainExtent.width; + createInfo.height = swapChainExtent.height; + createInfo.layers = 1; + + if (vkCreateFramebuffer(device, &createInfo, nullptr, &swapChainFramebuffers[i]) != VK_SUCCESS) { + throw love::Exception("failed to create framebuffer"); + } + } + + return swapChainFramebuffers; +} + +VkFramebuffer Graphics::getSwapChainFramebuffer(VkRenderPass renderPass) { + auto it = swapChainFramebufferVector.find(renderPass); + if (it != swapChainFramebufferVector.end()) { + return it->second.at(imageIndex); + } else { + auto frameBuffers = createSwapChainFramebuffers(renderPass); + swapChainFramebufferVector[renderPass] = frameBuffers; + return frameBuffers.at(imageIndex); + } +} + void Graphics::createDefaultShaders() { for (int i = 0; i < Shader::STANDARD_MAX_ENUM; i++) { auto stype = (Shader::StandardShader)i; @@ -1060,13 +1097,48 @@ void Graphics::createDefaultShaders() { } } +VkRenderPass Graphics::createRenderPass(RenderPassConfiguration configuration) { + VkAttachmentDescription colorDescription{}; + colorDescription.format = configuration.frameBufferFormat; + colorDescription.samples = VK_SAMPLE_COUNT_1_BIT; + colorDescription.loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; + colorDescription.storeOp = VK_ATTACHMENT_STORE_OP_STORE; + colorDescription.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; + colorDescription.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; + colorDescription.initialLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; + colorDescription.finalLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; + + VkAttachmentReference colorAttachmentRef{}; + colorAttachmentRef.attachment = 0; + colorAttachmentRef.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; + + VkSubpassDescription subPass{}; + subPass.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS; + subPass.colorAttachmentCount = 1; + subPass.pColorAttachments = &colorAttachmentRef; + + VkRenderPassCreateInfo createInfo{}; + createInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO; + createInfo.attachmentCount = 1; + createInfo.pAttachments = &colorDescription; + createInfo.subpassCount = 1; + createInfo.pSubpasses = &subPass; + + VkRenderPass renderPass; + if (vkCreateRenderPass(device, &createInfo, nullptr, &renderPass) != VK_SUCCESS) { + throw love::Exception("failed to create render pass"); + } + + return renderPass; +} + bool Graphics::usesConstantVertexColor(const VertexAttributes& vertexAttributes) { return !!(vertexAttributes.enableBits & (1u << ATTRIB_COLOR)); } void Graphics::createVulkanVertexFormat( - VertexAttributes vertexAttributes, - std::vector &bindingDescriptions, + VertexAttributes vertexAttributes, + std::vector &bindingDescriptions, std::vector &attributeDescriptions) { std::set usedBuffers; @@ -1075,7 +1147,7 @@ void Graphics::createVulkanVertexFormat( bool usesColor = false; uint8_t highestBufferBinding = 0; - + for (uint32_t i = 0; i < VertexAttributes::MAX; i++) { // change to loop like in opengl implementation ? uint32 bit = 1u << i; if (allBits & bit) { @@ -1135,6 +1207,7 @@ void Graphics::createVulkanVertexFormat( void Graphics::prepareDraw(const VertexAttributes& attributes, const BufferBindings& buffers, graphics::Texture* texture, PrimitiveType primitiveType, CullMode cullmode) { GraphicsPipelineConfiguration configuration; + configuration.renderPass = currentRenderPass; configuration.vertexAttributes = attributes; configuration.shader = (Shader*)Shader::current; configuration.primitiveType = primitiveType; @@ -1143,7 +1216,6 @@ void Graphics::prepareDraw(const VertexAttributes& attributes, const BufferBindi configuration.colorChannelMask = states.back().colorMask; configuration.winding = states.back().winding; configuration.cullmode = cullmode; - configuration.framebufferFormat = currentFramebufferOutputFormat; configuration.viewportWidth = currentViewportWidth; configuration.viewportHeight = currentViewportHeight; if (states.back().scissor) { @@ -1183,46 +1255,59 @@ void Graphics::prepareDraw(const VertexAttributes& attributes, const BufferBindi } void Graphics::startRenderPass(Texture* texture, uint32_t w, uint32_t h) { - VkRenderingAttachmentInfo colorAttachmentInfo{}; - colorAttachmentInfo.sType = VK_STRUCTURE_TYPE_RENDERING_ATTACHMENT_INFO; - colorAttachmentInfo.imageLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; - colorAttachmentInfo.loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; + RenderPassConfiguration renderPassConfiguration{}; + if (texture) { - colorAttachmentInfo.imageView = (VkImageView)texture->getRenderTargetHandle(); auto vulkanFormat = Vulkan::getTextureFormat(texture->getPixelFormat()); currentFramebufferOutputFormat = vulkanFormat.internalFormat; + renderPassConfiguration.frameBufferFormat = vulkanFormat.internalFormat; renderTargetTexture = texture; } else { - colorAttachmentInfo.imageView = swapChainImageViews[imageIndex]; currentFramebufferOutputFormat = swapChainImageFormat; + renderPassConfiguration.frameBufferFormat = swapChainImageFormat; renderTargetTexture = nullptr; } - colorAttachmentInfo.storeOp = VK_ATTACHMENT_STORE_OP_STORE; - - VkRenderingInfo renderingInfo{}; - renderingInfo.sType = VK_STRUCTURE_TYPE_RENDERING_INFO; - renderingInfo.renderArea.extent.width = w; - renderingInfo.renderArea.extent.height = h; - renderingInfo.layerCount = 1; - renderingInfo.colorAttachmentCount = 1; - renderingInfo.pColorAttachments = &colorAttachmentInfo; currentViewportWidth = (float)w; currentViewportHeight = (float)h; - if (renderTargetTexture) { + VkRenderPass renderPass; + + auto it = renderPasses.find(renderPassConfiguration); + if (it != renderPasses.end()) { + renderPass = it->second; + } else { + renderPass = createRenderPass(renderPassConfiguration); + renderPasses[renderPassConfiguration] = renderPass; + } + + VkRenderPassBeginInfo renderPassInfo{}; + renderPassInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO; + renderPassInfo.renderPass = renderPass; + if (renderTargetTexture == nullptr) { + renderPassInfo.framebuffer = getSwapChainFramebuffer(renderPass); + } else { + renderPassInfo.framebuffer = (VkFramebuffer) texture->getRenderTargetHandle(); + } + renderPassInfo.renderArea.offset = {0, 0}; + renderPassInfo.renderArea.extent.width = static_cast(w); + renderPassInfo.renderArea.extent.height = static_cast(h); + + if (renderTargetTexture) { Vulkan::cmdTransitionImageLayout(commandBuffers.at(currentFrame), (VkImage)texture->getHandle(), VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL); } - vkCmdBeginRendering(commandBuffers.at(currentFrame), &renderingInfo); + vkCmdBeginRenderPass(commandBuffers.at(currentFrame), &renderPassInfo, VK_SUBPASS_CONTENTS_INLINE); + currentRenderPass = renderPass; currentGraphicsPipeline = VK_NULL_HANDLE; } void Graphics::endRenderPass() { - vkCmdEndRendering(commandBuffers.at(currentFrame)); + vkCmdEndRenderPass(commandBuffers.at(currentFrame)); + currentRenderPass = VK_NULL_HANDLE; if (renderTargetTexture) { Vulkan::cmdTransitionImageLayout(commandBuffers.at(currentFrame), (VkImage)renderTargetTexture->getHandle(), VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL); @@ -1281,7 +1366,7 @@ VkPipeline Graphics::createGraphicsPipeline(GraphicsPipelineConfiguration config std::vector bindingDescriptions; std::vector attributeDescriptions; - + createVulkanVertexFormat(configuration.vertexAttributes, bindingDescriptions, attributeDescriptions); VkPipelineVertexInputStateCreateInfo vertexInputInfo{}; @@ -1295,7 +1380,7 @@ VkPipeline Graphics::createGraphicsPipeline(GraphicsPipelineConfiguration config inputAssembly.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO; inputAssembly.topology = Vulkan::getPrimitiveTypeTopology(configuration.primitiveType); inputAssembly.primitiveRestartEnable = VK_FALSE; - + VkViewport viewport{}; viewport.x = 0.0f; viewport.y = 0.0f; @@ -1366,13 +1451,6 @@ VkPipeline Graphics::createGraphicsPipeline(GraphicsPipelineConfiguration config colorBlending.blendConstants[2] = 0.0f; colorBlending.blendConstants[3] = 0.0f; - VkFormat framebufferOutputFormat = configuration.framebufferFormat; - - VkPipelineRenderingCreateInfo pipelineRenderingCreateInfo{}; - pipelineRenderingCreateInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_RENDERING_CREATE_INFO; - pipelineRenderingCreateInfo.colorAttachmentCount = 1; - pipelineRenderingCreateInfo.pColorAttachmentFormats = &framebufferOutputFormat; - VkGraphicsPipelineCreateInfo pipelineInfo{}; pipelineInfo.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO; pipelineInfo.stageCount = static_cast(shaderStages.size()); @@ -1389,7 +1467,7 @@ VkPipeline Graphics::createGraphicsPipeline(GraphicsPipelineConfiguration config pipelineInfo.subpass = 0; pipelineInfo.basePipelineHandle = VK_NULL_HANDLE; pipelineInfo.basePipelineIndex = -1; - pipelineInfo.pNext = &pipelineRenderingCreateInfo; + pipelineInfo.renderPass = configuration.renderPass; VkPipeline graphicsPipeline; if (vkCreateGraphicsPipelines(device, VK_NULL_HANDLE, 1, &pipelineInfo, nullptr, &graphicsPipeline) != VK_SUCCESS) { @@ -1522,9 +1600,9 @@ void Graphics::cleanup() { } void Graphics::cleanupSwapChain() { - for (size_t i = 0; i < swapChainImageViews.size(); i++) { - vkDestroyImageView(device, swapChainImageViews[i], nullptr); - } + for (auto & swapChainImageView : swapChainImageViews) { + vkDestroyImageView(device, swapChainImageView, nullptr); + } vkDestroySwapchainKHR(device, swapChain, nullptr); } diff --git a/src/modules/graphics/vulkan/Graphics.h b/src/modules/graphics/vulkan/Graphics.h index 0507c25df..309a89640 100644 --- a/src/modules/graphics/vulkan/Graphics.h +++ b/src/modules/graphics/vulkan/Graphics.h @@ -24,7 +24,22 @@ namespace love { namespace graphics { namespace vulkan { +struct RenderPassConfiguration { + VkFormat frameBufferFormat; + + bool operator==(const RenderPassConfiguration& conf) const { + return memcmp(this, &conf, sizeof(RenderPassConfiguration)) == 0; + } +}; + +struct RenderPassConfigurationHasher { + size_t operator()(const RenderPassConfiguration &configuration) const { + return XXH32(&configuration, sizeof(RenderPassConfiguration), 0); + } +}; + struct GraphicsPipelineConfiguration { + VkRenderPass renderPass; VertexAttributes vertexAttributes; Shader* shader = nullptr; PrimitiveType primitiveType = PRIMITIVE_MAX_ENUM; @@ -33,7 +48,6 @@ struct GraphicsPipelineConfiguration { ColorChannelMask colorChannelMask; Winding winding; CullMode cullmode; - VkFormat framebufferFormat; float viewportWidth; float viewportHeight; std::optional scissorRect; @@ -172,7 +186,10 @@ private: VkExtent2D chooseSwapExtent(const VkSurfaceCapabilitiesKHR& capabilities); void createSwapChain(); void createImageViews(); + std::vector createSwapChainFramebuffers(VkRenderPass); + VkFramebuffer getSwapChainFramebuffer(VkRenderPass); void createDefaultShaders(); + VkRenderPass createRenderPass(RenderPassConfiguration); VkPipeline createGraphicsPipeline(GraphicsPipelineConfiguration); void createCommandPool(); void createCommandBuffers(); @@ -207,8 +224,10 @@ private: VkFormat swapChainImageFormat = VK_FORMAT_UNDEFINED; VkExtent2D swapChainExtent = VkExtent2D(); std::vector swapChainImageViews; - VkPipelineLayout pipelineLayout = VK_NULL_HANDLE; + std::unordered_map> swapChainFramebufferVector; VkPipeline currentGraphicsPipeline = VK_NULL_HANDLE; + VkRenderPass currentRenderPass = VK_NULL_HANDLE; + std::unordered_map renderPasses; std::unordered_map graphicsPipelines; std::unordered_map samplers; VkCommandPool commandPool = VK_NULL_HANDLE;