From 7e7d2884c8098b9caffdec4896795175ae76319e Mon Sep 17 00:00:00 2001 From: niki Date: Mon, 9 Jan 2023 16:37:12 +0100 Subject: [PATCH 01/16] vulkan: fix shader crash --- src/modules/graphics/vulkan/Graphics.cpp | 6 ++++-- src/modules/graphics/vulkan/Graphics.h | 2 +- src/modules/graphics/vulkan/Shader.cpp | 10 +++------- 3 files changed, 8 insertions(+), 10 deletions(-) diff --git a/src/modules/graphics/vulkan/Graphics.cpp b/src/modules/graphics/vulkan/Graphics.cpp index 768d4056e..8270faf28 100644 --- a/src/modules/graphics/vulkan/Graphics.cpp +++ b/src/modules/graphics/vulkan/Graphics.cpp @@ -1131,6 +1131,8 @@ void Graphics::beginFrame() Vulkan::resetShaderSwitches(); + for (const auto shader : usedShadersInFrame) + shader->newFrame(); usedShadersInFrame.clear(); } @@ -2478,9 +2480,9 @@ void Graphics::setComputeShader(Shader *shader) computeShader = shader; } -std::set &Graphics::getUsedShadersInFrame() +void Graphics::markShaderUsed(Shader *shader) { - return usedShadersInFrame; + usedShadersInFrame.insert(shader); } VkSampler Graphics::getCachedSampler(const SamplerState &samplerState) diff --git a/src/modules/graphics/vulkan/Graphics.h b/src/modules/graphics/vulkan/Graphics.h index 7d88e58f6..8109ed3b1 100644 --- a/src/modules/graphics/vulkan/Graphics.h +++ b/src/modules/graphics/vulkan/Graphics.h @@ -293,7 +293,7 @@ public: graphics::Texture *getDefaultTexture() const; VkSampler getCachedSampler(const SamplerState &sampler); void setComputeShader(Shader *computeShader); - std::set &getUsedShadersInFrame(); + void markShaderUsed(Shader*); graphics::Shader::BuiltinUniformData getCurrentBuiltinUniformData(); const OptionalDeviceFeatures &getEnabledOptionalDeviceExtensions() const; VkSampleCountFlagBits getMsaaCount(int requestedMsaa) const; diff --git a/src/modules/graphics/vulkan/Shader.cpp b/src/modules/graphics/vulkan/Shader.cpp index d09cdb36a..7bf87ad0f 100644 --- a/src/modules/graphics/vulkan/Shader.cpp +++ b/src/modules/graphics/vulkan/Shader.cpp @@ -200,6 +200,7 @@ bool Shader::loadVolatile() currentFrame = 0; currentUsedUniformStreamBuffersCount = 0; currentUsedDescriptorSetsCount = 0; + newFrame(); return true; } @@ -384,7 +385,7 @@ void Shader::cmdPushDescriptorSets(VkCommandBuffer commandBuffer, VkPipelineBind for (const auto &u : uniformInfos) { if (updatedUniforms.find(u.second.location) == updatedUniforms.end()) - updateUniform(&u.second, u.second.count); + updateUniform(&u.second, u.second.count, true); } vkCmdBindDescriptorSets(commandBuffer, bindPoint, pipelineLayout, 0, 1, ¤tDescriptorSet, 0, nullptr); @@ -406,12 +407,7 @@ Shader::~Shader() void Shader::attach() { - auto &usedShadersInFrame = vgfx->getUsedShadersInFrame(); - if (usedShadersInFrame.find(this) == usedShadersInFrame.end()) - { - newFrame(); - usedShadersInFrame.insert(this); - } + vgfx->markShaderUsed(this); if (!isCompute) { From a2466a4a1ba69a7c0aff7260d191e4732e029264 Mon Sep 17 00:00:00 2001 From: niki Date: Sun, 22 Jan 2023 00:17:42 +0100 Subject: [PATCH 02/16] vulkan: use temporary pipeline cache --- src/modules/graphics/vulkan/Graphics.cpp | 22 ++++++++++++++++------ src/modules/graphics/vulkan/Graphics.h | 2 ++ 2 files changed, 18 insertions(+), 6 deletions(-) diff --git a/src/modules/graphics/vulkan/Graphics.cpp b/src/modules/graphics/vulkan/Graphics.cpp index 8270faf28..2ee3ca231 100644 --- a/src/modules/graphics/vulkan/Graphics.cpp +++ b/src/modules/graphics/vulkan/Graphics.cpp @@ -493,6 +493,7 @@ bool Graphics::setMode(void *context, int width, int height, int pixelwidth, int createSurface(); pickPhysicalDevice(); createLogicalDevice(); + createPipelineCache(); initVMA(); initCapabilities(); createSwapChain(); @@ -1573,6 +1574,15 @@ void Graphics::createLogicalDevice() vkGetDeviceQueue(device, indices.presentFamily.value, 0, &presentQueue); } +void Graphics::createPipelineCache() +{ + VkPipelineCacheCreateInfo cacheInfo{}; + cacheInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_CACHE_CREATE_INFO; + + if (vkCreatePipelineCache(device, &cacheInfo, nullptr, &pipelineCache) != VK_SUCCESS) + throw love::Exception("could not create pipeline cache"); +} + void Graphics::initVMA() { VmaAllocatorCreateInfo allocatorCreateInfo = {}; @@ -2301,11 +2311,10 @@ void Graphics::setRenderPass(const RenderTargets &rts, int pixelw, int pixelh, b false, dynamic_cast(color.texture)->getMsaaSamples() }); if (rts.depthStencil.texture != nullptr) - if (rts.depthStencil.texture != nullptr) - renderPassConfiguration.staticData.depthAttachment = { - Vulkan::getTextureFormat(rts.depthStencil.texture->getPixelFormat(), false).internalFormat, - false, - dynamic_cast(rts.depthStencil.texture)->getMsaaSamples() }; + renderPassConfiguration.staticData.depthAttachment = { + Vulkan::getTextureFormat(rts.depthStencil.texture->getPixelFormat(), false).internalFormat, + false, + dynamic_cast(rts.depthStencil.texture)->getMsaaSamples() }; FramebufferConfiguration configuration{}; @@ -2648,7 +2657,7 @@ VkPipeline Graphics::createGraphicsPipeline(GraphicsPipelineConfiguration &confi pipelineInfo.renderPass = configuration.renderPass; VkPipeline graphicsPipeline; - if (vkCreateGraphicsPipelines(device, VK_NULL_HANDLE, 1, &pipelineInfo, nullptr, &graphicsPipeline) != VK_SUCCESS) + if (vkCreateGraphicsPipelines(device, pipelineCache, 1, &pipelineInfo, nullptr, &graphicsPipeline) != VK_SUCCESS) throw love::Exception("failed to create graphics pipeline"); return graphicsPipeline; } @@ -2934,6 +2943,7 @@ void Graphics::cleanup() graphicsPipelines.clear(); vkDestroyCommandPool(device, commandPool, nullptr); + vkDestroyPipelineCache(device, pipelineCache, nullptr); vkDestroyDevice(device, nullptr); vkDestroySurfaceKHR(instance, surface, nullptr); vkDestroyInstance(instance, nullptr); diff --git a/src/modules/graphics/vulkan/Graphics.h b/src/modules/graphics/vulkan/Graphics.h index 8109ed3b1..a1cb0bbf2 100644 --- a/src/modules/graphics/vulkan/Graphics.h +++ b/src/modules/graphics/vulkan/Graphics.h @@ -316,6 +316,7 @@ private: int rateDeviceSuitability(VkPhysicalDevice device); QueueFamilyIndices findQueueFamilies(VkPhysicalDevice device); void createLogicalDevice(); + void createPipelineCache(); void initVMA(); void createSurface(); bool checkDeviceExtensionSupport(VkPhysicalDevice device); @@ -393,6 +394,7 @@ private: VkImageView depthImageView = VK_NULL_HANDLE; VmaAllocation depthImageAllocation = VK_NULL_HANDLE; VkRenderPass defaultRenderPass = VK_NULL_HANDLE; + VkPipelineCache pipelineCache; std::vector defaultFramebuffers; std::unordered_map renderPasses; std::unordered_map framebuffers; From 377d269f4a9e7fa600765ccf87d00a611b08a706 Mon Sep 17 00:00:00 2001 From: niki Date: Fri, 27 Jan 2023 02:36:10 +0100 Subject: [PATCH 03/16] vulkan: remap bindings to prevent clash Vulkan does not differentiate between between bindings for textures and buffers, as opposed to opengl. This can lead to situations, where different uniforms get assigned the same binding leading to a crash, when trying to update a descriptor set with the wrong type. This patch solves this problem, by remapping the bindings when needed. --- src/modules/graphics/vulkan/Graphics.cpp | 6 +- src/modules/graphics/vulkan/Shader.cpp | 129 +++++++++++++++++------ 2 files changed, 99 insertions(+), 36 deletions(-) diff --git a/src/modules/graphics/vulkan/Graphics.cpp b/src/modules/graphics/vulkan/Graphics.cpp index 2ee3ca231..869ff8531 100644 --- a/src/modules/graphics/vulkan/Graphics.cpp +++ b/src/modules/graphics/vulkan/Graphics.cpp @@ -579,9 +579,9 @@ void Graphics::initCapabilities() capabilities.limits[LIMIT_CUBE_TEXTURE_SIZE] = properties.limits.maxImageDimensionCube; capabilities.limits[LIMIT_TEXEL_BUFFER_SIZE] = properties.limits.maxTexelBufferElements; capabilities.limits[LIMIT_SHADER_STORAGE_BUFFER_SIZE] = properties.limits.maxStorageBufferRange; - capabilities.limits[LIMIT_THREADGROUPS_X] = properties.limits.maxComputeWorkGroupSize[0]; - capabilities.limits[LIMIT_THREADGROUPS_Y] = properties.limits.maxComputeWorkGroupSize[1]; - capabilities.limits[LIMIT_THREADGROUPS_Z] = properties.limits.maxComputeWorkGroupSize[2]; + capabilities.limits[LIMIT_THREADGROUPS_X] = properties.limits.maxComputeWorkGroupCount[0]; + capabilities.limits[LIMIT_THREADGROUPS_Y] = properties.limits.maxComputeWorkGroupCount[1]; + capabilities.limits[LIMIT_THREADGROUPS_Z] = properties.limits.maxComputeWorkGroupCount[2]; capabilities.limits[LIMIT_RENDER_TARGETS] = properties.limits.maxColorAttachments; capabilities.limits[LIMIT_TEXTURE_MSAA] = static_cast(getMsaaCount(64)); capabilities.limits[LIMIT_ANISOTROPY] = properties.limits.maxSamplerAnisotropy; diff --git a/src/modules/graphics/vulkan/Shader.cpp b/src/modules/graphics/vulkan/Shader.cpp index 7bf87ad0f..8d71c7f43 100644 --- a/src/modules/graphics/vulkan/Shader.cpp +++ b/src/modules/graphics/vulkan/Shader.cpp @@ -144,6 +144,72 @@ static const TBuiltInResource defaultTBuiltInResource = { static const uint32_t STREAMBUFFER_DEFAULT_SIZE = 16; static const uint32_t DESCRIPTOR_POOL_SIZE = 1; +class BindingMapper +{ +public: + uint32_t operator()(spirv_cross::CompilerGLSL &comp, std::vector &spirv, const std::string &name, const spirv_cross::ID &id) + { + auto it = bindingMappings.find(name); + if (it == bindingMappings.end()) + { + auto binding = comp.get_decoration(id, spv::DecorationBinding); + + if (isFreeBinding(binding)) + { + bindingMappings[name] = binding; + return binding; + } + else + { + uint32_t freeBinding = getFreeBinding(); + + uint32_t binaryBindingOffset; + if (!comp.get_binary_offset_for_decoration(id, spv::DecorationBinding, binaryBindingOffset)) + throw love::Exception("could not get binary offset for binding"); + + spirv[binaryBindingOffset] = freeBinding; + + bindingMappings[name] = freeBinding; + + return freeBinding; + } + } + else + return it->second; + }; + + +private: + 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) + return i; + } + } + + bool isFreeBinding(uint32_t binding) { + for (const auto &entry : bindingMappings) + { + if (entry.second == binding) + return false; + } + return true; + } + + std::map bindingMappings; + +}; + static VkShaderStageFlagBits getStageBit(ShaderStageType type) { switch (type) @@ -735,14 +801,16 @@ void Shader::compileShaders() uniformInfos.clear(); + BindingMapper bindingMapper; + for (int i = 0; i < SHADERSTAGE_MAX_ENUM; i++) { auto shaderStage = (ShaderStageType)i; auto glslangStage = getGlslShaderType(shaderStage); auto intermediate = program->getIntermediate(glslangStage); - if (intermediate == nullptr) { + + if (intermediate == nullptr) continue; - } spv::SpvBuildLogger logger; glslang::SpvOptions opt; @@ -751,31 +819,6 @@ void Shader::compileShaders() std::vector spirv; GlslangToSpv(*intermediate, spirv, &logger, &opt); - std::string msgs = logger.getAllMessages(); - - VkShaderModuleCreateInfo createInfo{}; - createInfo.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO; - createInfo.codeSize = spirv.size() * sizeof(uint32_t); - createInfo.pCode = spirv.data(); - - auto device = vgfx->getDevice(); - - VkShaderModule shaderModule; - - if (vkCreateShaderModule(device, &createInfo, nullptr, &shaderModule) != VK_SUCCESS) { - throw love::Exception("failed to create shader module"); - } - - shaderModules.push_back(shaderModule); - - VkPipelineShaderStageCreateInfo shaderStageInfo{}; - shaderStageInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; - shaderStageInfo.stage = getStageBit((ShaderStageType)i); - shaderStageInfo.module = shaderModule; - shaderStageInfo.pName = "main"; - - shaderStages.push_back(shaderStageInfo); - spirv_cross::CompilerGLSL comp(spirv); // we only care about variables that are actually getting used. @@ -792,7 +835,7 @@ void Shader::compileShaders() auto defaultUniformBlockSize = comp.get_declared_struct_size(type); localUniformStagingData.resize(defaultUniformBlockSize); localUniformData.resize(defaultUniformBlockSize); - localUniformLocation = comp.get_decoration(resource.id, spv::DecorationBinding); + localUniformLocation = bindingMapper(comp, spirv, resource.name, resource.id); memset(localUniformStagingData.data(), 0, defaultUniformBlockSize); memset(localUniformData.data(), 0, defaultUniformBlockSize); @@ -813,7 +856,7 @@ void Shader::compileShaders() const SPIRType &imagetype = comp.get_type(basetype.image.type); graphics::Shader::UniformInfo info; - info.location = comp.get_decoration(r.id, spv::DecorationBinding); + info.location = bindingMapper(comp, spirv, r.name, r.id); info.baseType = UNIFORM_SAMPLER; info.name = r.name; info.count = type.array.empty() ? 1 : type.array[0]; @@ -894,7 +937,7 @@ void Shader::compileShaders() if (!fillUniformReflectionData(u)) continue; - u.location = comp.get_decoration(r.id, spv::DecorationBinding); + u.location = bindingMapper(comp, spirv, r.name, r.id); u.buffers = new love::graphics::Buffer *[u.count]; for (int i = 0; i < u.count; i++) @@ -917,13 +960,11 @@ void Shader::compileShaders() continue; u.textures = new love::graphics::Texture *[u.count]; - u.location = comp.get_decoration(r.id, spv::DecorationBinding); + u.location = bindingMapper(comp, spirv, r.name, r.id); for (int i = 0; i < u.count; i++) u.textures[i] = nullptr; - // some stuff missing ? - uniformInfos[u.name] = u; } @@ -936,6 +977,28 @@ void Shader::compileShaders() attributes[name] = attributeLocation; } } + + VkShaderModuleCreateInfo createInfo{}; + createInfo.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO; + createInfo.codeSize = spirv.size() * sizeof(uint32_t); + createInfo.pCode = spirv.data(); + + auto device = vgfx->getDevice(); + + VkShaderModule shaderModule; + + if (vkCreateShaderModule(device, &createInfo, nullptr, &shaderModule) != VK_SUCCESS) + throw love::Exception("failed to create shader module"); + + shaderModules.push_back(shaderModule); + + VkPipelineShaderStageCreateInfo shaderStageInfo{}; + shaderStageInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; + shaderStageInfo.stage = getStageBit((ShaderStageType)i); + shaderStageInfo.module = shaderModule; + shaderStageInfo.pName = "main"; + + shaderStages.push_back(shaderStageInfo); } delete program; From f01457a610ceb3c866bd3d9bd38e3cb23baf9c8c Mon Sep 17 00:00:00 2001 From: niki Date: Fri, 27 Jan 2023 14:10:19 +0100 Subject: [PATCH 04/16] vulkan: remove internal Shader::attach call Shader::attach() should not be called internally by a graphics backend. --- src/modules/graphics/vulkan/Graphics.cpp | 9 +++------ src/modules/graphics/vulkan/Graphics.h | 3 +-- src/modules/graphics/vulkan/Shader.cpp | 4 ---- 3 files changed, 4 insertions(+), 12 deletions(-) diff --git a/src/modules/graphics/vulkan/Graphics.cpp b/src/modules/graphics/vulkan/Graphics.cpp index 869ff8531..7166b22f9 100644 --- a/src/modules/graphics/vulkan/Graphics.cpp +++ b/src/modules/graphics/vulkan/Graphics.cpp @@ -1007,6 +1007,8 @@ graphics::StreamBuffer *Graphics::newStreamBuffer(BufferUsage type, size_t size) bool Graphics::dispatch(int x, int y, int z) { + usedShadersInFrame.insert(computeShader); + if (renderPassState.active) endRenderPass(); @@ -2226,7 +2228,7 @@ void Graphics::prepareDraw(const VertexAttributes &attributes, const BufferBindi if (!renderPassState.active) startRenderPass(); - Shader::current->attach(); + usedShadersInFrame.insert((dynamic_cast(Shader::current))); GraphicsPipelineConfiguration configuration{}; @@ -2489,11 +2491,6 @@ void Graphics::setComputeShader(Shader *shader) computeShader = shader; } -void Graphics::markShaderUsed(Shader *shader) -{ - usedShadersInFrame.insert(shader); -} - VkSampler Graphics::getCachedSampler(const SamplerState &samplerState) { auto samplerkey = samplerState.toKey(); diff --git a/src/modules/graphics/vulkan/Graphics.h b/src/modules/graphics/vulkan/Graphics.h index a1cb0bbf2..3606cf842 100644 --- a/src/modules/graphics/vulkan/Graphics.h +++ b/src/modules/graphics/vulkan/Graphics.h @@ -293,7 +293,6 @@ public: graphics::Texture *getDefaultTexture() const; VkSampler getCachedSampler(const SamplerState &sampler); void setComputeShader(Shader *computeShader); - void markShaderUsed(Shader*); graphics::Shader::BuiltinUniformData getCurrentBuiltinUniformData(); const OptionalDeviceFeatures &getEnabledOptionalDeviceExtensions() const; VkSampleCountFlagBits getMsaaCount(int requestedMsaa) const; @@ -394,7 +393,7 @@ private: VkImageView depthImageView = VK_NULL_HANDLE; VmaAllocation depthImageAllocation = VK_NULL_HANDLE; VkRenderPass defaultRenderPass = VK_NULL_HANDLE; - VkPipelineCache pipelineCache; + VkPipelineCache pipelineCache = VK_NULL_HANDLE; std::vector defaultFramebuffers; std::unordered_map renderPasses; std::unordered_map framebuffers; diff --git a/src/modules/graphics/vulkan/Shader.cpp b/src/modules/graphics/vulkan/Shader.cpp index 8d71c7f43..4a33e87d7 100644 --- a/src/modules/graphics/vulkan/Shader.cpp +++ b/src/modules/graphics/vulkan/Shader.cpp @@ -25,8 +25,6 @@ #include "libraries/glslang/SPIRV/GlslangToSpv.h" -#include - namespace love { namespace graphics @@ -473,8 +471,6 @@ Shader::~Shader() void Shader::attach() { - vgfx->markShaderUsed(this); - if (!isCompute) { if (Shader::current != this) From 0e1f6455389c1dded424ac70e5cede8402ee0f60 Mon Sep 17 00:00:00 2001 From: niki Date: Sun, 29 Jan 2023 01:14:06 +0100 Subject: [PATCH 05/16] vulkan: clean up glslang objects properly By using smart pointers we don't want to worry about explicitely deleting. --- src/modules/graphics/vulkan/Shader.cpp | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/src/modules/graphics/vulkan/Shader.cpp b/src/modules/graphics/vulkan/Shader.cpp index 4a33e87d7..ee596114c 100644 --- a/src/modules/graphics/vulkan/Shader.cpp +++ b/src/modules/graphics/vulkan/Shader.cpp @@ -734,9 +734,9 @@ void Shader::compileShaders() using namespace glslang; using namespace spirv_cross; - std::vector glslangShaders; + std::vector> glslangShaders; - auto program = new TProgram(); + auto program = std::make_unique(); device = vgfx->getDevice(); @@ -753,7 +753,7 @@ void Shader::compileShaders() isCompute = true; auto glslangShaderStage = getGlslShaderType(stage); - auto tshader = new TShader(glslangShaderStage); + auto tshader = std::make_unique(glslangShaderStage); tshader->setEnvInput(EShSourceGlsl, glslangShaderStage, EShClientVulkan, 450); tshader->setEnvClient(EShClientVulkan, EShTargetVulkan_1_2); @@ -779,14 +779,18 @@ void Shader::compileShaders() if (!tshader->parse(&defaultTBuiltInResource, defaultVersion, defaultProfile, forceDefault, forwardCompat, EShMsgSuppressWarnings)) { - const char *msg1 = tshader->getInfoLog(); - const char *msg2 = tshader->getInfoDebugLog(); + const char *stageName = "unknown"; + ShaderStage::getConstant(stage, stageName); - throw love::Exception("error while parsing shader"); + std::string err = "Error parsing " + std::string(stageName) + " shader:\n\n" + + std::string(tshader->getInfoLog()) + "\n" + + std::string(tshader->getInfoDebugLog()); + + throw love::Exception("%s", err.c_str()); } - program->addShader(tshader); - glslangShaders.push_back(tshader); + program->addShader(tshader.get()); + glslangShaders.push_back(std::move(tshader)); } if (!program->link(EShMsgDefault)) @@ -996,10 +1000,6 @@ void Shader::compileShaders() shaderStages.push_back(shaderStageInfo); } - - delete program; - for (auto shader : glslangShaders) - delete shader; } void Shader::createDescriptorSetLayout() From 9f452474c72fde29525c1c512d20d1788a9b6773 Mon Sep 17 00:00:00 2001 From: niki Date: Tue, 31 Jan 2023 01:07:02 +0100 Subject: [PATCH 06/16] vulkan: remove unnecessary getDevice() calls --- src/modules/graphics/vulkan/Shader.cpp | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/modules/graphics/vulkan/Shader.cpp b/src/modules/graphics/vulkan/Shader.cpp index ee596114c..94c06f53a 100644 --- a/src/modules/graphics/vulkan/Shader.cpp +++ b/src/modules/graphics/vulkan/Shader.cpp @@ -249,6 +249,8 @@ Shader::Shader(StrongRef stages[]) bool Shader::loadVolatile() { + device = vgfx->getDevice(); + computePipeline = VK_NULL_HANDLE; for (int i = 0; i < BUILTIN_MAX_ENUM; i++) @@ -738,8 +740,6 @@ void Shader::compileShaders() auto program = std::make_unique(); - device = vgfx->getDevice(); - const auto &enabledExtensions = vgfx->getEnabledOptionalDeviceExtensions(); for (int i = 0; i < SHADERSTAGE_MAX_ENUM; i++) @@ -983,8 +983,6 @@ void Shader::compileShaders() createInfo.codeSize = spirv.size() * sizeof(uint32_t); createInfo.pCode = spirv.data(); - auto device = vgfx->getDevice(); - VkShaderModule shaderModule; if (vkCreateShaderModule(device, &createInfo, nullptr, &shaderModule) != VK_SUCCESS) From 094d6e39d1dfa04e32ab09c97ebe3a4caf4b99a8 Mon Sep 17 00:00:00 2001 From: niki Date: Sat, 11 Feb 2023 20:06:19 +0100 Subject: [PATCH 07/16] vulkan: improve render pass performance Before this patch some common patterns would lead to very suboptimal render passes. Consider the following code: ```lua local canvas = love.graphics.newCanvas(...) function love.draw() love.graphics.setCanvas(canvas) love.graphics.clear(...) love.graphics.draw(...) love.graphics.setCanvas() love.graphics.draw(canvas) end ``` This would lead to the following rendering: 1) render pass on main window with loadOp=load, followed by an immediate call to vkCmdClearAttachments 2) render pass on canvas with loadOp=load, followed by an immediate call to vkCmdClearAttachments 3) render pass on main window with loadOp=load This patch changes the behaviour to the more performant (and equivalent) version: 1) render pass on canvas with loadOp=clear 2) render pass on main window with loadOp=clear This is especially helpful on mobile devices, where creating render passes is an expensive operation. --- src/modules/graphics/vulkan/Graphics.cpp | 342 ++++++++++++++--------- src/modules/graphics/vulkan/Graphics.h | 35 ++- 2 files changed, 241 insertions(+), 136 deletions(-) diff --git a/src/modules/graphics/vulkan/Graphics.cpp b/src/modules/graphics/vulkan/Graphics.cpp index 7166b22f9..ebc35cdab 100644 --- a/src/modules/graphics/vulkan/Graphics.cpp +++ b/src/modules/graphics/vulkan/Graphics.cpp @@ -110,66 +110,10 @@ void Graphics::clear(OptionalColorD color, OptionalInt stencil, OptionalDouble d flushBatchedDraws(); - if (!renderPassState.active) - startRenderPass(); - - VkClearAttachment attachment{}; - - if (color.hasValue) - { - Colorf cf((float)color.value.r, (float)color.value.g, (float)color.value.b, (float)color.value.a); - gammaCorrectColor(cf); - - attachment.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; - attachment.clearValue.color.float32[0] = static_cast(cf.r); - attachment.clearValue.color.float32[1] = static_cast(cf.g); - attachment.clearValue.color.float32[2] = static_cast(cf.b); - attachment.clearValue.color.float32[3] = static_cast(cf.a); - } - - 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); - } - - std::array attachments = { - attachment, - depthStencilAttachment - }; - - VkClearRect rect{}; - rect.layerCount = 1; - rect.rect.extent.width = static_cast(renderPassState.width); - rect.rect.extent.height = static_cast(renderPassState.height); - - vkCmdClearAttachments( - commandBuffers[currentFrame], - static_cast(attachments.size()), attachments.data(), - 1, &rect); -} - -void Graphics::clear(const std::vector &colors, OptionalInt stencil, OptionalDouble depth) -{ - if (colors.empty() && !stencil.hasValue && !depth.hasValue) - return; - - flushBatchedDraws(); - - if (!renderPassState.active) - startRenderPass(); - - std::vector attachments; - for (const auto &color : colors) + if (renderPassState.active) { VkClearAttachment attachment{}; + if (color.hasValue) { Colorf cf((float)color.value.r, (float)color.value.g, (float)color.value.b, (float)color.value.a); @@ -181,33 +125,154 @@ void Graphics::clear(const std::vector &colors, OptionalInt sten attachment.clearValue.color.float32[2] = static_cast(cf.b); attachment.clearValue.color.float32[3] = static_cast(cf.a); } - 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); + } + + std::array attachments = { + attachment, + depthStencilAttachment + }; + + VkClearRect rect{}; + rect.layerCount = 1; + rect.rect.extent.width = static_cast(renderPassState.width); + rect.rect.extent.height = static_cast(renderPassState.height); + + vkCmdClearAttachments( + commandBuffers[currentFrame], + static_cast(attachments.size()), attachments.data(), + 1, &rect); } - - VkClearAttachment depthStencilAttachment{}; - - if (stencil.hasValue) + else { - depthStencilAttachment.aspectMask |= VK_IMAGE_ASPECT_STENCIL_BIT; - depthStencilAttachment.clearValue.depthStencil.stencil = static_cast(stencil.value); + renderPassState.useConfigurations = true; + + if (color.hasValue) + { + renderPassState.renderPassConfiguration.colorAttachments[0].loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR; + renderPassState.clearColors[0].color.float32[0] = static_cast(color.value.r); + renderPassState.clearColors[0].color.float32[1] = static_cast(color.value.g); + renderPassState.clearColors[0].color.float32[2] = static_cast(color.value.b); + renderPassState.clearColors[0].color.float32[3] = static_cast(color.value.a); + } + + if (depth.hasValue) + { + renderPassState.renderPassConfiguration.staticData.depthStencilAttachment.depthLoadOp = VK_ATTACHMENT_LOAD_OP_CLEAR; + renderPassState.clearColors[1].depthStencil.depth = static_cast(depth.value); + } + + if (stencil.hasValue) + { + renderPassState.renderPassConfiguration.staticData.depthStencilAttachment.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_CLEAR; + renderPassState.clearColors[1].depthStencil.stencil = static_cast(stencil.value); + } + + if (renderPassState.isWindow) + { + renderPassState.windowClearRequested = true; + renderPassState.mainWindowClearColorValue = color; + renderPassState.mainWindowClearDepthValue = depth; + renderPassState.mainWindowClearStencilValue = stencil; + } + else + startRenderPass(); } - if (depth.hasValue) +} + +void Graphics::clear(const std::vector &colors, OptionalInt stencil, OptionalDouble depth) +{ + if (colors.empty() && !stencil.hasValue && !depth.hasValue) + return; + + flushBatchedDraws(); + + if (renderPassState.active) { - depthStencilAttachment.aspectMask |= VK_IMAGE_ASPECT_DEPTH_BIT; - depthStencilAttachment.clearValue.depthStencil.depth = static_cast(depth.value); + std::vector attachments; + for (const auto &color : colors) + { + VkClearAttachment attachment{}; + if (color.hasValue) + { + Colorf cf((float)color.value.r, (float)color.value.g, (float)color.value.b, (float)color.value.a); + gammaCorrectColor(cf); + + attachment.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + attachment.clearValue.color.float32[0] = static_cast(cf.r); + attachment.clearValue.color.float32[1] = static_cast(cf.g); + attachment.clearValue.color.float32[2] = static_cast(cf.b); + attachment.clearValue.color.float32[3] = static_cast(cf.a); + } + 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(renderPassState.width); + rect.rect.extent.height = static_cast(renderPassState.height); + + vkCmdClearAttachments( + commandBuffers[currentFrame], + static_cast(attachments.size()), attachments.data(), + 1, &rect); } + else + { + renderPassState.useConfigurations = true; - attachments.push_back(depthStencilAttachment); + for (size_t i = 0; i < colors.size(); i++) + { + if (colors[i].hasValue) + { + renderPassState.renderPassConfiguration.colorAttachments[i].loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR; + renderPassState.clearColors[i].color.float32[0] = colors[i].value.r; + renderPassState.clearColors[i].color.float32[1] = colors[i].value.g; + renderPassState.clearColors[i].color.float32[2] = colors[i].value.b; + renderPassState.clearColors[i].color.float32[3] = colors[i].value.a; + } + } - VkClearRect rect{}; - rect.layerCount = 1; - rect.rect.extent.width = static_cast(renderPassState.width); - rect.rect.extent.height = static_cast(renderPassState.height); + if (depth.hasValue) + { + renderPassState.renderPassConfiguration.staticData.depthStencilAttachment.depthLoadOp = VK_ATTACHMENT_LOAD_OP_LOAD; + renderPassState.clearColors[colors.size()].depthStencil.depth = depth.value; + } - vkCmdClearAttachments( - commandBuffers[currentFrame], - static_cast(attachments.size()), attachments.data(), - 1, &rect); + if (stencil.hasValue) + { + renderPassState.renderPassConfiguration.staticData.depthStencilAttachment.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_CLEAR; + renderPassState.clearColors[colors.size()].depthStencil.stencil = stencil.value; + } + + startRenderPass(); + } } void Graphics::discard(const std::vector &colorbuffers, bool depthstencil) @@ -215,40 +280,19 @@ void Graphics::discard(const std::vector &colorbuffers, bool depthstencil) if (renderPassState.active) endRenderPass(); - if (renderPassState.useConfigurations) - { - auto & renderPassConfiguration = renderPassState.renderPassConfiguration; + renderPassState.useConfigurations = true; + auto & renderPassConfiguration = renderPassState.renderPassConfiguration; - for (size_t i = 0; i < colorbuffers.size(); i++) - renderPassConfiguration.colorAttachments[i].discard = colorbuffers[i]; - renderPassConfiguration.staticData.depthAttachment.discard = depthstencil; + for (size_t i = 0; i < colorbuffers.size(); i++) + { + if (colorbuffers[i]) + renderPassConfiguration.colorAttachments[i].loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; } - else + + if (depthstencil) { - RenderPassConfiguration renderPassConfiguration{}; - renderPassConfiguration.colorAttachments.push_back({ swapChainImageFormat, colorbuffers[0], msaaSamples }); - renderPassConfiguration.staticData.depthAttachment = { findDepthFormat(), depthstencil, msaaSamples }; - if (msaaSamples & VK_SAMPLE_COUNT_1_BIT) - renderPassConfiguration.staticData.resolve = false; - else - renderPassConfiguration.staticData.resolve = true; - - FramebufferConfiguration framebufferConfiguration{}; - framebufferConfiguration.staticData.depthView = depthImageView; - if (msaaSamples & VK_SAMPLE_COUNT_1_BIT) - { - framebufferConfiguration.colorViews.push_back(swapChainImageViews.at(imageIndex)); - framebufferConfiguration.staticData.resolveView = VK_NULL_HANDLE; - } - else - { - framebufferConfiguration.colorViews.push_back(colorImageView); - framebufferConfiguration.staticData.resolveView = swapChainImageViews.at(imageIndex); - } - - renderPassState.useConfigurations = true; - renderPassState.renderPassConfiguration = renderPassConfiguration; - renderPassState.framebufferConfiguration = framebufferConfiguration; + renderPassConfiguration.staticData.depthStencilAttachment.depthLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; + renderPassConfiguration.staticData.depthStencilAttachment.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; } startRenderPass(); @@ -422,6 +466,9 @@ void Graphics::present(void *screenshotCallbackdata) if (isRenderTargetActive()) throw love::Exception("present cannot be called while a render target is active."); + if (!renderPassState.active && renderPassState.windowClearRequested) + startRenderPass(); + deprecations.draw(this); submitGpuCommands(true, screenshotCallbackdata); @@ -1938,8 +1985,8 @@ void Graphics::createScreenshotCallbackBuffers() void Graphics::createDefaultRenderPass() { RenderPassConfiguration renderPassConfiguration{}; - renderPassConfiguration.colorAttachments.push_back({ swapChainImageFormat, false, msaaSamples }); - renderPassConfiguration.staticData.depthAttachment = { findDepthFormat(), false, msaaSamples }; + renderPassConfiguration.colorAttachments.push_back({ swapChainImageFormat, VK_ATTACHMENT_LOAD_OP_LOAD, msaaSamples }); + renderPassConfiguration.staticData.depthStencilAttachment = { findDepthFormat(), VK_ATTACHMENT_LOAD_OP_LOAD, VK_ATTACHMENT_LOAD_OP_LOAD, msaaSamples }; if (msaaSamples & VK_SAMPLE_COUNT_1_BIT) renderPassConfiguration.staticData.resolve = false; else @@ -2050,10 +2097,7 @@ VkRenderPass Graphics::createRenderPass(RenderPassConfiguration &configuration) VkAttachmentDescription colorDescription{}; colorDescription.format = colorAttachment.format; colorDescription.samples = colorAttachment.msaaSamples; - if (colorAttachment.discard) - colorDescription.loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; - else - colorDescription.loadOp = VK_ATTACHMENT_LOAD_OP_LOAD; + colorDescription.loadOp = colorAttachment.loadOp; colorDescription.storeOp = VK_ATTACHMENT_STORE_OP_STORE; colorDescription.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; colorDescription.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; @@ -2066,24 +2110,18 @@ VkRenderPass Graphics::createRenderPass(RenderPassConfiguration &configuration) subPass.pColorAttachments = colorAttachmentRefs.data(); VkAttachmentReference depthStencilAttachmentRef{}; - if (configuration.staticData.depthAttachment.format != VK_FORMAT_UNDEFINED) + if (configuration.staticData.depthStencilAttachment.format != VK_FORMAT_UNDEFINED) { depthStencilAttachmentRef.attachment = attachment++; depthStencilAttachmentRef.layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; subPass.pDepthStencilAttachment = &depthStencilAttachmentRef; VkAttachmentDescription depthStencilAttachment{}; - depthStencilAttachment.format = configuration.staticData.depthAttachment.format; - depthStencilAttachment.samples = configuration.staticData.depthAttachment.msaaSamples; - if (configuration.staticData.depthAttachment.discard) - depthStencilAttachment.loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; - else - depthStencilAttachment.loadOp = VK_ATTACHMENT_LOAD_OP_LOAD; + depthStencilAttachment.format = configuration.staticData.depthStencilAttachment.format; + depthStencilAttachment.samples = configuration.staticData.depthStencilAttachment.msaaSamples; + depthStencilAttachment.loadOp = configuration.staticData.depthStencilAttachment.depthLoadOp; depthStencilAttachment.storeOp = VK_ATTACHMENT_STORE_OP_STORE; - if (configuration.staticData.depthAttachment.discard) - depthStencilAttachment.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; - else - depthStencilAttachment.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_LOAD; + depthStencilAttachment.stencilLoadOp = configuration.staticData.depthStencilAttachment.stencilLoadOp; depthStencilAttachment.stencilStoreOp = VK_ATTACHMENT_STORE_OP_STORE; depthStencilAttachment.initialLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; depthStencilAttachment.finalLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; @@ -2285,13 +2323,18 @@ void Graphics::prepareDraw(const VertexAttributes &attributes, const BufferBindi void Graphics::setDefaultRenderPass() { + uint32_t numClearValues = 2; + renderPassState.clearColors.resize(numClearValues); + renderPassState.beginInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO; renderPassState.beginInfo.renderPass = defaultRenderPass; renderPassState.beginInfo.framebuffer = defaultFramebuffers[imageIndex]; renderPassState.beginInfo.renderArea.offset = { 0, 0 }; renderPassState.beginInfo.renderArea.extent = swapChainExtent; - renderPassState.beginInfo.clearValueCount = 0; + renderPassState.beginInfo.clearValueCount = numClearValues; + renderPassState.beginInfo.pClearValues = renderPassState.clearColors.data(); + renderPassState.isWindow = true; renderPassState.useConfigurations = false; renderPassState.pipeline = VK_NULL_HANDLE; renderPassState.width = static_cast(swapChainExtent.width); @@ -2299,6 +2342,36 @@ void Graphics::setDefaultRenderPass() renderPassState.msaa = msaaSamples; renderPassState.numColorAttachments = 1; renderPassState.transitionImages.clear(); + + RenderPassConfiguration renderPassConfiguration{}; + renderPassConfiguration.colorAttachments.push_back({ swapChainImageFormat, VK_ATTACHMENT_LOAD_OP_LOAD, msaaSamples }); + renderPassConfiguration.staticData.depthStencilAttachment = { findDepthFormat(), VK_ATTACHMENT_LOAD_OP_LOAD, VK_ATTACHMENT_LOAD_OP_LOAD, msaaSamples }; + if (msaaSamples & VK_SAMPLE_COUNT_1_BIT) + renderPassConfiguration.staticData.resolve = false; + else + renderPassConfiguration.staticData.resolve = true; + + FramebufferConfiguration framebufferConfiguration{}; + framebufferConfiguration.staticData.depthView = depthImageView; + framebufferConfiguration.staticData.width = swapChainExtent.width; + framebufferConfiguration.staticData.height = swapChainExtent.height; + + if (msaaSamples & VK_SAMPLE_COUNT_1_BIT) + { + framebufferConfiguration.colorViews.push_back(swapChainImageViews.at(imageIndex)); + framebufferConfiguration.staticData.resolveView = VK_NULL_HANDLE; + } + else + { + framebufferConfiguration.colorViews.push_back(colorImageView); + framebufferConfiguration.staticData.resolveView = swapChainImageViews.at(imageIndex); + } + + renderPassState.renderPassConfiguration = renderPassConfiguration; + renderPassState.framebufferConfiguration = framebufferConfiguration; + + if (renderPassState.windowClearRequested) + clear(renderPassState.mainWindowClearColorValue, renderPassState.mainWindowClearStencilValue, renderPassState.mainWindowClearDepthValue); } void Graphics::setRenderPass(const RenderTargets &rts, int pixelw, int pixelh, bool hasSRGBtexture) @@ -2310,12 +2383,13 @@ void Graphics::setRenderPass(const RenderTargets &rts, int pixelw, int pixelh, b for (const auto &color : rts.colors) renderPassConfiguration.colorAttachments.push_back({ Vulkan::getTextureFormat(color.texture->getPixelFormat(), isPixelFormatSRGB(color.texture->getPixelFormat())).internalFormat, - false, + VK_ATTACHMENT_LOAD_OP_LOAD, dynamic_cast(color.texture)->getMsaaSamples() }); if (rts.depthStencil.texture != nullptr) - renderPassConfiguration.staticData.depthAttachment = { + renderPassConfiguration.staticData.depthStencilAttachment = { Vulkan::getTextureFormat(rts.depthStencil.texture->getPixelFormat(), false).internalFormat, - false, + VK_ATTACHMENT_LOAD_OP_LOAD, + VK_ATTACHMENT_LOAD_OP_LOAD, dynamic_cast(rts.depthStencil.texture)->getMsaaSamples() }; FramebufferConfiguration configuration{}; @@ -2333,14 +2407,19 @@ void Graphics::setRenderPass(const RenderTargets &rts, int pixelw, int pixelh, b configuration.staticData.width = static_cast(pixelw); configuration.staticData.height = static_cast(pixelh); + uint32_t numClearValues = rts.colors.size() + 1; + renderPassState.clearColors.resize(numClearValues); + renderPassState.beginInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO; renderPassState.beginInfo.renderPass = VK_NULL_HANDLE; renderPassState.beginInfo.framebuffer = VK_NULL_HANDLE; renderPassState.beginInfo.renderArea.offset = {0, 0}; renderPassState.beginInfo.renderArea.extent.width = static_cast(pixelw); renderPassState.beginInfo.renderArea.extent.height = static_cast(pixelh); - renderPassState.beginInfo.clearValueCount = 0; + renderPassState.beginInfo.clearValueCount = numClearValues; + renderPassState.beginInfo.pClearValues = renderPassState.clearColors.data(); + renderPassState.isWindow = false; renderPassState.useConfigurations = true; renderPassState.renderPassConfiguration = renderPassConfiguration; renderPassState.framebufferConfiguration = configuration; @@ -2356,6 +2435,9 @@ void Graphics::startRenderPass() { renderPassState.active = true; + if (renderPassState.isWindow && renderPassState.windowClearRequested) + renderPassState.windowClearRequested = false; + VkViewport viewport{}; viewport.x = 0.0f; viewport.y = 0.0f; diff --git a/src/modules/graphics/vulkan/Graphics.h b/src/modules/graphics/vulkan/Graphics.h index 3606cf842..06533d670 100644 --- a/src/modules/graphics/vulkan/Graphics.h +++ b/src/modules/graphics/vulkan/Graphics.h @@ -46,27 +46,43 @@ namespace graphics namespace vulkan { -struct RenderPassAttachment +struct ColorAttachment { VkFormat format = VK_FORMAT_UNDEFINED; - bool discard = true; + VkAttachmentLoadOp loadOp = VK_ATTACHMENT_LOAD_OP_LOAD; VkSampleCountFlagBits msaaSamples = VK_SAMPLE_COUNT_1_BIT; - bool operator==(const RenderPassAttachment &attachment) const + bool operator==(const ColorAttachment&attachment) const { return format == attachment.format && - discard == attachment.discard && + loadOp == attachment.loadOp && + msaaSamples == attachment.msaaSamples; + } +}; + +struct DepthStencilAttachment +{ + VkFormat format = VK_FORMAT_UNDEFINED; + VkAttachmentLoadOp depthLoadOp = VK_ATTACHMENT_LOAD_OP_LOAD; + VkAttachmentLoadOp stencilLoadOp = VK_ATTACHMENT_LOAD_OP_LOAD; + VkSampleCountFlagBits msaaSamples = VK_SAMPLE_COUNT_1_BIT; + + bool operator==(const DepthStencilAttachment &attachment) const + { + return format == attachment.format && + depthLoadOp == attachment.depthLoadOp && + stencilLoadOp == attachment.stencilLoadOp && msaaSamples == attachment.msaaSamples; } }; struct RenderPassConfiguration { - std::vector colorAttachments; + std::vector colorAttachments; struct StaticRenderPassConfiguration { - RenderPassAttachment depthAttachment; + DepthStencilAttachment depthStencilAttachment; bool resolve = false; } staticData; @@ -216,6 +232,7 @@ struct RenderpassState { bool active = false; VkRenderPassBeginInfo beginInfo{}; + bool isWindow = false; bool useConfigurations = false; RenderPassConfiguration renderPassConfiguration{}; FramebufferConfiguration framebufferConfiguration{}; @@ -225,6 +242,12 @@ struct RenderpassState float width = 0.0f; float height = 0.0f; VkSampleCountFlagBits msaa = VK_SAMPLE_COUNT_1_BIT; + std::vector clearColors; + + bool windowClearRequested = false; + OptionalColorD mainWindowClearColorValue; + OptionalDouble mainWindowClearDepthValue; + OptionalInt mainWindowClearStencilValue; }; struct ScreenshotReadbackBuffer From b04ba7ecb4053ddca2c3bcf5c5f4e8efa3374d16 Mon Sep 17 00:00:00 2001 From: niki Date: Sat, 11 Feb 2023 20:20:49 +0100 Subject: [PATCH 08/16] vulkan: fix incorrect loadOp --- src/modules/graphics/vulkan/Graphics.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/modules/graphics/vulkan/Graphics.cpp b/src/modules/graphics/vulkan/Graphics.cpp index 13ceb647d..52ba1bced 100644 --- a/src/modules/graphics/vulkan/Graphics.cpp +++ b/src/modules/graphics/vulkan/Graphics.cpp @@ -261,7 +261,7 @@ void Graphics::clear(const std::vector &colors, OptionalInt sten if (depth.hasValue) { - renderPassState.renderPassConfiguration.staticData.depthStencilAttachment.depthLoadOp = VK_ATTACHMENT_LOAD_OP_LOAD; + renderPassState.renderPassConfiguration.staticData.depthStencilAttachment.depthLoadOp = VK_ATTACHMENT_LOAD_OP_CLEAR; renderPassState.clearColors[colors.size()].depthStencil.depth = depth.value; } From 7415cb2d0254ccfe448ae3caab6fcdbed58d6c0f Mon Sep 17 00:00:00 2001 From: niki Date: Sat, 11 Feb 2023 20:25:54 +0100 Subject: [PATCH 09/16] vulkan: fix incorrect render pass hashing --- src/modules/graphics/vulkan/Graphics.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/modules/graphics/vulkan/Graphics.h b/src/modules/graphics/vulkan/Graphics.h index e5483a5e1..d92504741 100644 --- a/src/modules/graphics/vulkan/Graphics.h +++ b/src/modules/graphics/vulkan/Graphics.h @@ -98,7 +98,7 @@ struct RenderPassConfigurationHasher size_t operator()(const RenderPassConfiguration &configuration) const { size_t hashes[] = { - XXH32(configuration.colorAttachments.data(), configuration.colorAttachments.size() * sizeof(VkFormat), 0), + XXH32(configuration.colorAttachments.data(), configuration.colorAttachments.size() * sizeof(ColorAttachment), 0), XXH32(&configuration.staticData, sizeof(configuration.staticData), 0), }; return XXH32(hashes, sizeof(hashes), 0); From b698c0f11aabe48856ad4bd403e56aba85e33b05 Mon Sep 17 00:00:00 2001 From: niki Date: Sat, 11 Feb 2023 22:21:07 +0100 Subject: [PATCH 10/16] vulkan: rename to OptionalDeviceExtensions The previous name was misleading. --- src/modules/graphics/vulkan/Graphics.cpp | 98 ++++++++++++------------ src/modules/graphics/vulkan/Graphics.h | 6 +- 2 files changed, 52 insertions(+), 52 deletions(-) diff --git a/src/modules/graphics/vulkan/Graphics.cpp b/src/modules/graphics/vulkan/Graphics.cpp index 52ba1bced..af282e24e 100644 --- a/src/modules/graphics/vulkan/Graphics.cpp +++ b/src/modules/graphics/vulkan/Graphics.cpp @@ -252,23 +252,23 @@ void Graphics::clear(const std::vector &colors, OptionalInt sten if (colors[i].hasValue) { renderPassState.renderPassConfiguration.colorAttachments[i].loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR; - renderPassState.clearColors[i].color.float32[0] = colors[i].value.r; - renderPassState.clearColors[i].color.float32[1] = colors[i].value.g; - renderPassState.clearColors[i].color.float32[2] = colors[i].value.b; - renderPassState.clearColors[i].color.float32[3] = colors[i].value.a; + renderPassState.clearColors[i].color.float32[0] = static_cast(colors[i].value.r); + renderPassState.clearColors[i].color.float32[1] = static_cast(colors[i].value.g); + renderPassState.clearColors[i].color.float32[2] = static_cast(colors[i].value.b); + renderPassState.clearColors[i].color.float32[3] = static_cast(colors[i].value.a); } } if (depth.hasValue) { renderPassState.renderPassConfiguration.staticData.depthStencilAttachment.depthLoadOp = VK_ATTACHMENT_LOAD_OP_CLEAR; - renderPassState.clearColors[colors.size()].depthStencil.depth = depth.value; + renderPassState.clearColors[colors.size()].depthStencil.depth = static_cast(depth.value); } if (stencil.hasValue) { renderPassState.renderPassConfiguration.staticData.depthStencilAttachment.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_CLEAR; - renderPassState.clearColors[colors.size()].depthStencil.stencil = stencil.value; + renderPassState.clearColors[colors.size()].depthStencil.stencil = static_cast(stencil.value); } startRenderPass(); @@ -686,7 +686,7 @@ void Graphics::setFrontFaceWinding(Winding winding) states.back().winding = winding; - if (optionalDeviceFeatures.extendedDynamicState) + if (optionalDeviceExtensions.extendedDynamicState) vkCmdSetFrontFaceEXT( commandBuffers.at(currentFrame), Vulkan::getFrontFace(winding)); @@ -923,7 +923,7 @@ void Graphics::setStencilMode(StencilAction action, CompareMode compare, int val vkCmdSetStencilCompareMask(commandBuffers.at(currentFrame), VK_STENCIL_FRONT_AND_BACK, readmask); vkCmdSetStencilReference(commandBuffers.at(currentFrame), VK_STENCIL_FRONT_AND_BACK, value); - if (optionalDeviceFeatures.extendedDynamicState) + if (optionalDeviceExtensions.extendedDynamicState) vkCmdSetStencilOpEXT( commandBuffers.at(currentFrame), VK_STENCIL_FRONT_AND_BACK, @@ -941,7 +941,7 @@ void Graphics::setDepthMode(CompareMode compare, bool write) { flushBatchedDraws(); - if (optionalDeviceFeatures.extendedDynamicState) + if (optionalDeviceExtensions.extendedDynamicState) { vkCmdSetDepthCompareOpEXT( commandBuffers.at(currentFrame), Vulkan::getCompareOp(compare)); @@ -1144,7 +1144,7 @@ void Graphics::initDynamicState() vkCmdSetStencilCompareMask(commandBuffers.at(currentFrame), VK_STENCIL_FRONT_AND_BACK, states.back().stencil.readMask); vkCmdSetStencilReference(commandBuffers.at(currentFrame), VK_STENCIL_FRONT_AND_BACK, states.back().stencil.value); - if (optionalDeviceFeatures.extendedDynamicState) + if (optionalDeviceExtensions.extendedDynamicState) { vkCmdSetStencilOpEXT( commandBuffers.at(currentFrame), @@ -1321,9 +1321,9 @@ graphics::Shader::BuiltinUniformData Graphics::getCurrentBuiltinUniformData() return data; } -const OptionalDeviceFeatures &Graphics::getEnabledOptionalDeviceExtensions() const +const OptionalDeviceExtensions&Graphics::getEnabledOptionalDeviceExtensions() const { - return optionalDeviceFeatures; + return optionalDeviceExtensions; } static void checkOptionalInstanceExtensions(OptionalInstanceExtensions &ext) @@ -1550,7 +1550,7 @@ QueueFamilyIndices Graphics::findQueueFamilies(VkPhysicalDevice device) return indices; } -static void findOptionalDeviceExtensions(VkPhysicalDevice physicalDevice, OptionalDeviceFeatures &optionalDeviceFeatures) +static void findOptionalDeviceExtensions(VkPhysicalDevice physicalDevice, OptionalDeviceExtensions &optionalDeviceExtensions) { uint32_t extensionCount; vkEnumerateDeviceExtensionProperties(physicalDevice, nullptr, &extensionCount, nullptr); @@ -1561,19 +1561,19 @@ static void findOptionalDeviceExtensions(VkPhysicalDevice physicalDevice, Option for (const auto &extension : availableExtensions) { if (strcmp(extension.extensionName, VK_EXT_EXTENDED_DYNAMIC_STATE_EXTENSION_NAME) == 0) - optionalDeviceFeatures.extendedDynamicState = true; + optionalDeviceExtensions.extendedDynamicState = true; if (strcmp(extension.extensionName, VK_KHR_GET_MEMORY_REQUIREMENTS_2_EXTENSION_NAME) == 0) - optionalDeviceFeatures.memoryRequirements2 = true; + optionalDeviceExtensions.memoryRequirements2 = true; if (strcmp(extension.extensionName, VK_KHR_DEDICATED_ALLOCATION_EXTENSION_NAME) == 0) - optionalDeviceFeatures.dedicatedAllocation = true; + optionalDeviceExtensions.dedicatedAllocation = true; if (strcmp(extension.extensionName, VK_KHR_BUFFER_DEVICE_ADDRESS_EXTENSION_NAME) == 0) - optionalDeviceFeatures.bufferDeviceAddress = true; + optionalDeviceExtensions.bufferDeviceAddress = true; if (strcmp(extension.extensionName, VK_EXT_MEMORY_BUDGET_EXTENSION_NAME) == 0) - optionalDeviceFeatures.memoryBudget = true; + optionalDeviceExtensions.memoryBudget = true; if (strcmp(extension.extensionName, VK_KHR_SHADER_FLOAT_CONTROLS_EXTENSION_NAME) == 0) - optionalDeviceFeatures.shaderFloatControls = true; + optionalDeviceExtensions.shaderFloatControls = true; if (strcmp(extension.extensionName, VK_KHR_SPIRV_1_4_EXTENSION_NAME) == 0) - optionalDeviceFeatures.spirv14 = true; + optionalDeviceExtensions.spirv14 = true; } } @@ -1598,22 +1598,22 @@ void Graphics::createLogicalDevice() queueCreateInfos.push_back(queueCreateInfo); } - findOptionalDeviceExtensions(physicalDevice, optionalDeviceFeatures); + findOptionalDeviceExtensions(physicalDevice, optionalDeviceExtensions); // sanity check for dependencies. - if (optionalDeviceFeatures.extendedDynamicState && !optionalInstanceExtensions.physicalDeviceProperties2) - optionalDeviceFeatures.extendedDynamicState = false; - if (optionalDeviceFeatures.dedicatedAllocation && !optionalDeviceFeatures.memoryRequirements2) - optionalDeviceFeatures.dedicatedAllocation = false; - if (optionalDeviceFeatures.bufferDeviceAddress && !optionalInstanceExtensions.physicalDeviceProperties2) - optionalDeviceFeatures.bufferDeviceAddress = false; - if (optionalDeviceFeatures.memoryBudget && !optionalInstanceExtensions.physicalDeviceProperties2) - optionalDeviceFeatures.memoryBudget = false; - if (optionalDeviceFeatures.spirv14 && !optionalDeviceFeatures.shaderFloatControls) - optionalDeviceFeatures.spirv14 = false; - if (optionalDeviceFeatures.spirv14 && deviceApiVersion < VK_API_VERSION_1_1) - optionalDeviceFeatures.spirv14 = false; + if (optionalDeviceExtensions.extendedDynamicState && !optionalInstanceExtensions.physicalDeviceProperties2) + optionalDeviceExtensions.extendedDynamicState = false; + if (optionalDeviceExtensions.dedicatedAllocation && !optionalDeviceExtensions.memoryRequirements2) + optionalDeviceExtensions.dedicatedAllocation = false; + if (optionalDeviceExtensions.bufferDeviceAddress && !optionalInstanceExtensions.physicalDeviceProperties2) + optionalDeviceExtensions.bufferDeviceAddress = false; + if (optionalDeviceExtensions.memoryBudget && !optionalInstanceExtensions.physicalDeviceProperties2) + optionalDeviceExtensions.memoryBudget = false; + if (optionalDeviceExtensions.spirv14 && !optionalDeviceExtensions.shaderFloatControls) + optionalDeviceExtensions.spirv14 = false; + if (optionalDeviceExtensions.spirv14 && deviceApiVersion < VK_API_VERSION_1_1) + optionalDeviceExtensions.spirv14 = false; VkPhysicalDeviceFeatures deviceFeatures{}; deviceFeatures.samplerAnisotropy = VK_TRUE; @@ -1626,19 +1626,19 @@ void Graphics::createLogicalDevice() createInfo.pEnabledFeatures = &deviceFeatures; std::vector enabledExtensions(deviceExtensions.begin(), deviceExtensions.end()); - if (optionalDeviceFeatures.extendedDynamicState) + if (optionalDeviceExtensions.extendedDynamicState) enabledExtensions.push_back(VK_EXT_EXTENDED_DYNAMIC_STATE_EXTENSION_NAME); - if (optionalDeviceFeatures.memoryRequirements2) + if (optionalDeviceExtensions.memoryRequirements2) enabledExtensions.push_back(VK_KHR_GET_MEMORY_REQUIREMENTS_2_EXTENSION_NAME); - if (optionalDeviceFeatures.dedicatedAllocation) + if (optionalDeviceExtensions.dedicatedAllocation) enabledExtensions.push_back(VK_KHR_DEDICATED_ALLOCATION_EXTENSION_NAME); - if (optionalDeviceFeatures.bufferDeviceAddress) + if (optionalDeviceExtensions.bufferDeviceAddress) enabledExtensions.push_back(VK_KHR_BUFFER_DEVICE_ADDRESS_EXTENSION_NAME); - if (optionalDeviceFeatures.memoryBudget) + if (optionalDeviceExtensions.memoryBudget) enabledExtensions.push_back(VK_EXT_MEMORY_BUDGET_EXTENSION_NAME); - if (optionalDeviceFeatures.shaderFloatControls) + if (optionalDeviceExtensions.shaderFloatControls) enabledExtensions.push_back(VK_KHR_SHADER_FLOAT_CONTROLS_EXTENSION_NAME); - if (optionalDeviceFeatures.spirv14) + if (optionalDeviceExtensions.spirv14) enabledExtensions.push_back(VK_KHR_SPIRV_1_4_EXTENSION_NAME); if (deviceApiVersion >= VK_API_VERSION_1_1) enabledExtensions.push_back(VK_KHR_BIND_MEMORY_2_EXTENSION_NAME); @@ -1654,7 +1654,7 @@ void Graphics::createLogicalDevice() VkPhysicalDeviceExtendedDynamicStateFeaturesEXT extendedDynamicStateFeatures{}; extendedDynamicStateFeatures.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTENDED_DYNAMIC_STATE_FEATURES_EXT; - extendedDynamicStateFeatures.extendedDynamicState = Vulkan::getBool(optionalDeviceFeatures.extendedDynamicState); + extendedDynamicStateFeatures.extendedDynamicState = Vulkan::getBool(optionalDeviceExtensions.extendedDynamicState); extendedDynamicStateFeatures.pNext = nullptr; createInfo.pNext = &extendedDynamicStateFeatures; @@ -1718,9 +1718,9 @@ void Graphics::initVMA() allocatorCreateInfo.pVulkanFunctions = &vulkanFunctions; allocatorCreateInfo.flags |= VMA_ALLOCATOR_CREATE_EXTERNALLY_SYNCHRONIZED_BIT; - if (optionalDeviceFeatures.dedicatedAllocation) + if (optionalDeviceExtensions.dedicatedAllocation) allocatorCreateInfo.flags |= VMA_ALLOCATOR_CREATE_KHR_DEDICATED_ALLOCATION_BIT; - if (optionalDeviceFeatures.memoryBudget) + if (optionalDeviceExtensions.memoryBudget) allocatorCreateInfo.flags |= VMA_ALLOCATOR_CREATE_EXT_MEMORY_BUDGET_BIT; if (vmaCreateAllocator(&allocatorCreateInfo, &vmaAllocator) != VK_SUCCESS) @@ -2325,7 +2325,7 @@ void Graphics::prepareDraw(const VertexAttributes &attributes, const BufferBindi configuration.numColorAttachments = renderPassState.numColorAttachments; configuration.primitiveType = primitiveType; - if (optionalDeviceFeatures.extendedDynamicState) + if (optionalDeviceExtensions.extendedDynamicState) vkCmdSetCullModeEXT(commandBuffers.at(currentFrame), Vulkan::getCullMode(cullmode)); else { @@ -2452,7 +2452,7 @@ void Graphics::setRenderPass(const RenderTargets &rts, int pixelw, int pixelh, b configuration.staticData.width = static_cast(pixelw); configuration.staticData.height = static_cast(pixelh); - uint32_t numClearValues = rts.colors.size() + 1; + uint32_t numClearValues = static_cast(rts.colors.size() + 1); renderPassState.clearColors.resize(numClearValues); renderPassState.beginInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO; @@ -2667,7 +2667,7 @@ VkPipeline Graphics::createGraphicsPipeline(GraphicsPipelineConfiguration &confi rasterizer.rasterizerDiscardEnable = VK_FALSE; rasterizer.polygonMode = Vulkan::getPolygonMode(configuration.wireFrame); rasterizer.lineWidth = 1.0f; - if (!optionalDeviceFeatures.extendedDynamicState) + if (!optionalDeviceExtensions.extendedDynamicState) { rasterizer.cullMode = Vulkan::getCullMode(configuration.dynamicState.cullmode); rasterizer.frontFace = Vulkan::getFrontFace(configuration.dynamicState.winding); @@ -2686,7 +2686,7 @@ VkPipeline Graphics::createGraphicsPipeline(GraphicsPipelineConfiguration &confi VkPipelineDepthStencilStateCreateInfo depthStencil{}; depthStencil.sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO; depthStencil.depthTestEnable = VK_TRUE; - if (!optionalDeviceFeatures.extendedDynamicState) + if (!optionalDeviceExtensions.extendedDynamicState) { depthStencil.depthWriteEnable = Vulkan::getBool(configuration.dynamicState.depthState.write); depthStencil.depthCompareOp = Vulkan::getCompareOp(configuration.dynamicState.depthState.compare); @@ -2697,7 +2697,7 @@ VkPipeline Graphics::createGraphicsPipeline(GraphicsPipelineConfiguration &confi depthStencil.stencilTestEnable = VK_TRUE; - if (!optionalDeviceFeatures.extendedDynamicState) + if (!optionalDeviceExtensions.extendedDynamicState) { depthStencil.front.failOp = VK_STENCIL_OP_KEEP; depthStencil.front.passOp = Vulkan::getStencilOp(configuration.dynamicState.stencilAction); @@ -2737,7 +2737,7 @@ VkPipeline Graphics::createGraphicsPipeline(GraphicsPipelineConfiguration &confi std::vector dynamicStates; - if (optionalDeviceFeatures.extendedDynamicState) + if (optionalDeviceExtensions.extendedDynamicState) dynamicStates = { VK_DYNAMIC_STATE_SCISSOR, VK_DYNAMIC_STATE_VIEWPORT, diff --git a/src/modules/graphics/vulkan/Graphics.h b/src/modules/graphics/vulkan/Graphics.h index d92504741..4e9972fde 100644 --- a/src/modules/graphics/vulkan/Graphics.h +++ b/src/modules/graphics/vulkan/Graphics.h @@ -146,7 +146,7 @@ struct OptionalInstanceExtensions bool physicalDeviceProperties2 = false; }; -struct OptionalDeviceFeatures +struct OptionalDeviceExtensions { // VK_EXT_extended_dynamic_state bool extendedDynamicState = false; @@ -317,7 +317,7 @@ public: VkSampler getCachedSampler(const SamplerState &sampler); void setComputeShader(Shader *computeShader); graphics::Shader::BuiltinUniformData getCurrentBuiltinUniformData(); - const OptionalDeviceFeatures &getEnabledOptionalDeviceExtensions() const; + const OptionalDeviceExtensions &getEnabledOptionalDeviceExtensions() const; VkSampleCountFlagBits getMsaaCount(int requestedMsaa) const; void setVsync(int vsync); int getVsync() const; @@ -398,7 +398,7 @@ private: int requestedMsaa = 0; VkDevice device = VK_NULL_HANDLE; OptionalInstanceExtensions optionalInstanceExtensions; - OptionalDeviceFeatures optionalDeviceFeatures; + OptionalDeviceExtensions optionalDeviceExtensions; VkQueue graphicsQueue = VK_NULL_HANDLE; VkQueue presentQueue = VK_NULL_HANDLE; VkSurfaceKHR surface = VK_NULL_HANDLE; From 14e08a2b037280a46505ceb13fb11f329357e27f Mon Sep 17 00:00:00 2001 From: niki Date: Sat, 11 Feb 2023 22:36:39 +0100 Subject: [PATCH 11/16] vulkan: remove default renderpasses & framebuffers There is little to no performance gain, with a lot of burden to maintenance of the extra path. It's better to unify the code with the other render pass logic. --- src/modules/graphics/vulkan/Graphics.cpp | 87 ++++++------------------ src/modules/graphics/vulkan/Graphics.h | 5 -- 2 files changed, 19 insertions(+), 73 deletions(-) diff --git a/src/modules/graphics/vulkan/Graphics.cpp b/src/modules/graphics/vulkan/Graphics.cpp index af282e24e..9db9bea76 100644 --- a/src/modules/graphics/vulkan/Graphics.cpp +++ b/src/modules/graphics/vulkan/Graphics.cpp @@ -156,8 +156,6 @@ void Graphics::clear(OptionalColorD color, OptionalInt stencil, OptionalDouble d } else { - renderPassState.useConfigurations = true; - if (color.hasValue) { renderPassState.renderPassConfiguration.colorAttachments[0].loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR; @@ -245,8 +243,6 @@ void Graphics::clear(const std::vector &colors, OptionalInt sten } else { - renderPassState.useConfigurations = true; - for (size_t i = 0; i < colors.size(); i++) { if (colors[i].hasValue) @@ -280,7 +276,6 @@ void Graphics::discard(const std::vector &colorbuffers, bool depthstencil) if (renderPassState.active) endRenderPass(); - renderPassState.useConfigurations = true; auto & renderPassConfiguration = renderPassState.renderPassConfiguration; for (size_t i = 0; i < colorbuffers.size(); i++) @@ -550,8 +545,6 @@ bool Graphics::setMode(void *context, int width, int height, int pixelwidth, int createColorResources(); createDepthResources(); transitionColorDepthLayouts = true; - createDefaultRenderPass(); - createDefaultFramebuffers(); createCommandPool(); createCommandBuffers(); @@ -1100,6 +1093,8 @@ bool Graphics::dispatch(love::graphics::Shader *shader, int x, int y, int z) bool Graphics::dispatch(love::graphics::Shader *shader, love::graphics::Buffer *indirectargs, size_t argsoffset) { + usedShadersInFrame.insert(computeShader); + if (renderPassState.active) endRenderPass(); @@ -2027,40 +2022,6 @@ void Graphics::createScreenshotCallbackBuffers() } } -void Graphics::createDefaultRenderPass() -{ - RenderPassConfiguration renderPassConfiguration{}; - renderPassConfiguration.colorAttachments.push_back({ swapChainImageFormat, VK_ATTACHMENT_LOAD_OP_LOAD, msaaSamples }); - renderPassConfiguration.staticData.depthStencilAttachment = { findDepthFormat(), VK_ATTACHMENT_LOAD_OP_LOAD, VK_ATTACHMENT_LOAD_OP_LOAD, msaaSamples }; - if (msaaSamples & VK_SAMPLE_COUNT_1_BIT) - renderPassConfiguration.staticData.resolve = false; - else - renderPassConfiguration.staticData.resolve = true; - defaultRenderPass = createRenderPass(renderPassConfiguration); -} - -void Graphics::createDefaultFramebuffers() -{ - defaultFramebuffers.clear(); - - for (const auto view : swapChainImageViews) - { - FramebufferConfiguration configuration{}; - configuration.staticData.renderPass = defaultRenderPass; - configuration.staticData.width = swapChainExtent.width; - configuration.staticData.height = swapChainExtent.height; - configuration.staticData.depthView = depthImageView; - if (msaaSamples & VK_SAMPLE_COUNT_1_BIT) - configuration.colorViews.push_back(view); - else - { - configuration.colorViews.push_back(colorImageView); - configuration.staticData.resolveView = view; - } - defaultFramebuffers.push_back(createFramebuffer(configuration)); - } -} - VkFramebuffer Graphics::createFramebuffer(FramebufferConfiguration &configuration) { std::vector attachments; @@ -2372,15 +2333,14 @@ void Graphics::setDefaultRenderPass() renderPassState.clearColors.resize(numClearValues); renderPassState.beginInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO; - renderPassState.beginInfo.renderPass = defaultRenderPass; - renderPassState.beginInfo.framebuffer = defaultFramebuffers[imageIndex]; + renderPassState.beginInfo.renderPass = VK_NULL_HANDLE; + renderPassState.beginInfo.framebuffer = VK_NULL_HANDLE; renderPassState.beginInfo.renderArea.offset = { 0, 0 }; renderPassState.beginInfo.renderArea.extent = swapChainExtent; renderPassState.beginInfo.clearValueCount = numClearValues; renderPassState.beginInfo.pClearValues = renderPassState.clearColors.data(); renderPassState.isWindow = true; - renderPassState.useConfigurations = false; renderPassState.pipeline = VK_NULL_HANDLE; renderPassState.width = static_cast(swapChainExtent.width); renderPassState.height = static_cast(swapChainExtent.height); @@ -2465,7 +2425,6 @@ void Graphics::setRenderPass(const RenderTargets &rts, int pixelw, int pixelh, b renderPassState.beginInfo.pClearValues = renderPassState.clearColors.data(); renderPassState.isWindow = false; - renderPassState.useConfigurations = true; renderPassState.renderPassConfiguration = renderPassConfiguration; renderPassState.framebufferConfiguration = configuration; renderPassState.pipeline = VK_NULL_HANDLE; @@ -2493,26 +2452,23 @@ void Graphics::startRenderPass() vkCmdSetViewport(commandBuffers.at(currentFrame), 0, 1, &viewport); - if (renderPassState.useConfigurations) + auto &renderPassConfiguration = renderPassState.renderPassConfiguration; + VkRenderPass renderPass; + auto it = renderPasses.find(renderPassConfiguration); + if (it != renderPasses.end()) + renderPass = it->second; + else { - auto &renderPassConfiguration = renderPassState.renderPassConfiguration; - VkRenderPass renderPass; - auto it = renderPasses.find(renderPassConfiguration); - if (it != renderPasses.end()) - renderPass = it->second; - else - { - renderPass = createRenderPass(renderPassConfiguration); - renderPasses[renderPassConfiguration] = renderPass; - } - renderPassState.beginInfo.renderPass = renderPass; - - renderPassUsages[renderPass] = true; - - auto &framebufferConfiguration = renderPassState.framebufferConfiguration; - framebufferConfiguration.staticData.renderPass = renderPass; - renderPassState.beginInfo.framebuffer = getFramebuffer(framebufferConfiguration); + renderPass = createRenderPass(renderPassConfiguration); + renderPasses[renderPassConfiguration] = renderPass; } + renderPassState.beginInfo.renderPass = renderPass; + + renderPassUsages[renderPass] = true; + + auto &framebufferConfiguration = renderPassState.framebufferConfiguration; + framebufferConfiguration.staticData.renderPass = renderPass; + renderPassState.beginInfo.framebuffer = getFramebuffer(framebufferConfiguration); for (const auto &image : renderPassState.transitionImages) Vulkan::cmdTransitionImageLayout(commandBuffers.at(currentFrame), image, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL); @@ -3080,9 +3036,6 @@ void Graphics::cleanupSwapChain() vmaDestroyBuffer(vmaAllocator, readbackBuffer.buffer, readbackBuffer.allocation); vmaDestroyImage(vmaAllocator, readbackBuffer.image, readbackBuffer.imageAllocation); } - for (const auto &framebuffer : defaultFramebuffers) - vkDestroyFramebuffer(device, framebuffer, nullptr); - vkDestroyRenderPass(device, defaultRenderPass, nullptr); vkDestroyImageView(device, colorImageView, nullptr); vmaDestroyImage(vmaAllocator, colorImage, colorImageAllocation); vkDestroyImageView(device, depthImageView, nullptr); @@ -3106,8 +3059,6 @@ void Graphics::recreateSwapChain() createScreenshotCallbackBuffers(); createColorResources(); createDepthResources(); - createDefaultRenderPass(); - createDefaultFramebuffers(); transitionColorDepthLayouts = true; } diff --git a/src/modules/graphics/vulkan/Graphics.h b/src/modules/graphics/vulkan/Graphics.h index 4e9972fde..2fe384314 100644 --- a/src/modules/graphics/vulkan/Graphics.h +++ b/src/modules/graphics/vulkan/Graphics.h @@ -233,7 +233,6 @@ struct RenderpassState bool active = false; VkRenderPassBeginInfo beginInfo{}; bool isWindow = false; - bool useConfigurations = false; RenderPassConfiguration renderPassConfiguration{}; FramebufferConfiguration framebufferConfiguration{}; VkPipeline pipeline = VK_NULL_HANDLE; @@ -351,8 +350,6 @@ private: void createSwapChain(); void createImageViews(); void createScreenshotCallbackBuffers(); - void createDefaultRenderPass(); - void createDefaultFramebuffers(); VkFramebuffer createFramebuffer(FramebufferConfiguration &configuration); VkFramebuffer getFramebuffer(FramebufferConfiguration &configuration); void createDefaultShaders(); @@ -416,9 +413,7 @@ private: VkImage depthImage = VK_NULL_HANDLE; VkImageView depthImageView = VK_NULL_HANDLE; VmaAllocation depthImageAllocation = VK_NULL_HANDLE; - VkRenderPass defaultRenderPass = VK_NULL_HANDLE; VkPipelineCache pipelineCache = VK_NULL_HANDLE; - std::vector defaultFramebuffers; std::unordered_map renderPasses; std::unordered_map framebuffers; std::unordered_map graphicsPipelines; From 2fc5a8afe0c1153513178f8e617ece4c7e8433aa Mon Sep 17 00:00:00 2001 From: niki Date: Sun, 12 Feb 2023 00:22:51 +0100 Subject: [PATCH 12/16] vulkan: removed unused optional extension --- src/modules/graphics/vulkan/Graphics.cpp | 6 ------ src/modules/graphics/vulkan/Graphics.h | 3 --- 2 files changed, 9 deletions(-) diff --git a/src/modules/graphics/vulkan/Graphics.cpp b/src/modules/graphics/vulkan/Graphics.cpp index 9db9bea76..ecfa74224 100644 --- a/src/modules/graphics/vulkan/Graphics.cpp +++ b/src/modules/graphics/vulkan/Graphics.cpp @@ -1562,8 +1562,6 @@ static void findOptionalDeviceExtensions(VkPhysicalDevice physicalDevice, Option if (strcmp(extension.extensionName, VK_KHR_DEDICATED_ALLOCATION_EXTENSION_NAME) == 0) optionalDeviceExtensions.dedicatedAllocation = true; if (strcmp(extension.extensionName, VK_KHR_BUFFER_DEVICE_ADDRESS_EXTENSION_NAME) == 0) - optionalDeviceExtensions.bufferDeviceAddress = true; - if (strcmp(extension.extensionName, VK_EXT_MEMORY_BUDGET_EXTENSION_NAME) == 0) optionalDeviceExtensions.memoryBudget = true; if (strcmp(extension.extensionName, VK_KHR_SHADER_FLOAT_CONTROLS_EXTENSION_NAME) == 0) optionalDeviceExtensions.shaderFloatControls = true; @@ -1601,8 +1599,6 @@ void Graphics::createLogicalDevice() optionalDeviceExtensions.extendedDynamicState = false; if (optionalDeviceExtensions.dedicatedAllocation && !optionalDeviceExtensions.memoryRequirements2) optionalDeviceExtensions.dedicatedAllocation = false; - if (optionalDeviceExtensions.bufferDeviceAddress && !optionalInstanceExtensions.physicalDeviceProperties2) - optionalDeviceExtensions.bufferDeviceAddress = false; if (optionalDeviceExtensions.memoryBudget && !optionalInstanceExtensions.physicalDeviceProperties2) optionalDeviceExtensions.memoryBudget = false; if (optionalDeviceExtensions.spirv14 && !optionalDeviceExtensions.shaderFloatControls) @@ -1627,8 +1623,6 @@ void Graphics::createLogicalDevice() enabledExtensions.push_back(VK_KHR_GET_MEMORY_REQUIREMENTS_2_EXTENSION_NAME); if (optionalDeviceExtensions.dedicatedAllocation) enabledExtensions.push_back(VK_KHR_DEDICATED_ALLOCATION_EXTENSION_NAME); - if (optionalDeviceExtensions.bufferDeviceAddress) - enabledExtensions.push_back(VK_KHR_BUFFER_DEVICE_ADDRESS_EXTENSION_NAME); if (optionalDeviceExtensions.memoryBudget) enabledExtensions.push_back(VK_EXT_MEMORY_BUDGET_EXTENSION_NAME); if (optionalDeviceExtensions.shaderFloatControls) diff --git a/src/modules/graphics/vulkan/Graphics.h b/src/modules/graphics/vulkan/Graphics.h index 2fe384314..a284f64b4 100644 --- a/src/modules/graphics/vulkan/Graphics.h +++ b/src/modules/graphics/vulkan/Graphics.h @@ -157,9 +157,6 @@ struct OptionalDeviceExtensions // VK_KHR_dedicated_allocation bool dedicatedAllocation = false; - // VK_KHR_buffer_device_address - bool bufferDeviceAddress = false; - // VK_EXT_memory_budget bool memoryBudget = false; From 6183f67598d3102795db267d50b4400f194dbcdc Mon Sep 17 00:00:00 2001 From: niki Date: Sun, 12 Feb 2023 00:54:03 +0100 Subject: [PATCH 13/16] vulkan: fix wrong attachment load op --- src/modules/graphics/vulkan/Graphics.cpp | 47 +++++++++++++++--------- src/modules/graphics/vulkan/Graphics.h | 1 + 2 files changed, 30 insertions(+), 18 deletions(-) diff --git a/src/modules/graphics/vulkan/Graphics.cpp b/src/modules/graphics/vulkan/Graphics.cpp index ecfa74224..07718cef6 100644 --- a/src/modules/graphics/vulkan/Graphics.cpp +++ b/src/modules/graphics/vulkan/Graphics.cpp @@ -276,7 +276,7 @@ void Graphics::discard(const std::vector &colorbuffers, bool depthstencil) if (renderPassState.active) endRenderPass(); - auto & renderPassConfiguration = renderPassState.renderPassConfiguration; + auto &renderPassConfiguration = renderPassState.renderPassConfiguration; for (size_t i = 0; i < colorbuffers.size(); i++) { @@ -1316,7 +1316,7 @@ graphics::Shader::BuiltinUniformData Graphics::getCurrentBuiltinUniformData() return data; } -const OptionalDeviceExtensions&Graphics::getEnabledOptionalDeviceExtensions() const +const OptionalDeviceExtensions &Graphics::getEnabledOptionalDeviceExtensions() const { return optionalDeviceExtensions; } @@ -2181,6 +2181,24 @@ VkRenderPass Graphics::createRenderPass(RenderPassConfiguration &configuration) return renderPass; } + +VkRenderPass Graphics::getRenderPass(RenderPassConfiguration& configuration) +{ + VkRenderPass renderPass; + auto it = renderPasses.find(configuration); + if (it != renderPasses.end()) + renderPass = it->second; + else + { + renderPass = createRenderPass(configuration); + renderPasses[configuration] = renderPass; + } + + renderPassUsages[renderPass] = true; + + return renderPass; +} + bool Graphics::usesConstantVertexColor(const VertexAttributes &vertexAttributes) { return !!(vertexAttributes.enableBits & (1u << ATTRIB_COLOR)); @@ -2446,23 +2464,10 @@ void Graphics::startRenderPass() vkCmdSetViewport(commandBuffers.at(currentFrame), 0, 1, &viewport); - auto &renderPassConfiguration = renderPassState.renderPassConfiguration; - VkRenderPass renderPass; - auto it = renderPasses.find(renderPassConfiguration); - if (it != renderPasses.end()) - renderPass = it->second; - else - { - renderPass = createRenderPass(renderPassConfiguration); - renderPasses[renderPassConfiguration] = renderPass; - } - renderPassState.beginInfo.renderPass = renderPass; + renderPassState.beginInfo.renderPass = getRenderPass(renderPassState.renderPassConfiguration); - renderPassUsages[renderPass] = true; - - auto &framebufferConfiguration = renderPassState.framebufferConfiguration; - framebufferConfiguration.staticData.renderPass = renderPass; - renderPassState.beginInfo.framebuffer = getFramebuffer(framebufferConfiguration); + renderPassState.framebufferConfiguration.staticData.renderPass = renderPassState.beginInfo.renderPass; + renderPassState.beginInfo.framebuffer = getFramebuffer(renderPassState.framebufferConfiguration); for (const auto &image : renderPassState.transitionImages) Vulkan::cmdTransitionImageLayout(commandBuffers.at(currentFrame), image, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL); @@ -2478,6 +2483,12 @@ void Graphics::endRenderPass() for (const auto &image : renderPassState.transitionImages) Vulkan::cmdTransitionImageLayout(commandBuffers.at(currentFrame), image, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL); + + for (auto &colorAttachment : renderPassState.renderPassConfiguration.colorAttachments) + colorAttachment.loadOp = VK_ATTACHMENT_LOAD_OP_LOAD; + + renderPassState.renderPassConfiguration.staticData.depthStencilAttachment.depthLoadOp = VK_ATTACHMENT_LOAD_OP_LOAD; + renderPassState.renderPassConfiguration.staticData.depthStencilAttachment.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_LOAD; } VkSampler Graphics::createSampler(const SamplerState &samplerState) diff --git a/src/modules/graphics/vulkan/Graphics.h b/src/modules/graphics/vulkan/Graphics.h index a284f64b4..da4dd829e 100644 --- a/src/modules/graphics/vulkan/Graphics.h +++ b/src/modules/graphics/vulkan/Graphics.h @@ -351,6 +351,7 @@ private: VkFramebuffer getFramebuffer(FramebufferConfiguration &configuration); void createDefaultShaders(); VkRenderPass createRenderPass(RenderPassConfiguration &configuration); + VkRenderPass getRenderPass(RenderPassConfiguration& configuration); VkPipeline createGraphicsPipeline(GraphicsPipelineConfiguration &configuration); void createColorResources(); VkFormat findSupportedFormat(const std::vector &candidates, VkImageTiling tiling, VkFormatFeatureFlags features); From dc6e080d18ac22790af9fc168fa9112881aad847 Mon Sep 17 00:00:00 2001 From: niki Date: Sun, 12 Feb 2023 14:18:26 +0100 Subject: [PATCH 14/16] vulkan: code styling --- src/modules/graphics/vulkan/Graphics.cpp | 2 +- src/modules/graphics/vulkan/Graphics.h | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/modules/graphics/vulkan/Graphics.cpp b/src/modules/graphics/vulkan/Graphics.cpp index 07718cef6..761ccee32 100644 --- a/src/modules/graphics/vulkan/Graphics.cpp +++ b/src/modules/graphics/vulkan/Graphics.cpp @@ -2182,7 +2182,7 @@ VkRenderPass Graphics::createRenderPass(RenderPassConfiguration &configuration) } -VkRenderPass Graphics::getRenderPass(RenderPassConfiguration& configuration) +VkRenderPass Graphics::getRenderPass(RenderPassConfiguration &configuration) { VkRenderPass renderPass; auto it = renderPasses.find(configuration); diff --git a/src/modules/graphics/vulkan/Graphics.h b/src/modules/graphics/vulkan/Graphics.h index da4dd829e..dfc1cf489 100644 --- a/src/modules/graphics/vulkan/Graphics.h +++ b/src/modules/graphics/vulkan/Graphics.h @@ -52,7 +52,7 @@ struct ColorAttachment VkAttachmentLoadOp loadOp = VK_ATTACHMENT_LOAD_OP_LOAD; VkSampleCountFlagBits msaaSamples = VK_SAMPLE_COUNT_1_BIT; - bool operator==(const ColorAttachment&attachment) const + bool operator==(const ColorAttachment &attachment) const { return format == attachment.format && loadOp == attachment.loadOp && @@ -351,7 +351,7 @@ private: VkFramebuffer getFramebuffer(FramebufferConfiguration &configuration); void createDefaultShaders(); VkRenderPass createRenderPass(RenderPassConfiguration &configuration); - VkRenderPass getRenderPass(RenderPassConfiguration& configuration); + VkRenderPass getRenderPass(RenderPassConfiguration &configuration); VkPipeline createGraphicsPipeline(GraphicsPipelineConfiguration &configuration); void createColorResources(); VkFormat findSupportedFormat(const std::vector &candidates, VkImageTiling tiling, VkFormatFeatureFlags features); From 4f321d69e7c03fb3e31b928174b0dd30386b329c Mon Sep 17 00:00:00 2001 From: niki Date: Sun, 12 Feb 2023 14:52:30 +0100 Subject: [PATCH 15/16] vulkan: cache depthStencilFormat --- src/modules/graphics/vulkan/Graphics.cpp | 14 ++++++-------- src/modules/graphics/vulkan/Graphics.h | 1 + 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/src/modules/graphics/vulkan/Graphics.cpp b/src/modules/graphics/vulkan/Graphics.cpp index 761ccee32..e21097959 100644 --- a/src/modules/graphics/vulkan/Graphics.cpp +++ b/src/modules/graphics/vulkan/Graphics.cpp @@ -1448,6 +1448,7 @@ void Graphics::pickPhysicalDevice() deviceApiVersion = properties.apiVersion; msaaSamples = getMsaaCount(requestedMsaa); + depthStencilFormat = findDepthFormat(); } bool Graphics::checkDeviceExtensionSupport(VkPhysicalDevice device) @@ -2181,7 +2182,6 @@ VkRenderPass Graphics::createRenderPass(RenderPassConfiguration &configuration) return renderPass; } - VkRenderPass Graphics::getRenderPass(RenderPassConfiguration &configuration) { VkRenderPass renderPass; @@ -2362,7 +2362,7 @@ void Graphics::setDefaultRenderPass() RenderPassConfiguration renderPassConfiguration{}; renderPassConfiguration.colorAttachments.push_back({ swapChainImageFormat, VK_ATTACHMENT_LOAD_OP_LOAD, msaaSamples }); - renderPassConfiguration.staticData.depthStencilAttachment = { findDepthFormat(), VK_ATTACHMENT_LOAD_OP_LOAD, VK_ATTACHMENT_LOAD_OP_LOAD, msaaSamples }; + renderPassConfiguration.staticData.depthStencilAttachment = { depthStencilFormat, VK_ATTACHMENT_LOAD_OP_LOAD, VK_ATTACHMENT_LOAD_OP_LOAD, msaaSamples }; if (msaaSamples & VK_SAMPLE_COUNT_1_BIT) renderPassConfiguration.staticData.resolve = false; else @@ -2384,8 +2384,8 @@ void Graphics::setDefaultRenderPass() framebufferConfiguration.staticData.resolveView = swapChainImageViews.at(imageIndex); } - renderPassState.renderPassConfiguration = renderPassConfiguration; - renderPassState.framebufferConfiguration = framebufferConfiguration; + renderPassState.renderPassConfiguration = std::move(renderPassConfiguration); + renderPassState.framebufferConfiguration = std::move(framebufferConfiguration); if (renderPassState.windowClearRequested) clear(renderPassState.mainWindowClearColorValue, renderPassState.mainWindowClearStencilValue, renderPassState.mainWindowClearDepthValue); @@ -2890,12 +2890,10 @@ VkFormat Graphics::findDepthFormat() void Graphics::createDepthResources() { - VkFormat depthAttachment = findDepthFormat(); - VkImageCreateInfo imageInfo{}; imageInfo.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO; imageInfo.imageType = VK_IMAGE_TYPE_2D; - imageInfo.format = depthAttachment; + imageInfo.format = depthStencilFormat; imageInfo.extent.width = swapChainExtent.width; imageInfo.extent.height = swapChainExtent.height; imageInfo.extent.depth = 1; @@ -2918,7 +2916,7 @@ void Graphics::createDepthResources() imageViewInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; imageViewInfo.image = depthImage; imageViewInfo.viewType = VK_IMAGE_VIEW_TYPE_2D; - imageViewInfo.format = depthAttachment; + imageViewInfo.format = depthStencilFormat; imageViewInfo.components.r = VK_COMPONENT_SWIZZLE_IDENTITY; imageViewInfo.components.g = VK_COMPONENT_SWIZZLE_IDENTITY; imageViewInfo.components.b = VK_COMPONENT_SWIZZLE_IDENTITY; diff --git a/src/modules/graphics/vulkan/Graphics.h b/src/modules/graphics/vulkan/Graphics.h index dfc1cf489..ddd7ee42c 100644 --- a/src/modules/graphics/vulkan/Graphics.h +++ b/src/modules/graphics/vulkan/Graphics.h @@ -402,6 +402,7 @@ private: Matrix4 displayRotation; std::vector swapChainImages; VkFormat swapChainImageFormat = VK_FORMAT_UNDEFINED; + VkFormat depthStencilFormat = VK_FORMAT_UNDEFINED; VkExtent2D swapChainExtent = VkExtent2D(); std::vector swapChainImageViews; VkSampleCountFlagBits msaaSamples = VK_SAMPLE_COUNT_1_BIT; From 5eae82ab331b2a46ad1171fa7c14763f91792e92 Mon Sep 17 00:00:00 2001 From: niki Date: Wed, 15 Feb 2023 01:22:38 +0100 Subject: [PATCH 16/16] vulkan: fix gammacorrect in Graphics::clear --- src/modules/graphics/vulkan/Graphics.cpp | 25 ++++++++++++++++-------- 1 file changed, 17 insertions(+), 8 deletions(-) diff --git a/src/modules/graphics/vulkan/Graphics.cpp b/src/modules/graphics/vulkan/Graphics.cpp index e21097959..2131e4977 100644 --- a/src/modules/graphics/vulkan/Graphics.cpp +++ b/src/modules/graphics/vulkan/Graphics.cpp @@ -159,10 +159,14 @@ void Graphics::clear(OptionalColorD color, OptionalInt stencil, OptionalDouble d if (color.hasValue) { renderPassState.renderPassConfiguration.colorAttachments[0].loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR; - renderPassState.clearColors[0].color.float32[0] = static_cast(color.value.r); - renderPassState.clearColors[0].color.float32[1] = static_cast(color.value.g); - renderPassState.clearColors[0].color.float32[2] = static_cast(color.value.b); - renderPassState.clearColors[0].color.float32[3] = static_cast(color.value.a); + + Colorf cf((float)color.value.r, (float)color.value.g, (float)color.value.b, (float)color.value.a); + gammaCorrectColor(cf); + + renderPassState.clearColors[0].color.float32[0] = static_cast(cf.r); + renderPassState.clearColors[0].color.float32[1] = static_cast(cf.g); + renderPassState.clearColors[0].color.float32[2] = static_cast(cf.b); + renderPassState.clearColors[0].color.float32[3] = static_cast(cf.a); } if (depth.hasValue) @@ -248,10 +252,15 @@ void Graphics::clear(const std::vector &colors, OptionalInt sten if (colors[i].hasValue) { renderPassState.renderPassConfiguration.colorAttachments[i].loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR; - renderPassState.clearColors[i].color.float32[0] = static_cast(colors[i].value.r); - renderPassState.clearColors[i].color.float32[1] = static_cast(colors[i].value.g); - renderPassState.clearColors[i].color.float32[2] = static_cast(colors[i].value.b); - renderPassState.clearColors[i].color.float32[3] = static_cast(colors[i].value.a); + + auto &color = colors[i]; + Colorf cf((float)color.value.r, (float)color.value.g, (float)color.value.b, (float)color.value.a); + gammaCorrectColor(cf); + + renderPassState.clearColors[i].color.float32[0] = static_cast(cf.r); + renderPassState.clearColors[i].color.float32[1] = static_cast(cf.g); + renderPassState.clearColors[i].color.float32[2] = static_cast(cf.b); + renderPassState.clearColors[i].color.float32[3] = static_cast(cf.a); } }