From a08395e12d72d06588ef8cd6482e00eda39e6ffc Mon Sep 17 00:00:00 2001 From: niki Date: Mon, 22 Aug 2022 23:09:21 +0200 Subject: [PATCH] vulkan: implement msaa --- src/modules/graphics/vulkan/Graphics.cpp | 166 +++++++++++++++++++---- src/modules/graphics/vulkan/Graphics.h | 26 ++-- 2 files changed, 153 insertions(+), 39 deletions(-) diff --git a/src/modules/graphics/vulkan/Graphics.cpp b/src/modules/graphics/vulkan/Graphics.cpp index 759ee9437..8bb023246 100644 --- a/src/modules/graphics/vulkan/Graphics.cpp +++ b/src/modules/graphics/vulkan/Graphics.cpp @@ -220,6 +220,8 @@ void Graphics::setViewportSize(int width, int height, int pixelwidth, int pixelh } bool Graphics::setMode(void* context, int width, int height, int pixelwidth, int pixelheight, bool windowhasstencil, int msaa) { + requestedMsaa = msaa; + cleanUpFunctions.clear(); cleanUpFunctions.resize(MAX_FRAMES_IN_FLIGHT); @@ -232,6 +234,7 @@ bool Graphics::setMode(void* context, int width, int height, int pixelwidth, int createSwapChain(); createImageViews(); createSyncObjects(); + createColorResources(); createDepthResources(); createCommandPool(); createCommandBuffers(); @@ -324,7 +327,7 @@ void Graphics::initCapabilities() { } void Graphics::getAPIStats(int& shaderswitches) const { - shaderswitches = Vulkan::getNumShaderSwitches(); + shaderswitches = static_cast(Vulkan::getNumShaderSwitches()); } void Graphics::unSetMode() { @@ -340,6 +343,14 @@ void Graphics::setActive(bool enable) { active = enable; } +int Graphics::getRequestedBackbufferMSAA() const { + return requestedMsaa; +} + +int Graphics::getBackbufferMSAA() const { + return actualMsaa; +} + void Graphics::setFrontFaceWinding(Winding winding) { const auto& currentState = states.back(); @@ -555,19 +566,23 @@ Matrix4 Graphics::computeDeviceProjection(const Matrix4& projection, bool render void Graphics::setRenderTargetsInternal(const RenderTargets& rts, int pixelw, int pixelh, bool hasSRGBtexture) { endRenderPass(); - if (rts.colors.size() == 0) { + if (rts.colors.empty()) { startRenderPass(nullptr, swapChainExtent.width, swapChainExtent.height); } else { // fixme: multi canvas render. auto& firstRenderTarget = rts.getFirstTarget(); - startRenderPass(static_cast(firstRenderTarget.texture), pixelw, pixelh); + startRenderPass(dynamic_cast(firstRenderTarget.texture), pixelw, pixelh); } } // END IMPLEMENTATION OVERRIDDEN FUNCTIONS void Graphics::initDynamicState() { - setScissor(); + if (states.back().scissor) { + setScissor(states.back().scissorRect); + } else { + setScissor(); + } } void Graphics::startRecordingGraphicsCommands() { @@ -804,6 +819,8 @@ void Graphics::pickPhysicalDevice() { VkPhysicalDeviceProperties properties; vkGetPhysicalDeviceProperties(physicalDevice, &properties); minUniformBufferOffsetAlignment = properties.limits.minUniformBufferOffsetAlignment; + + getMaxUsableSampleCount(); } bool Graphics::checkDeviceExtensionSupport(VkPhysicalDevice device) { @@ -1147,25 +1164,22 @@ VkPresentModeKHR Graphics::chooseSwapPresentMode(const std::vectorgetHandle(); int width, height; - // is this the equivalent of glfwGetFramebufferSize ? SDL_Vulkan_GetDrawableSize((SDL_Window*)handle, &width, &height); VkExtent2D actualExtent = { @@ -1237,9 +1250,10 @@ void Graphics::createImageViews() { } VkFramebuffer Graphics::createFramebuffer(FramebufferConfiguration configuration) { - std::array attachments = { + std::array attachments = { + colorImageView, + depthImageView, configuration.imageView, - depthImageView }; VkFramebufferCreateInfo createInfo{}; @@ -1285,18 +1299,18 @@ void Graphics::createDefaultShaders() { VkRenderPass Graphics::createRenderPass(RenderPassConfiguration configuration) { VkAttachmentDescription colorDescription{}; - colorDescription.format = configuration.frameBufferFormat; - colorDescription.samples = VK_SAMPLE_COUNT_1_BIT; + colorDescription.format = swapChainImageFormat; + colorDescription.samples = msaaSamples; 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.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; colorDescription.finalLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; VkAttachmentDescription depthStencilAttachment{}; depthStencilAttachment.format = findDepthFormat(); - depthStencilAttachment.samples = VK_SAMPLE_COUNT_1_BIT; + depthStencilAttachment.samples = msaaSamples; depthStencilAttachment.loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; depthStencilAttachment.storeOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; depthStencilAttachment.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; @@ -1304,6 +1318,16 @@ VkRenderPass Graphics::createRenderPass(RenderPassConfiguration configuration) { depthStencilAttachment.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; depthStencilAttachment.finalLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; + VkAttachmentDescription colorAttachmentResolve{}; + colorAttachmentResolve.format = configuration.frameBufferFormat; + colorAttachmentResolve.samples = VK_SAMPLE_COUNT_1_BIT; + colorAttachmentResolve.loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; + colorAttachmentResolve.storeOp = VK_ATTACHMENT_STORE_OP_STORE; + colorAttachmentResolve.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; + colorAttachmentResolve.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; + colorAttachmentResolve.initialLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; + colorAttachmentResolve.finalLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; + VkAttachmentReference colorAttachmentRef{}; colorAttachmentRef.attachment = 0; colorAttachmentRef.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; @@ -1312,13 +1336,18 @@ VkRenderPass Graphics::createRenderPass(RenderPassConfiguration configuration) { depthStencilAttachmentRef.attachment = 1; depthStencilAttachmentRef.layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; + VkAttachmentReference colorAttachmentResolveRef{}; + colorAttachmentResolveRef.attachment = 2; + colorAttachmentResolveRef.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; + VkSubpassDescription subPass{}; subPass.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS; subPass.colorAttachmentCount = 1; subPass.pColorAttachments = &colorAttachmentRef; subPass.pDepthStencilAttachment = &depthStencilAttachmentRef; + subPass.pResolveAttachments = &colorAttachmentResolveRef; - std::array attachments = { colorDescription, depthStencilAttachment }; + std::array attachments = { colorDescription, depthStencilAttachment, colorAttachmentResolve }; VkSubpassDependency dependency{}; dependency.srcSubpass = VK_SUBPASS_EXTERNAL; @@ -1419,8 +1448,6 @@ void Graphics::createVulkanVertexFormat( } void Graphics::prepareDraw(const VertexAttributes& attributes, const BufferBindings& buffers, graphics::Texture* texture, PrimitiveType primitiveType, CullMode cullmode) { - states.back().stencil; - GraphicsPipelineConfiguration configuration; configuration.renderPass = currentRenderPass; configuration.vertexAttributes = attributes; @@ -1624,7 +1651,7 @@ VkPipeline Graphics::createGraphicsPipeline(GraphicsPipelineConfiguration config VkPipelineMultisampleStateCreateInfo multisampling{}; multisampling.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO; multisampling.sampleShadingEnable = VK_FALSE; - multisampling.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT; + multisampling.rasterizationSamples = msaaSamples; multisampling.minSampleShading = 1.0f; // Optional multisampling.pSampleMask = nullptr; // Optional multisampling.alphaToCoverageEnable = VK_FALSE; // Optional @@ -1726,6 +1753,83 @@ void Graphics::ensureGraphicsPipelineConfiguration(GraphicsPipelineConfiguration } } +void Graphics::getMaxUsableSampleCount() { + VkPhysicalDeviceProperties physicalDeviceProperties; + vkGetPhysicalDeviceProperties(physicalDevice, &physicalDeviceProperties); + + VkSampleCountFlags counts = physicalDeviceProperties.limits.framebufferColorSampleCounts & physicalDeviceProperties.limits.framebufferDepthSampleCounts; + + if (counts & VK_SAMPLE_COUNT_64_BIT && requestedMsaa >= 64) { + msaaSamples = VK_SAMPLE_COUNT_64_BIT; + actualMsaa = 64; + } else if (counts & VK_SAMPLE_COUNT_32_BIT && requestedMsaa >= 32) { + msaaSamples = VK_SAMPLE_COUNT_32_BIT; + actualMsaa = 32; + } + else if (counts & VK_SAMPLE_COUNT_16_BIT && requestedMsaa >= 16) { + msaaSamples = VK_SAMPLE_COUNT_16_BIT; + actualMsaa = 16; + } + else if (counts & VK_SAMPLE_COUNT_8_BIT && requestedMsaa >= 8) { + msaaSamples = VK_SAMPLE_COUNT_8_BIT; + actualMsaa = 8; + } + else if (counts & VK_SAMPLE_COUNT_4_BIT && requestedMsaa >= 4) { + msaaSamples = VK_SAMPLE_COUNT_4_BIT; + actualMsaa = 4; + } + else if (counts & VK_SAMPLE_COUNT_2_BIT && requestedMsaa >= 2) { + msaaSamples = VK_SAMPLE_COUNT_2_BIT; + actualMsaa = 2; + } + else { + msaaSamples = VK_SAMPLE_COUNT_1_BIT; + actualMsaa = 1; + } +} + +void Graphics::createColorResources() { + VkFormat colorFormat = swapChainImageFormat; + + VkImageCreateInfo imageInfo{}; + imageInfo.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO; + imageInfo.imageType = VK_IMAGE_TYPE_2D; + imageInfo.format = colorFormat; + imageInfo.extent.width = swapChainExtent.width; + imageInfo.extent.height = swapChainExtent.height; + imageInfo.extent.depth = 1; + imageInfo.mipLevels = 1; + imageInfo.arrayLayers = 1; + imageInfo.samples = msaaSamples; + imageInfo.tiling = VK_IMAGE_TILING_OPTIMAL; + imageInfo.usage = VK_IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT | VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT; + imageInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE; + imageInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; + + VmaAllocationCreateInfo allocationInfo{}; + allocationInfo.usage = VMA_MEMORY_USAGE_AUTO; + allocationInfo.flags = VMA_ALLOCATION_CREATE_DEDICATED_MEMORY_BIT; + + vmaCreateImage(vmaAllocator, &imageInfo, &allocationInfo, &colorImage, &colorImageAllocation, nullptr); + + VkImageViewCreateInfo imageViewInfo{}; + imageViewInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; + imageViewInfo.image = colorImage; + imageViewInfo.viewType = VK_IMAGE_VIEW_TYPE_2D; + imageViewInfo.format = colorFormat; + imageViewInfo.components.r = VK_COMPONENT_SWIZZLE_IDENTITY; + imageViewInfo.components.g = VK_COMPONENT_SWIZZLE_IDENTITY; + imageViewInfo.components.b = VK_COMPONENT_SWIZZLE_IDENTITY; + imageViewInfo.components.a = VK_COMPONENT_SWIZZLE_IDENTITY; + imageViewInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + imageViewInfo.subresourceRange.baseMipLevel = 0; + imageViewInfo.subresourceRange.levelCount = 1; + imageViewInfo.subresourceRange.baseArrayLayer = 0; + imageViewInfo.subresourceRange.layerCount = 1; + + vkCreateImageView(device, &imageViewInfo, nullptr, &colorImageView); +} + VkFormat Graphics::findSupportedFormat(const std::vector& candidates, VkImageTiling tiling, VkFormatFeatureFlags features) { for (auto format : candidates) { VkFormatProperties properties; @@ -1741,7 +1845,6 @@ VkFormat Graphics::findSupportedFormat(const std::vector& candidates, throw love::Exception("failed to find supported format"); } - VkFormat Graphics::findDepthFormat() { return findSupportedFormat( { VK_FORMAT_D32_SFLOAT_S8_UINT, VK_FORMAT_D24_UNORM_S8_UINT }, @@ -1762,7 +1865,7 @@ void Graphics::createDepthResources() { imageInfo.extent.depth = 1; imageInfo.mipLevels = 1; imageInfo.arrayLayers = 1; - imageInfo.samples = VK_SAMPLE_COUNT_1_BIT; + imageInfo.samples = msaaSamples; imageInfo.tiling = VK_IMAGE_TILING_OPTIMAL; imageInfo.usage = VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT; imageInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE; @@ -1854,7 +1957,7 @@ void Graphics::createSyncObjects() { void Graphics::createDefaultTexture() { Texture::Settings settings; - standardTexture.reset((Texture*)newTexture(settings)); + standardTexture.reset((Texture*)newTexture(settings, nullptr)); uint8_t whitePixels[] = {255, 255, 255, 255}; standardTexture->replacePixels(whitePixels, sizeof(whitePixels), 0, 0, { 0, 0, 1, 1 }, false); } @@ -1905,6 +2008,8 @@ void Graphics::cleanup() { } void Graphics::cleanupSwapChain() { + vkDestroyImageView(device, colorImageView, nullptr); + vmaDestroyImage(vmaAllocator, colorImage, colorImageAllocation); vkDestroyImageView(device, depthImageView, nullptr); vmaDestroyImage(vmaAllocator, depthImage, depthImageAllocation); for (const auto& [key, val] : framebuffers) { @@ -1925,6 +2030,7 @@ void Graphics::recreateSwapChain() { createSwapChain(); createImageViews(); + createColorResources(); createDepthResources(); } diff --git a/src/modules/graphics/vulkan/Graphics.h b/src/modules/graphics/vulkan/Graphics.h index ea3e59bc5..e390a0c24 100644 --- a/src/modules/graphics/vulkan/Graphics.h +++ b/src/modules/graphics/vulkan/Graphics.h @@ -139,7 +139,7 @@ public: const VmaAllocator getVmaAllocator() const; // implementation for virtual functions - love::graphics::Texture* newTexture(const love::graphics::Texture::Settings& settings, const love::graphics::Texture::Slices* data = nullptr) override; + love::graphics::Texture* newTexture(const love::graphics::Texture::Settings& settings, const love::graphics::Texture::Slices* data) override; love::graphics::Buffer* newBuffer(const love::graphics::Buffer::Settings& settings, const std::vector& format, const void* data, size_t size, size_t arraylength) override; void clear(OptionalColorD color, OptionalInt stencil, OptionalDouble depth) override; void clear(const std::vector& colors, OptionalInt stencil, OptionalDouble depth) override; @@ -150,8 +150,8 @@ public: bool setMode(void* context, int width, int height, int pixelwidth, int pixelheight, bool windowhasstencil, int msaa) override; void unSetMode() override; void setActive(bool active) override; - int getRequestedBackbufferMSAA() const override { return 0; } - int getBackbufferMSAA() const override { return 0; } + int getRequestedBackbufferMSAA() const override; + int getBackbufferMSAA() const override; void setColor(Colorf c) override; void setScissor(const Rect& rect) override; void setScissor() override; @@ -163,7 +163,7 @@ public: void setPointSize(float size) override; void setWireframe(bool enable) override; PixelFormat getSizedFormat(PixelFormat format, bool rendertarget, bool readable) const override; - bool isPixelFormatSupported(PixelFormat format, uint32 usage, bool sRGB = false) override; + bool isPixelFormatSupported(PixelFormat format, uint32 usage, bool sRGB) override; Renderer getRenderer() const override; bool usesGLSLES() const override; RendererInfo getRendererInfo() const override; @@ -172,7 +172,7 @@ public: void drawQuads(int start, int count, const VertexAttributes& attributes, const BufferBindings& buffers, graphics::Texture* texture) override; 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; } + GraphicsReadback* newReadbackInternal(ReadbackMethod method, love::graphics::Texture* texture, int slice, int mipmap, const Rect& rect, image::ImageData* dest, int destx, int desty) override { return nullptr; } VkCommandBuffer getDataTransferCommandBuffer(); void queueCleanUp(std::function cleanUp); @@ -199,6 +199,7 @@ private: void createVulkanInstance(); bool checkValidationSupport(); void pickPhysicalDevice(); + void getMaxUsableSampleCount(); int rateDeviceSuitability(VkPhysicalDevice device); QueueFamilyIndices findQueueFamilies(VkPhysicalDevice device); void createLogicalDevice(); @@ -217,6 +218,7 @@ private: void createDefaultShaders(); VkRenderPass createRenderPass(RenderPassConfiguration); VkPipeline createGraphicsPipeline(GraphicsPipelineConfiguration); + void createColorResources(); VkFormat findSupportedFormat(const std::vector& candidates, VkImageTiling tiling, VkFormatFeatureFlags features); VkFormat findDepthFormat(); void createDepthResources(); @@ -245,12 +247,14 @@ private: VkInstance instance = VK_NULL_HANDLE; VkPhysicalDevice physicalDevice = VK_NULL_HANDLE; + int requestedMsaa = 0; + int actualMsaa = 0; VkDevice device = VK_NULL_HANDLE; VkQueue graphicsQueue = VK_NULL_HANDLE; VkQueue presentQueue = VK_NULL_HANDLE; VkSurfaceKHR surface = VK_NULL_HANDLE; VkSwapchainKHR swapChain = VK_NULL_HANDLE; - VkSurfaceTransformFlagBitsKHR preTransform; + VkSurfaceTransformFlagBitsKHR preTransform = {}; Matrix4 displayRotation; std::vector swapChainImages; VkFormat swapChainImageFormat = VK_FORMAT_UNDEFINED; @@ -258,9 +262,13 @@ private: std::vector swapChainImageViews; VkPipeline currentGraphicsPipeline = VK_NULL_HANDLE; VkRenderPass currentRenderPass = VK_NULL_HANDLE; - VkImage depthImage; - VkImageView depthImageView; - VmaAllocation depthImageAllocation; + VkSampleCountFlagBits msaaSamples; + VkImage colorImage = VK_NULL_HANDLE; + VkImageView colorImageView = VK_NULL_HANDLE; + VmaAllocation colorImageAllocation = VK_NULL_HANDLE; + VkImage depthImage = VK_NULL_HANDLE; + VkImageView depthImageView = VK_NULL_HANDLE; + VmaAllocation depthImageAllocation = VK_NULL_HANDLE; std::unordered_map renderPasses; std::unordered_map framebuffers; std::unordered_map graphicsPipelines;