diff --git a/src/modules/graphics/vulkan/Graphics.cpp b/src/modules/graphics/vulkan/Graphics.cpp index 2131e4977..8a4f7500f 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; @@ -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); @@ -1173,7 +1181,6 @@ void Graphics::beginFrame() if (frameCounter >= USAGES_POLL_INTERVAL) { - vkDeviceWaitIdle(device); cleanupUnusedObjects(); frameCounter = 0; } @@ -1263,11 +1270,6 @@ const VkDeviceSize Graphics::getMinUniformBufferOffsetAlignment() const return minUniformBufferOffsetAlignment; } -graphics::Texture *Graphics::getDefaultTexture() const -{ - return defaultTexture; -} - VkCommandBuffer Graphics::getCommandBufferForDataTransfer() { if (renderPassState.active) @@ -1653,10 +1655,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"); @@ -1850,20 +1853,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()) + { + formatOrder = { + VK_FORMAT_B8G8R8A8_SRGB, + VK_FORMAT_R8G8B8A8_SRGB, + }; + } + else + { + formatOrder = { + VK_FORMAT_B8G8R8A8_UNORM, + VK_FORMAT_R8G8B8A8_SNORM, + }; + } + + for (const auto format : formatOrder) { 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) + { + if (availableFormat.format == format && availableFormat.colorSpace == VK_COLORSPACE_SRGB_NONLINEAR_KHR) return availableFormat; + } } - - 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; - + return availableFormats[0]; } @@ -2208,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, @@ -2224,6 +2236,7 @@ void Graphics::createVulkanVertexFormat( auto allBits = enableBits; bool usesColor = false; + bool usesTexCoord = false; uint8_t highestBufferBinding = 0; @@ -2233,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; @@ -2267,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; @@ -2331,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); @@ -2402,8 +2443,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/Graphics.h b/src/modules/graphics/vulkan/Graphics.h index ddd7ee42c..04161b9e8 100644 --- a/src/modules/graphics/vulkan/Graphics.h +++ b/src/modules/graphics/vulkan/Graphics.h @@ -262,13 +262,12 @@ class Graphics final : public love::graphics::Graphics 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 @@ class Graphics final : public love::graphics::Graphics 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(); @@ -369,7 +366,6 @@ class Graphics final : public love::graphics::Graphics void startRecordingGraphicsCommands(); void endRecordingGraphicsCommands(); void ensureGraphicsPipelineConfiguration(GraphicsPipelineConfiguration &configuration); - bool usesConstantVertexColor(const VertexAttributes &attribs); void createVulkanVertexFormat( VertexAttributes vertexAttributes, std::vector &bindingDescriptions, @@ -438,6 +434,7 @@ class Graphics final : public love::graphics::Graphics 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; diff --git a/src/modules/graphics/vulkan/Shader.cpp b/src/modules/graphics/vulkan/Shader.cpp index 94c06f53a..3ad661164 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" @@ -140,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 = 1000; class BindingMapper { @@ -178,24 +179,17 @@ class BindingMapper 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 +212,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"); } } @@ -238,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) { @@ -262,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; @@ -302,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); @@ -312,9 +317,6 @@ void Shader::unloadVolatile() vkDestroyPipeline(device, computePipeline, nullptr); }); - while (!freeDescriptorSets.empty()) - freeDescriptorSets.pop(); - for (const auto streamBuffer : streamBuffers) streamBuffer->release(); @@ -322,7 +324,6 @@ void Shader::unloadVolatile() shaderStages.clear(); streamBuffers.clear(); descriptorPools.clear(); - descriptorSetsVector.clear(); } const std::vector &Shader::getShaderStages() const @@ -344,9 +345,8 @@ void Shader::newFrame() { currentFrame = (currentFrame + 1) % MAX_FRAMES_IN_FLIGHT; - updatedUniforms.clear(); currentUsedUniformStreamBuffersCount = 0; - currentUsedDescriptorSetsCount = 0; + currentDescriptorPool = 0; if (streamBuffers.size() > 1) { @@ -362,14 +362,25 @@ 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); + for (VkDescriptorPool pool : descriptorPools[currentFrame]) + vkResetDescriptorPool(device, pool, 0); } void Shader::cmdPushDescriptorSets(VkCommandBuffer commandBuffer, VkPipelineBindPoint bindPoint) { + VkDescriptorSet currentDescriptorSet = allocateDescriptorSet(); + + 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; @@ -398,6 +409,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; @@ -405,65 +418,109 @@ 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++; - - 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) + for (const auto &u : uniformInfos) { - if (builtinUniformInfo[builtin] != nullptr) + auto &info = u.second; + + if (usesLocalUniformData(&info)) + continue; + + if (info.baseType == UNIFORM_SAMPLER || info.baseType == UNIFORM_STORAGETEXTURE) { - auto texture = dynamic_cast(builtinUniformInfo[builtin]->textures[0]); + bool isSampler = info.baseType == UNIFORM_SAMPLER; + + 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 = texture->getImageLayout(); - imageInfo.imageView = (VkImageView)texture->getRenderTargetHandle(); - imageInfo.sampler = (VkSampler)texture->getSamplerHandle(); + VkDescriptorImageInfo imageInfo{}; - auto location = builtinUniformInfo[builtin]->location; + imageInfo.imageLayout = vkTexture->getImageLayout(); + imageInfo.imageView = (VkImageView)vkTexture->getRenderTargetHandle(); + if (isSampler) + imageInfo.sampler = (VkSampler)vkTexture->getSamplerHandle(); - 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; + imageInfos.push_back(imageInfo); + } - vkUpdateDescriptorSets(device, 1, &textureWrite, 0, nullptr); + 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[imageInfos.size() - info.count]; - updatedUniforms.insert(location); + descriptorWrites.push_back(write); } - } + 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; + + 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()); - for (const auto &u : uniformInfos) - { - if (updatedUniforms.find(u.second.location) == updatedUniforms.end()) - updateUniform(&u.second, u.second.count, true); - } + VkDescriptorBufferInfo bufferInfo{}; + bufferInfo.buffer = (VkBuffer)info.buffers[i]->getHandle();; + bufferInfo.offset = 0; + bufferInfo.range = info.buffers[i]->getSize(); - vkCmdBindDescriptorSets(commandBuffer, bindPoint, pipelineLayout, 0, 1, ¤tDescriptorSet, 0, nullptr); + bufferInfos.push_back(bufferInfo); + } - currentUsedDescriptorSetsCount++; + write.pBufferInfo = &bufferInfos[bufferInfos.size() - info.count]; - if (currentUsedDescriptorSetsCount >= static_cast(descriptorSetsVector.at(currentFrame).size())) - descriptorSetsVector.at(currentFrame).push_back(allocateDescriptorSet()); + descriptorWrites.push_back(write); + } + 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; + + 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()); + } - currentDescriptorSet = descriptorSetsVector.at(currentFrame).at(currentUsedDescriptorSetsCount); + write.pTexelBufferView = &bufferViews[bufferViews.size() - info.count]; - updatedUniforms.clear(); + descriptorWrites.push_back(write); + } + } + + vkUpdateDescriptorSets(device, descriptorWrites.size(), descriptorWrites.data(), 0, nullptr); + + vkCmdBindDescriptorSets(commandBuffer, bindPoint, pipelineLayout, 0, 1, ¤tDescriptorSet, 0, nullptr); } Shader::~Shader() @@ -502,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) @@ -627,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) @@ -641,17 +590,13 @@ void Shader::sendBuffers(const UniformInfo *info, love::graphics::Buffer **buffe if (oldBuffer) oldBuffer->release(); } - - updateUniform(info, count); } 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; } @@ -830,9 +775,9 @@ 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); + const auto &type = comp.get_type(resource.base_type_id); + size_t defaultUniformBlockSize = comp.get_declared_struct_size(type); + localUniformStagingData.resize(defaultUniformBlockSize); localUniformData.resize(defaultUniformBlockSize); localUniformLocation = bindingMapper(comp, spirv, resource.name, resource.id); @@ -910,11 +855,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; } } @@ -970,11 +913,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; } } @@ -998,6 +955,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() @@ -1085,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); @@ -1120,7 +1103,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]; } } @@ -1136,47 +1120,56 @@ 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; } } -VkDescriptorSet Shader::allocateDescriptorSet() +void Shader::createDescriptorPool() { - if (freeDescriptorSets.empty()) - { - 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(); + 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); + VkDescriptorPool pool; + if (vkCreateDescriptorPool(device, &createInfo, nullptr, &pool) != VK_SUCCESS) + throw love::Exception("failed to create descriptor pool"); - std::vector layouts(DESCRIPTOR_POOL_SIZE, descriptorSetLayout); + descriptorPools[currentFrame].push_back(pool); +} + +VkDescriptorSet Shader::allocateDescriptorSet() +{ + if (descriptorPools[currentFrame].empty()) + createDescriptorPool(); + while (true) + { VkDescriptorSetAllocateInfo allocInfo{}; allocInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO; - allocInfo.descriptorPool = pool; - allocInfo.descriptorSetCount = DESCRIPTOR_POOL_SIZE; - allocInfo.pSetLayouts = layouts.data(); - - std::vector descriptorSet; - descriptorSet.resize(DESCRIPTOR_POOL_SIZE); - VkResult result = vkAllocateDescriptorSets(device, &allocInfo, descriptorSet.data()); - if (result != VK_SUCCESS) - throw love::Exception("failed to allocate descriptor set"); + allocInfo.descriptorPool = descriptorPools[currentFrame][currentDescriptorPool]; + allocInfo.descriptorSetCount = 1; + allocInfo.pSetLayouts = &descriptorSetLayout; - for (const auto ds : descriptorSet) - freeDescriptorSets.push(ds); - } + VkDescriptorSet descriptorSet; + VkResult result = vkAllocateDescriptorSets(device, &allocInfo, &descriptorSet); - auto ds = freeDescriptorSets.front(); - freeDescriptorSets.pop(); - return ds; + switch (result) + { + case VK_SUCCESS: + return descriptorSet; + case VK_ERROR_OUT_OF_POOL_MEMORY: + currentDescriptorPool++; + if (descriptorPools[currentFrame].size() <= currentDescriptorPool) + createDescriptorPool(); + continue; + default: + throw love::Exception("failed to allocate descriptor set"); + } + } } } // vulkan diff --git a/src/modules/graphics/vulkan/Shader.h b/src/modules/graphics/vulkan/Shader.h index 9a65048e1..af997b408 100644 --- a/src/modules/graphics/vulkan/Shader.h +++ b/src/modules/graphics/vulkan/Shader.h @@ -70,7 +70,7 @@ class Shader final void attach() override; - ptrdiff_t getHandle() const { return 0; } + ptrdiff_t getHandle() const override { return 0; } std::string getWarnings() const override { return ""; } @@ -97,19 +97,18 @@ class Shader final 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 updateUniform(const UniformInfo *info, int count, bool internal); - + void buildLocalUniforms(spirv_cross::Compiler &comp, const spirv_cross::SPIRType &type, size_t baseoff, const std::string &basename); + void createDescriptorPool(); VkDescriptorSet allocateDescriptorSet(); VkDeviceSize uniformBufferSizeAligned; VkPipeline computePipeline; + uint32_t numTextures; + uint32_t numBuffers; + uint32_t numBufferViews; + VkDescriptorSetLayout descriptorSetLayout; VkPipelineLayout pipelineLayout; std::vector descriptorPoolSizes; @@ -117,11 +116,7 @@ class Shader final // 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::queue freeDescriptorSets; - std::vector> descriptorSetsVector; - - std::set updatedUniforms; + std::vector> descriptorPools; std::vector shaderStages; std::vector shaderModules; @@ -142,11 +137,9 @@ class Shader final std::unordered_map attributes; - VkDescriptorSet currentDescriptorSet; - uint32_t currentFrame; uint32_t currentUsedUniformStreamBuffersCount; - uint32_t currentUsedDescriptorSetsCount; + uint32_t currentDescriptorPool; }; } 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; - - 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) - { - barrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT; + setImageLayoutTransitionOptions(true, oldLayout, barrier.srcAccessMask, sourceStage, depthStencil); + setImageLayoutTransitionOptions(false, newLayout, barrier.dstAccessMask, destinationStage, depthStencil); - 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) - { + if (depthStencil) 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,