diff --git a/src/modules/graphics/vulkan/Graphics.cpp b/src/modules/graphics/vulkan/Graphics.cpp index c9fe696d1..2131e4977 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,159 @@ 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); + if (color.hasValue) + { + renderPassState.renderPassConfiguration.colorAttachments[0].loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR; + + Colorf cf((float)color.value.r, (float)color.value.g, (float)color.value.b, (float)color.value.a); + gammaCorrectColor(cf); + + renderPassState.clearColors[0].color.float32[0] = static_cast(cf.r); + renderPassState.clearColors[0].color.float32[1] = static_cast(cf.g); + renderPassState.clearColors[0].color.float32[2] = static_cast(cf.b); + renderPassState.clearColors[0].color.float32[3] = static_cast(cf.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 + { + for (size_t i = 0; i < colors.size(); i++) + { + if (colors[i].hasValue) + { + renderPassState.renderPassConfiguration.colorAttachments[i].loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR; - attachments.push_back(depthStencilAttachment); + auto &color = colors[i]; + Colorf cf((float)color.value.r, (float)color.value.g, (float)color.value.b, (float)color.value.a); + gammaCorrectColor(cf); - VkClearRect rect{}; - rect.layerCount = 1; - rect.rect.extent.width = static_cast(renderPassState.width); - rect.rect.extent.height = static_cast(renderPassState.height); + renderPassState.clearColors[i].color.float32[0] = static_cast(cf.r); + renderPassState.clearColors[i].color.float32[1] = static_cast(cf.g); + renderPassState.clearColors[i].color.float32[2] = static_cast(cf.b); + renderPassState.clearColors[i].color.float32[3] = static_cast(cf.a); + } + } - vkCmdClearAttachments( - commandBuffers[currentFrame], - static_cast(attachments.size()), attachments.data(), - 1, &rect); + if (depth.hasValue) + { + renderPassState.renderPassConfiguration.staticData.depthStencilAttachment.depthLoadOp = VK_ATTACHMENT_LOAD_OP_CLEAR; + renderPassState.clearColors[colors.size()].depthStencil.depth = static_cast(depth.value); + } + + if (stencil.hasValue) + { + renderPassState.renderPassConfiguration.staticData.depthStencilAttachment.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_CLEAR; + renderPassState.clearColors[colors.size()].depthStencil.stencil = static_cast(stencil.value); + } + + startRenderPass(); + } } void Graphics::discard(const std::vector &colorbuffers, bool depthstencil) @@ -215,40 +285,18 @@ void Graphics::discard(const std::vector &colorbuffers, bool depthstencil) if (renderPassState.active) endRenderPass(); - if (renderPassState.useConfigurations) - { - auto & renderPassConfiguration = renderPassState.renderPassConfiguration; + 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 +470,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); @@ -493,6 +544,7 @@ bool Graphics::setMode(void *context, int width, int height, int pixelwidth, int createSurface(); pickPhysicalDevice(); createLogicalDevice(); + createPipelineCache(); initVMA(); initCapabilities(); createSwapChain(); @@ -502,8 +554,6 @@ bool Graphics::setMode(void *context, int width, int height, int pixelwidth, int createColorResources(); createDepthResources(); transitionColorDepthLayouts = true; - createDefaultRenderPass(); - createDefaultFramebuffers(); createCommandPool(); createCommandBuffers(); @@ -580,9 +630,9 @@ void Graphics::initCapabilities() capabilities.limits[LIMIT_CUBE_TEXTURE_SIZE] = properties.limits.maxImageDimensionCube; capabilities.limits[LIMIT_TEXEL_BUFFER_SIZE] = properties.limits.maxTexelBufferElements; capabilities.limits[LIMIT_SHADER_STORAGE_BUFFER_SIZE] = properties.limits.maxStorageBufferRange; - capabilities.limits[LIMIT_THREADGROUPS_X] = properties.limits.maxComputeWorkGroupSize[0]; - capabilities.limits[LIMIT_THREADGROUPS_Y] = properties.limits.maxComputeWorkGroupSize[1]; - capabilities.limits[LIMIT_THREADGROUPS_Z] = properties.limits.maxComputeWorkGroupSize[2]; + capabilities.limits[LIMIT_THREADGROUPS_X] = properties.limits.maxComputeWorkGroupCount[0]; + capabilities.limits[LIMIT_THREADGROUPS_Y] = properties.limits.maxComputeWorkGroupCount[1]; + capabilities.limits[LIMIT_THREADGROUPS_Z] = properties.limits.maxComputeWorkGroupCount[2]; capabilities.limits[LIMIT_RENDER_TARGETS] = properties.limits.maxColorAttachments; capabilities.limits[LIMIT_TEXTURE_MSAA] = static_cast(getMsaaCount(64)); capabilities.limits[LIMIT_ANISOTROPY] = properties.limits.maxSamplerAnisotropy; @@ -638,7 +688,7 @@ void Graphics::setFrontFaceWinding(Winding winding) states.back().winding = winding; - if (optionalDeviceFeatures.extendedDynamicState) + if (optionalDeviceExtensions.extendedDynamicState) vkCmdSetFrontFaceEXT( commandBuffers.at(currentFrame), Vulkan::getFrontFace(winding)); @@ -875,7 +925,7 @@ void Graphics::setStencilMode(StencilAction action, CompareMode compare, int val vkCmdSetStencilCompareMask(commandBuffers.at(currentFrame), VK_STENCIL_FRONT_AND_BACK, readmask); vkCmdSetStencilReference(commandBuffers.at(currentFrame), VK_STENCIL_FRONT_AND_BACK, value); - if (optionalDeviceFeatures.extendedDynamicState) + if (optionalDeviceExtensions.extendedDynamicState) vkCmdSetStencilOpEXT( commandBuffers.at(currentFrame), VK_STENCIL_FRONT_AND_BACK, @@ -893,7 +943,7 @@ void Graphics::setDepthMode(CompareMode compare, bool write) { flushBatchedDraws(); - if (optionalDeviceFeatures.extendedDynamicState) + if (optionalDeviceExtensions.extendedDynamicState) { vkCmdSetDepthCompareOpEXT( commandBuffers.at(currentFrame), Vulkan::getCompareOp(compare)); @@ -1035,6 +1085,8 @@ graphics::StreamBuffer *Graphics::newStreamBuffer(BufferUsage type, size_t size) bool Graphics::dispatch(love::graphics::Shader *shader, int x, int y, int z) { + usedShadersInFrame.insert(computeShader); + if (renderPassState.active) endRenderPass(); @@ -1050,6 +1102,8 @@ bool Graphics::dispatch(love::graphics::Shader *shader, int x, int y, int z) bool Graphics::dispatch(love::graphics::Shader *shader, love::graphics::Buffer *indirectargs, size_t argsoffset) { + usedShadersInFrame.insert(computeShader); + if (renderPassState.active) endRenderPass(); @@ -1094,7 +1148,7 @@ void Graphics::initDynamicState() vkCmdSetStencilCompareMask(commandBuffers.at(currentFrame), VK_STENCIL_FRONT_AND_BACK, states.back().stencil.readMask); vkCmdSetStencilReference(commandBuffers.at(currentFrame), VK_STENCIL_FRONT_AND_BACK, states.back().stencil.value); - if (optionalDeviceFeatures.extendedDynamicState) + if (optionalDeviceExtensions.extendedDynamicState) { vkCmdSetStencilOpEXT( commandBuffers.at(currentFrame), @@ -1176,6 +1230,8 @@ void Graphics::beginFrame() Vulkan::resetShaderSwitches(); + for (const auto shader : usedShadersInFrame) + shader->newFrame(); usedShadersInFrame.clear(); } @@ -1269,9 +1325,9 @@ graphics::Shader::BuiltinUniformData Graphics::getCurrentBuiltinUniformData() return data; } -const OptionalDeviceFeatures &Graphics::getEnabledOptionalDeviceExtensions() const +const OptionalDeviceExtensions &Graphics::getEnabledOptionalDeviceExtensions() const { - return optionalDeviceFeatures; + return optionalDeviceExtensions; } static void checkOptionalInstanceExtensions(OptionalInstanceExtensions &ext) @@ -1401,6 +1457,7 @@ void Graphics::pickPhysicalDevice() deviceApiVersion = properties.apiVersion; msaaSamples = getMsaaCount(requestedMsaa); + depthStencilFormat = findDepthFormat(); } bool Graphics::checkDeviceExtensionSupport(VkPhysicalDevice device) @@ -1498,7 +1555,7 @@ QueueFamilyIndices Graphics::findQueueFamilies(VkPhysicalDevice device) return indices; } -static void findOptionalDeviceExtensions(VkPhysicalDevice physicalDevice, OptionalDeviceFeatures &optionalDeviceFeatures) +static void findOptionalDeviceExtensions(VkPhysicalDevice physicalDevice, OptionalDeviceExtensions &optionalDeviceExtensions) { uint32_t extensionCount; vkEnumerateDeviceExtensionProperties(physicalDevice, nullptr, &extensionCount, nullptr); @@ -1509,19 +1566,17 @@ static void findOptionalDeviceExtensions(VkPhysicalDevice physicalDevice, Option for (const auto &extension : availableExtensions) { if (strcmp(extension.extensionName, VK_EXT_EXTENDED_DYNAMIC_STATE_EXTENSION_NAME) == 0) - optionalDeviceFeatures.extendedDynamicState = true; + optionalDeviceExtensions.extendedDynamicState = true; if (strcmp(extension.extensionName, VK_KHR_GET_MEMORY_REQUIREMENTS_2_EXTENSION_NAME) == 0) - optionalDeviceFeatures.memoryRequirements2 = true; + optionalDeviceExtensions.memoryRequirements2 = true; if (strcmp(extension.extensionName, VK_KHR_DEDICATED_ALLOCATION_EXTENSION_NAME) == 0) - optionalDeviceFeatures.dedicatedAllocation = true; + optionalDeviceExtensions.dedicatedAllocation = true; if (strcmp(extension.extensionName, VK_KHR_BUFFER_DEVICE_ADDRESS_EXTENSION_NAME) == 0) - optionalDeviceFeatures.bufferDeviceAddress = true; - if (strcmp(extension.extensionName, VK_EXT_MEMORY_BUDGET_EXTENSION_NAME) == 0) - optionalDeviceFeatures.memoryBudget = true; + optionalDeviceExtensions.memoryBudget = true; if (strcmp(extension.extensionName, VK_KHR_SHADER_FLOAT_CONTROLS_EXTENSION_NAME) == 0) - optionalDeviceFeatures.shaderFloatControls = true; + optionalDeviceExtensions.shaderFloatControls = true; if (strcmp(extension.extensionName, VK_KHR_SPIRV_1_4_EXTENSION_NAME) == 0) - optionalDeviceFeatures.spirv14 = true; + optionalDeviceExtensions.spirv14 = true; } } @@ -1546,22 +1601,20 @@ void Graphics::createLogicalDevice() queueCreateInfos.push_back(queueCreateInfo); } - findOptionalDeviceExtensions(physicalDevice, optionalDeviceFeatures); + findOptionalDeviceExtensions(physicalDevice, optionalDeviceExtensions); // sanity check for dependencies. - if (optionalDeviceFeatures.extendedDynamicState && !optionalInstanceExtensions.physicalDeviceProperties2) - optionalDeviceFeatures.extendedDynamicState = false; - if (optionalDeviceFeatures.dedicatedAllocation && !optionalDeviceFeatures.memoryRequirements2) - optionalDeviceFeatures.dedicatedAllocation = false; - if (optionalDeviceFeatures.bufferDeviceAddress && !optionalInstanceExtensions.physicalDeviceProperties2) - optionalDeviceFeatures.bufferDeviceAddress = false; - if (optionalDeviceFeatures.memoryBudget && !optionalInstanceExtensions.physicalDeviceProperties2) - optionalDeviceFeatures.memoryBudget = false; - if (optionalDeviceFeatures.spirv14 && !optionalDeviceFeatures.shaderFloatControls) - optionalDeviceFeatures.spirv14 = false; - if (optionalDeviceFeatures.spirv14 && deviceApiVersion < VK_API_VERSION_1_1) - optionalDeviceFeatures.spirv14 = false; + if (optionalDeviceExtensions.extendedDynamicState && !optionalInstanceExtensions.physicalDeviceProperties2) + optionalDeviceExtensions.extendedDynamicState = false; + if (optionalDeviceExtensions.dedicatedAllocation && !optionalDeviceExtensions.memoryRequirements2) + optionalDeviceExtensions.dedicatedAllocation = false; + if (optionalDeviceExtensions.memoryBudget && !optionalInstanceExtensions.physicalDeviceProperties2) + optionalDeviceExtensions.memoryBudget = false; + if (optionalDeviceExtensions.spirv14 && !optionalDeviceExtensions.shaderFloatControls) + optionalDeviceExtensions.spirv14 = false; + if (optionalDeviceExtensions.spirv14 && deviceApiVersion < VK_API_VERSION_1_1) + optionalDeviceExtensions.spirv14 = false; VkPhysicalDeviceFeatures deviceFeatures{}; deviceFeatures.samplerAnisotropy = VK_TRUE; @@ -1574,19 +1627,17 @@ void Graphics::createLogicalDevice() createInfo.pEnabledFeatures = &deviceFeatures; std::vector enabledExtensions(deviceExtensions.begin(), deviceExtensions.end()); - if (optionalDeviceFeatures.extendedDynamicState) + if (optionalDeviceExtensions.extendedDynamicState) enabledExtensions.push_back(VK_EXT_EXTENDED_DYNAMIC_STATE_EXTENSION_NAME); - if (optionalDeviceFeatures.memoryRequirements2) + if (optionalDeviceExtensions.memoryRequirements2) enabledExtensions.push_back(VK_KHR_GET_MEMORY_REQUIREMENTS_2_EXTENSION_NAME); - if (optionalDeviceFeatures.dedicatedAllocation) + if (optionalDeviceExtensions.dedicatedAllocation) enabledExtensions.push_back(VK_KHR_DEDICATED_ALLOCATION_EXTENSION_NAME); - if (optionalDeviceFeatures.bufferDeviceAddress) - enabledExtensions.push_back(VK_KHR_BUFFER_DEVICE_ADDRESS_EXTENSION_NAME); - if (optionalDeviceFeatures.memoryBudget) + if (optionalDeviceExtensions.memoryBudget) enabledExtensions.push_back(VK_EXT_MEMORY_BUDGET_EXTENSION_NAME); - if (optionalDeviceFeatures.shaderFloatControls) + if (optionalDeviceExtensions.shaderFloatControls) enabledExtensions.push_back(VK_KHR_SHADER_FLOAT_CONTROLS_EXTENSION_NAME); - if (optionalDeviceFeatures.spirv14) + if (optionalDeviceExtensions.spirv14) enabledExtensions.push_back(VK_KHR_SPIRV_1_4_EXTENSION_NAME); if (deviceApiVersion >= VK_API_VERSION_1_1) enabledExtensions.push_back(VK_KHR_BIND_MEMORY_2_EXTENSION_NAME); @@ -1602,7 +1653,7 @@ void Graphics::createLogicalDevice() VkPhysicalDeviceExtendedDynamicStateFeaturesEXT extendedDynamicStateFeatures{}; extendedDynamicStateFeatures.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTENDED_DYNAMIC_STATE_FEATURES_EXT; - extendedDynamicStateFeatures.extendedDynamicState = Vulkan::getBool(optionalDeviceFeatures.extendedDynamicState); + extendedDynamicStateFeatures.extendedDynamicState = Vulkan::getBool(optionalDeviceExtensions.extendedDynamicState); extendedDynamicStateFeatures.pNext = nullptr; createInfo.pNext = &extendedDynamicStateFeatures; @@ -1616,6 +1667,15 @@ void Graphics::createLogicalDevice() vkGetDeviceQueue(device, indices.presentFamily.value, 0, &presentQueue); } +void Graphics::createPipelineCache() +{ + VkPipelineCacheCreateInfo cacheInfo{}; + cacheInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_CACHE_CREATE_INFO; + + if (vkCreatePipelineCache(device, &cacheInfo, nullptr, &pipelineCache) != VK_SUCCESS) + throw love::Exception("could not create pipeline cache"); +} + void Graphics::initVMA() { VmaAllocatorCreateInfo allocatorCreateInfo = {}; @@ -1657,9 +1717,9 @@ void Graphics::initVMA() allocatorCreateInfo.pVulkanFunctions = &vulkanFunctions; allocatorCreateInfo.flags |= VMA_ALLOCATOR_CREATE_EXTERNALLY_SYNCHRONIZED_BIT; - if (optionalDeviceFeatures.dedicatedAllocation) + if (optionalDeviceExtensions.dedicatedAllocation) allocatorCreateInfo.flags |= VMA_ALLOCATOR_CREATE_KHR_DEDICATED_ALLOCATION_BIT; - if (optionalDeviceFeatures.memoryBudget) + if (optionalDeviceExtensions.memoryBudget) allocatorCreateInfo.flags |= VMA_ALLOCATOR_CREATE_EXT_MEMORY_BUDGET_BIT; if (vmaCreateAllocator(&allocatorCreateInfo, &vmaAllocator) != VK_SUCCESS) @@ -1966,40 +2026,6 @@ void Graphics::createScreenshotCallbackBuffers() } } -void Graphics::createDefaultRenderPass() -{ - RenderPassConfiguration renderPassConfiguration{}; - renderPassConfiguration.colorAttachments.push_back({ swapChainImageFormat, false, msaaSamples }); - renderPassConfiguration.staticData.depthAttachment = { findDepthFormat(), false, msaaSamples }; - if (msaaSamples & VK_SAMPLE_COUNT_1_BIT) - renderPassConfiguration.staticData.resolve = false; - else - renderPassConfiguration.staticData.resolve = true; - defaultRenderPass = createRenderPass(renderPassConfiguration); -} - -void Graphics::createDefaultFramebuffers() -{ - defaultFramebuffers.clear(); - - for (const auto view : swapChainImageViews) - { - FramebufferConfiguration configuration{}; - configuration.staticData.renderPass = defaultRenderPass; - configuration.staticData.width = swapChainExtent.width; - configuration.staticData.height = swapChainExtent.height; - configuration.staticData.depthView = depthImageView; - if (msaaSamples & VK_SAMPLE_COUNT_1_BIT) - configuration.colorViews.push_back(view); - else - { - configuration.colorViews.push_back(colorImageView); - configuration.staticData.resolveView = view; - } - defaultFramebuffers.push_back(createFramebuffer(configuration)); - } -} - VkFramebuffer Graphics::createFramebuffer(FramebufferConfiguration &configuration) { std::vector attachments; @@ -2081,10 +2107,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; @@ -2097,24 +2120,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; @@ -2174,6 +2191,23 @@ VkRenderPass Graphics::createRenderPass(RenderPassConfiguration &configuration) return renderPass; } +VkRenderPass Graphics::getRenderPass(RenderPassConfiguration &configuration) +{ + VkRenderPass renderPass; + auto it = renderPasses.find(configuration); + if (it != renderPasses.end()) + renderPass = it->second; + else + { + renderPass = createRenderPass(configuration); + renderPasses[configuration] = renderPass; + } + + renderPassUsages[renderPass] = true; + + return renderPass; +} + bool Graphics::usesConstantVertexColor(const VertexAttributes &vertexAttributes) { return !!(vertexAttributes.enableBits & (1u << ATTRIB_COLOR)); @@ -2259,7 +2293,7 @@ void Graphics::prepareDraw(const VertexAttributes &attributes, const BufferBindi if (!renderPassState.active) startRenderPass(); - Shader::current->attach(); + usedShadersInFrame.insert((dynamic_cast(Shader::current))); GraphicsPipelineConfiguration configuration{}; @@ -2273,7 +2307,7 @@ void Graphics::prepareDraw(const VertexAttributes &attributes, const BufferBindi configuration.numColorAttachments = renderPassState.numColorAttachments; configuration.primitiveType = primitiveType; - if (optionalDeviceFeatures.extendedDynamicState) + if (optionalDeviceExtensions.extendedDynamicState) vkCmdSetCullModeEXT(commandBuffers.at(currentFrame), Vulkan::getCullMode(cullmode)); else { @@ -2316,20 +2350,54 @@ 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.renderPass = VK_NULL_HANDLE; + renderPassState.beginInfo.framebuffer = VK_NULL_HANDLE; 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.useConfigurations = false; + renderPassState.isWindow = true; renderPassState.pipeline = VK_NULL_HANDLE; renderPassState.width = static_cast(swapChainExtent.width); renderPassState.height = static_cast(swapChainExtent.height); 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 = { depthStencilFormat, 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 = std::move(renderPassConfiguration); + renderPassState.framebufferConfiguration = std::move(framebufferConfiguration); + + if (renderPassState.windowClearRequested) + clear(renderPassState.mainWindowClearColorValue, renderPassState.mainWindowClearStencilValue, renderPassState.mainWindowClearDepthValue); } void Graphics::setRenderPass(const RenderTargets &rts, int pixelw, int pixelh, bool hasSRGBtexture) @@ -2341,14 +2409,14 @@ 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) - if (rts.depthStencil.texture != nullptr) - renderPassConfiguration.staticData.depthAttachment = { - Vulkan::getTextureFormat(rts.depthStencil.texture->getPixelFormat(), false).internalFormat, - false, - dynamic_cast(rts.depthStencil.texture)->getMsaaSamples() }; + renderPassConfiguration.staticData.depthStencilAttachment = { + Vulkan::getTextureFormat(rts.depthStencil.texture->getPixelFormat(), false).internalFormat, + VK_ATTACHMENT_LOAD_OP_LOAD, + VK_ATTACHMENT_LOAD_OP_LOAD, + dynamic_cast(rts.depthStencil.texture)->getMsaaSamples() }; FramebufferConfiguration configuration{}; @@ -2365,15 +2433,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 = static_cast(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.useConfigurations = true; + renderPassState.isWindow = false; renderPassState.renderPassConfiguration = renderPassConfiguration; renderPassState.framebufferConfiguration = configuration; renderPassState.pipeline = VK_NULL_HANDLE; @@ -2388,6 +2460,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; @@ -2398,26 +2473,10 @@ void Graphics::startRenderPass() vkCmdSetViewport(commandBuffers.at(currentFrame), 0, 1, &viewport); - if (renderPassState.useConfigurations) - { - auto &renderPassConfiguration = renderPassState.renderPassConfiguration; - VkRenderPass renderPass; - auto it = renderPasses.find(renderPassConfiguration); - if (it != renderPasses.end()) - renderPass = it->second; - else - { - renderPass = createRenderPass(renderPassConfiguration); - renderPasses[renderPassConfiguration] = renderPass; - } - renderPassState.beginInfo.renderPass = renderPass; + renderPassState.beginInfo.renderPass = getRenderPass(renderPassState.renderPassConfiguration); - renderPassUsages[renderPass] = true; - - auto &framebufferConfiguration = renderPassState.framebufferConfiguration; - framebufferConfiguration.staticData.renderPass = renderPass; - renderPassState.beginInfo.framebuffer = getFramebuffer(framebufferConfiguration); - } + renderPassState.framebufferConfiguration.staticData.renderPass = renderPassState.beginInfo.renderPass; + renderPassState.beginInfo.framebuffer = getFramebuffer(renderPassState.framebufferConfiguration); for (const auto &image : renderPassState.transitionImages) Vulkan::cmdTransitionImageLayout(commandBuffers.at(currentFrame), image, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL); @@ -2433,6 +2492,12 @@ void Graphics::endRenderPass() for (const auto &image : renderPassState.transitionImages) Vulkan::cmdTransitionImageLayout(commandBuffers.at(currentFrame), image, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL); + + for (auto &colorAttachment : renderPassState.renderPassConfiguration.colorAttachments) + colorAttachment.loadOp = VK_ATTACHMENT_LOAD_OP_LOAD; + + renderPassState.renderPassConfiguration.staticData.depthStencilAttachment.depthLoadOp = VK_ATTACHMENT_LOAD_OP_LOAD; + renderPassState.renderPassConfiguration.staticData.depthStencilAttachment.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_LOAD; } VkSampler Graphics::createSampler(const SamplerState &samplerState) @@ -2523,11 +2588,6 @@ void Graphics::setComputeShader(Shader *shader) computeShader = shader; } -std::set &Graphics::getUsedShadersInFrame() -{ - return usedShadersInFrame; -} - VkSampler Graphics::getCachedSampler(const SamplerState &samplerState) { auto samplerkey = samplerState.toKey(); @@ -2577,7 +2637,7 @@ VkPipeline Graphics::createGraphicsPipeline(GraphicsPipelineConfiguration &confi rasterizer.rasterizerDiscardEnable = VK_FALSE; rasterizer.polygonMode = Vulkan::getPolygonMode(configuration.wireFrame); rasterizer.lineWidth = 1.0f; - if (!optionalDeviceFeatures.extendedDynamicState) + if (!optionalDeviceExtensions.extendedDynamicState) { rasterizer.cullMode = Vulkan::getCullMode(configuration.dynamicState.cullmode); rasterizer.frontFace = Vulkan::getFrontFace(configuration.dynamicState.winding); @@ -2596,7 +2656,7 @@ VkPipeline Graphics::createGraphicsPipeline(GraphicsPipelineConfiguration &confi VkPipelineDepthStencilStateCreateInfo depthStencil{}; depthStencil.sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO; depthStencil.depthTestEnable = VK_TRUE; - if (!optionalDeviceFeatures.extendedDynamicState) + if (!optionalDeviceExtensions.extendedDynamicState) { depthStencil.depthWriteEnable = Vulkan::getBool(configuration.dynamicState.depthState.write); depthStencil.depthCompareOp = Vulkan::getCompareOp(configuration.dynamicState.depthState.compare); @@ -2607,7 +2667,7 @@ VkPipeline Graphics::createGraphicsPipeline(GraphicsPipelineConfiguration &confi depthStencil.stencilTestEnable = VK_TRUE; - if (!optionalDeviceFeatures.extendedDynamicState) + if (!optionalDeviceExtensions.extendedDynamicState) { depthStencil.front.failOp = VK_STENCIL_OP_KEEP; depthStencil.front.passOp = Vulkan::getStencilOp(configuration.dynamicState.stencilAction); @@ -2647,7 +2707,7 @@ VkPipeline Graphics::createGraphicsPipeline(GraphicsPipelineConfiguration &confi std::vector dynamicStates; - if (optionalDeviceFeatures.extendedDynamicState) + if (optionalDeviceExtensions.extendedDynamicState) dynamicStates = { VK_DYNAMIC_STATE_SCISSOR, VK_DYNAMIC_STATE_VIEWPORT, @@ -2691,7 +2751,7 @@ VkPipeline Graphics::createGraphicsPipeline(GraphicsPipelineConfiguration &confi pipelineInfo.renderPass = configuration.renderPass; VkPipeline graphicsPipeline; - if (vkCreateGraphicsPipelines(device, VK_NULL_HANDLE, 1, &pipelineInfo, nullptr, &graphicsPipeline) != VK_SUCCESS) + if (vkCreateGraphicsPipelines(device, pipelineCache, 1, &pipelineInfo, nullptr, &graphicsPipeline) != VK_SUCCESS) throw love::Exception("failed to create graphics pipeline"); return graphicsPipeline; } @@ -2839,12 +2899,10 @@ VkFormat Graphics::findDepthFormat() void Graphics::createDepthResources() { - VkFormat depthAttachment = findDepthFormat(); - VkImageCreateInfo imageInfo{}; imageInfo.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO; imageInfo.imageType = VK_IMAGE_TYPE_2D; - imageInfo.format = depthAttachment; + imageInfo.format = depthStencilFormat; imageInfo.extent.width = swapChainExtent.width; imageInfo.extent.height = swapChainExtent.height; imageInfo.extent.depth = 1; @@ -2867,7 +2925,7 @@ void Graphics::createDepthResources() imageViewInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; imageViewInfo.image = depthImage; imageViewInfo.viewType = VK_IMAGE_VIEW_TYPE_2D; - imageViewInfo.format = depthAttachment; + imageViewInfo.format = depthStencilFormat; imageViewInfo.components.r = VK_COMPONENT_SWIZZLE_IDENTITY; imageViewInfo.components.g = VK_COMPONENT_SWIZZLE_IDENTITY; imageViewInfo.components.b = VK_COMPONENT_SWIZZLE_IDENTITY; @@ -2977,6 +3035,7 @@ void Graphics::cleanup() graphicsPipelines.clear(); vkDestroyCommandPool(device, commandPool, nullptr); + vkDestroyPipelineCache(device, pipelineCache, nullptr); vkDestroyDevice(device, nullptr); vkDestroySurfaceKHR(instance, surface, nullptr); vkDestroyInstance(instance, nullptr); @@ -2989,9 +3048,6 @@ void Graphics::cleanupSwapChain() vmaDestroyBuffer(vmaAllocator, readbackBuffer.buffer, readbackBuffer.allocation); vmaDestroyImage(vmaAllocator, readbackBuffer.image, readbackBuffer.imageAllocation); } - for (const auto &framebuffer : defaultFramebuffers) - vkDestroyFramebuffer(device, framebuffer, nullptr); - vkDestroyRenderPass(device, defaultRenderPass, nullptr); vkDestroyImageView(device, colorImageView, nullptr); vmaDestroyImage(vmaAllocator, colorImage, colorImageAllocation); vkDestroyImageView(device, depthImageView, nullptr); @@ -3015,8 +3071,6 @@ void Graphics::recreateSwapChain() createScreenshotCallbackBuffers(); createColorResources(); createDepthResources(); - createDefaultRenderPass(); - createDefaultFramebuffers(); transitionColorDepthLayouts = true; } diff --git a/src/modules/graphics/vulkan/Graphics.h b/src/modules/graphics/vulkan/Graphics.h index d699fbbc8..ddd7ee42c 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; @@ -82,7 +98,7 @@ struct RenderPassConfigurationHasher size_t operator()(const RenderPassConfiguration &configuration) const { size_t hashes[] = { - XXH32(configuration.colorAttachments.data(), configuration.colorAttachments.size() * sizeof(VkFormat), 0), + XXH32(configuration.colorAttachments.data(), configuration.colorAttachments.size() * sizeof(ColorAttachment), 0), XXH32(&configuration.staticData, sizeof(configuration.staticData), 0), }; return XXH32(hashes, sizeof(hashes), 0); @@ -130,7 +146,7 @@ struct OptionalInstanceExtensions bool physicalDeviceProperties2 = false; }; -struct OptionalDeviceFeatures +struct OptionalDeviceExtensions { // VK_EXT_extended_dynamic_state bool extendedDynamicState = false; @@ -141,9 +157,6 @@ struct OptionalDeviceFeatures // VK_KHR_dedicated_allocation bool dedicatedAllocation = false; - // VK_KHR_buffer_device_address - bool bufferDeviceAddress = false; - // VK_EXT_memory_budget bool memoryBudget = false; @@ -216,7 +229,7 @@ struct RenderpassState { bool active = false; VkRenderPassBeginInfo beginInfo{}; - bool useConfigurations = false; + bool isWindow = false; RenderPassConfiguration renderPassConfiguration{}; FramebufferConfiguration framebufferConfiguration{}; VkPipeline pipeline = VK_NULL_HANDLE; @@ -225,6 +238,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 @@ -293,9 +312,8 @@ public: graphics::Texture *getDefaultTexture() const; VkSampler getCachedSampler(const SamplerState &sampler); void setComputeShader(Shader *computeShader); - std::set &getUsedShadersInFrame(); graphics::Shader::BuiltinUniformData getCurrentBuiltinUniformData(); - const OptionalDeviceFeatures &getEnabledOptionalDeviceExtensions() const; + const OptionalDeviceExtensions &getEnabledOptionalDeviceExtensions() const; VkSampleCountFlagBits getMsaaCount(int requestedMsaa) const; void setVsync(int vsync); int getVsync() const; @@ -317,6 +335,7 @@ private: int rateDeviceSuitability(VkPhysicalDevice device); QueueFamilyIndices findQueueFamilies(VkPhysicalDevice device); void createLogicalDevice(); + void createPipelineCache(); void initVMA(); void createSurface(); bool checkDeviceExtensionSupport(VkPhysicalDevice device); @@ -328,12 +347,11 @@ private: void createSwapChain(); void createImageViews(); void createScreenshotCallbackBuffers(); - void createDefaultRenderPass(); - void createDefaultFramebuffers(); VkFramebuffer createFramebuffer(FramebufferConfiguration &configuration); VkFramebuffer getFramebuffer(FramebufferConfiguration &configuration); void createDefaultShaders(); VkRenderPass createRenderPass(RenderPassConfiguration &configuration); + VkRenderPass getRenderPass(RenderPassConfiguration &configuration); VkPipeline createGraphicsPipeline(GraphicsPipelineConfiguration &configuration); void createColorResources(); VkFormat findSupportedFormat(const std::vector &candidates, VkImageTiling tiling, VkFormatFeatureFlags features); @@ -375,7 +393,7 @@ private: int requestedMsaa = 0; VkDevice device = VK_NULL_HANDLE; OptionalInstanceExtensions optionalInstanceExtensions; - OptionalDeviceFeatures optionalDeviceFeatures; + OptionalDeviceExtensions optionalDeviceExtensions; VkQueue graphicsQueue = VK_NULL_HANDLE; VkQueue presentQueue = VK_NULL_HANDLE; VkSurfaceKHR surface = VK_NULL_HANDLE; @@ -384,6 +402,7 @@ private: Matrix4 displayRotation; std::vector swapChainImages; VkFormat swapChainImageFormat = VK_FORMAT_UNDEFINED; + VkFormat depthStencilFormat = VK_FORMAT_UNDEFINED; VkExtent2D swapChainExtent = VkExtent2D(); std::vector swapChainImageViews; VkSampleCountFlagBits msaaSamples = VK_SAMPLE_COUNT_1_BIT; @@ -393,8 +412,7 @@ private: VkImage depthImage = VK_NULL_HANDLE; VkImageView depthImageView = VK_NULL_HANDLE; VmaAllocation depthImageAllocation = VK_NULL_HANDLE; - VkRenderPass defaultRenderPass = VK_NULL_HANDLE; - std::vector defaultFramebuffers; + VkPipelineCache pipelineCache = VK_NULL_HANDLE; std::unordered_map renderPasses; std::unordered_map framebuffers; std::unordered_map graphicsPipelines; diff --git a/src/modules/graphics/vulkan/Shader.cpp b/src/modules/graphics/vulkan/Shader.cpp index d09cdb36a..94c06f53a 100644 --- a/src/modules/graphics/vulkan/Shader.cpp +++ b/src/modules/graphics/vulkan/Shader.cpp @@ -25,8 +25,6 @@ #include "libraries/glslang/SPIRV/GlslangToSpv.h" -#include - namespace love { namespace graphics @@ -144,6 +142,72 @@ static const TBuiltInResource defaultTBuiltInResource = { static const uint32_t STREAMBUFFER_DEFAULT_SIZE = 16; static const uint32_t DESCRIPTOR_POOL_SIZE = 1; +class BindingMapper +{ +public: + uint32_t operator()(spirv_cross::CompilerGLSL &comp, std::vector &spirv, const std::string &name, const spirv_cross::ID &id) + { + auto it = bindingMappings.find(name); + if (it == bindingMappings.end()) + { + auto binding = comp.get_decoration(id, spv::DecorationBinding); + + if (isFreeBinding(binding)) + { + bindingMappings[name] = binding; + return binding; + } + else + { + uint32_t freeBinding = getFreeBinding(); + + uint32_t binaryBindingOffset; + if (!comp.get_binary_offset_for_decoration(id, spv::DecorationBinding, binaryBindingOffset)) + throw love::Exception("could not get binary offset for binding"); + + spirv[binaryBindingOffset] = freeBinding; + + bindingMappings[name] = freeBinding; + + return freeBinding; + } + } + else + return it->second; + }; + + +private: + uint32_t getFreeBinding() { + for (uint32_t i = 0;; i++) + { + bool free = true; + for (const auto &entry : bindingMappings) + { + if (entry.second == i) + { + free = false; + break; + } + } + if (free) + return i; + } + } + + bool isFreeBinding(uint32_t binding) { + for (const auto &entry : bindingMappings) + { + if (entry.second == binding) + return false; + } + return true; + } + + std::map bindingMappings; + +}; + static VkShaderStageFlagBits getStageBit(ShaderStageType type) { switch (type) @@ -185,6 +249,8 @@ Shader::Shader(StrongRef stages[]) bool Shader::loadVolatile() { + device = vgfx->getDevice(); + computePipeline = VK_NULL_HANDLE; for (int i = 0; i < BUILTIN_MAX_ENUM; i++) @@ -200,6 +266,7 @@ bool Shader::loadVolatile() currentFrame = 0; currentUsedUniformStreamBuffersCount = 0; currentUsedDescriptorSetsCount = 0; + newFrame(); return true; } @@ -384,7 +451,7 @@ void Shader::cmdPushDescriptorSets(VkCommandBuffer commandBuffer, VkPipelineBind for (const auto &u : uniformInfos) { if (updatedUniforms.find(u.second.location) == updatedUniforms.end()) - updateUniform(&u.second, u.second.count); + updateUniform(&u.second, u.second.count, true); } vkCmdBindDescriptorSets(commandBuffer, bindPoint, pipelineLayout, 0, 1, ¤tDescriptorSet, 0, nullptr); @@ -406,13 +473,6 @@ Shader::~Shader() void Shader::attach() { - auto &usedShadersInFrame = vgfx->getUsedShadersInFrame(); - if (usedShadersInFrame.find(this) == usedShadersInFrame.end()) - { - newFrame(); - usedShadersInFrame.insert(this); - } - if (!isCompute) { if (Shader::current != this) @@ -676,11 +736,9 @@ void Shader::compileShaders() using namespace glslang; using namespace spirv_cross; - std::vector glslangShaders; + std::vector> glslangShaders; - auto program = new TProgram(); - - device = vgfx->getDevice(); + auto program = std::make_unique(); const auto &enabledExtensions = vgfx->getEnabledOptionalDeviceExtensions(); @@ -695,7 +753,7 @@ void Shader::compileShaders() isCompute = true; auto glslangShaderStage = getGlslShaderType(stage); - auto tshader = new TShader(glslangShaderStage); + auto tshader = std::make_unique(glslangShaderStage); tshader->setEnvInput(EShSourceGlsl, glslangShaderStage, EShClientVulkan, 450); tshader->setEnvClient(EShClientVulkan, EShTargetVulkan_1_2); @@ -721,14 +779,18 @@ void Shader::compileShaders() if (!tshader->parse(&defaultTBuiltInResource, defaultVersion, defaultProfile, forceDefault, forwardCompat, EShMsgSuppressWarnings)) { - const char *msg1 = tshader->getInfoLog(); - const char *msg2 = tshader->getInfoDebugLog(); + const char *stageName = "unknown"; + ShaderStage::getConstant(stage, stageName); - throw love::Exception("error while parsing shader"); + std::string err = "Error parsing " + std::string(stageName) + " shader:\n\n" + + std::string(tshader->getInfoLog()) + "\n" + + std::string(tshader->getInfoDebugLog()); + + throw love::Exception("%s", err.c_str()); } - program->addShader(tshader); - glslangShaders.push_back(tshader); + program->addShader(tshader.get()); + glslangShaders.push_back(std::move(tshader)); } if (!program->link(EShMsgDefault)) @@ -739,14 +801,16 @@ void Shader::compileShaders() uniformInfos.clear(); + BindingMapper bindingMapper; + for (int i = 0; i < SHADERSTAGE_MAX_ENUM; i++) { auto shaderStage = (ShaderStageType)i; auto glslangStage = getGlslShaderType(shaderStage); auto intermediate = program->getIntermediate(glslangStage); - if (intermediate == nullptr) { + + if (intermediate == nullptr) continue; - } spv::SpvBuildLogger logger; glslang::SpvOptions opt; @@ -755,31 +819,6 @@ void Shader::compileShaders() std::vector spirv; GlslangToSpv(*intermediate, spirv, &logger, &opt); - std::string msgs = logger.getAllMessages(); - - VkShaderModuleCreateInfo createInfo{}; - createInfo.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO; - createInfo.codeSize = spirv.size() * sizeof(uint32_t); - createInfo.pCode = spirv.data(); - - auto device = vgfx->getDevice(); - - VkShaderModule shaderModule; - - if (vkCreateShaderModule(device, &createInfo, nullptr, &shaderModule) != VK_SUCCESS) { - throw love::Exception("failed to create shader module"); - } - - shaderModules.push_back(shaderModule); - - VkPipelineShaderStageCreateInfo shaderStageInfo{}; - shaderStageInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; - shaderStageInfo.stage = getStageBit((ShaderStageType)i); - shaderStageInfo.module = shaderModule; - shaderStageInfo.pName = "main"; - - shaderStages.push_back(shaderStageInfo); - spirv_cross::CompilerGLSL comp(spirv); // we only care about variables that are actually getting used. @@ -796,7 +835,7 @@ void Shader::compileShaders() auto defaultUniformBlockSize = comp.get_declared_struct_size(type); localUniformStagingData.resize(defaultUniformBlockSize); localUniformData.resize(defaultUniformBlockSize); - localUniformLocation = comp.get_decoration(resource.id, spv::DecorationBinding); + localUniformLocation = bindingMapper(comp, spirv, resource.name, resource.id); memset(localUniformStagingData.data(), 0, defaultUniformBlockSize); memset(localUniformData.data(), 0, defaultUniformBlockSize); @@ -817,7 +856,7 @@ void Shader::compileShaders() const SPIRType &imagetype = comp.get_type(basetype.image.type); graphics::Shader::UniformInfo info; - info.location = comp.get_decoration(r.id, spv::DecorationBinding); + info.location = bindingMapper(comp, spirv, r.name, r.id); info.baseType = UNIFORM_SAMPLER; info.name = r.name; info.count = type.array.empty() ? 1 : type.array[0]; @@ -898,7 +937,7 @@ void Shader::compileShaders() if (!fillUniformReflectionData(u)) continue; - u.location = comp.get_decoration(r.id, spv::DecorationBinding); + u.location = bindingMapper(comp, spirv, r.name, r.id); u.buffers = new love::graphics::Buffer *[u.count]; for (int i = 0; i < u.count; i++) @@ -921,13 +960,11 @@ void Shader::compileShaders() continue; u.textures = new love::graphics::Texture *[u.count]; - u.location = comp.get_decoration(r.id, spv::DecorationBinding); + u.location = bindingMapper(comp, spirv, r.name, r.id); for (int i = 0; i < u.count; i++) u.textures[i] = nullptr; - // some stuff missing ? - uniformInfos[u.name] = u; } @@ -940,11 +977,27 @@ void Shader::compileShaders() attributes[name] = attributeLocation; } } - } - delete program; - for (auto shader : glslangShaders) - delete shader; + VkShaderModuleCreateInfo createInfo{}; + createInfo.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO; + createInfo.codeSize = spirv.size() * sizeof(uint32_t); + createInfo.pCode = spirv.data(); + + VkShaderModule shaderModule; + + if (vkCreateShaderModule(device, &createInfo, nullptr, &shaderModule) != VK_SUCCESS) + throw love::Exception("failed to create shader module"); + + shaderModules.push_back(shaderModule); + + VkPipelineShaderStageCreateInfo shaderStageInfo{}; + shaderStageInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; + shaderStageInfo.stage = getStageBit((ShaderStageType)i); + shaderStageInfo.module = shaderModule; + shaderStageInfo.pName = "main"; + + shaderStages.push_back(shaderStageInfo); + } } void Shader::createDescriptorSetLayout()