From 284a3850621a3030007a225d535ed913b25bf703 Mon Sep 17 00:00:00 2001 From: niki Date: Fri, 31 Mar 2023 17:19:38 +0200 Subject: [PATCH 01/14] support more swapchain image formats --- src/modules/graphics/vulkan/Graphics.cpp | 34 +++++++++++++++++------- 1 file changed, 24 insertions(+), 10 deletions(-) diff --git a/src/modules/graphics/vulkan/Graphics.cpp b/src/modules/graphics/vulkan/Graphics.cpp index 2131e4977..90f24957e 100644 --- a/src/modules/graphics/vulkan/Graphics.cpp +++ b/src/modules/graphics/vulkan/Graphics.cpp @@ -514,7 +514,7 @@ void Graphics::present(void *screenshotCallbackdata) void Graphics::setViewportSize(int width, int height, int pixelwidth, int pixelheight) { - if (swapChain != VK_NULL_HANDLE && (pixelWidth != this->pixelWidth || pixelHeight != this->pixelHeight || width != this->width || height != this->height)) + if (swapChain != VK_NULL_HANDLE && (pixelwidth != this->pixelWidth || pixelheight != this->pixelHeight || width != this->width || height != this->height)) requestSwapchainRecreation(); this->width = width; @@ -1850,20 +1850,34 @@ void Graphics::createSwapChain() VkSurfaceFormatKHR Graphics::chooseSwapSurfaceFormat(const std::vector &availableFormats) { + std::vector formatOrder; + // TODO: turn off GammaCorrect if a sRGB format can't be found? + // TODO: does every platform have these formats? if (isGammaCorrect()) { - for (const auto &availableFormat : availableFormats) - // fixme: what if this format and colorspace is not available? - if (availableFormat.format == VK_FORMAT_B8G8R8A8_SRGB && availableFormat.colorSpace == VK_COLOR_SPACE_SRGB_NONLINEAR_KHR) - return availableFormat; + formatOrder = { + VK_FORMAT_B8G8R8A8_SRGB, + VK_FORMAT_R8G8B8A8_SRGB, + }; + } + else + { + formatOrder = { + VK_FORMAT_B8G8R8A8_UNORM, + VK_FORMAT_R8G8B8A8_SNORM, + }; } - for (const auto &availableFormat : availableFormats) - // fixme: what if this format and colorspace is not available? - if (availableFormat.format == VK_FORMAT_B8G8R8A8_UNORM && availableFormat.colorSpace == VK_COLOR_SPACE_SRGB_NONLINEAR_KHR) - return availableFormat; - + for (const auto format : formatOrder) + { + for (const auto &availableFormat : availableFormats) + { + if (availableFormat.format == format && availableFormat.colorSpace == VK_COLORSPACE_SRGB_NONLINEAR_KHR) + return availableFormat; + } + } + return availableFormats[0]; } From 37013267f7ecae01905b8d4c2cc1929d6d5fdec8 Mon Sep 17 00:00:00 2001 From: niki Date: Sun, 16 Apr 2023 00:10:41 +0200 Subject: [PATCH 02/14] vulkan: improve readability / maintainability --- src/modules/graphics/vulkan/Vulkan.cpp | 214 ++++++------------------- 1 file changed, 53 insertions(+), 161 deletions(-) diff --git a/src/modules/graphics/vulkan/Vulkan.cpp b/src/modules/graphics/vulkan/Vulkan.cpp index 22d9b10f8..817f6fdb7 100644 --- a/src/modules/graphics/vulkan/Vulkan.cpp +++ b/src/modules/graphics/vulkan/Vulkan.cpp @@ -747,8 +747,54 @@ VkIndexType Vulkan::getVulkanIndexBufferType(IndexDataType type) } } -void Vulkan::cmdTransitionImageLayout(VkCommandBuffer commandBuffer, VkImage image, VkImageLayout oldLayout, VkImageLayout newLayout, - uint32_t baseLevel, uint32_t levelCount, uint32_t baseLayer, uint32_t layerCount) +static void setImageLayoutTransitionOptions(bool previous, VkImageLayout layout, VkAccessFlags &accessMask, VkPipelineStageFlags &stageFlags, bool &depthStencil) +{ + switch (layout) + { + case VK_IMAGE_LAYOUT_UNDEFINED: + accessMask = 0; + if (previous) + stageFlags = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT; + else + stageFlags = VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT; + break; + case VK_IMAGE_LAYOUT_GENERAL: + // We use the general image layout for images that are both compute write and readable. + // todo: can we optimize this? + accessMask = VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT | VK_ACCESS_TRANSFER_WRITE_BIT | VK_ACCESS_TRANSFER_READ_BIT; + stageFlags = VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT | VK_PIPELINE_STAGE_TRANSFER_BIT; + break; + case VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL: + accessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT; + stageFlags = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; + break; + case VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL: + depthStencil = true; + accessMask = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT; + stageFlags = VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT; + break; + case VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL: + accessMask = VK_ACCESS_SHADER_READ_BIT; + stageFlags = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT; + break; + case VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL: + accessMask = VK_ACCESS_TRANSFER_READ_BIT; + stageFlags = VK_PIPELINE_STAGE_TRANSFER_BIT; + break; + case VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL: + accessMask = VK_ACCESS_TRANSFER_WRITE_BIT; + stageFlags = VK_PIPELINE_STAGE_TRANSFER_BIT; + break; + case VK_IMAGE_LAYOUT_PRESENT_SRC_KHR: + accessMask = 0; + stageFlags = VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT; + break; + default: + throw love::Exception("unimplemented image layout"); + } +} + +void Vulkan::cmdTransitionImageLayout(VkCommandBuffer commandBuffer, VkImage image, VkImageLayout oldLayout, VkImageLayout newLayout, uint32_t baseLevel, uint32_t levelCount, uint32_t baseLayer, uint32_t layerCount) { VkImageMemoryBarrier barrier{}; barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; @@ -757,176 +803,22 @@ void Vulkan::cmdTransitionImageLayout(VkCommandBuffer commandBuffer, VkImage ima barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; barrier.image = image; - barrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; barrier.subresourceRange.baseMipLevel = baseLevel; barrier.subresourceRange.levelCount = levelCount; barrier.subresourceRange.baseArrayLayer = baseLayer; barrier.subresourceRange.layerCount = layerCount; + bool depthStencil = false; VkPipelineStageFlags sourceStage; VkPipelineStageFlags destinationStage; - if (oldLayout == VK_IMAGE_LAYOUT_UNDEFINED && newLayout == VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL) - { - barrier.srcAccessMask = 0; - barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT; + setImageLayoutTransitionOptions(true, oldLayout, barrier.srcAccessMask, sourceStage, depthStencil); + setImageLayoutTransitionOptions(false, newLayout, barrier.dstAccessMask, destinationStage, depthStencil); - sourceStage = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT; - destinationStage = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT; - } - else if (oldLayout == VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL && newLayout == VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL) - { - barrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; - barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT; - - sourceStage = VK_PIPELINE_STAGE_TRANSFER_BIT; - destinationStage = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT; - } - else if (oldLayout == VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL && newLayout == VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL) - { - barrier.srcAccessMask = VK_ACCESS_SHADER_READ_BIT; - barrier.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; - - sourceStage = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT; - destinationStage = VK_PIPELINE_STAGE_TRANSFER_BIT; - } - else if (oldLayout == VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL && newLayout == VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL) - { - barrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; - barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT; - - sourceStage = VK_PIPELINE_STAGE_TRANSFER_BIT; - destinationStage = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT; - } - else if (oldLayout == VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL && newLayout == VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL) - { - barrier.srcAccessMask = VK_ACCESS_SHADER_READ_BIT; - barrier.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; - - sourceStage = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT; - destinationStage = VK_PIPELINE_STAGE_TRANSFER_BIT; - } - else if (oldLayout == VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL && newLayout == VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL) - { - barrier.srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT; - barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT; - - sourceStage = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; - destinationStage = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT; - } - else if (oldLayout == VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL && newLayout == VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL) - { - barrier.srcAccessMask = VK_ACCESS_SHADER_READ_BIT; - barrier.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT; - - sourceStage = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT; - destinationStage = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; - } - else if (oldLayout == VK_IMAGE_LAYOUT_UNDEFINED && newLayout == VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL) - { - barrier.srcAccessMask = 0; - barrier.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT; - - sourceStage = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT; - destinationStage = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; - } - else if (oldLayout == VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL && newLayout == VK_IMAGE_LAYOUT_PRESENT_SRC_KHR) - { - barrier.srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT; - barrier.dstAccessMask = 0; - - sourceStage = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; - destinationStage = VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT; - } - // we use general for images that are both sampled and compute write - else if (oldLayout == VK_IMAGE_LAYOUT_UNDEFINED && newLayout == VK_IMAGE_LAYOUT_GENERAL) - { - barrier.srcAccessMask = 0; - barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT | VK_ACCESS_TRANSFER_WRITE_BIT | VK_ACCESS_TRANSFER_READ_BIT; - - sourceStage = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT; - destinationStage = VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT | VK_PIPELINE_STAGE_TRANSFER_BIT; - } - else if (oldLayout == VK_IMAGE_LAYOUT_UNDEFINED && newLayout == VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL) - { + if (depthStencil) barrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT; - - barrier.srcAccessMask = 0; - barrier.dstAccessMask = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT; - - sourceStage = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT; - destinationStage = VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT; - } - else if (oldLayout == VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL && newLayout == VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL) - { - barrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT; - - barrier.srcAccessMask = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT; - barrier.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; - - sourceStage = VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT; - destinationStage = VK_PIPELINE_STAGE_TRANSFER_BIT; - } - else if (oldLayout == VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL && newLayout == VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL) - { - barrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT; - - barrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; - barrier.dstAccessMask = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT; - - sourceStage = VK_PIPELINE_STAGE_TRANSFER_BIT; - destinationStage = VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT; - } - else if (oldLayout == VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL && newLayout == VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL) - { - barrier.srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT; - barrier.dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT; - - sourceStage = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; - destinationStage = VK_PIPELINE_STAGE_TRANSFER_BIT; - } - else if (oldLayout == VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL && newLayout == VK_IMAGE_LAYOUT_PRESENT_SRC_KHR) - { - barrier.srcAccessMask = VK_ACCESS_TRANSFER_READ_BIT; - barrier.dstAccessMask = 0; - - sourceStage = VK_PIPELINE_STAGE_TRANSFER_BIT; - destinationStage = VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT; - } - else if (oldLayout == VK_IMAGE_LAYOUT_UNDEFINED && newLayout == VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL) - { - barrier.srcAccessMask = 0; - barrier.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; - - sourceStage = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT; - destinationStage = VK_PIPELINE_STAGE_TRANSFER_BIT; - } - else if (oldLayout == VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL && newLayout == VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL) - { - barrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; - barrier.dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT; - - sourceStage = VK_PIPELINE_STAGE_TRANSFER_BIT; - destinationStage = VK_PIPELINE_STAGE_TRANSFER_BIT; - } - else if (oldLayout == VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL && newLayout == VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL) - { - barrier.srcAccessMask = VK_ACCESS_TRANSFER_READ_BIT; - barrier.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; - - sourceStage = VK_PIPELINE_STAGE_TRANSFER_BIT; - destinationStage = VK_PIPELINE_STAGE_TRANSFER_BIT; - } - else if (oldLayout == VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL && newLayout == VK_IMAGE_LAYOUT_UNDEFINED) - { - barrier.srcAccessMask = VK_ACCESS_TRANSFER_READ_BIT; - barrier.dstAccessMask = 0; - - sourceStage = VK_PIPELINE_STAGE_TRANSFER_BIT; - destinationStage = VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT; - } else - throw std::invalid_argument("unsupported layout transition!"); + barrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; vkCmdPipelineBarrier( commandBuffer, From 8b419522d7b594cfaabb5b25949e3ee4ad26c858 Mon Sep 17 00:00:00 2001 From: niki Date: Fri, 28 Apr 2023 14:27:46 +0200 Subject: [PATCH 03/14] vulkan: simplify code slightly --- src/modules/graphics/vulkan/Shader.cpp | 21 +++++++-------------- 1 file changed, 7 insertions(+), 14 deletions(-) diff --git a/src/modules/graphics/vulkan/Shader.cpp b/src/modules/graphics/vulkan/Shader.cpp index 94c06f53a..88f7f3537 100644 --- a/src/modules/graphics/vulkan/Shader.cpp +++ b/src/modules/graphics/vulkan/Shader.cpp @@ -178,24 +178,17 @@ public: private: - uint32_t getFreeBinding() { + 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) + if (isFreeBinding(i)) return i; } } - bool isFreeBinding(uint32_t binding) { + bool isFreeBinding(uint32_t binding) + { for (const auto &entry : bindingMappings) { if (entry.second == binding) @@ -218,8 +211,8 @@ static VkShaderStageFlagBits getStageBit(ShaderStageType type) return VK_SHADER_STAGE_FRAGMENT_BIT; case SHADERSTAGE_COMPUTE: return VK_SHADER_STAGE_COMPUTE_BIT; - default: - throw love::Exception("invalid type"); + default: + throw love::Exception("invalid type"); } } From 332b456131928038db168775d78b5d8184ced877 Mon Sep 17 00:00:00 2001 From: niki Date: Thu, 11 May 2023 11:56:06 +0200 Subject: [PATCH 04/14] vulkan: remove getDefaultTexture --- src/modules/graphics/vulkan/Graphics.cpp | 5 ----- src/modules/graphics/vulkan/Graphics.h | 13 +++++-------- src/modules/graphics/vulkan/Shader.cpp | 10 +++++----- src/modules/graphics/vulkan/Shader.h | 2 +- 4 files changed, 11 insertions(+), 19 deletions(-) diff --git a/src/modules/graphics/vulkan/Graphics.cpp b/src/modules/graphics/vulkan/Graphics.cpp index 90f24957e..a8d1ce47b 100644 --- a/src/modules/graphics/vulkan/Graphics.cpp +++ b/src/modules/graphics/vulkan/Graphics.cpp @@ -1263,11 +1263,6 @@ const VkDeviceSize Graphics::getMinUniformBufferOffsetAlignment() const return minUniformBufferOffsetAlignment; } -graphics::Texture *Graphics::getDefaultTexture() const -{ - return defaultTexture; -} - VkCommandBuffer Graphics::getCommandBufferForDataTransfer() { if (renderPassState.active) diff --git a/src/modules/graphics/vulkan/Graphics.h b/src/modules/graphics/vulkan/Graphics.h index ddd7ee42c..b2daa27ae 100644 --- a/src/modules/graphics/vulkan/Graphics.h +++ b/src/modules/graphics/vulkan/Graphics.h @@ -262,13 +262,12 @@ public: Graphics(); ~Graphics(); - const char *getName() const override; - const VkDevice getDevice() const; - const VmaAllocator getVmaAllocator() const; - // implementation for virtual functions + const char *getName() const 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; + graphics::GraphicsReadback *newReadbackInternal(ReadbackMethod method, love::graphics::Buffer *buffer, size_t offset, size_t size, data::ByteData *dest, size_t destoffset) override; + graphics::GraphicsReadback *newReadbackInternal(ReadbackMethod method, love::graphics::Texture *texture, int slice, int mipmap, const Rect &rect, image::ImageData *dest, int destx, int desty) override; void clear(OptionalColorD color, OptionalInt stencil, OptionalDouble depth) override; void clear(const std::vector &colors, OptionalInt stencil, OptionalDouble depth) override; Matrix4 computeDeviceProjection(const Matrix4 &projection, bool rendertotexture) const override; @@ -299,17 +298,15 @@ public: void draw(const DrawIndexedCommand &cmd) override; void drawQuads(int start, int count, const VertexAttributes &attributes, const BufferBindings &buffers, graphics::Texture *texture) override; - graphics::GraphicsReadback *newReadbackInternal(ReadbackMethod method, love::graphics::Buffer *buffer, size_t offset, size_t size, data::ByteData *dest, size_t destoffset) override; - graphics::GraphicsReadback *newReadbackInternal(ReadbackMethod method, love::graphics::Texture *texture, int slice, int mipmap, const Rect &rect, image::ImageData *dest, int destx, int desty) override; - // internal functions. + const VkDevice getDevice() const; + const VmaAllocator getVmaAllocator() const; VkCommandBuffer getCommandBufferForDataTransfer(); void queueCleanUp(std::function cleanUp); void addReadbackCallback(std::function callback); void submitGpuCommands(bool present, void *screenshotCallbackData = nullptr); const VkDeviceSize getMinUniformBufferOffsetAlignment() const; - graphics::Texture *getDefaultTexture() const; VkSampler getCachedSampler(const SamplerState &sampler); void setComputeShader(Shader *computeShader); graphics::Shader::BuiltinUniformData getCurrentBuiltinUniformData(); diff --git a/src/modules/graphics/vulkan/Shader.cpp b/src/modules/graphics/vulkan/Shader.cpp index 88f7f3537..adae93550 100644 --- a/src/modules/graphics/vulkan/Shader.cpp +++ b/src/modules/graphics/vulkan/Shader.cpp @@ -903,11 +903,9 @@ void Shader::compileShaders() } else { - auto tex = vgfx->getDefaultTexture(); for (int i = 0; i < info.count; i++) { - info.textures[i] = tex; - tex->retain(); + info.textures[i] = nullptr; } } @@ -1113,7 +1111,8 @@ void Shader::setVideoTextures(graphics::Texture *ytexture, graphics::Texture *cb if (builtinUniformInfo[builtIns[i]] != nullptr) { textures[i]->retain(); - builtinUniformInfo[builtIns[i]]->textures[0]->release(); + if (builtinUniformInfo[builtIns[i]]->textures[0]) + builtinUniformInfo[builtIns[i]]->textures[0]->release(); builtinUniformInfo[builtIns[i]]->textures[0] = textures[i]; } } @@ -1129,7 +1128,8 @@ void Shader::setMainTex(graphics::Texture *texture) if (builtinUniformInfo[BUILTIN_TEXTURE_MAIN] != nullptr) { texture->retain(); - builtinUniformInfo[BUILTIN_TEXTURE_MAIN]->textures[0]->release(); + if (builtinUniformInfo[BUILTIN_TEXTURE_MAIN]->textures[0]) + builtinUniformInfo[BUILTIN_TEXTURE_MAIN]->textures[0]->release(); builtinUniformInfo[BUILTIN_TEXTURE_MAIN]->textures[0] = texture; } } diff --git a/src/modules/graphics/vulkan/Shader.h b/src/modules/graphics/vulkan/Shader.h index 9a65048e1..742f6e8f3 100644 --- a/src/modules/graphics/vulkan/Shader.h +++ b/src/modules/graphics/vulkan/Shader.h @@ -70,7 +70,7 @@ public: void attach() override; - ptrdiff_t getHandle() const { return 0; } + ptrdiff_t getHandle() const override { return 0; } std::string getWarnings() const override { return ""; } From 5254417c63ef0a99d26d3de9620adedd7d7ec041 Mon Sep 17 00:00:00 2001 From: niki Date: Fri, 12 May 2023 12:47:13 +0200 Subject: [PATCH 05/14] vulkan: remove unnecessary vkDeviceWaitIdle Since we are only cleaning up objects that haven't been used in the last 5000 frames, we do not need to wait to delete them. --- src/modules/graphics/vulkan/Graphics.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/modules/graphics/vulkan/Graphics.cpp b/src/modules/graphics/vulkan/Graphics.cpp index a8d1ce47b..00ac0db69 100644 --- a/src/modules/graphics/vulkan/Graphics.cpp +++ b/src/modules/graphics/vulkan/Graphics.cpp @@ -1173,7 +1173,6 @@ void Graphics::beginFrame() if (frameCounter >= USAGES_POLL_INTERVAL) { - vkDeviceWaitIdle(device); cleanupUnusedObjects(); frameCounter = 0; } From 04de1ade9e4e9413ae34cfd450a8d0907240de0d Mon Sep 17 00:00:00 2001 From: niki Date: Sat, 8 Jul 2023 13:23:13 +0200 Subject: [PATCH 06/14] vulkan: correctly deal with custom input attribs --- src/modules/graphics/vulkan/Graphics.cpp | 2 -- src/modules/graphics/vulkan/Shader.cpp | 25 +++++++++++++++++++----- 2 files changed, 20 insertions(+), 7 deletions(-) diff --git a/src/modules/graphics/vulkan/Graphics.cpp b/src/modules/graphics/vulkan/Graphics.cpp index 00ac0db69..21b1afd4a 100644 --- a/src/modules/graphics/vulkan/Graphics.cpp +++ b/src/modules/graphics/vulkan/Graphics.cpp @@ -2410,8 +2410,6 @@ void Graphics::setDefaultRenderPass() void Graphics::setRenderPass(const RenderTargets &rts, int pixelw, int pixelh, bool hasSRGBtexture) { - auto currentCommandBuffer = commandBuffers.at(currentFrame); - // fixme: hasSRGBtexture RenderPassConfiguration renderPassConfiguration{}; for (const auto &color : rts.colors) diff --git a/src/modules/graphics/vulkan/Shader.cpp b/src/modules/graphics/vulkan/Shader.cpp index adae93550..9d02a950a 100644 --- a/src/modules/graphics/vulkan/Shader.cpp +++ b/src/modules/graphics/vulkan/Shader.cpp @@ -18,6 +18,7 @@ * 3. This notice may not be removed or altered from any source distribution. **/ +#include "graphics/vertex.h" #include "Shader.h" #include "Graphics.h" @@ -824,8 +825,8 @@ void Shader::compileShaders() if (resource.name == "gl_DefaultUniformBlock") { const auto& type = comp.get_type(resource.base_type_id); - size_t uniformBufferObjectSize = comp.get_declared_struct_size(type); - auto defaultUniformBlockSize = comp.get_declared_struct_size(type); + size_t defaultUniformBlockSize = comp.get_declared_struct_size(type); + localUniformStagingData.resize(defaultUniformBlockSize); localUniformData.resize(defaultUniformBlockSize); localUniformLocation = bindingMapper(comp, spirv, resource.name, resource.id); @@ -961,11 +962,25 @@ void Shader::compileShaders() if (shaderStage == SHADERSTAGE_VERTEX) { + int nextAttributeIndex = ATTRIB_MAX_ENUM; + for (const auto &r : shaderResources.stage_inputs) { - const auto &name = r.name; - const int attributeLocation = static_cast(comp.get_decoration(r.id, spv::DecorationLocation)); - attributes[name] = attributeLocation; + int index; + + BuiltinVertexAttribute builtinAttribute; + if (graphics::getConstant(r.name.c_str(), builtinAttribute)) + index = (int)builtinAttribute; + else + index = nextAttributeIndex++; + + uint32_t locationOffset; + if (!comp.get_binary_offset_for_decoration(r.id, spv::DecorationLocation, locationOffset)) + throw love::Exception("could not get binary offset for location"); + + spirv[locationOffset] = (uint32_t)index; + + attributes[r.name] = index; } } From ba15a2ab05bc04017de8bdb6c5290710c32db7ee Mon Sep 17 00:00:00 2001 From: niki Date: Tue, 18 Jul 2023 14:01:05 +0200 Subject: [PATCH 07/14] vulkan: correct usage of pNext chain for device For systems where VK_EXT_extended_dynamic_state is not supported it is not valid to extend VkDeviceCreateInfo with an unknown struct. Todo: if more extensions are supported in the future this code probably needs adjustments to correctly build a pNext chain. --- src/modules/graphics/vulkan/Graphics.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/modules/graphics/vulkan/Graphics.cpp b/src/modules/graphics/vulkan/Graphics.cpp index 21b1afd4a..82ca210b6 100644 --- a/src/modules/graphics/vulkan/Graphics.cpp +++ b/src/modules/graphics/vulkan/Graphics.cpp @@ -1647,10 +1647,11 @@ void Graphics::createLogicalDevice() VkPhysicalDeviceExtendedDynamicStateFeaturesEXT extendedDynamicStateFeatures{}; extendedDynamicStateFeatures.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTENDED_DYNAMIC_STATE_FEATURES_EXT; - extendedDynamicStateFeatures.extendedDynamicState = Vulkan::getBool(optionalDeviceExtensions.extendedDynamicState); + extendedDynamicStateFeatures.extendedDynamicState = VK_TRUE; extendedDynamicStateFeatures.pNext = nullptr; - createInfo.pNext = &extendedDynamicStateFeatures; + if (optionalDeviceExtensions.extendedDynamicState) + createInfo.pNext = &extendedDynamicStateFeatures; if (vkCreateDevice(physicalDevice, &createInfo, nullptr, &device) != VK_SUCCESS) throw love::Exception("failed to create logical device"); From 3b9476b5dd0da9a99f71972c609ccb893f26bf02 Mon Sep 17 00:00:00 2001 From: niki Date: Tue, 18 Jul 2023 14:56:42 +0200 Subject: [PATCH 08/14] vulkan: fix validation warnings Sometimes no buffer for tex coords are given, however the shader still expects some. We can fix this by using a default buffer, which contains the constant tex coords (0, 0), which is then bound instead. --- src/modules/graphics/vulkan/Graphics.cpp | 50 +++++++++++++++++++----- src/modules/graphics/vulkan/Graphics.h | 2 +- 2 files changed, 42 insertions(+), 10 deletions(-) diff --git a/src/modules/graphics/vulkan/Graphics.cpp b/src/modules/graphics/vulkan/Graphics.cpp index 82ca210b6..8a4f7500f 100644 --- a/src/modules/graphics/vulkan/Graphics.cpp +++ b/src/modules/graphics/vulkan/Graphics.cpp @@ -559,8 +559,6 @@ bool Graphics::setMode(void *context, int width, int height, int pixelwidth, int beginFrame(); - uint8 whiteColor[] = { 255, 255, 255, 255 }; - if (batchedDrawState.vb[0] == nullptr) { // Initial sizes that should be good enough for most cases. It will @@ -570,9 +568,19 @@ bool Graphics::setMode(void *context, int width, int height, int pixelwidth, int batchedDrawState.indexBuffer = new StreamBuffer(this, BUFFERUSAGE_INDEX, sizeof(uint16) * LOVE_UINT16_MAX); } + // sometimes the VertexTexCoord is not set, so we manually adjust it to (0, 0) + if (defaultConstantTexCoord == nullptr) + { + float zeroTexCoord[2] = { 0.0f, 0.0f }; + Buffer::DataDeclaration format("ConstantTexCoord", DATAFORMAT_FLOAT_VEC2); + Buffer::Settings settings(BUFFERUSAGEFLAG_VERTEX, BUFFERDATAUSAGE_STATIC); + defaultConstantTexCoord = newBuffer(settings, { format }, zeroTexCoord, sizeof(zeroTexCoord), 1); + } + // sometimes the VertexColor is not set, so we manually adjust it to white color if (defaultConstantColor == nullptr) { + uint8 whiteColor[] = { 255, 255, 255, 255 }; Buffer::DataDeclaration format("ConstantColor", DATAFORMAT_UNORM8_VEC4); Buffer::Settings settings(BUFFERUSAGEFLAG_VERTEX, BUFFERDATAUSAGE_STATIC); defaultConstantColor = newBuffer(settings, { format }, whiteColor, sizeof(whiteColor), 1); @@ -2217,11 +2225,6 @@ VkRenderPass Graphics::getRenderPass(RenderPassConfiguration &configuration) return renderPass; } -bool Graphics::usesConstantVertexColor(const VertexAttributes &vertexAttributes) -{ - return !!(vertexAttributes.enableBits & (1u << ATTRIB_COLOR)); -} - void Graphics::createVulkanVertexFormat( VertexAttributes vertexAttributes, std::vector &bindingDescriptions, @@ -2233,6 +2236,7 @@ void Graphics::createVulkanVertexFormat( auto allBits = enableBits; bool usesColor = false; + bool usesTexCoord = false; uint8_t highestBufferBinding = 0; @@ -2242,6 +2246,8 @@ void Graphics::createVulkanVertexFormat( uint32 bit = 1u << i; if (enableBits & bit) { + if (i == ATTRIB_TEXCOORD) + usesTexCoord = true; if (i == ATTRIB_COLOR) usesColor = true; @@ -2276,11 +2282,31 @@ void Graphics::createVulkanVertexFormat( allBits >>= 1; } + if (!usesTexCoord) + { + // FIXME: is there a case where gaps happen between buffer bindings? + // then this doesn't work. We might need to enable null buffers again. + const auto constantTexCoordBufferBinding = ++highestBufferBinding; + + VkVertexInputBindingDescription bindingDescription{}; + bindingDescription.binding = constantTexCoordBufferBinding; + bindingDescription.inputRate = VK_VERTEX_INPUT_RATE_VERTEX; + bindingDescription.stride = 0; // no stride, will always read the same coord multiple times. + bindingDescriptions.push_back(bindingDescription); + + VkVertexInputAttributeDescription attributeDescription{}; + attributeDescription.binding = constantTexCoordBufferBinding; + attributeDescription.location = ATTRIB_TEXCOORD; + attributeDescription.offset = 0; + attributeDescription.format = VK_FORMAT_R32G32_SFLOAT; + attributeDescriptions.push_back(attributeDescription); + } + if (!usesColor) { // FIXME: is there a case where gaps happen between buffer bindings? // then this doesn't work. We might need to enable null buffers again. - const auto constantColorBufferBinding = highestBufferBinding + 1; + const auto constantColorBufferBinding = ++highestBufferBinding; VkVertexInputBindingDescription bindingDescription{}; bindingDescription.binding = constantColorBufferBinding; @@ -2340,7 +2366,13 @@ void Graphics::prepareDraw(const VertexAttributes &attributes, const BufferBindi } } - if (!usesConstantVertexColor(attributes)) + if (!(attributes.enableBits & (1u << ATTRIB_TEXCOORD))) + { + bufferVector.push_back((VkBuffer)defaultConstantTexCoord->getHandle()); + offsets.push_back((VkDeviceSize)0); + } + + if (!(attributes.enableBits & (1u << ATTRIB_COLOR))) { bufferVector.push_back((VkBuffer)defaultConstantColor->getHandle()); offsets.push_back((VkDeviceSize)0); diff --git a/src/modules/graphics/vulkan/Graphics.h b/src/modules/graphics/vulkan/Graphics.h index b2daa27ae..04161b9e8 100644 --- a/src/modules/graphics/vulkan/Graphics.h +++ b/src/modules/graphics/vulkan/Graphics.h @@ -366,7 +366,6 @@ private: void startRecordingGraphicsCommands(); void endRecordingGraphicsCommands(); void ensureGraphicsPipelineConfiguration(GraphicsPipelineConfiguration &configuration); - bool usesConstantVertexColor(const VertexAttributes &attribs); void createVulkanVertexFormat( VertexAttributes vertexAttributes, std::vector &bindingDescriptions, @@ -435,6 +434,7 @@ private: VmaAllocator vmaAllocator = VK_NULL_HANDLE; StrongRef defaultTexture; StrongRef defaultConstantColor; + StrongRef defaultConstantTexCoord; // functions that need to be called to cleanup objects that were needed for rendering a frame. // We need a vector for each frame in flight. std::vector>> cleanUpFunctions; From e08ade86b56cad43e2af6aa770ac1bfc3b8ae32a Mon Sep 17 00:00:00 2001 From: niki Date: Tue, 25 Jul 2023 16:26:26 +0200 Subject: [PATCH 09/14] vulkan: simplify shader code slightly --- src/modules/graphics/vulkan/Shader.cpp | 257 ++++++++++--------------- src/modules/graphics/vulkan/Shader.h | 3 - 2 files changed, 105 insertions(+), 155 deletions(-) diff --git a/src/modules/graphics/vulkan/Shader.cpp b/src/modules/graphics/vulkan/Shader.cpp index 9d02a950a..8846fa261 100644 --- a/src/modules/graphics/vulkan/Shader.cpp +++ b/src/modules/graphics/vulkan/Shader.cpp @@ -232,6 +232,15 @@ static EShLanguage getGlslShaderType(ShaderStageType stage) } } +static bool usesLocalUniformData(const graphics::Shader::UniformInfo* info) +{ + return info->baseType == graphics::Shader::UNIFORM_BOOL || + info->baseType == graphics::Shader::UNIFORM_FLOAT || + info->baseType == graphics::Shader::UNIFORM_INT || + info->baseType == graphics::Shader::UNIFORM_MATRIX || + info->baseType == graphics::Shader::UNIFORM_UINT; +} + Shader::Shader(StrongRef stages[]) : graphics::Shader(stages) { @@ -338,7 +347,6 @@ void Shader::newFrame() { currentFrame = (currentFrame + 1) % MAX_FRAMES_IN_FLIGHT; - updatedUniforms.clear(); currentUsedUniformStreamBuffersCount = 0; currentUsedDescriptorSetsCount = 0; @@ -404,48 +412,105 @@ void Shader::cmdPushDescriptorSets(VkCommandBuffer commandBuffer, VkPipelineBind vkUpdateDescriptorSets(device, 1, &uniformWrite, 0, nullptr); currentUsedUniformStreamBuffersCount++; - - updatedUniforms.insert(localUniformLocation); - } - - static const std::vector builtinUniformTextures = { - BUILTIN_TEXTURE_MAIN, - BUILTIN_TEXTURE_VIDEO_Y, - BUILTIN_TEXTURE_VIDEO_CB, - BUILTIN_TEXTURE_VIDEO_CR, - }; - - for (const auto &builtin : builtinUniformTextures) - { - if (builtinUniformInfo[builtin] != nullptr) - { - auto texture = dynamic_cast(builtinUniformInfo[builtin]->textures[0]); - - VkDescriptorImageInfo imageInfo{}; - imageInfo.imageLayout = texture->getImageLayout(); - imageInfo.imageView = (VkImageView)texture->getRenderTargetHandle(); - imageInfo.sampler = (VkSampler)texture->getSamplerHandle(); - - auto location = builtinUniformInfo[builtin]->location; - - VkWriteDescriptorSet textureWrite{}; - textureWrite.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; - textureWrite.dstSet = currentDescriptorSet; - textureWrite.dstBinding = location; - textureWrite.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; - textureWrite.descriptorCount = 1; - textureWrite.pImageInfo = &imageInfo; - - vkUpdateDescriptorSets(device, 1, &textureWrite, 0, nullptr); - - updatedUniforms.insert(location); - } } for (const auto &u : uniformInfos) { - if (updatedUniforms.find(u.second.location) == updatedUniforms.end()) - updateUniform(&u.second, u.second.count, true); + auto &info = u.second; + + if (usesLocalUniformData(&info)) + continue; + + if (info.baseType == UNIFORM_SAMPLER || info.baseType == UNIFORM_STORAGETEXTURE) + { + bool isSampler = info.baseType == UNIFORM_SAMPLER; + + std::vector imageInfos; + + for (int i = 0; i < info.count; i++) + { + auto vkTexture = dynamic_cast(info.textures[i]); + + if (vkTexture == nullptr) + throw love::Exception("uniform variable %s is not set.", info.name.c_str()); + + VkDescriptorImageInfo imageInfo{}; + + imageInfo.imageLayout = vkTexture->getImageLayout(); + imageInfo.imageView = (VkImageView)vkTexture->getRenderTargetHandle(); + if (isSampler) + imageInfo.sampler = (VkSampler)vkTexture->getSamplerHandle(); + + imageInfos.push_back(imageInfo); + } + + VkWriteDescriptorSet write{}; + write.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; + write.dstSet = currentDescriptorSet; + write.dstBinding = info.location; + write.dstArrayElement = 0; + if (isSampler) + write.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; + else + write.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE; + write.descriptorCount = static_cast(info.count); + write.pImageInfo = imageInfos.data(); + + vkUpdateDescriptorSets(device, 1, &write, 0, nullptr); + } + if (info.baseType == UNIFORM_STORAGEBUFFER) + { + VkWriteDescriptorSet write{}; + write.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; + write.dstSet = currentDescriptorSet; + write.dstBinding = info.location; + write.dstArrayElement = 0; + write.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER; + write.descriptorCount = info.count; + + std::vector bufferInfos; + + for (int i = 0; i < info.count; i++) + { + if (info.buffers[i] == nullptr) + throw love::Exception("uniform variable %s is not set.", info.name.c_str()); + + VkDescriptorBufferInfo bufferInfo{}; + bufferInfo.buffer = (VkBuffer)info.buffers[i]->getHandle();; + bufferInfo.offset = 0; + bufferInfo.range = info.buffers[i]->getSize(); + + bufferInfos.push_back(bufferInfo); + } + + write.pBufferInfo = bufferInfos.data(); + + vkUpdateDescriptorSets(device, 1, &write, 0, nullptr); + } + if (info.baseType == UNIFORM_TEXELBUFFER) + { + VkWriteDescriptorSet write{}; + write.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; + write.dstSet = currentDescriptorSet; + write.dstBinding = info.location; + write.dstArrayElement = 0; + write.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER; + write.descriptorCount = info.count; + + std::vector bufferViews; + + for (int i = 0; i < info.count; i++) + { + if (info.buffers[i] == nullptr) + throw love::Exception("uniform variable %s is not set.", info.name.c_str()); + + bufferViews.push_back((VkBufferView)info.buffers[i]->getTexelBufferHandle()); + } + + write.pTexelBufferView = bufferViews.data(); + + vkUpdateDescriptorSets(device, 1, &write, 0, nullptr); + } } vkCmdBindDescriptorSets(commandBuffer, bindPoint, pipelineLayout, 0, 1, ¤tDescriptorSet, 0, nullptr); @@ -456,8 +521,6 @@ void Shader::cmdPushDescriptorSets(VkCommandBuffer commandBuffer, VkPipelineBind descriptorSetsVector.at(currentFrame).push_back(allocateDescriptorSet()); currentDescriptorSet = descriptorSetsVector.at(currentFrame).at(currentUsedDescriptorSetsCount); - - updatedUniforms.clear(); } Shader::~Shader() @@ -496,119 +559,13 @@ const Shader::UniformInfo *Shader::getUniformInfo(BuiltinUniform builtin) const return builtinUniformInfo[builtin]; } -static bool usesLocalUniformData(const graphics::Shader::UniformInfo *info) -{ - return info->baseType == graphics::Shader::UNIFORM_BOOL || - info->baseType == graphics::Shader::UNIFORM_FLOAT || - info->baseType == graphics::Shader::UNIFORM_INT || - info->baseType == graphics::Shader::UNIFORM_MATRIX || - info->baseType == graphics::Shader::UNIFORM_UINT; -} - void Shader::updateUniform(const UniformInfo *info, int count) { - updateUniform(info, count, false); -} - -void Shader::updateUniform(const UniformInfo* info, int count, bool internal) -{ - if (!internal && current == this) + if (current == this) Graphics::flushBatchedDrawsGlobal(); if (usesLocalUniformData(info)) memcpy(localUniformData.data(), localUniformStagingData.data(), localUniformStagingData.size()); - if (info->baseType == UNIFORM_SAMPLER || info->baseType == UNIFORM_STORAGETEXTURE) - { - bool isSampler = info->baseType == UNIFORM_SAMPLER; - - std::vector imageInfos; - - for (int i = 0; i < count; i++) - { - auto vkTexture = dynamic_cast(info->textures[i]); - - if (vkTexture == nullptr) - throw love::Exception("uniform variable %s is not set.", info->name.c_str()); - - VkDescriptorImageInfo imageInfo{}; - - imageInfo.imageLayout = vkTexture->getImageLayout(); - imageInfo.imageView = (VkImageView)vkTexture->getRenderTargetHandle(); - if (isSampler) - imageInfo.sampler = (VkSampler)vkTexture->getSamplerHandle(); - - imageInfos.push_back(imageInfo); - } - - VkWriteDescriptorSet write{}; - write.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; - write.dstSet = currentDescriptorSet; - write.dstBinding = info->location; - write.dstArrayElement = 0; - if (isSampler) - write.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; - else - write.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE; - write.descriptorCount = static_cast(count); - write.pImageInfo = imageInfos.data(); - - vkUpdateDescriptorSets(device, 1, &write, 0, nullptr); - } - if (info->baseType == UNIFORM_STORAGEBUFFER) - { - VkWriteDescriptorSet write{}; - write.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; - write.dstSet = currentDescriptorSet; - write.dstBinding = info->location; - write.dstArrayElement = 0; - write.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER; - write.descriptorCount = info->count; - - std::vector bufferInfos; - - for (int i = 0; i < info->count; i++) - { - if (info->buffers[i] == nullptr) - throw love::Exception("uniform variable %s is not set.", info->name.c_str()); - - VkDescriptorBufferInfo bufferInfo{}; - bufferInfo.buffer = (VkBuffer)info->buffers[i]->getHandle();; - bufferInfo.offset = 0; - bufferInfo.range = info->buffers[i]->getSize(); - - bufferInfos.push_back(bufferInfo); - } - - write.pBufferInfo = bufferInfos.data(); - - vkUpdateDescriptorSets(device, 1, &write, 0, nullptr); - } - if (info->baseType == UNIFORM_TEXELBUFFER) - { - VkWriteDescriptorSet write{}; - write.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; - write.dstSet = currentDescriptorSet; - write.dstBinding = info->location; - write.dstArrayElement = 0; - write.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER; - write.descriptorCount = info->count; - - std::vector bufferViews; - - for (int i = 0; i < info->count; i++) - { - if (info->buffers[i] == nullptr) - throw love::Exception("uniform variable %s is not set.", info->name.c_str()); - - bufferViews.push_back((VkBufferView)info->buffers[i]->getTexelBufferHandle()); - } - - write.pTexelBufferView = bufferViews.data(); - - vkUpdateDescriptorSets(device, 1, &write, 0, nullptr); - } - - updatedUniforms.insert(info->location); } void Shader::sendTextures(const UniformInfo *info, graphics::Texture **textures, int count) @@ -621,8 +578,6 @@ void Shader::sendTextures(const UniformInfo *info, graphics::Texture **textures, if (oldTexture) oldTexture->release(); } - - updateUniform(info, count); } void Shader::sendBuffers(const UniformInfo *info, love::graphics::Buffer **buffers, int count) @@ -635,8 +590,6 @@ void Shader::sendBuffers(const UniformInfo *info, love::graphics::Buffer **buffe if (oldBuffer) oldBuffer->release(); } - - updateUniform(info, count); } void Shader::calculateUniformBufferSizeAligned() diff --git a/src/modules/graphics/vulkan/Shader.h b/src/modules/graphics/vulkan/Shader.h index 742f6e8f3..be2817807 100644 --- a/src/modules/graphics/vulkan/Shader.h +++ b/src/modules/graphics/vulkan/Shader.h @@ -102,7 +102,6 @@ private: const spirv_cross::SPIRType &type, size_t baseoff, const std::string &basename); - void updateUniform(const UniformInfo *info, int count, bool internal); VkDescriptorSet allocateDescriptorSet(); @@ -121,8 +120,6 @@ private: std::queue freeDescriptorSets; std::vector> descriptorSetsVector; - std::set updatedUniforms; - std::vector shaderStages; std::vector shaderModules; From f30bf9bee057036a0adb322e45f610ff8cdef487 Mon Sep 17 00:00:00 2001 From: niki Date: Tue, 25 Jul 2023 16:37:53 +0200 Subject: [PATCH 10/14] vulkan: better api use of descriptor pools Some implementations allow for bottomless pools, which never run out of pool memory. This new implementation allows for this case to happen. --- src/modules/graphics/vulkan/Shader.cpp | 67 ++++++++++++++------------ src/modules/graphics/vulkan/Shader.h | 9 +--- 2 files changed, 37 insertions(+), 39 deletions(-) diff --git a/src/modules/graphics/vulkan/Shader.cpp b/src/modules/graphics/vulkan/Shader.cpp index 8846fa261..fd589b7b2 100644 --- a/src/modules/graphics/vulkan/Shader.cpp +++ b/src/modules/graphics/vulkan/Shader.cpp @@ -141,7 +141,7 @@ static const TBuiltInResource defaultTBuiltInResource = { }; static const uint32_t STREAMBUFFER_DEFAULT_SIZE = 16; -static const uint32_t DESCRIPTOR_POOL_SIZE = 1; +static const uint32_t DESCRIPTOR_POOL_SIZE = 16; class BindingMapper { @@ -315,9 +315,6 @@ void Shader::unloadVolatile() vkDestroyPipeline(device, computePipeline, nullptr); }); - while (!freeDescriptorSets.empty()) - freeDescriptorSets.pop(); - for (const auto streamBuffer : streamBuffers) streamBuffer->release(); @@ -1102,42 +1099,48 @@ void Shader::setMainTex(graphics::Texture *texture) } } +VkDescriptorPool Shader::createDescriptorPool() +{ + VkDescriptorPoolCreateInfo createInfo{}; + createInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO; + createInfo.maxSets = DESCRIPTOR_POOL_SIZE; + createInfo.poolSizeCount = static_cast(descriptorPoolSizes.size()); + createInfo.pPoolSizes = descriptorPoolSizes.data(); + + VkDescriptorPool pool; + if (vkCreateDescriptorPool(device, &createInfo, nullptr, &pool) != VK_SUCCESS) + throw love::Exception("failed to create descriptor pool"); + + descriptorPools.push_back(pool); +} + VkDescriptorSet Shader::allocateDescriptorSet() { - if (freeDescriptorSets.empty()) + if (descriptorPools.empty()) + createDescriptorPool(); + + while (true) { - VkDescriptorPoolCreateInfo createInfo{}; - createInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO; - createInfo.maxSets = DESCRIPTOR_POOL_SIZE; - createInfo.poolSizeCount = static_cast(descriptorPoolSizes.size()); - createInfo.pPoolSizes = descriptorPoolSizes.data(); - - VkDescriptorPool pool; - if (vkCreateDescriptorPool(device, &createInfo, nullptr, &pool) != VK_SUCCESS) - throw love::Exception("failed to create descriptor pool"); - descriptorPools.push_back(pool); - - std::vector layouts(DESCRIPTOR_POOL_SIZE, descriptorSetLayout); - VkDescriptorSetAllocateInfo allocInfo{}; allocInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO; - allocInfo.descriptorPool = pool; - allocInfo.descriptorSetCount = DESCRIPTOR_POOL_SIZE; - allocInfo.pSetLayouts = layouts.data(); + allocInfo.descriptorPool = descriptorPools.back(); + allocInfo.descriptorSetCount = 1; + allocInfo.pSetLayouts = &descriptorSetLayout; - std::vector descriptorSet; - descriptorSet.resize(DESCRIPTOR_POOL_SIZE); - VkResult result = vkAllocateDescriptorSets(device, &allocInfo, descriptorSet.data()); - if (result != VK_SUCCESS) + VkDescriptorSet descriptorSet; + VkResult result = vkAllocateDescriptorSets(device, &allocInfo, &descriptorSet); + + switch (result) + { + case VK_SUCCESS: + return descriptorSet; + case VK_ERROR_OUT_OF_POOL_MEMORY: + createDescriptorPool(); + continue; + default: throw love::Exception("failed to allocate descriptor set"); - - for (const auto ds : descriptorSet) - freeDescriptorSets.push(ds); + } } - - auto ds = freeDescriptorSets.front(); - freeDescriptorSets.pop(); - return ds; } } // vulkan diff --git a/src/modules/graphics/vulkan/Shader.h b/src/modules/graphics/vulkan/Shader.h index be2817807..3ac688063 100644 --- a/src/modules/graphics/vulkan/Shader.h +++ b/src/modules/graphics/vulkan/Shader.h @@ -97,12 +97,8 @@ private: void createPipelineLayout(); void createDescriptorPoolSizes(); void createStreamBuffers(); - void buildLocalUniforms( - spirv_cross::Compiler &comp, - const spirv_cross::SPIRType &type, - size_t baseoff, - const std::string &basename); - + void buildLocalUniforms(spirv_cross::Compiler &comp, const spirv_cross::SPIRType &type, size_t baseoff, const std::string &basename); + VkDescriptorPool createDescriptorPool(); VkDescriptorSet allocateDescriptorSet(); VkDeviceSize uniformBufferSizeAligned; @@ -117,7 +113,6 @@ private: // we keep a vector of stream buffers that gets dynamically increased if more memory is needed std::vector streamBuffers; std::vector descriptorPools; - std::queue freeDescriptorSets; std::vector> descriptorSetsVector; std::vector shaderStages; From af717c8cabb21a0d68ac68899ee1f2ba722f5228 Mon Sep 17 00:00:00 2001 From: niki Date: Tue, 25 Jul 2023 16:50:39 +0200 Subject: [PATCH 11/14] vulkan: fix incorrect return type --- src/modules/graphics/vulkan/Shader.cpp | 2 +- src/modules/graphics/vulkan/Shader.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/modules/graphics/vulkan/Shader.cpp b/src/modules/graphics/vulkan/Shader.cpp index fd589b7b2..4b16d0291 100644 --- a/src/modules/graphics/vulkan/Shader.cpp +++ b/src/modules/graphics/vulkan/Shader.cpp @@ -1099,7 +1099,7 @@ void Shader::setMainTex(graphics::Texture *texture) } } -VkDescriptorPool Shader::createDescriptorPool() +void Shader::createDescriptorPool() { VkDescriptorPoolCreateInfo createInfo{}; createInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO; diff --git a/src/modules/graphics/vulkan/Shader.h b/src/modules/graphics/vulkan/Shader.h index 3ac688063..2639da477 100644 --- a/src/modules/graphics/vulkan/Shader.h +++ b/src/modules/graphics/vulkan/Shader.h @@ -98,7 +98,7 @@ private: void createDescriptorPoolSizes(); void createStreamBuffers(); void buildLocalUniforms(spirv_cross::Compiler &comp, const spirv_cross::SPIRType &type, size_t baseoff, const std::string &basename); - VkDescriptorPool createDescriptorPool(); + void createDescriptorPool(); VkDescriptorSet allocateDescriptorSet(); VkDeviceSize uniformBufferSizeAligned; From 9d9e2da763f9a7667511abf9995a73d9d089b762 Mon Sep 17 00:00:00 2001 From: niki Date: Tue, 25 Jul 2023 21:39:28 +0200 Subject: [PATCH 12/14] vulkan: optimize vkUpdateDescriptorSets calls --- src/modules/graphics/vulkan/Shader.cpp | 78 ++++++++++++++++++-------- src/modules/graphics/vulkan/Shader.h | 6 +- 2 files changed, 58 insertions(+), 26 deletions(-) diff --git a/src/modules/graphics/vulkan/Shader.cpp b/src/modules/graphics/vulkan/Shader.cpp index 4b16d0291..f1863420f 100644 --- a/src/modules/graphics/vulkan/Shader.cpp +++ b/src/modules/graphics/vulkan/Shader.cpp @@ -360,15 +360,26 @@ void Shader::newFrame() } else streamBuffers.at(0)->nextFrame(); - - if (descriptorSetsVector.at(currentFrame).size() == 0) - descriptorSetsVector.at(currentFrame).push_back(allocateDescriptorSet()); - - currentDescriptorSet = descriptorSetsVector.at(currentFrame).at(0); } void Shader::cmdPushDescriptorSets(VkCommandBuffer commandBuffer, VkPipelineBindPoint bindPoint) { + if (currentUsedDescriptorSetsCount >= static_cast(descriptorSetsVector.at(currentFrame).size())) + descriptorSetsVector.at(currentFrame).push_back(allocateDescriptorSet()); + + VkDescriptorSet currentDescriptorSet = descriptorSetsVector.at(currentFrame).at(currentUsedDescriptorSetsCount); + + std::vector bufferInfos{}; + bufferInfos.reserve(numBuffers); + + std::vector imageInfos{}; + imageInfos.reserve(numTextures); + + std::vector bufferViews; + bufferViews.reserve(numBufferViews); + + std::vector descriptorWrites; + if (!localUniformData.empty()) { auto usedStreamBufferMemory = currentUsedUniformStreamBuffersCount * uniformBufferSizeAligned; @@ -397,6 +408,8 @@ void Shader::cmdPushDescriptorSets(VkCommandBuffer commandBuffer, VkPipelineBind bufferInfo.offset = offset; bufferInfo.range = localUniformData.size(); + bufferInfos.push_back(bufferInfo); + VkWriteDescriptorSet uniformWrite{}; uniformWrite.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; uniformWrite.dstSet = currentDescriptorSet; @@ -404,9 +417,9 @@ void Shader::cmdPushDescriptorSets(VkCommandBuffer commandBuffer, VkPipelineBind uniformWrite.dstArrayElement = 0; uniformWrite.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; uniformWrite.descriptorCount = 1; - uniformWrite.pBufferInfo = &bufferInfo; + uniformWrite.pBufferInfo = &bufferInfos[bufferInfos.size() - 1]; - vkUpdateDescriptorSets(device, 1, &uniformWrite, 0, nullptr); + descriptorWrites.push_back(uniformWrite); currentUsedUniformStreamBuffersCount++; } @@ -422,8 +435,6 @@ void Shader::cmdPushDescriptorSets(VkCommandBuffer commandBuffer, VkPipelineBind { bool isSampler = info.baseType == UNIFORM_SAMPLER; - std::vector imageInfos; - for (int i = 0; i < info.count; i++) { auto vkTexture = dynamic_cast(info.textures[i]); @@ -451,9 +462,9 @@ void Shader::cmdPushDescriptorSets(VkCommandBuffer commandBuffer, VkPipelineBind else write.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE; write.descriptorCount = static_cast(info.count); - write.pImageInfo = imageInfos.data(); + write.pImageInfo = &imageInfos[imageInfos.size() - info.count]; - vkUpdateDescriptorSets(device, 1, &write, 0, nullptr); + descriptorWrites.push_back(write); } if (info.baseType == UNIFORM_STORAGEBUFFER) { @@ -465,8 +476,6 @@ void Shader::cmdPushDescriptorSets(VkCommandBuffer commandBuffer, VkPipelineBind write.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER; write.descriptorCount = info.count; - std::vector bufferInfos; - for (int i = 0; i < info.count; i++) { if (info.buffers[i] == nullptr) @@ -480,9 +489,9 @@ void Shader::cmdPushDescriptorSets(VkCommandBuffer commandBuffer, VkPipelineBind bufferInfos.push_back(bufferInfo); } - write.pBufferInfo = bufferInfos.data(); + write.pBufferInfo = &bufferInfos[bufferInfos.size() - info.count]; - vkUpdateDescriptorSets(device, 1, &write, 0, nullptr); + descriptorWrites.push_back(write); } if (info.baseType == UNIFORM_TEXELBUFFER) { @@ -494,8 +503,6 @@ void Shader::cmdPushDescriptorSets(VkCommandBuffer commandBuffer, VkPipelineBind write.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER; write.descriptorCount = info.count; - std::vector bufferViews; - for (int i = 0; i < info.count; i++) { if (info.buffers[i] == nullptr) @@ -504,20 +511,17 @@ void Shader::cmdPushDescriptorSets(VkCommandBuffer commandBuffer, VkPipelineBind bufferViews.push_back((VkBufferView)info.buffers[i]->getTexelBufferHandle()); } - write.pTexelBufferView = bufferViews.data(); + write.pTexelBufferView = &bufferViews[bufferViews.size() - info.count]; - vkUpdateDescriptorSets(device, 1, &write, 0, nullptr); + descriptorWrites.push_back(write); } } + vkUpdateDescriptorSets(device, descriptorWrites.size(), descriptorWrites.data(), 0, nullptr); + vkCmdBindDescriptorSets(commandBuffer, bindPoint, pipelineLayout, 0, 1, ¤tDescriptorSet, 0, nullptr); currentUsedDescriptorSetsCount++; - - if (currentUsedDescriptorSetsCount >= static_cast(descriptorSetsVector.at(currentFrame).size())) - descriptorSetsVector.at(currentFrame).push_back(allocateDescriptorSet()); - - currentDescriptorSet = descriptorSetsVector.at(currentFrame).at(currentUsedDescriptorSetsCount); } Shader::~Shader() @@ -954,6 +958,32 @@ void Shader::compileShaders() shaderStages.push_back(shaderStageInfo); } + + numBuffers = 0; + numTextures = 0; + numBufferViews = 0; + + if (localUniformData.size() > 0) + numBuffers++; + + for (const auto &u : uniformInfos) + { + switch (u.second.baseType) + { + case UNIFORM_SAMPLER: + case UNIFORM_STORAGETEXTURE: + numTextures++; + break; + case UNIFORM_STORAGEBUFFER: + numBuffers++; + break; + case UNIFORM_TEXELBUFFER: + numBufferViews++; + break; + default: + continue; + } + } } void Shader::createDescriptorSetLayout() diff --git a/src/modules/graphics/vulkan/Shader.h b/src/modules/graphics/vulkan/Shader.h index 2639da477..1af256732 100644 --- a/src/modules/graphics/vulkan/Shader.h +++ b/src/modules/graphics/vulkan/Shader.h @@ -105,6 +105,10 @@ private: VkPipeline computePipeline; + uint32_t numTextures; + uint32_t numBuffers; + uint32_t numBufferViews; + VkDescriptorSetLayout descriptorSetLayout; VkPipelineLayout pipelineLayout; std::vector descriptorPoolSizes; @@ -134,8 +138,6 @@ private: std::unordered_map attributes; - VkDescriptorSet currentDescriptorSet; - uint32_t currentFrame; uint32_t currentUsedUniformStreamBuffersCount; uint32_t currentUsedDescriptorSetsCount; From 8096cab5bc2b29645199371b58c4f82ac2bb670e Mon Sep 17 00:00:00 2001 From: niki Date: Sun, 30 Jul 2023 15:35:20 +0200 Subject: [PATCH 13/14] vulkan: use vkResetDescriptorPool --- src/modules/graphics/vulkan/Shader.cpp | 39 +++++++++++++------------- src/modules/graphics/vulkan/Shader.h | 5 ++-- 2 files changed, 21 insertions(+), 23 deletions(-) diff --git a/src/modules/graphics/vulkan/Shader.cpp b/src/modules/graphics/vulkan/Shader.cpp index f1863420f..a4aebe588 100644 --- a/src/modules/graphics/vulkan/Shader.cpp +++ b/src/modules/graphics/vulkan/Shader.cpp @@ -141,7 +141,7 @@ static const TBuiltInResource defaultTBuiltInResource = { }; static const uint32_t STREAMBUFFER_DEFAULT_SIZE = 16; -static const uint32_t DESCRIPTOR_POOL_SIZE = 16; +static const uint32_t DESCRIPTOR_POOL_SIZE = 1000; class BindingMapper { @@ -265,10 +265,9 @@ bool Shader::loadVolatile() createPipelineLayout(); createDescriptorPoolSizes(); createStreamBuffers(); - descriptorSetsVector.resize(MAX_FRAMES_IN_FLIGHT); + descriptorPools.resize(MAX_FRAMES_IN_FLIGHT); currentFrame = 0; currentUsedUniformStreamBuffersCount = 0; - currentUsedDescriptorSetsCount = 0; newFrame(); return true; @@ -305,8 +304,11 @@ void Shader::unloadVolatile() } vgfx->queueCleanUp([shaderModules = std::move(shaderModules), device = device, descriptorSetLayout = descriptorSetLayout, pipelineLayout = pipelineLayout, descriptorPools = descriptorPools, computePipeline = computePipeline](){ - for (const auto pool : descriptorPools) - vkDestroyDescriptorPool(device, pool, nullptr); + for (const auto& pools : descriptorPools) + { + for (const auto pool : pools) + vkDestroyDescriptorPool(device, pool, nullptr); + } for (const auto shaderModule : shaderModules) vkDestroyShaderModule(device, shaderModule, nullptr); vkDestroyDescriptorSetLayout(device, descriptorSetLayout, nullptr); @@ -322,7 +324,6 @@ void Shader::unloadVolatile() shaderStages.clear(); streamBuffers.clear(); descriptorPools.clear(); - descriptorSetsVector.clear(); } const std::vector &Shader::getShaderStages() const @@ -345,7 +346,7 @@ void Shader::newFrame() currentFrame = (currentFrame + 1) % MAX_FRAMES_IN_FLIGHT; currentUsedUniformStreamBuffersCount = 0; - currentUsedDescriptorSetsCount = 0; + currentDescriptorPool = 0; if (streamBuffers.size() > 1) { @@ -360,14 +361,14 @@ void Shader::newFrame() } else streamBuffers.at(0)->nextFrame(); + + for (VkDescriptorPool pool : descriptorPools[currentFrame]) + vkResetDescriptorPool(device, pool, 0); } void Shader::cmdPushDescriptorSets(VkCommandBuffer commandBuffer, VkPipelineBindPoint bindPoint) { - if (currentUsedDescriptorSetsCount >= static_cast(descriptorSetsVector.at(currentFrame).size())) - descriptorSetsVector.at(currentFrame).push_back(allocateDescriptorSet()); - - VkDescriptorSet currentDescriptorSet = descriptorSetsVector.at(currentFrame).at(currentUsedDescriptorSetsCount); + VkDescriptorSet currentDescriptorSet = allocateDescriptorSet(); std::vector bufferInfos{}; bufferInfos.reserve(numBuffers); @@ -520,8 +521,6 @@ void Shader::cmdPushDescriptorSets(VkCommandBuffer commandBuffer, VkPipelineBind vkUpdateDescriptorSets(device, descriptorWrites.size(), descriptorWrites.data(), 0, nullptr); vkCmdBindDescriptorSets(commandBuffer, bindPoint, pipelineLayout, 0, 1, ¤tDescriptorSet, 0, nullptr); - - currentUsedDescriptorSetsCount++; } Shader::~Shader() @@ -597,9 +596,7 @@ void Shader::calculateUniformBufferSizeAligned() { auto minAlignment = vgfx->getMinUniformBufferOffsetAlignment(); size_t size = localUniformStagingData.size(); - auto factor = static_cast(std::ceil( - static_cast(size) / static_cast(minAlignment) - )); + auto factor = static_cast(std::ceil(static_cast(size) / static_cast(minAlignment))); uniformBufferSizeAligned = factor * minAlignment; } @@ -1141,19 +1138,19 @@ void Shader::createDescriptorPool() if (vkCreateDescriptorPool(device, &createInfo, nullptr, &pool) != VK_SUCCESS) throw love::Exception("failed to create descriptor pool"); - descriptorPools.push_back(pool); + descriptorPools[currentFrame].push_back(pool); } VkDescriptorSet Shader::allocateDescriptorSet() { - if (descriptorPools.empty()) + if (descriptorPools[currentFrame].empty()) createDescriptorPool(); while (true) { VkDescriptorSetAllocateInfo allocInfo{}; allocInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO; - allocInfo.descriptorPool = descriptorPools.back(); + allocInfo.descriptorPool = descriptorPools[currentFrame][currentDescriptorPool]; allocInfo.descriptorSetCount = 1; allocInfo.pSetLayouts = &descriptorSetLayout; @@ -1165,7 +1162,9 @@ VkDescriptorSet Shader::allocateDescriptorSet() case VK_SUCCESS: return descriptorSet; case VK_ERROR_OUT_OF_POOL_MEMORY: - createDescriptorPool(); + currentDescriptorPool++; + if (descriptorPools[currentFrame].size() <= currentDescriptorPool) + createDescriptorPool(); continue; default: throw love::Exception("failed to allocate descriptor set"); diff --git a/src/modules/graphics/vulkan/Shader.h b/src/modules/graphics/vulkan/Shader.h index 1af256732..af997b408 100644 --- a/src/modules/graphics/vulkan/Shader.h +++ b/src/modules/graphics/vulkan/Shader.h @@ -116,8 +116,7 @@ private: // we don't know how much memory we need per frame for the uniform buffer descriptors // we keep a vector of stream buffers that gets dynamically increased if more memory is needed std::vector streamBuffers; - std::vector descriptorPools; - std::vector> descriptorSetsVector; + std::vector> descriptorPools; std::vector shaderStages; std::vector shaderModules; @@ -140,7 +139,7 @@ private: uint32_t currentFrame; uint32_t currentUsedUniformStreamBuffersCount; - uint32_t currentUsedDescriptorSetsCount; + uint32_t currentDescriptorPool; }; } From 61cafd7dd426cf53218cbf8b17e1e967660f22a6 Mon Sep 17 00:00:00 2001 From: niki Date: Tue, 1 Aug 2023 14:23:10 +0200 Subject: [PATCH 14/14] adjust code styling --- src/modules/graphics/vulkan/Shader.cpp | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/modules/graphics/vulkan/Shader.cpp b/src/modules/graphics/vulkan/Shader.cpp index a4aebe588..3ad661164 100644 --- a/src/modules/graphics/vulkan/Shader.cpp +++ b/src/modules/graphics/vulkan/Shader.cpp @@ -232,7 +232,7 @@ static EShLanguage getGlslShaderType(ShaderStageType stage) } } -static bool usesLocalUniformData(const graphics::Shader::UniformInfo* info) +static bool usesLocalUniformData(const graphics::Shader::UniformInfo *info) { return info->baseType == graphics::Shader::UNIFORM_BOOL || info->baseType == graphics::Shader::UNIFORM_FLOAT || @@ -304,7 +304,7 @@ void Shader::unloadVolatile() } vgfx->queueCleanUp([shaderModules = std::move(shaderModules), device = device, descriptorSetLayout = descriptorSetLayout, pipelineLayout = pipelineLayout, descriptorPools = descriptorPools, computePipeline = computePipeline](){ - for (const auto& pools : descriptorPools) + for (const auto &pools : descriptorPools) { for (const auto pool : pools) vkDestroyDescriptorPool(device, pool, nullptr); @@ -370,10 +370,10 @@ void Shader::cmdPushDescriptorSets(VkCommandBuffer commandBuffer, VkPipelineBind { VkDescriptorSet currentDescriptorSet = allocateDescriptorSet(); - std::vector bufferInfos{}; + std::vector bufferInfos; bufferInfos.reserve(numBuffers); - std::vector imageInfos{}; + std::vector imageInfos; imageInfos.reserve(numTextures); std::vector bufferViews; @@ -775,7 +775,7 @@ void Shader::compileShaders() { if (resource.name == "gl_DefaultUniformBlock") { - const auto& type = comp.get_type(resource.base_type_id); + const auto &type = comp.get_type(resource.base_type_id); size_t defaultUniformBlockSize = comp.get_declared_struct_size(type); localUniformStagingData.resize(defaultUniformBlockSize); @@ -1068,9 +1068,9 @@ void Shader::createDescriptorPoolSizes() { VkDescriptorPoolSize size{}; auto type = Vulkan::getDescriptorType(entry.second.baseType); - if (type == VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER) { + if (type == VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER) continue; - } + size.type = type; size.descriptorCount = 1; descriptorPoolSizes.push_back(size);