diff --git a/src/modules/graphics/Shader.cpp b/src/modules/graphics/Shader.cpp index e0eec23ff..415a71ce3 100644 --- a/src/modules/graphics/Shader.cpp +++ b/src/modules/graphics/Shader.cpp @@ -56,10 +56,8 @@ static const char global_syntax[] = R"( #endif #if __VERSION__ >= 300 #define LOVE_IO_LOCATION(x) layout (location = x) -#define LOVE_IO_BINDING(x) layout (binding = x) #else #define LOVE_IO_LOCATION(x) -#define LOVE_IO_BINDING(x) #endif #define number float #define Image sampler2D @@ -311,9 +309,9 @@ static const char pixel_header[] = R"( )"; static const char pixel_functions[] = R"( -LOVE_IO_BINDING(2) uniform sampler2D love_VideoYChannel; -LOVE_IO_BINDING(3) uniform sampler2D love_VideoCbChannel; -LOVE_IO_BINDING(4) uniform sampler2D love_VideoCrChannel; +uniform sampler2D love_VideoYChannel; +uniform sampler2D love_VideoCbChannel; +uniform sampler2D love_VideoCrChannel; vec4 VideoTexel(vec2 texcoords) { vec3 yuv; @@ -339,7 +337,7 @@ static const char pixel_main[] = R"( #define love_PixelColor gl_FragColor #endif -LOVE_IO_BINDING(1) uniform sampler2D MainTex; +uniform sampler2D MainTex; LOVE_IO_LOCATION(0) varying LOVE_HIGHP_OR_MEDIUMP vec4 VaryingTexCoord; LOVE_IO_LOCATION(1) varying mediump vec4 VaryingColor; diff --git a/src/modules/graphics/vulkan/Graphics.cpp b/src/modules/graphics/vulkan/Graphics.cpp index f4ee9713c..43b07a130 100644 --- a/src/modules/graphics/vulkan/Graphics.cpp +++ b/src/modules/graphics/vulkan/Graphics.cpp @@ -325,7 +325,6 @@ void Graphics::getAPIStats(int& shaderswitches) const { void Graphics::unSetMode() { created = false; - auto fpn = vkDeviceWaitIdle; vkDeviceWaitIdle(device); Volatile::unloadAll(); cleanup(); @@ -559,12 +558,11 @@ Matrix4 Graphics::computeDeviceProjection(const Matrix4& projection, bool render void Graphics::setRenderTargetsInternal(const RenderTargets& rts, int pixelw, int pixelh, bool hasSRGBtexture) { endRenderPass(); - if (rts.colors.empty()) { - startRenderPass(nullptr, swapChainExtent.width, swapChainExtent.height); + bool isWindow = rts.getFirstTarget().texture == nullptr; + if (isWindow) { + startDefaultRenderPass(); } else { - // fixme: multi canvas render. - auto& firstRenderTarget = rts.getFirstTarget(); - startRenderPass(dynamic_cast(firstRenderTarget.texture), pixelw, pixelh); + startRenderPass(rts, pixelw, pixelh, hasSRGBtexture); } } @@ -615,7 +613,7 @@ void Graphics::startRecordingGraphicsCommands() { Vulkan::cmdTransitionImageLayout(commandBuffers.at(currentFrame), swapChainImages[imageIndex], VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL); - startRenderPass(nullptr, swapChainExtent.width, swapChainExtent.height); + startDefaultRenderPass(); Vulkan::resetShaderSwitches(); } @@ -1166,7 +1164,7 @@ VkPresentModeKHR Graphics::chooseSwapPresentMode(const std::vector attachments = { - colorImageView, - depthImageView, + std::vector attachments = { configuration.imageView, }; + if (configuration.depthView) { + attachments.push_back(configuration.depthView); + } + + if (configuration.resolveView) { + attachments.push_back(configuration.resolveView); + } + VkFramebufferCreateInfo createInfo{}; createInfo.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO; createInfo.renderPass = configuration.renderPass; @@ -1310,35 +1319,44 @@ void Graphics::createDefaultShaders() { } VkRenderPass Graphics::createRenderPass(RenderPassConfiguration configuration) { + std::vector attachments; + VkAttachmentDescription colorDescription{}; - colorDescription.format = swapChainImageFormat; - colorDescription.samples = msaaSamples; + colorDescription.format = configuration.colorFormat; + colorDescription.samples = configuration.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_UNDEFINED; colorDescription.finalLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; + attachments.push_back(colorDescription); - VkAttachmentDescription depthStencilAttachment{}; - depthStencilAttachment.format = findDepthFormat(); - 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; - depthStencilAttachment.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; - depthStencilAttachment.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; - depthStencilAttachment.finalLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; + if (configuration.depthFormat != VK_FORMAT_UNDEFINED) { + VkAttachmentDescription depthStencilAttachment{}; + depthStencilAttachment.format = configuration.depthFormat; + depthStencilAttachment.samples = configuration.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; + depthStencilAttachment.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; + depthStencilAttachment.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; + depthStencilAttachment.finalLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; + attachments.push_back(depthStencilAttachment); + } - 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; + if (configuration.resolve) { + VkAttachmentDescription colorAttachmentResolve{}; + colorAttachmentResolve.format = configuration.colorFormat; + 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; + attachments.push_back(colorAttachmentResolve); + } VkAttachmentReference colorAttachmentRef{}; colorAttachmentRef.attachment = 0; @@ -1356,10 +1374,14 @@ VkRenderPass Graphics::createRenderPass(RenderPassConfiguration configuration) { subPass.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS; subPass.colorAttachmentCount = 1; subPass.pColorAttachments = &colorAttachmentRef; - subPass.pDepthStencilAttachment = &depthStencilAttachmentRef; - subPass.pResolveAttachments = &colorAttachmentResolveRef; - std::array attachments = { colorDescription, depthStencilAttachment, colorAttachmentResolve }; + if (configuration.depthFormat != VK_FORMAT_UNDEFINED) { + subPass.pDepthStencilAttachment = &depthStencilAttachmentRef; + } + + if (configuration.resolve) { + subPass.pResolveAttachments = &colorAttachmentResolveRef; + } VkSubpassDependency dependency{}; dependency.srcSubpass = VK_SUBPASS_EXTERNAL; @@ -1475,6 +1497,8 @@ void Graphics::prepareDraw(const VertexAttributes& attributes, const BufferBindi configuration.cullmode = cullmode; configuration.viewportWidth = currentViewportWidth; configuration.viewportHeight = currentViewportHeight; + configuration.msaaSamples = currentMsaaSamples; + std::vector bufferVector; std::vector offsets; @@ -1505,54 +1529,63 @@ void Graphics::prepareDraw(const VertexAttributes& attributes, const BufferBindi vkCmdBindVertexBuffers(commandBuffers.at(currentFrame), 0, static_cast(bufferVector.size()), bufferVector.data(), offsets.data()); } -void Graphics::startRenderPass(Texture* texture, uint32_t w, uint32_t h) { +void Graphics::startDefaultRenderPass() { + VkRenderPassBeginInfo renderPassInfo{}; + renderPassInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO; + renderPassInfo.renderPass = defaultRenderPass; + renderPassInfo.framebuffer = defaultFramebuffers[imageIndex]; + renderPassInfo.renderArea.offset = { 0, 0 }; + renderPassInfo.renderArea.extent = swapChainExtent; + + vkCmdBeginRenderPass(commandBuffers.at(currentFrame), &renderPassInfo, VK_SUBPASS_CONTENTS_INLINE); + + currentRenderPass = defaultRenderPass; + currentGraphicsPipeline = VK_NULL_HANDLE; + renderTargetTexture = VK_NULL_HANDLE; + currentViewportWidth = (float)swapChainExtent.width; + currentViewportHeight = (float)swapChainExtent.height; + currentMsaaSamples = msaaSamples; +} + +void Graphics::startRenderPass(const RenderTargets& rts, int pixelw, int pixelh, bool hasSRGBtexture) { + renderTargetTexture = dynamic_cast(rts.colors[0].texture); + + RenderPassConfiguration renderPassConfiguration{}; + renderPassConfiguration.colorFormat = Vulkan::getTextureFormat(renderTargetTexture->getPixelFormat()).internalFormat; + VkRenderPass renderPass; - VkFramebuffer framebuffer; - - if (texture == nullptr) { - renderTargetTexture = nullptr; - renderPass = defaultRenderPass; - framebuffer = defaultFramebuffers[imageIndex]; + auto it = renderPasses.find(renderPassConfiguration); + if (it != renderPasses.end()) { + renderPass = it->second; } else { - RenderPassConfiguration renderPassConfiguration{}; - - renderPassConfiguration.frameBufferFormat = Vulkan::getTextureFormat(texture->getPixelFormat()).internalFormat; - renderTargetTexture = texture; - - auto it = renderPasses.find(renderPassConfiguration); - if (it != renderPasses.end()) { - renderPass = it->second; - } else { - renderPass = createRenderPass(renderPassConfiguration); - renderPasses[renderPassConfiguration] = renderPass; - } - - FramebufferConfiguration configuration{}; - configuration.renderPass = renderPass; - configuration.imageView = (VkImageView)texture->getRenderTargetHandle(); - configuration.width = w; - configuration.height = h; - framebuffer = getFramebuffer(configuration); + renderPass = createRenderPass(renderPassConfiguration); + renderPasses[renderPassConfiguration] = renderPass; } + FramebufferConfiguration configuration{}; + configuration.renderPass = renderPass; + configuration.imageView = (VkImageView)renderTargetTexture->getRenderTargetHandle(); + configuration.width = static_cast(renderTargetTexture->getWidth()); + configuration.height = static_cast(renderTargetTexture->getHeight()); + VkFramebuffer framebuffer = getFramebuffer(configuration); + + Vulkan::cmdTransitionImageLayout(commandBuffers.at(currentFrame), (VkImage)renderTargetTexture->getHandle(), VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL); + VkRenderPassBeginInfo renderPassInfo{}; renderPassInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO; renderPassInfo.renderPass = renderPass; renderPassInfo.framebuffer = framebuffer; 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); - } + renderPassInfo.renderArea.extent.width = static_cast(renderTargetTexture->getWidth()); + renderPassInfo.renderArea.extent.height = static_cast(renderTargetTexture->getHeight()); vkCmdBeginRenderPass(commandBuffers.at(currentFrame), &renderPassInfo, VK_SUBPASS_CONTENTS_INLINE); currentRenderPass = renderPass; currentGraphicsPipeline = VK_NULL_HANDLE; - currentViewportWidth = (float)w; - currentViewportHeight = (float)h; + currentViewportWidth = (float)renderTargetTexture->getWidth(); + currentViewportHeight = (float)renderTargetTexture->getHeight(); + currentMsaaSamples = VK_SAMPLE_COUNT_1_BIT; } void Graphics::endRenderPass() { @@ -1661,7 +1694,7 @@ VkPipeline Graphics::createGraphicsPipeline(GraphicsPipelineConfiguration config VkPipelineMultisampleStateCreateInfo multisampling{}; multisampling.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO; multisampling.sampleShadingEnable = VK_FALSE; - multisampling.rasterizationSamples = msaaSamples; + multisampling.rasterizationSamples = configuration.msaaSamples; multisampling.minSampleShading = 1.0f; // Optional multisampling.pSampleMask = nullptr; // Optional multisampling.alphaToCoverageEnable = VK_FALSE; // Optional diff --git a/src/modules/graphics/vulkan/Graphics.h b/src/modules/graphics/vulkan/Graphics.h index d4c9d69f0..ccdf7e4e3 100644 --- a/src/modules/graphics/vulkan/Graphics.h +++ b/src/modules/graphics/vulkan/Graphics.h @@ -25,7 +25,10 @@ namespace love { namespace graphics { namespace vulkan { struct RenderPassConfiguration { - VkFormat frameBufferFormat; + VkFormat colorFormat = VK_FORMAT_UNDEFINED; + VkSampleCountFlagBits msaaSamples = VK_SAMPLE_COUNT_1_BIT; + VkFormat depthFormat = VK_FORMAT_UNDEFINED; + bool resolve = false; bool operator==(const RenderPassConfiguration& conf) const { return memcmp(this, &conf, sizeof(RenderPassConfiguration)) == 0; @@ -41,6 +44,8 @@ struct RenderPassConfigurationHasher { struct FramebufferConfiguration { VkRenderPass renderPass = VK_NULL_HANDLE; VkImageView imageView = VK_NULL_HANDLE; + VkImageView depthView = VK_NULL_HANDLE; + VkImageView resolveView = VK_NULL_HANDLE; uint32_t width = 0; uint32_t height = 0; @@ -69,6 +74,7 @@ struct GraphicsPipelineConfiguration { float viewportHeight; StencilState stencil; DepthState depthState; + VkSampleCountFlagBits msaaSamples; GraphicsPipelineConfiguration() { memset(this, 0, sizeof(GraphicsPipelineConfiguration)); @@ -122,14 +128,16 @@ struct SwapChainSupportDetails { class Graphics final : public love::graphics::Graphics { public: - Graphics() { #ifdef LOVE_ANDROID + Graphics() { auto result = volkInitialize(); if (result != VK_SUCCESS) { throw love::Exception("could not initialize volk"); } -#endif } +#else + Graphics() = default; +#endif virtual ~Graphics(); @@ -243,7 +251,8 @@ private: std::vector &bindingDescriptions, std::vector &attributeDescriptions); void prepareDraw(const VertexAttributes& attributes, const BufferBindings& buffers, graphics::Texture* texture, PrimitiveType, CullMode); - void startRenderPass(Texture*, uint32_t w, uint32_t h); + void startRenderPass(const RenderTargets& rts, int pixelw, int pixelh, bool hasSRGBtexture); + void startDefaultRenderPass(); void endRenderPass(); VkSampler createSampler(const SamplerState&); @@ -271,7 +280,7 @@ private: VkImage depthImage = VK_NULL_HANDLE; VkImageView depthImageView = VK_NULL_HANDLE; VmaAllocation depthImageAllocation = VK_NULL_HANDLE; - VkRenderPass defaultRenderPass; + VkRenderPass defaultRenderPass = VK_NULL_HANDLE; std::vector defaultFramebuffers; std::unordered_map renderPasses; std::unordered_map framebuffers; @@ -298,10 +307,10 @@ private: std::vector>> cleanUpFunctions; // render pass variables. - graphics::Texture* currentTexture = nullptr; Texture* renderTargetTexture = nullptr; float currentViewportWidth = 0; float currentViewportHeight = 0; + VkSampleCountFlagBits currentMsaaSamples = VK_SAMPLE_COUNT_1_BIT; }; } // vulkan } // graphics