diff --git a/src/modules/graphics/vulkan/Graphics.cpp b/src/modules/graphics/vulkan/Graphics.cpp index 27a334cf1..0e0dde6ce 100644 --- a/src/modules/graphics/vulkan/Graphics.cpp +++ b/src/modules/graphics/vulkan/Graphics.cpp @@ -240,6 +240,11 @@ void Graphics::present(void *screenshotCallbackdata) if (!isActive()) return; + if (isRenderTargetActive()) + throw love::Exception("present cannot be called while a render target is active."); + + deprecations.draw(this); + submitGpuCommands(true); VkPresentInfoKHR presentInfo{}; @@ -266,6 +271,13 @@ void Graphics::present(void *screenshotCallbackdata) else if (result != VK_SUCCESS) throw love::Exception("failed to present swap chain image"); + drawCalls = 0; + renderTargetSwitchCount = 0; + drawCallsBatched = 0; + + updatePendingReadbacks(); + updateTemporaryResources(); + currentFrame = (currentFrame + 1) % MAX_FRAMES_IN_FLIGHT; beginFrame(); @@ -720,7 +732,7 @@ bool Graphics::dispatch(int x, int y, int z) vkCmdBindPipeline(commandBuffers.at(currentFrame), VK_PIPELINE_BIND_POINT_COMPUTE, computeShader->getComputePipeline()); - computeShader->cmdPushDescriptorSets(commandBuffers.at(currentFrame), currentFrame, VK_PIPELINE_BIND_POINT_COMPUTE); + computeShader->cmdPushDescriptorSets(commandBuffers.at(currentFrame), static_cast(currentFrame), VK_PIPELINE_BIND_POINT_COMPUTE); vkCmdDispatch(commandBuffers.at(currentFrame), static_cast(x), static_cast(y), static_cast(z)); @@ -1475,8 +1487,8 @@ VkPresentModeKHR Graphics::chooseSwapPresentMode(const std::vector& Shader::getShaderStages() const +const std::vector &Shader::getShaderStages() const { return shaderStages; } @@ -232,7 +232,7 @@ VkPipeline Shader::getComputePipeline() const return computePipeline; } -static VkDescriptorImageInfo* createDescriptorImageInfo(graphics::Texture* texture, bool sampler) +static VkDescriptorImageInfo* createDescriptorImageInfo(graphics::Texture *texture, bool sampler) { auto vkTexture = (Texture*)texture; @@ -409,13 +409,13 @@ void Shader::attach() vgfx->setComputeShader(this); } -int Shader::getVertexAttributeIndex(const std::string& name) +int Shader::getVertexAttributeIndex(const std::string &name) { auto it = attributes.find(name); return it == attributes.end() ? -1 : it->second; } -const Shader::UniformInfo* Shader::getUniformInfo(const std::string& name) const +const Shader::UniformInfo* Shader::getUniformInfo(const std::string &name) const { return &uniformInfos.at(name); } @@ -425,7 +425,13 @@ const Shader::UniformInfo* Shader::getUniformInfo(BuiltinUniform builtin) const return builtinUniformInfo[builtin]; } -void Shader::sendTextures(const UniformInfo* info, graphics::Texture** textures, int count) +void Shader::updateUniform(const UniformInfo* info, int count) +{ + if (current == this) + Graphics::flushBatchedDrawsGlobal(); +} + +void Shader::sendTextures(const UniformInfo *info, graphics::Texture **textures, int count) { for (unsigned i = 0; i < count; i++) { @@ -447,7 +453,7 @@ void Shader::calculateUniformBufferSizeAligned() uniformBufferSizeAligned = factor * minAlignment; } -void Shader::buildLocalUniforms(spirv_cross::Compiler& comp, const spirv_cross::SPIRType &type, size_t baseoff, const std::string &basename) +void Shader::buildLocalUniforms(spirv_cross::Compiler &comp, const spirv_cross::SPIRType &type, size_t baseoff, const std::string &basename) { using namespace spirv_cross; diff --git a/src/modules/graphics/vulkan/Shader.h b/src/modules/graphics/vulkan/Shader.h index 3e732ad6d..8ec87c2c5 100644 --- a/src/modules/graphics/vulkan/Shader.h +++ b/src/modules/graphics/vulkan/Shader.h @@ -1,8 +1,8 @@ #pragma once // LÖVE -#include -#include +#include "graphics/Shader.h" +#include "graphics/vulkan/ShaderStage.h" #include "Vulkan.h" // Libraries @@ -39,7 +39,7 @@ public: VkPipeline getComputePipeline() const; - const std::vector& getShaderStages() const; + const std::vector &getShaderStages() const; const VkPipelineLayout getGraphicsPipelineLayout() const; @@ -51,26 +51,23 @@ public: std::string getWarnings() const override { return ""; } - int getVertexAttributeIndex(const std::string& name) override; + int getVertexAttributeIndex(const std::string &name) override; - const UniformInfo* getUniformInfo(const std::string& name) const override; - const UniformInfo* getUniformInfo(BuiltinUniform builtin) const override; + const UniformInfo *getUniformInfo(const std::string &name) const override; + const UniformInfo *getUniformInfo(BuiltinUniform builtin) const override; - // Not needed right now, since the logic that links the values of the uniforms to the shader is done in cmdPushDescriptorSets - // which gets called from the vulkan::Graphics class whenever a draw call happens. - // I'll have to reevaluate the use of this function in the future though. - void updateUniform(const UniformInfo* info, int count) override {} + void updateUniform(const UniformInfo *info, int count) override; - void sendTextures(const UniformInfo* info, graphics::Texture** textures, int count) override; - void sendBuffers(const UniformInfo* info, love::graphics::Buffer** buffers, int count) override {} + void sendTextures(const UniformInfo *info, graphics::Texture **textures, int count) override; + void sendBuffers(const UniformInfo *info, love::graphics::Buffer **buffers, int count) override {} - bool hasUniform(const std::string& name) const override; + bool hasUniform(const std::string &name) const override; - void setVideoTextures(graphics::Texture* ytexture, graphics::Texture* cbtexture, graphics::Texture* crtexture) override; + void setVideoTextures(graphics::Texture *ytexture, graphics::Texture *cbtexture, graphics::Texture *crtexture) override; // fixme: use normal methods for this in the future. - void setUniformData(BuiltinUniformData& data); - void setMainTex(graphics::Texture* texture); + void setUniformData(BuiltinUniformData &data); + void setMainTex(graphics::Texture *texture); private: void calculateUniformBufferSizeAligned(); @@ -79,10 +76,10 @@ private: void createPipelineLayout(); void createStreamBuffers(); void buildLocalUniforms( - spirv_cross::Compiler& comp, - const spirv_cross::SPIRType& type, + spirv_cross::Compiler &comp, + const spirv_cross::SPIRType &type, size_t baseoff, - const std::string& basename); + const std::string &basename); VkDescriptorSet allocateDescriptorSet(); @@ -112,7 +109,7 @@ private: bool isCompute = false; std::unordered_map uniformInfos; - UniformInfo* builtinUniformInfo[BUILTIN_MAX_ENUM]; + UniformInfo *builtinUniformInfo[BUILTIN_MAX_ENUM]; std::unique_ptr uniformBufferObjectBuffer; std::vector localUniformStagingData; diff --git a/src/modules/graphics/vulkan/Texture.cpp b/src/modules/graphics/vulkan/Texture.cpp index 23cf0cf19..7a6508709 100644 --- a/src/modules/graphics/vulkan/Texture.cpp +++ b/src/modules/graphics/vulkan/Texture.cpp @@ -79,7 +79,11 @@ bool Texture::loadVolatile() auto commandBuffer = vgfx->getCommandBufferForDataTransfer(); - if (computeWrite) + if (isPixelFormatDepthStencil(format)) + imageLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; + else if (isPixelFormatDepth(format)) + imageLayout = VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_OPTIMAL; + else if (computeWrite) imageLayout = VK_IMAGE_LAYOUT_GENERAL; else imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; @@ -103,7 +107,7 @@ bool Texture::loadVolatile() sliceCount = slices.getSliceCount(); for (int slice = 0; slice < sliceCount; slice++) { - auto* id = slices.get(slice, mip); + auto *id = slices.get(slice, mip); if (id != nullptr) uploadImageData(id, mip, slice, 0, 0); } @@ -200,29 +204,54 @@ void Texture::clear() { auto commandBuffer = vgfx->getCommandBufferForDataTransfer(); - auto clearColor = getClearValue(); - VkImageSubresourceRange range{}; - range.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + if (isPixelFormatDepthStencil(format)) + range.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT; + else if (isPixelFormatDepth(format)) + range.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT; + else + range.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; range.baseMipLevel = 0; range.levelCount = VK_REMAINING_MIP_LEVELS; range.baseArrayLayer = 0; range.layerCount = VK_REMAINING_ARRAY_LAYERS; - if (imageLayout != VK_IMAGE_LAYOUT_GENERAL) + if (imageLayout == VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL) { - Vulkan::cmdTransitionImageLayout(commandBuffer, textureImage, - VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, - 0, range.levelCount, 0, range.layerCount); + Vulkan::cmdTransitionImageLayout(commandBuffer, textureImage, + VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, + 0, VK_REMAINING_MIP_LEVELS, 0, VK_REMAINING_ARRAY_LAYERS); + + auto clearColor = getClearValue(); vkCmdClearColorImage(commandBuffer, textureImage, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, &clearColor, 1, &range); - Vulkan::cmdTransitionImageLayout(commandBuffer, textureImage, - VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, - 0, range.levelCount, 0, range.layerCount); + Vulkan::cmdTransitionImageLayout(commandBuffer, textureImage, + VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, + 0, VK_REMAINING_MIP_LEVELS, 0, VK_REMAINING_ARRAY_LAYERS); + } + else if (imageLayout == VK_IMAGE_LAYOUT_GENERAL) + { + auto clearColor = getClearValue(); + + vkCmdClearColorImage(commandBuffer, textureImage, VK_IMAGE_LAYOUT_GENERAL, &clearColor, 1, &range); } else - vkCmdClearColorImage(commandBuffer, textureImage, VK_IMAGE_LAYOUT_GENERAL, &clearColor, 1, &range); + { + Vulkan::cmdTransitionImageLayout(commandBuffer, textureImage, + imageLayout, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, + 0, VK_REMAINING_MIP_LEVELS, 0, VK_REMAINING_ARRAY_LAYERS); + + VkClearDepthStencilValue depthStencilColor{}; + depthStencilColor.depth = 0.0f; + depthStencilColor.stencil = 0; + + vkCmdClearDepthStencilImage(commandBuffer, textureImage, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, &depthStencilColor, 1, &range); + + Vulkan::cmdTransitionImageLayout(commandBuffer, textureImage, + VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, imageLayout, + 0, VK_REMAINING_MIP_LEVELS, 0, VK_REMAINING_ARRAY_LAYERS); + } } VkClearColorValue Texture::getClearValue() diff --git a/src/modules/graphics/vulkan/Vulkan.cpp b/src/modules/graphics/vulkan/Vulkan.cpp index 363310847..8f8f82016 100644 --- a/src/modules/graphics/vulkan/Vulkan.cpp +++ b/src/modules/graphics/vulkan/Vulkan.cpp @@ -789,6 +789,33 @@ void Vulkan::cmdTransitionImageLayout(VkCommandBuffer commandBuffer, VkImage ima 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 || newLayout == VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_OPTIMAL)) + { + 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 || oldLayout == VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_OPTIMAL) && + newLayout == VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL) + { + 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 || newLayout == VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_OPTIMAL)) + { + 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 throw std::invalid_argument("unsupported layout transition!"); @@ -801,6 +828,7 @@ void Vulkan::cmdTransitionImageLayout(VkCommandBuffer commandBuffer, VkImage ima 1, &barrier ); } + } // vulkan } // graphics } // love