From 6d7bd645fc362da74960939b35c1a19b44d1a2df Mon Sep 17 00:00:00 2001 From: niki Date: Sun, 24 Jul 2022 13:43:48 +0200 Subject: [PATCH] vulkan: use vkCmdClearColorImage to clear texture using the vulkan functionality probably leads to less bugs. Until now it was assumed that any image was in the rgba8 format, which is of course not correct. Clearing a texture to white or black should now work for any format. --- src/modules/graphics/vulkan/Shader.cpp | 1 + src/modules/graphics/vulkan/Texture.cpp | 90 +++++++++++++++++++------ src/modules/graphics/vulkan/Texture.h | 3 + src/modules/graphics/vulkan/Vulkan.cpp | 35 ++++++++++ src/modules/graphics/vulkan/Vulkan.h | 8 +++ 5 files changed, 118 insertions(+), 19 deletions(-) diff --git a/src/modules/graphics/vulkan/Shader.cpp b/src/modules/graphics/vulkan/Shader.cpp index 60e1b7b62..6d9717331 100644 --- a/src/modules/graphics/vulkan/Shader.cpp +++ b/src/modules/graphics/vulkan/Shader.cpp @@ -203,6 +203,7 @@ namespace love { if (currentImage != imageIndex) { currentImage = imageIndex; count = 0; + streamBuffers[currentImage]->nextFrame(); } else { if (count >= STREAMBUFFER_SIZE) { diff --git a/src/modules/graphics/vulkan/Texture.cpp b/src/modules/graphics/vulkan/Texture.cpp index 5cc07d3df..21d5b71d3 100644 --- a/src/modules/graphics/vulkan/Texture.cpp +++ b/src/modules/graphics/vulkan/Texture.cpp @@ -2,6 +2,8 @@ #include "Graphics.h" #include "Vulkan.h" +#include + // make vulkan::Graphics functions available #define vgfx ((Graphics*)gfx) @@ -19,11 +21,7 @@ namespace love { auto vulkanFormat = Vulkan::getTextureFormat(format); - VkImageUsageFlags usageFlags = VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT; - - if (isRenderTarget()) { - usageFlags |= VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT; - } + VkImageUsageFlags usageFlags = VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT; VkImageCreateInfo imageInfo{}; imageInfo.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO; @@ -60,22 +58,10 @@ namespace love { uploadByteData(format, dataPtr, size, 0, 0, rect); } else { if (isRenderTarget()) { - std::vector defaultPixels; - defaultPixels.reserve(width * height * 4); - for (size_t i = 0; i < width * height; i++) { - // transparent black - defaultPixels.push_back(0); - defaultPixels.push_back(0); - defaultPixels.push_back(0); - defaultPixels.push_back(255); - } - Rect rect = { 0, 0, width, height }; - uploadByteData(PIXELFORMAT_RGBA8_UNORM, defaultPixels.data(), defaultPixels.size(), 0, 0, rect); + clear(false); } else { - std::vector defaultPixels(width * height * 4, 255); - Rect rect = { 0, 0, width, height }; - uploadByteData(PIXELFORMAT_RGBA8_UNORM, defaultPixels.data(), defaultPixels.size(), 0, 0, rect); + clear(true); } } createTextureImageView(); @@ -153,6 +139,72 @@ namespace love { } } + void Texture::clear(bool white) { + auto commandBuffer = vgfx->beginSingleTimeCommands(); + + auto clearColor = getClearValue(white); + + VkImageSubresourceRange range{}; + range.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + range.layerCount = 1; + range.levelCount = 1; + + vkCmdClearColorImage(commandBuffer, textureImage, VK_IMAGE_LAYOUT_GENERAL, &clearColor, 1, &range); + + vgfx->endSingleTimeCommands(commandBuffer); + } + + VkClearColorValue Texture::getClearValue(bool white) { + auto vulkanFormat = Vulkan::getTextureFormat(format); + + VkClearColorValue clearColor{}; + if (white) { + switch (vulkanFormat.internalFormatRepresentation) { + case FORMATREPRESENTATION_FLOAT: + clearColor.float32[0] = 1.0f; + clearColor.float32[1] = 1.0f; + clearColor.float32[2] = 1.0f; + clearColor.float32[3] = 1.0f; + break; + case FORMATREPRESENTATION_SINT: + clearColor.int32[0] = std::numeric_limits::max(); + clearColor.int32[1] = std::numeric_limits::max(); + clearColor.int32[2] = std::numeric_limits::max(); + clearColor.int32[3] = std::numeric_limits::max(); + break; + case FORMATREPRESENTATION_UINT: + clearColor.uint32[0] = std::numeric_limits::max(); + clearColor.uint32[1] = std::numeric_limits::max(); + clearColor.uint32[2] = std::numeric_limits::max(); + clearColor.uint32[3] = std::numeric_limits::max(); + break; + } + } + else { + switch (vulkanFormat.internalFormatRepresentation) { + case FORMATREPRESENTATION_FLOAT: + clearColor.float32[0] = 0.0f; + clearColor.float32[1] = 0.0f; + clearColor.float32[2] = 0.0f; + clearColor.float32[3] = 0.0f; + break; + case FORMATREPRESENTATION_SINT: + clearColor.int32[0] = 0; + clearColor.int32[1] = 0; + clearColor.int32[2] = 0; + clearColor.int32[3] = 0; + break; + case FORMATREPRESENTATION_UINT: + clearColor.uint32[0] = 0; + clearColor.uint32[1] = 0; + clearColor.uint32[2] = 0; + clearColor.uint32[3] = 0; + break; + } + } + return clearColor; + } + void Texture::transitionImageLayout(VkImage image, VkImageLayout oldLayout, VkImageLayout newLayout) { auto commandBuffer = vgfx->beginSingleTimeCommands(); diff --git a/src/modules/graphics/vulkan/Texture.h b/src/modules/graphics/vulkan/Texture.h index e123f3271..df0b1900d 100644 --- a/src/modules/graphics/vulkan/Texture.h +++ b/src/modules/graphics/vulkan/Texture.h @@ -40,6 +40,9 @@ namespace love { void copyBufferToImage(VkBuffer, VkImage, const Rect&); void createTextureImageView(); void createTextureSampler(); + void clear(bool white); + + VkClearColorValue getClearValue(bool white); graphics::Graphics* gfx; VkDevice device; diff --git a/src/modules/graphics/vulkan/Vulkan.cpp b/src/modules/graphics/vulkan/Vulkan.cpp index 66fdfe920..c10b2bdaa 100644 --- a/src/modules/graphics/vulkan/Vulkan.cpp +++ b/src/modules/graphics/vulkan/Vulkan.cpp @@ -109,47 +109,61 @@ namespace love { throw love::Exception("unknown pixel format"); case PIXELFORMAT_NORMAL: textureFormat.internalFormat = VK_FORMAT_R8G8B8A8_SRGB; + textureFormat.internalFormatRepresentation = FORMATREPRESENTATION_FLOAT; break; case PIXELFORMAT_HDR: throw love::Exception("unimplemented pixel format: hdr"); case PIXELFORMAT_R8_UNORM: textureFormat.internalFormat = VK_FORMAT_R8_UNORM; + textureFormat.internalFormatRepresentation = FORMATREPRESENTATION_FLOAT; break; case PIXELFORMAT_R8_INT: textureFormat.internalFormat = VK_FORMAT_R8_SINT; + textureFormat.internalFormatRepresentation = FORMATREPRESENTATION_SINT; break; case PIXELFORMAT_R8_UINT: textureFormat.internalFormat = VK_FORMAT_R8_UINT; + textureFormat.internalFormatRepresentation = FORMATREPRESENTATION_UINT; break; case PIXELFORMAT_R16_UNORM: textureFormat.internalFormat = VK_FORMAT_R16_UNORM; + textureFormat.internalFormatRepresentation = FORMATREPRESENTATION_FLOAT; break; case PIXELFORMAT_R16_FLOAT: textureFormat.internalFormat = VK_FORMAT_R16_SFLOAT; + textureFormat.internalFormatRepresentation = FORMATREPRESENTATION_FLOAT; break; case PIXELFORMAT_R16_INT: textureFormat.internalFormat = VK_FORMAT_R16_SINT; + textureFormat.internalFormatRepresentation = FORMATREPRESENTATION_SINT; break; case PIXELFORMAT_R16_UINT: textureFormat.internalFormat = VK_FORMAT_R16_UINT; + textureFormat.internalFormatRepresentation = FORMATREPRESENTATION_UINT; break; case PIXELFORMAT_R32_FLOAT: textureFormat.internalFormat = VK_FORMAT_R32_SFLOAT; + textureFormat.internalFormatRepresentation = FORMATREPRESENTATION_FLOAT; break; case PIXELFORMAT_R32_INT: textureFormat.internalFormat = VK_FORMAT_R32_SINT; + textureFormat.internalFormatRepresentation = FORMATREPRESENTATION_SINT; break; case PIXELFORMAT_R32_UINT: textureFormat.internalFormat = VK_FORMAT_R32_UINT; + textureFormat.internalFormatRepresentation = FORMATREPRESENTATION_UINT; break; case PIXELFORMAT_RG8_UNORM: textureFormat.internalFormat = VK_FORMAT_R8G8_UNORM; + textureFormat.internalFormatRepresentation = FORMATREPRESENTATION_FLOAT; break; case PIXELFORMAT_RG8_INT: textureFormat.internalFormat = VK_FORMAT_R8G8_SINT; + textureFormat.internalFormatRepresentation = FORMATREPRESENTATION_SINT; break; case PIXELFORMAT_RG8_UINT: textureFormat.internalFormat = VK_FORMAT_R8G8_UINT; + textureFormat.internalFormatRepresentation = FORMATREPRESENTATION_UINT; break; case PIXELFORMAT_LA8_UNORM: // Same as RG8: but accessed as (L: L: L: A) textureFormat.internalFormat = VK_FORMAT_R8G8_UNORM; @@ -157,66 +171,87 @@ namespace love { textureFormat.swizzleG = VK_COMPONENT_SWIZZLE_R; textureFormat.swizzleB = VK_COMPONENT_SWIZZLE_R; textureFormat.swizzleA = VK_COMPONENT_SWIZZLE_G; + textureFormat.internalFormatRepresentation = FORMATREPRESENTATION_FLOAT; break; case PIXELFORMAT_RG16_UNORM: textureFormat.internalFormat = VK_FORMAT_R16G16_UNORM; + textureFormat.internalFormatRepresentation = FORMATREPRESENTATION_FLOAT; break; case PIXELFORMAT_RG16_FLOAT: textureFormat.internalFormat = VK_FORMAT_R16G16_SFLOAT; + textureFormat.internalFormatRepresentation = FORMATREPRESENTATION_FLOAT; break; case PIXELFORMAT_RG16_INT: textureFormat.internalFormat = VK_FORMAT_R16G16_SINT; + textureFormat.internalFormatRepresentation = FORMATREPRESENTATION_SINT; break; case PIXELFORMAT_RG16_UINT: textureFormat.internalFormat = VK_FORMAT_R16G16_UINT; + textureFormat.internalFormatRepresentation = FORMATREPRESENTATION_UINT; break; case PIXELFORMAT_RG32_FLOAT: textureFormat.internalFormat = VK_FORMAT_R32G32_SFLOAT; + textureFormat.internalFormatRepresentation = FORMATREPRESENTATION_FLOAT; break; case PIXELFORMAT_RG32_INT: textureFormat.internalFormat = VK_FORMAT_R32G32_SINT; + textureFormat.internalFormatRepresentation = FORMATREPRESENTATION_SINT; break; case PIXELFORMAT_RG32_UINT: textureFormat.internalFormat = VK_FORMAT_R32G32_UINT; + textureFormat.internalFormatRepresentation = FORMATREPRESENTATION_UINT; break; case PIXELFORMAT_RGBA8_UNORM: textureFormat.internalFormat = VK_FORMAT_R8G8B8A8_SRGB; // fixme? + textureFormat.internalFormatRepresentation = FORMATREPRESENTATION_FLOAT; break; case PIXELFORMAT_RGBA8_UNORM_sRGB: textureFormat.internalFormat = VK_FORMAT_R8G8B8A8_SRGB; + textureFormat.internalFormatRepresentation = FORMATREPRESENTATION_FLOAT; break; case PIXELFORMAT_BGRA8_UNORM: textureFormat.internalFormat = VK_FORMAT_B8G8R8A8_UNORM; + textureFormat.internalFormatRepresentation = FORMATREPRESENTATION_FLOAT; break; case PIXELFORMAT_BGRA8_UNORM_sRGB: textureFormat.internalFormat = VK_FORMAT_B8G8R8A8_SRGB; + textureFormat.internalFormatRepresentation = FORMATREPRESENTATION_FLOAT; break; case PIXELFORMAT_RGBA8_INT: textureFormat.internalFormat = VK_FORMAT_R8G8B8A8_SINT; + textureFormat.internalFormatRepresentation = FORMATREPRESENTATION_SINT; break; case PIXELFORMAT_RGBA8_UINT: textureFormat.internalFormat = VK_FORMAT_R8G8B8A8_UINT; + textureFormat.internalFormatRepresentation = FORMATREPRESENTATION_UINT; break; case PIXELFORMAT_RGBA16_UNORM: textureFormat.internalFormat = VK_FORMAT_R16G16B16A16_UNORM; + textureFormat.internalFormatRepresentation = FORMATREPRESENTATION_FLOAT; break; case PIXELFORMAT_RGBA16_FLOAT: textureFormat.internalFormat = VK_FORMAT_R16G16B16A16_SFLOAT; + textureFormat.internalFormatRepresentation = FORMATREPRESENTATION_FLOAT; break; case PIXELFORMAT_RGBA16_INT: textureFormat.internalFormat = VK_FORMAT_R16G16B16A16_SINT; + textureFormat.internalFormatRepresentation = FORMATREPRESENTATION_SINT; break; case PIXELFORMAT_RGBA16_UINT: textureFormat.internalFormat = VK_FORMAT_R16G16B16A16_UINT; + textureFormat.internalFormatRepresentation = FORMATREPRESENTATION_UINT; break; case PIXELFORMAT_RGBA32_FLOAT: textureFormat.internalFormat = VK_FORMAT_R32G32B32A32_SFLOAT; + textureFormat.internalFormatRepresentation = FORMATREPRESENTATION_FLOAT; break; case PIXELFORMAT_RGBA32_INT: textureFormat.internalFormat = VK_FORMAT_R32G32B32A32_SINT; + textureFormat.internalFormatRepresentation = FORMATREPRESENTATION_SINT; break; case PIXELFORMAT_RGBA32_UINT: textureFormat.internalFormat = VK_FORMAT_R32G32B32A32_UINT; + textureFormat.internalFormatRepresentation = FORMATREPRESENTATION_UINT; break; case PIXELFORMAT_RGBA4_UNORM: // LSB->MSB: [a: b: g: r] case PIXELFORMAT_RGB5A1_UNORM: // LSB->MSB: [a: b: g: r] diff --git a/src/modules/graphics/vulkan/Vulkan.h b/src/modules/graphics/vulkan/Vulkan.h index a4b8f010b..c8c438f74 100644 --- a/src/modules/graphics/vulkan/Vulkan.h +++ b/src/modules/graphics/vulkan/Vulkan.h @@ -7,7 +7,15 @@ namespace love { namespace graphics { namespace vulkan { + enum InternalFormatRepresentation { + FORMATREPRESENTATION_FLOAT, + FORMATREPRESENTATION_UINT, + FORMATREPRESENTATION_SINT, + FORMATREPRESENTATION_MAX_ENUM + }; + struct TextureFormat { + InternalFormatRepresentation internalFormatRepresentation; VkFormat internalFormat = VK_FORMAT_UNDEFINED; VkComponentSwizzle swizzleR = VK_COMPONENT_SWIZZLE_IDENTITY;