diff --git a/src/modules/graphics/vulkan/Graphics.cpp b/src/modules/graphics/vulkan/Graphics.cpp index 7166b22f9..ebc35cdab 100644 --- a/src/modules/graphics/vulkan/Graphics.cpp +++ b/src/modules/graphics/vulkan/Graphics.cpp @@ -110,66 +110,10 @@ void Graphics::clear(OptionalColorD color, OptionalInt stencil, OptionalDouble d flushBatchedDraws(); - if (!renderPassState.active) - startRenderPass(); - - VkClearAttachment attachment{}; - - if (color.hasValue) - { - Colorf cf((float)color.value.r, (float)color.value.g, (float)color.value.b, (float)color.value.a); - gammaCorrectColor(cf); - - attachment.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; - attachment.clearValue.color.float32[0] = static_cast(cf.r); - attachment.clearValue.color.float32[1] = static_cast(cf.g); - attachment.clearValue.color.float32[2] = static_cast(cf.b); - attachment.clearValue.color.float32[3] = static_cast(cf.a); - } - - VkClearAttachment depthStencilAttachment{}; - - if (stencil.hasValue) - { - depthStencilAttachment.aspectMask = VK_IMAGE_ASPECT_STENCIL_BIT; - depthStencilAttachment.clearValue.depthStencil.stencil = static_cast(stencil.value); - } - if (depth.hasValue) - { - depthStencilAttachment.aspectMask |= VK_IMAGE_ASPECT_DEPTH_BIT; - depthStencilAttachment.clearValue.depthStencil.depth = static_cast(depth.value); - } - - std::array attachments = { - attachment, - depthStencilAttachment - }; - - VkClearRect rect{}; - rect.layerCount = 1; - rect.rect.extent.width = static_cast(renderPassState.width); - rect.rect.extent.height = static_cast(renderPassState.height); - - vkCmdClearAttachments( - commandBuffers[currentFrame], - static_cast(attachments.size()), attachments.data(), - 1, &rect); -} - -void Graphics::clear(const std::vector &colors, OptionalInt stencil, OptionalDouble depth) -{ - if (colors.empty() && !stencil.hasValue && !depth.hasValue) - return; - - flushBatchedDraws(); - - if (!renderPassState.active) - startRenderPass(); - - std::vector attachments; - for (const auto &color : colors) + if (renderPassState.active) { VkClearAttachment attachment{}; + if (color.hasValue) { Colorf cf((float)color.value.r, (float)color.value.g, (float)color.value.b, (float)color.value.a); @@ -181,33 +125,154 @@ void Graphics::clear(const std::vector &colors, OptionalInt sten attachment.clearValue.color.float32[2] = static_cast(cf.b); attachment.clearValue.color.float32[3] = static_cast(cf.a); } - attachments.push_back(attachment); + + VkClearAttachment depthStencilAttachment{}; + + if (stencil.hasValue) + { + depthStencilAttachment.aspectMask = VK_IMAGE_ASPECT_STENCIL_BIT; + depthStencilAttachment.clearValue.depthStencil.stencil = static_cast(stencil.value); + } + if (depth.hasValue) + { + depthStencilAttachment.aspectMask |= VK_IMAGE_ASPECT_DEPTH_BIT; + depthStencilAttachment.clearValue.depthStencil.depth = static_cast(depth.value); + } + + std::array attachments = { + attachment, + depthStencilAttachment + }; + + VkClearRect rect{}; + rect.layerCount = 1; + rect.rect.extent.width = static_cast(renderPassState.width); + rect.rect.extent.height = static_cast(renderPassState.height); + + vkCmdClearAttachments( + commandBuffers[currentFrame], + static_cast(attachments.size()), attachments.data(), + 1, &rect); } - - VkClearAttachment depthStencilAttachment{}; - - if (stencil.hasValue) + else { - depthStencilAttachment.aspectMask |= VK_IMAGE_ASPECT_STENCIL_BIT; - depthStencilAttachment.clearValue.depthStencil.stencil = static_cast(stencil.value); + renderPassState.useConfigurations = true; + + if (color.hasValue) + { + renderPassState.renderPassConfiguration.colorAttachments[0].loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR; + renderPassState.clearColors[0].color.float32[0] = static_cast(color.value.r); + renderPassState.clearColors[0].color.float32[1] = static_cast(color.value.g); + renderPassState.clearColors[0].color.float32[2] = static_cast(color.value.b); + renderPassState.clearColors[0].color.float32[3] = static_cast(color.value.a); + } + + if (depth.hasValue) + { + renderPassState.renderPassConfiguration.staticData.depthStencilAttachment.depthLoadOp = VK_ATTACHMENT_LOAD_OP_CLEAR; + renderPassState.clearColors[1].depthStencil.depth = static_cast(depth.value); + } + + if (stencil.hasValue) + { + renderPassState.renderPassConfiguration.staticData.depthStencilAttachment.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_CLEAR; + renderPassState.clearColors[1].depthStencil.stencil = static_cast(stencil.value); + } + + if (renderPassState.isWindow) + { + renderPassState.windowClearRequested = true; + renderPassState.mainWindowClearColorValue = color; + renderPassState.mainWindowClearDepthValue = depth; + renderPassState.mainWindowClearStencilValue = stencil; + } + else + startRenderPass(); } - if (depth.hasValue) +} + +void Graphics::clear(const std::vector &colors, OptionalInt stencil, OptionalDouble depth) +{ + if (colors.empty() && !stencil.hasValue && !depth.hasValue) + return; + + flushBatchedDraws(); + + if (renderPassState.active) { - depthStencilAttachment.aspectMask |= VK_IMAGE_ASPECT_DEPTH_BIT; - depthStencilAttachment.clearValue.depthStencil.depth = static_cast(depth.value); + std::vector attachments; + for (const auto &color : colors) + { + VkClearAttachment attachment{}; + if (color.hasValue) + { + Colorf cf((float)color.value.r, (float)color.value.g, (float)color.value.b, (float)color.value.a); + gammaCorrectColor(cf); + + attachment.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + attachment.clearValue.color.float32[0] = static_cast(cf.r); + attachment.clearValue.color.float32[1] = static_cast(cf.g); + attachment.clearValue.color.float32[2] = static_cast(cf.b); + attachment.clearValue.color.float32[3] = static_cast(cf.a); + } + attachments.push_back(attachment); + } + + VkClearAttachment depthStencilAttachment{}; + + if (stencil.hasValue) + { + depthStencilAttachment.aspectMask |= VK_IMAGE_ASPECT_STENCIL_BIT; + depthStencilAttachment.clearValue.depthStencil.stencil = static_cast(stencil.value); + } + if (depth.hasValue) + { + depthStencilAttachment.aspectMask |= VK_IMAGE_ASPECT_DEPTH_BIT; + depthStencilAttachment.clearValue.depthStencil.depth = static_cast(depth.value); + } + + attachments.push_back(depthStencilAttachment); + + VkClearRect rect{}; + rect.layerCount = 1; + rect.rect.extent.width = static_cast(renderPassState.width); + rect.rect.extent.height = static_cast(renderPassState.height); + + vkCmdClearAttachments( + commandBuffers[currentFrame], + static_cast(attachments.size()), attachments.data(), + 1, &rect); } + else + { + renderPassState.useConfigurations = true; - attachments.push_back(depthStencilAttachment); + for (size_t i = 0; i < colors.size(); i++) + { + if (colors[i].hasValue) + { + renderPassState.renderPassConfiguration.colorAttachments[i].loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR; + renderPassState.clearColors[i].color.float32[0] = colors[i].value.r; + renderPassState.clearColors[i].color.float32[1] = colors[i].value.g; + renderPassState.clearColors[i].color.float32[2] = colors[i].value.b; + renderPassState.clearColors[i].color.float32[3] = colors[i].value.a; + } + } - VkClearRect rect{}; - rect.layerCount = 1; - rect.rect.extent.width = static_cast(renderPassState.width); - rect.rect.extent.height = static_cast(renderPassState.height); + if (depth.hasValue) + { + renderPassState.renderPassConfiguration.staticData.depthStencilAttachment.depthLoadOp = VK_ATTACHMENT_LOAD_OP_LOAD; + renderPassState.clearColors[colors.size()].depthStencil.depth = depth.value; + } - vkCmdClearAttachments( - commandBuffers[currentFrame], - static_cast(attachments.size()), attachments.data(), - 1, &rect); + if (stencil.hasValue) + { + renderPassState.renderPassConfiguration.staticData.depthStencilAttachment.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_CLEAR; + renderPassState.clearColors[colors.size()].depthStencil.stencil = stencil.value; + } + + startRenderPass(); + } } void Graphics::discard(const std::vector &colorbuffers, bool depthstencil) @@ -215,40 +280,19 @@ void Graphics::discard(const std::vector &colorbuffers, bool depthstencil) if (renderPassState.active) endRenderPass(); - if (renderPassState.useConfigurations) - { - auto & renderPassConfiguration = renderPassState.renderPassConfiguration; + renderPassState.useConfigurations = true; + auto & renderPassConfiguration = renderPassState.renderPassConfiguration; - for (size_t i = 0; i < colorbuffers.size(); i++) - renderPassConfiguration.colorAttachments[i].discard = colorbuffers[i]; - renderPassConfiguration.staticData.depthAttachment.discard = depthstencil; + for (size_t i = 0; i < colorbuffers.size(); i++) + { + if (colorbuffers[i]) + renderPassConfiguration.colorAttachments[i].loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; } - else + + if (depthstencil) { - RenderPassConfiguration renderPassConfiguration{}; - renderPassConfiguration.colorAttachments.push_back({ swapChainImageFormat, colorbuffers[0], msaaSamples }); - renderPassConfiguration.staticData.depthAttachment = { findDepthFormat(), depthstencil, msaaSamples }; - if (msaaSamples & VK_SAMPLE_COUNT_1_BIT) - renderPassConfiguration.staticData.resolve = false; - else - renderPassConfiguration.staticData.resolve = true; - - FramebufferConfiguration framebufferConfiguration{}; - framebufferConfiguration.staticData.depthView = depthImageView; - if (msaaSamples & VK_SAMPLE_COUNT_1_BIT) - { - framebufferConfiguration.colorViews.push_back(swapChainImageViews.at(imageIndex)); - framebufferConfiguration.staticData.resolveView = VK_NULL_HANDLE; - } - else - { - framebufferConfiguration.colorViews.push_back(colorImageView); - framebufferConfiguration.staticData.resolveView = swapChainImageViews.at(imageIndex); - } - - renderPassState.useConfigurations = true; - renderPassState.renderPassConfiguration = renderPassConfiguration; - renderPassState.framebufferConfiguration = framebufferConfiguration; + renderPassConfiguration.staticData.depthStencilAttachment.depthLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; + renderPassConfiguration.staticData.depthStencilAttachment.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; } startRenderPass(); @@ -422,6 +466,9 @@ void Graphics::present(void *screenshotCallbackdata) if (isRenderTargetActive()) throw love::Exception("present cannot be called while a render target is active."); + if (!renderPassState.active && renderPassState.windowClearRequested) + startRenderPass(); + deprecations.draw(this); submitGpuCommands(true, screenshotCallbackdata); @@ -1938,8 +1985,8 @@ void Graphics::createScreenshotCallbackBuffers() void Graphics::createDefaultRenderPass() { RenderPassConfiguration renderPassConfiguration{}; - renderPassConfiguration.colorAttachments.push_back({ swapChainImageFormat, false, msaaSamples }); - renderPassConfiguration.staticData.depthAttachment = { findDepthFormat(), false, msaaSamples }; + renderPassConfiguration.colorAttachments.push_back({ swapChainImageFormat, VK_ATTACHMENT_LOAD_OP_LOAD, msaaSamples }); + renderPassConfiguration.staticData.depthStencilAttachment = { findDepthFormat(), VK_ATTACHMENT_LOAD_OP_LOAD, VK_ATTACHMENT_LOAD_OP_LOAD, msaaSamples }; if (msaaSamples & VK_SAMPLE_COUNT_1_BIT) renderPassConfiguration.staticData.resolve = false; else @@ -2050,10 +2097,7 @@ VkRenderPass Graphics::createRenderPass(RenderPassConfiguration &configuration) VkAttachmentDescription colorDescription{}; colorDescription.format = colorAttachment.format; colorDescription.samples = colorAttachment.msaaSamples; - if (colorAttachment.discard) - colorDescription.loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; - else - colorDescription.loadOp = VK_ATTACHMENT_LOAD_OP_LOAD; + colorDescription.loadOp = colorAttachment.loadOp; colorDescription.storeOp = VK_ATTACHMENT_STORE_OP_STORE; colorDescription.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; colorDescription.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; @@ -2066,24 +2110,18 @@ VkRenderPass Graphics::createRenderPass(RenderPassConfiguration &configuration) subPass.pColorAttachments = colorAttachmentRefs.data(); VkAttachmentReference depthStencilAttachmentRef{}; - if (configuration.staticData.depthAttachment.format != VK_FORMAT_UNDEFINED) + if (configuration.staticData.depthStencilAttachment.format != VK_FORMAT_UNDEFINED) { depthStencilAttachmentRef.attachment = attachment++; depthStencilAttachmentRef.layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; subPass.pDepthStencilAttachment = &depthStencilAttachmentRef; VkAttachmentDescription depthStencilAttachment{}; - depthStencilAttachment.format = configuration.staticData.depthAttachment.format; - depthStencilAttachment.samples = configuration.staticData.depthAttachment.msaaSamples; - if (configuration.staticData.depthAttachment.discard) - depthStencilAttachment.loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; - else - depthStencilAttachment.loadOp = VK_ATTACHMENT_LOAD_OP_LOAD; + depthStencilAttachment.format = configuration.staticData.depthStencilAttachment.format; + depthStencilAttachment.samples = configuration.staticData.depthStencilAttachment.msaaSamples; + depthStencilAttachment.loadOp = configuration.staticData.depthStencilAttachment.depthLoadOp; depthStencilAttachment.storeOp = VK_ATTACHMENT_STORE_OP_STORE; - if (configuration.staticData.depthAttachment.discard) - depthStencilAttachment.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; - else - depthStencilAttachment.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_LOAD; + depthStencilAttachment.stencilLoadOp = configuration.staticData.depthStencilAttachment.stencilLoadOp; depthStencilAttachment.stencilStoreOp = VK_ATTACHMENT_STORE_OP_STORE; depthStencilAttachment.initialLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; depthStencilAttachment.finalLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; @@ -2285,13 +2323,18 @@ void Graphics::prepareDraw(const VertexAttributes &attributes, const BufferBindi void Graphics::setDefaultRenderPass() { + uint32_t numClearValues = 2; + renderPassState.clearColors.resize(numClearValues); + renderPassState.beginInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO; renderPassState.beginInfo.renderPass = defaultRenderPass; renderPassState.beginInfo.framebuffer = defaultFramebuffers[imageIndex]; renderPassState.beginInfo.renderArea.offset = { 0, 0 }; renderPassState.beginInfo.renderArea.extent = swapChainExtent; - renderPassState.beginInfo.clearValueCount = 0; + renderPassState.beginInfo.clearValueCount = numClearValues; + renderPassState.beginInfo.pClearValues = renderPassState.clearColors.data(); + renderPassState.isWindow = true; renderPassState.useConfigurations = false; renderPassState.pipeline = VK_NULL_HANDLE; renderPassState.width = static_cast(swapChainExtent.width); @@ -2299,6 +2342,36 @@ void Graphics::setDefaultRenderPass() renderPassState.msaa = msaaSamples; renderPassState.numColorAttachments = 1; renderPassState.transitionImages.clear(); + + RenderPassConfiguration renderPassConfiguration{}; + renderPassConfiguration.colorAttachments.push_back({ swapChainImageFormat, VK_ATTACHMENT_LOAD_OP_LOAD, msaaSamples }); + renderPassConfiguration.staticData.depthStencilAttachment = { findDepthFormat(), VK_ATTACHMENT_LOAD_OP_LOAD, VK_ATTACHMENT_LOAD_OP_LOAD, msaaSamples }; + if (msaaSamples & VK_SAMPLE_COUNT_1_BIT) + renderPassConfiguration.staticData.resolve = false; + else + renderPassConfiguration.staticData.resolve = true; + + FramebufferConfiguration framebufferConfiguration{}; + framebufferConfiguration.staticData.depthView = depthImageView; + framebufferConfiguration.staticData.width = swapChainExtent.width; + framebufferConfiguration.staticData.height = swapChainExtent.height; + + if (msaaSamples & VK_SAMPLE_COUNT_1_BIT) + { + framebufferConfiguration.colorViews.push_back(swapChainImageViews.at(imageIndex)); + framebufferConfiguration.staticData.resolveView = VK_NULL_HANDLE; + } + else + { + framebufferConfiguration.colorViews.push_back(colorImageView); + framebufferConfiguration.staticData.resolveView = swapChainImageViews.at(imageIndex); + } + + renderPassState.renderPassConfiguration = renderPassConfiguration; + renderPassState.framebufferConfiguration = framebufferConfiguration; + + if (renderPassState.windowClearRequested) + clear(renderPassState.mainWindowClearColorValue, renderPassState.mainWindowClearStencilValue, renderPassState.mainWindowClearDepthValue); } void Graphics::setRenderPass(const RenderTargets &rts, int pixelw, int pixelh, bool hasSRGBtexture) @@ -2310,12 +2383,13 @@ void Graphics::setRenderPass(const RenderTargets &rts, int pixelw, int pixelh, b for (const auto &color : rts.colors) renderPassConfiguration.colorAttachments.push_back({ Vulkan::getTextureFormat(color.texture->getPixelFormat(), isPixelFormatSRGB(color.texture->getPixelFormat())).internalFormat, - false, + VK_ATTACHMENT_LOAD_OP_LOAD, dynamic_cast(color.texture)->getMsaaSamples() }); if (rts.depthStencil.texture != nullptr) - renderPassConfiguration.staticData.depthAttachment = { + renderPassConfiguration.staticData.depthStencilAttachment = { Vulkan::getTextureFormat(rts.depthStencil.texture->getPixelFormat(), false).internalFormat, - false, + VK_ATTACHMENT_LOAD_OP_LOAD, + VK_ATTACHMENT_LOAD_OP_LOAD, dynamic_cast(rts.depthStencil.texture)->getMsaaSamples() }; FramebufferConfiguration configuration{}; @@ -2333,14 +2407,19 @@ void Graphics::setRenderPass(const RenderTargets &rts, int pixelw, int pixelh, b configuration.staticData.width = static_cast(pixelw); configuration.staticData.height = static_cast(pixelh); + uint32_t numClearValues = rts.colors.size() + 1; + renderPassState.clearColors.resize(numClearValues); + renderPassState.beginInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO; renderPassState.beginInfo.renderPass = VK_NULL_HANDLE; renderPassState.beginInfo.framebuffer = VK_NULL_HANDLE; renderPassState.beginInfo.renderArea.offset = {0, 0}; renderPassState.beginInfo.renderArea.extent.width = static_cast(pixelw); renderPassState.beginInfo.renderArea.extent.height = static_cast(pixelh); - renderPassState.beginInfo.clearValueCount = 0; + renderPassState.beginInfo.clearValueCount = numClearValues; + renderPassState.beginInfo.pClearValues = renderPassState.clearColors.data(); + renderPassState.isWindow = false; renderPassState.useConfigurations = true; renderPassState.renderPassConfiguration = renderPassConfiguration; renderPassState.framebufferConfiguration = configuration; @@ -2356,6 +2435,9 @@ void Graphics::startRenderPass() { renderPassState.active = true; + if (renderPassState.isWindow && renderPassState.windowClearRequested) + renderPassState.windowClearRequested = false; + VkViewport viewport{}; viewport.x = 0.0f; viewport.y = 0.0f; diff --git a/src/modules/graphics/vulkan/Graphics.h b/src/modules/graphics/vulkan/Graphics.h index 3606cf842..06533d670 100644 --- a/src/modules/graphics/vulkan/Graphics.h +++ b/src/modules/graphics/vulkan/Graphics.h @@ -46,27 +46,43 @@ namespace graphics namespace vulkan { -struct RenderPassAttachment +struct ColorAttachment { VkFormat format = VK_FORMAT_UNDEFINED; - bool discard = true; + VkAttachmentLoadOp loadOp = VK_ATTACHMENT_LOAD_OP_LOAD; VkSampleCountFlagBits msaaSamples = VK_SAMPLE_COUNT_1_BIT; - bool operator==(const RenderPassAttachment &attachment) const + bool operator==(const ColorAttachment&attachment) const { return format == attachment.format && - discard == attachment.discard && + loadOp == attachment.loadOp && + msaaSamples == attachment.msaaSamples; + } +}; + +struct DepthStencilAttachment +{ + VkFormat format = VK_FORMAT_UNDEFINED; + VkAttachmentLoadOp depthLoadOp = VK_ATTACHMENT_LOAD_OP_LOAD; + VkAttachmentLoadOp stencilLoadOp = VK_ATTACHMENT_LOAD_OP_LOAD; + VkSampleCountFlagBits msaaSamples = VK_SAMPLE_COUNT_1_BIT; + + bool operator==(const DepthStencilAttachment &attachment) const + { + return format == attachment.format && + depthLoadOp == attachment.depthLoadOp && + stencilLoadOp == attachment.stencilLoadOp && msaaSamples == attachment.msaaSamples; } }; struct RenderPassConfiguration { - std::vector colorAttachments; + std::vector colorAttachments; struct StaticRenderPassConfiguration { - RenderPassAttachment depthAttachment; + DepthStencilAttachment depthStencilAttachment; bool resolve = false; } staticData; @@ -216,6 +232,7 @@ struct RenderpassState { bool active = false; VkRenderPassBeginInfo beginInfo{}; + bool isWindow = false; bool useConfigurations = false; RenderPassConfiguration renderPassConfiguration{}; FramebufferConfiguration framebufferConfiguration{}; @@ -225,6 +242,12 @@ struct RenderpassState float width = 0.0f; float height = 0.0f; VkSampleCountFlagBits msaa = VK_SAMPLE_COUNT_1_BIT; + std::vector clearColors; + + bool windowClearRequested = false; + OptionalColorD mainWindowClearColorValue; + OptionalDouble mainWindowClearDepthValue; + OptionalInt mainWindowClearStencilValue; }; struct ScreenshotReadbackBuffer