From d123021e26ba035e92f45eb0b03be851902dc5ac Mon Sep 17 00:00:00 2001 From: niki Date: Mon, 29 Aug 2022 17:43:54 +0200 Subject: [PATCH] vulkan: fix canvas rendering (on android) Before this patch, sometimes rendering a texture on an android device would result in random things appearing in the canvas, apart from the stuff that has been drawn properly. With these changes this does not seem to appear anymore. --- src/modules/graphics/vulkan/Graphics.cpp | 43 ++++++++++++++---------- src/modules/graphics/vulkan/Graphics.h | 1 + src/modules/graphics/vulkan/Shader.cpp | 4 +-- src/modules/graphics/vulkan/Texture.cpp | 14 ++++---- src/modules/graphics/vulkan/Vulkan.cpp | 42 ++++++++++++++++++++--- 5 files changed, 75 insertions(+), 29 deletions(-) diff --git a/src/modules/graphics/vulkan/Graphics.cpp b/src/modules/graphics/vulkan/Graphics.cpp index e4be8a2da..69662f309 100644 --- a/src/modules/graphics/vulkan/Graphics.cpp +++ b/src/modules/graphics/vulkan/Graphics.cpp @@ -126,6 +126,19 @@ void Graphics::clear(const std::vector& colors, OptionalInt sten 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(currentViewportWidth); @@ -1242,6 +1255,7 @@ void Graphics::createImageViews() { void Graphics::createDefaultRenderPass() { RenderPassConfiguration renderPassConfiguration{}; renderPassConfiguration.colorFormats.push_back(swapChainImageFormat); + renderPassConfiguration.staticData.initialColorImageLayout = VK_IMAGE_LAYOUT_UNDEFINED; renderPassConfiguration.staticData.msaaSamples = msaaSamples; renderPassConfiguration.staticData.depthFormat = findDepthFormat(); renderPassConfiguration.staticData.resolve = true; @@ -1336,11 +1350,11 @@ VkRenderPass Graphics::createRenderPass(RenderPassConfiguration configuration) { VkAttachmentDescription colorDescription{}; colorDescription.format = colorFormat; colorDescription.samples = configuration.staticData.msaaSamples; - colorDescription.loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; + colorDescription.loadOp = VK_ATTACHMENT_LOAD_OP_LOAD; 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.initialLayout = configuration.staticData.initialColorImageLayout; colorDescription.finalLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; attachments.push_back(colorDescription); } @@ -1387,8 +1401,8 @@ VkRenderPass Graphics::createRenderPass(RenderPassConfiguration configuration) { VkSubpassDependency dependency{}; dependency.srcSubpass = VK_SUBPASS_EXTERNAL; dependency.dstSubpass = 0; - dependency.srcStageMask = VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT; - dependency.srcAccessMask = 0; + dependency.srcStageMask = VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_TRANSFER_BIT; + dependency.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; dependency.dstStageMask = VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT; dependency.dstAccessMask = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT; @@ -1553,12 +1567,10 @@ void Graphics::startDefaultRenderPass() { void Graphics::startRenderPass(const RenderTargets& rts, int pixelw, int pixelh, bool hasSRGBtexture) { auto currentCommandBuffer = commandBuffers.at(currentFrame); - auto width = static_cast(rts.getFirstTarget().texture->getWidth()); - auto height = static_cast(rts.getFirstTarget().texture->getHeight()); - // fixme: hasSRGBtexture // fixme: msaaSamples RenderPassConfiguration renderPassConfiguration{}; + renderPassConfiguration.staticData.initialColorImageLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; for (const auto &color : rts.colors) { // fixme: use mipmap and slice. color.mipmap; @@ -1593,13 +1605,13 @@ void Graphics::startRenderPass(const RenderTargets& rts, int pixelw, int pixelh, transitionBackImages.push_back((VkImage) color.texture->getHandle()); } if (rts.depthStencil.texture != nullptr) { - configuration.colorViews.push_back((VkImageView)rts.depthStencil.texture->getRenderTargetHandle()); + configuration.staticData.depthView = (VkImageView)rts.depthStencil.texture->getRenderTargetHandle(); // fixme: layout transition of depth stencil image? } configuration.staticData.renderPass = renderPass; - configuration.staticData.width = static_cast(width); - configuration.staticData.height = static_cast(height); + configuration.staticData.width = static_cast(pixelw); + configuration.staticData.height = static_cast(pixelh); VkFramebuffer framebuffer = getFramebuffer(configuration); VkRenderPassBeginInfo renderPassInfo{}; @@ -1607,15 +1619,15 @@ void Graphics::startRenderPass(const RenderTargets& rts, int pixelw, int pixelh, renderPassInfo.renderPass = renderPass; renderPassInfo.framebuffer = framebuffer; renderPassInfo.renderArea.offset = {0, 0}; - renderPassInfo.renderArea.extent.width = static_cast(width); - renderPassInfo.renderArea.extent.height = static_cast(height); + renderPassInfo.renderArea.extent.width = static_cast(pixelw); + renderPassInfo.renderArea.extent.height = static_cast(pixelh); vkCmdBeginRenderPass(currentCommandBuffer, &renderPassInfo, VK_SUBPASS_CONTENTS_INLINE); currentRenderPass = renderPass; currentGraphicsPipeline = VK_NULL_HANDLE; - currentViewportWidth = (float)width; - currentViewportHeight = (float)height; + currentViewportWidth = (float)pixelw; + currentViewportHeight = (float)pixelh; currentMsaaSamples = VK_SAMPLE_COUNT_1_BIT; currentNumColorAttachments = static_cast(rts.colors.size()); @@ -2046,9 +2058,6 @@ void Graphics::createDefaultTexture() { } void Graphics::cleanup() { - delete quadIndexBuffer; - quadIndexBuffer = nullptr; - cleanupSwapChain(); for (auto &cleanUpFns : cleanUpFunctions) { diff --git a/src/modules/graphics/vulkan/Graphics.h b/src/modules/graphics/vulkan/Graphics.h index 69971e5fe..234ecf6b6 100644 --- a/src/modules/graphics/vulkan/Graphics.h +++ b/src/modules/graphics/vulkan/Graphics.h @@ -27,6 +27,7 @@ struct RenderPassConfiguration { std::vector colorFormats; struct StaticRenderPassConfiguration { + VkImageLayout initialColorImageLayout = VK_IMAGE_LAYOUT_UNDEFINED; VkSampleCountFlagBits msaaSamples = VK_SAMPLE_COUNT_1_BIT; VkFormat depthFormat = VK_FORMAT_UNDEFINED; bool resolve = false; diff --git a/src/modules/graphics/vulkan/Shader.cpp b/src/modules/graphics/vulkan/Shader.cpp index bd8bc4410..6dcffb2dd 100644 --- a/src/modules/graphics/vulkan/Shader.cpp +++ b/src/modules/graphics/vulkan/Shader.cpp @@ -652,12 +652,12 @@ void Shader::createDescriptorSetLayout() { layoutBinding.binding = val.location; layoutBinding.descriptorType = val.baseType == UNIFORM_SAMPLER ? VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER : VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; layoutBinding.descriptorCount = val.count; - layoutBinding.stageFlags = VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT | VK_SHADER_STAGE_COMPUTE_BIT; // fixme: can we determine in what shader it got used? + layoutBinding.stageFlags = VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT; bindings.push_back(layoutBinding); } } - + VkDescriptorSetLayoutBinding uniformBinding{}; uniformBinding.binding = uniformLocation; uniformBinding.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; diff --git a/src/modules/graphics/vulkan/Texture.cpp b/src/modules/graphics/vulkan/Texture.cpp index b393bfa79..2c0e11c5b 100644 --- a/src/modules/graphics/vulkan/Texture.cpp +++ b/src/modules/graphics/vulkan/Texture.cpp @@ -50,8 +50,8 @@ bool Texture::loadVolatile() { imageInfo.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO; imageInfo.flags = createFlags; imageInfo.imageType = Vulkan::getImageType(getTextureType()); - imageInfo.extent.width = static_cast(width); - imageInfo.extent.height = static_cast(height); + imageInfo.extent.width = static_cast(pixelWidth); + imageInfo.extent.height = static_cast(pixelHeight); imageInfo.extent.depth = 1; imageInfo.mipLevels = static_cast(getMipmapCount()); imageInfo.arrayLayers = static_cast(layerCount); @@ -164,8 +164,10 @@ void Texture::clear() { VkImageSubresourceRange range{}; range.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; - range.layerCount = static_cast(layerCount); - range.levelCount = static_cast(getMipmapCount()); + range.baseMipLevel = 0; + range.levelCount = VK_REMAINING_MIP_LEVELS; + range.baseArrayLayer = 0; + range.layerCount = VK_REMAINING_ARRAY_LAYERS; Vulkan::cmdTransitionImageLayout(commandBuffer, textureImage, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, @@ -263,14 +265,14 @@ void Texture::generateMipmapsInternal() { VkImageBlit blit{}; blit.srcOffsets[0] = { 0, 0, 0 }; - blit.srcOffsets[1] = { getWidth(i - 1), getHeight(i - 1), 1 }; + blit.srcOffsets[1] = { getPixelWidth(i - 1), getPixelHeight(i - 1), 1 }; blit.srcSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; blit.srcSubresource.mipLevel = i - 1; blit.srcSubresource.baseArrayLayer = 0; blit.srcSubresource.layerCount = static_cast(layerCount); blit.dstOffsets[0] = { 0, 0, 0 }; - blit.dstOffsets[1] = { getWidth(i), getHeight(i), 1 }; + blit.dstOffsets[1] = { getPixelWidth(i), getPixelHeight(i), 1 }; blit.dstSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; blit.dstSubresource.mipLevel = i; blit.dstSubresource.baseArrayLayer = 0; diff --git a/src/modules/graphics/vulkan/Vulkan.cpp b/src/modules/graphics/vulkan/Vulkan.cpp index aa29ab206..6a7cb2dc4 100644 --- a/src/modules/graphics/vulkan/Vulkan.cpp +++ b/src/modules/graphics/vulkan/Vulkan.cpp @@ -267,34 +267,68 @@ TextureFormat Vulkan::getTextureFormat(PixelFormat format) { case PIXELFORMAT_RGB565_UNORM: // LSB->MSB: [b: g: r] case PIXELFORMAT_RGB10A2_UNORM: // LSB->MSB: [r: g: b: a] case PIXELFORMAT_RG11B10_FLOAT: // LSB->MSB: [r: g: b] + throw love::Exception("unimplemented pixel format (rgba4, rgb5a1, rgb565, rgb10a2, rg11b10)"); case PIXELFORMAT_STENCIL8: + textureFormat.internalFormat = VK_FORMAT_S8_UINT; + textureFormat.internalFormatRepresentation = FORMATREPRESENTATION_UINT; + break; case PIXELFORMAT_DEPTH16_UNORM: - case PIXELFORMAT_DEPTH24_UNORM: - case PIXELFORMAT_DEPTH32_FLOAT: + textureFormat.internalFormat = VK_FORMAT_D16_UNORM; + textureFormat.internalFormatRepresentation = FORMATREPRESENTATION_UINT; + break; + case PIXELFORMAT_DEPTH24_UNORM: // ? case PIXELFORMAT_DEPTH24_UNORM_STENCIL8: + textureFormat.internalFormat = VK_FORMAT_D24_UNORM_S8_UINT; + textureFormat.internalFormatRepresentation = FORMATREPRESENTATION_UINT; + break; + case PIXELFORMAT_DEPTH32_FLOAT: + textureFormat.internalFormat = VK_FORMAT_D32_SFLOAT; + textureFormat.internalFormatRepresentation = FORMATREPRESENTATION_FLOAT; + break; case PIXELFORMAT_DEPTH32_FLOAT_STENCIL8: + textureFormat.internalFormat = VK_FORMAT_D32_SFLOAT_S8_UINT; + textureFormat.internalFormatRepresentation = FORMATREPRESENTATION_FLOAT; // ? + break; case PIXELFORMAT_DXT1_UNORM: case PIXELFORMAT_DXT3_UNORM: case PIXELFORMAT_DXT5_UNORM: + throw love::Exception("unimplemented: dxt"); case PIXELFORMAT_BC4_UNORM: + textureFormat.internalFormat = VK_FORMAT_BC4_UNORM_BLOCK; + break; case PIXELFORMAT_BC4_SNORM: + textureFormat.internalFormat = VK_FORMAT_BC4_SNORM_BLOCK; + break; case PIXELFORMAT_BC5_UNORM: + textureFormat.internalFormat = VK_FORMAT_BC5_UNORM_BLOCK; + break; case PIXELFORMAT_BC5_SNORM: + textureFormat.internalFormat = VK_FORMAT_BC5_SNORM_BLOCK; + break; case PIXELFORMAT_BC6H_UFLOAT: + textureFormat.internalFormat = VK_FORMAT_BC6H_UFLOAT_BLOCK; + break; case PIXELFORMAT_BC6H_FLOAT: + textureFormat.internalFormat = VK_FORMAT_BC6H_SFLOAT_BLOCK; + break; case PIXELFORMAT_BC7_UNORM: + textureFormat.internalFormat = VK_FORMAT_BC7_UNORM_BLOCK; + break; case PIXELFORMAT_PVR1_RGB2_UNORM: case PIXELFORMAT_PVR1_RGB4_UNORM: case PIXELFORMAT_PVR1_RGBA2_UNORM: case PIXELFORMAT_PVR1_RGBA4_UNORM: + throw love::Exception("unimplemented pixel format: pvr1"); case PIXELFORMAT_ETC1_UNORM: case PIXELFORMAT_ETC2_RGB_UNORM: case PIXELFORMAT_ETC2_RGBA_UNORM: case PIXELFORMAT_ETC2_RGBA1_UNORM: + throw love::Exception("unimplemented pixel format: etc"); case PIXELFORMAT_EAC_R_UNORM: case PIXELFORMAT_EAC_R_SNORM: case PIXELFORMAT_EAC_RG_UNORM: case PIXELFORMAT_EAC_RG_SNORM: + throw love::Exception("unimplemented pixel format: eac"); case PIXELFORMAT_ASTC_4x4: case PIXELFORMAT_ASTC_5x4: case PIXELFORMAT_ASTC_5x5: @@ -309,7 +343,7 @@ TextureFormat Vulkan::getTextureFormat(PixelFormat format) { case PIXELFORMAT_ASTC_10x10: case PIXELFORMAT_ASTC_12x10: case PIXELFORMAT_ASTC_12x12: - throw love::Exception("unimplemented pixel format"); + throw love::Exception("unimplemented pixel format: astc"); default: throw love::Exception("unknown pixel format"); } @@ -325,7 +359,7 @@ std::string Vulkan::getVendorName(uint32_t vendorId) { return "AMD"; case 4318: return "Nvidia"; - case 8086: + case 32902: return "Intel"; case 4203: return "Apple";