diff --git a/src/common/android.cpp b/src/common/android.cpp index 369258480..25c68e44b 100644 --- a/src/common/android.cpp +++ b/src/common/android.cpp @@ -98,26 +98,24 @@ bool getSafeArea(int &top, int &left, int &bottom, int &right) JNIEnv *env = (JNIEnv*) SDL_AndroidGetJNIEnv(); jobject activity = (jobject) SDL_AndroidGetActivity(); jclass clazz = env->GetObjectClass(activity); + jclass rectClass = env->FindClass("android/graphics/Rect"); + jmethodID methodID = env->GetMethodID(clazz, "getSafeArea", "()Landroid/graphics/Rect;"); + jobject safeArea = env->CallObjectMethod(activity, methodID); - static jmethodID methodID = env->GetMethodID(clazz, "getSafeArea", "()Z"); - - bool hasSafeArea = false; - - if (methodID == nullptr) - // NoSuchMethodException is thrown in case methodID is null - env->ExceptionClear(); - else if ((hasSafeArea = env->CallBooleanMethod(activity, methodID))) + if (safeArea != nullptr) { - top = env->GetIntField(activity, env->GetFieldID(clazz, "safeAreaTop", "I")); - left = env->GetIntField(activity, env->GetFieldID(clazz, "safeAreaLeft", "I")); - bottom = env->GetIntField(activity, env->GetFieldID(clazz, "safeAreaBottom", "I")); - right = env->GetIntField(activity, env->GetFieldID(clazz, "safeAreaRight", "I")); + top = env->GetIntField(activity, env->GetFieldID(rectClass, "top", "I")); + left = env->GetIntField(activity, env->GetFieldID(rectClass, "left", "I")); + bottom = env->GetIntField(activity, env->GetFieldID(rectClass, "bottom", "I")); + right = env->GetIntField(activity, env->GetFieldID(rectClass, "right", "I")); + env->DeleteLocalRef(safeArea); } + env->DeleteLocalRef(rectClass); env->DeleteLocalRef(clazz); env->DeleteLocalRef(activity); - return hasSafeArea; + return safeArea != nullptr; } bool openURL(const std::string &url) diff --git a/src/modules/graphics/vulkan/Graphics.cpp b/src/modules/graphics/vulkan/Graphics.cpp index 4b3d16687..5736188e8 100644 --- a/src/modules/graphics/vulkan/Graphics.cpp +++ b/src/modules/graphics/vulkan/Graphics.cpp @@ -2224,8 +2224,6 @@ VkRenderPass Graphics::getRenderPass(RenderPassConfiguration &configuration) renderPasses[configuration] = renderPass; } - renderPassUsages[renderPass] = true; - return renderPass; } @@ -2315,13 +2313,14 @@ void Graphics::prepareDraw(const VertexAttributes &attributes, const BufferBindi if (!renderPassState.active) startRenderPass(); - usedShadersInFrame.insert((dynamic_cast(Shader::current))); + auto s = dynamic_cast(Shader::current); + + usedShadersInFrame.insert(s); GraphicsPipelineConfiguration configuration{}; configuration.renderPass = renderPassState.beginInfo.renderPass; configuration.vertexAttributes = attributes; - configuration.shader = (Shader*)Shader::current; configuration.wireFrame = states.back().wireframe; configuration.blendState = states.back().blend; configuration.colorChannelMask = states.back().colorMask; @@ -2341,11 +2340,15 @@ void Graphics::prepareDraw(const VertexAttributes &attributes, const BufferBindi configuration.dynamicState.cullmode = cullmode; } - configuration.shader->setMainTex(texture); - - ensureGraphicsPipelineConfiguration(configuration); + VkPipeline pipeline = s->getCachedGraphicsPipeline(this, configuration); + if (pipeline != renderPassState.pipeline) + { + vkCmdBindPipeline(commandBuffers.at(currentFrame), VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline); + renderPassState.pipeline = pipeline; + } - configuration.shader->cmdPushDescriptorSets(commandBuffers.at(currentFrame), VK_PIPELINE_BIND_POINT_GRAPHICS); + s->setMainTex(texture); + s->cmdPushDescriptorSets(commandBuffers.at(currentFrame), VK_PIPELINE_BIND_POINT_GRAPHICS); VkBuffer vkbuffers[BufferBindings::MAX]; VkDeviceSize vkoffsets[BufferBindings::MAX]; @@ -2638,9 +2641,7 @@ static void eraseUnusedObjects( void Graphics::cleanupUnusedObjects() { - eraseUnusedObjects(renderPasses, renderPassUsages, vkDestroyRenderPass, device); eraseUnusedObjects(framebuffers, framebufferUsages, vkDestroyFramebuffer, device); - eraseUnusedObjects(graphicsPipelines, pipelineUsages, vkDestroyPipeline, device); } void Graphics::requestSwapchainRecreation() @@ -2670,17 +2671,17 @@ VkSampler Graphics::getCachedSampler(const SamplerState &samplerState) } } -VkPipeline Graphics::createGraphicsPipeline(GraphicsPipelineConfiguration &configuration) +VkPipeline Graphics::createGraphicsPipeline(Shader *shader, const GraphicsPipelineConfiguration &configuration) { VkGraphicsPipelineCreateInfo pipelineInfo{}; pipelineInfo.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO; - auto &shaderStages = configuration.shader->getShaderStages(); + auto &shaderStages = shader->getShaderStages(); std::vector bindingDescriptions; std::vector attributeDescriptions; - createVulkanVertexFormat(configuration.shader, configuration.vertexAttributes, bindingDescriptions, attributeDescriptions); + createVulkanVertexFormat(shader, configuration.vertexAttributes, bindingDescriptions, attributeDescriptions); VkPipelineVertexInputStateCreateInfo vertexInputInfo{}; vertexInputInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO; @@ -2812,7 +2813,7 @@ VkPipeline Graphics::createGraphicsPipeline(GraphicsPipelineConfiguration &confi pipelineInfo.pMultisampleState = &multisampling; pipelineInfo.pColorBlendState = &colorBlending; pipelineInfo.pDynamicState = &dynamicState; - pipelineInfo.layout = configuration.shader->getGraphicsPipelineLayout(); + pipelineInfo.layout = shader->getGraphicsPipelineLayout(); pipelineInfo.subpass = 0; pipelineInfo.basePipelineHandle = VK_NULL_HANDLE; pipelineInfo.basePipelineIndex = -1; @@ -2824,28 +2825,6 @@ VkPipeline Graphics::createGraphicsPipeline(GraphicsPipelineConfiguration &confi return graphicsPipeline; } -void Graphics::ensureGraphicsPipelineConfiguration(GraphicsPipelineConfiguration &configuration) -{ - auto it = graphicsPipelines.find(configuration); - if (it != graphicsPipelines.end()) - { - if (it->second != renderPassState.pipeline) - { - vkCmdBindPipeline(commandBuffers.at(currentFrame), VK_PIPELINE_BIND_POINT_GRAPHICS, it->second); - renderPassState.pipeline = it->second; - pipelineUsages[it->second] = true; - } - } - else - { - VkPipeline pipeline = createGraphicsPipeline(configuration); - graphicsPipelines.insert({configuration, pipeline}); - vkCmdBindPipeline(commandBuffers.at(currentFrame), VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline); - renderPassState.pipeline = pipeline; - pipelineUsages[pipeline] = true; - } -} - VkSampleCountFlagBits Graphics::getMsaaCount(int requestedMsaa) const { VkPhysicalDeviceProperties physicalDeviceProperties; @@ -3112,10 +3091,6 @@ void Graphics::cleanup() for (const auto &entry : framebuffers) vkDestroyFramebuffer(device, entry.second, nullptr); framebuffers.clear(); - - for (auto const &p : graphicsPipelines) - vkDestroyPipeline(device, p.second, nullptr); - graphicsPipelines.clear(); vkDestroyCommandPool(device, commandPool, nullptr); vkDestroyPipelineCache(device, pipelineCache, nullptr); diff --git a/src/modules/graphics/vulkan/Graphics.h b/src/modules/graphics/vulkan/Graphics.h index 1fb624d9c..82687458e 100644 --- a/src/modules/graphics/vulkan/Graphics.h +++ b/src/modules/graphics/vulkan/Graphics.h @@ -170,46 +170,6 @@ struct OptionalDeviceExtensions bool spirv14 = false; }; -struct GraphicsPipelineConfiguration -{ - VkRenderPass renderPass; - VertexAttributes vertexAttributes; - Shader *shader = nullptr; - bool wireFrame; - BlendState blendState; - ColorChannelMask colorChannelMask; - VkSampleCountFlagBits msaaSamples; - uint32_t numColorAttachments; - PrimitiveType primitiveType; - - struct DynamicState - { - CullMode cullmode = CULL_NONE; - Winding winding = WINDING_MAX_ENUM; - StencilAction stencilAction = STENCIL_MAX_ENUM; - CompareMode stencilCompare = COMPARE_MAX_ENUM; - DepthState depthState{}; - } dynamicState; - - GraphicsPipelineConfiguration() - { - memset(this, 0, sizeof(GraphicsPipelineConfiguration)); - } - - bool operator==(const GraphicsPipelineConfiguration &other) const - { - return memcmp(this, &other, sizeof(GraphicsPipelineConfiguration)) == 0; - } -}; - -struct GraphicsPipelineConfigurationHasher -{ - size_t operator() (const GraphicsPipelineConfiguration &configuration) const - { - return XXH32(&configuration, sizeof(GraphicsPipelineConfiguration), 0); - } -}; - struct QueueFamilyIndices { Optional graphicsFamily; @@ -315,6 +275,8 @@ class Graphics final : public love::graphics::Graphics int getVsync() const; void mapLocalUniformData(void *data, size_t size, VkDescriptorBufferInfo &bufferInfo); + VkPipeline createGraphicsPipeline(Shader *shader, const GraphicsPipelineConfiguration &configuration); + uint32 getDeviceApiVersion() const { return deviceApiVersion; } protected: @@ -349,7 +311,6 @@ class Graphics final : public love::graphics::Graphics 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); VkFormat findDepthFormat(); @@ -364,7 +325,6 @@ class Graphics final : public love::graphics::Graphics void beginFrame(); void startRecordingGraphicsCommands(); void endRecordingGraphicsCommands(); - void ensureGraphicsPipelineConfiguration(GraphicsPipelineConfiguration &configuration); void createVulkanVertexFormat( Shader *shader, const VertexAttributes &attributes, @@ -412,10 +372,7 @@ class Graphics final : public love::graphics::Graphics VkPipelineCache pipelineCache = VK_NULL_HANDLE; std::unordered_map renderPasses; std::unordered_map framebuffers; - std::unordered_map graphicsPipelines; - std::unordered_map renderPassUsages; std::unordered_map framebufferUsages; - std::unordered_map pipelineUsages; std::unordered_map samplers; VkCommandPool commandPool = VK_NULL_HANDLE; std::vector commandBuffers; diff --git a/src/modules/graphics/vulkan/Shader.cpp b/src/modules/graphics/vulkan/Shader.cpp index c99656e0b..a58239134 100644 --- a/src/modules/graphics/vulkan/Shader.cpp +++ b/src/modules/graphics/vulkan/Shader.cpp @@ -167,6 +167,7 @@ static bool usesLocalUniformData(const graphics::Shader::UniformInfo *info) Shader::Shader(StrongRef stages[], const CompileOptions &options) : graphics::Shader(stages, options) + , builtinUniformInfo() { auto gfx = Module::getInstance(Module::ModuleType::M_GRAPHICS); vgfx = dynamic_cast(gfx); @@ -199,7 +200,8 @@ void Shader::unloadVolatile() if (shaderModules.empty()) return; - vgfx->queueCleanUp([shaderModules = std::move(shaderModules), device = device, descriptorSetLayout = descriptorSetLayout, pipelineLayout = pipelineLayout, descriptorPools = descriptorPools, computePipeline = computePipeline](){ + vgfx->queueCleanUp([shaderModules = std::move(shaderModules), device = device, descriptorSetLayout = descriptorSetLayout, pipelineLayout = pipelineLayout, + descriptorPools = descriptorPools, computePipeline = computePipeline, graphicsPipelines = std::move(graphicsPipelines)](){ for (const auto &pools : descriptorPools) { for (const auto pool : pools) @@ -211,6 +213,8 @@ void Shader::unloadVolatile() vkDestroyPipelineLayout(device, pipelineLayout, nullptr); if (computePipeline != VK_NULL_HANDLE) vkDestroyPipeline(device, computePipeline, nullptr); + for (const auto& kvp : graphicsPipelines) + vkDestroyPipeline(device, kvp.second, nullptr); }); shaderModules.clear(); @@ -1199,6 +1203,18 @@ VkDescriptorSet Shader::allocateDescriptorSet() } } +VkPipeline Shader::getCachedGraphicsPipeline(Graphics *vgfx, const GraphicsPipelineConfiguration &configuration) +{ + auto it = graphicsPipelines.find(configuration); + if (it != graphicsPipelines.end()) + return it->second; + + VkPipeline pipeline = vgfx->createGraphicsPipeline(this, configuration); + graphicsPipelines.insert({ configuration, pipeline }); + + return pipeline; +} + } // vulkan } // graphics } // love diff --git a/src/modules/graphics/vulkan/Shader.h b/src/modules/graphics/vulkan/Shader.h index 3e4fe7edb..fa7ef04ec 100644 --- a/src/modules/graphics/vulkan/Shader.h +++ b/src/modules/graphics/vulkan/Shader.h @@ -29,6 +29,7 @@ // Libraries #include "VulkanWrapper.h" #include "libraries/spirv_cross/spirv_reflect.hpp" +#include "libraries/xxHash/xxhash.h" // C++ #include @@ -45,6 +46,45 @@ namespace graphics namespace vulkan { +struct GraphicsPipelineConfiguration +{ + VkRenderPass renderPass; + VertexAttributes vertexAttributes; + bool wireFrame; + BlendState blendState; + ColorChannelMask colorChannelMask; + VkSampleCountFlagBits msaaSamples; + uint32_t numColorAttachments; + PrimitiveType primitiveType; + + struct DynamicState + { + CullMode cullmode = CULL_NONE; + Winding winding = WINDING_MAX_ENUM; + StencilAction stencilAction = STENCIL_MAX_ENUM; + CompareMode stencilCompare = COMPARE_MAX_ENUM; + DepthState depthState{}; + } dynamicState; + + GraphicsPipelineConfiguration() + { + memset(this, 0, sizeof(GraphicsPipelineConfiguration)); + } + + bool operator==(const GraphicsPipelineConfiguration &other) const + { + return memcmp(this, &other, sizeof(GraphicsPipelineConfiguration)) == 0; + } +}; + +struct GraphicsPipelineConfigurationHasher +{ + size_t operator() (const GraphicsPipelineConfiguration &configuration) const + { + return XXH32(&configuration, sizeof(GraphicsPipelineConfiguration), 0); + } +}; + class Graphics; class Shader final @@ -95,6 +135,8 @@ class Shader final void setMainTex(graphics::Texture *texture); + VkPipeline getCachedGraphicsPipeline(Graphics *vgfx, const GraphicsPipelineConfiguration &configuration); + private: void compileShaders(); void createDescriptorSetLayout(); @@ -107,10 +149,10 @@ class Shader final void setTextureDescriptor(const UniformInfo *info, love::graphics::Texture *texture, int index); void setBufferDescriptor(const UniformInfo *info, love::graphics::Buffer *buffer, int index); - VkPipeline computePipeline; + VkPipeline computePipeline = VK_NULL_HANDLE; - VkDescriptorSetLayout descriptorSetLayout; - VkPipelineLayout pipelineLayout; + VkDescriptorSetLayout descriptorSetLayout = VK_NULL_HANDLE; + VkPipelineLayout pipelineLayout = VK_NULL_HANDLE; std::vector descriptorPoolSizes; std::vector> descriptorPools; @@ -124,7 +166,7 @@ class Shader final std::vector shaderModules; Graphics *vgfx = nullptr; - VkDevice device; + VkDevice device = VK_NULL_HANDLE; bool isCompute = false; bool resourceDescriptorsDirty = false; @@ -135,13 +177,15 @@ class Shader final std::unique_ptr uniformBufferObjectBuffer; std::vector localUniformData; std::vector localUniformStagingData; - uint32_t localUniformLocation; + uint32_t localUniformLocation = 0; OptionalInt builtinUniformDataOffset; std::unordered_map attributes; - uint32_t currentFrame; - uint32_t currentDescriptorPool; + std::unordered_map graphicsPipelines; + + uint32_t currentFrame = 0; + uint32_t currentDescriptorPool = 0; }; }