From aff5693fb97f6aef91033e96fa533201ebd4d803 Mon Sep 17 00:00:00 2001 From: Stefan Karschti Date: Wed, 15 May 2024 15:30:28 +0300 Subject: [PATCH] Fix Metal frame glitch on older devices (#2379) --- include/mbgl/shaders/mtl/shader_program.hpp | 5 ++++- src/mbgl/gfx/color_mode.hpp | 13 +++++++++++++ src/mbgl/mtl/context.cpp | 10 +++++++++- src/mbgl/mtl/drawable.cpp | 18 +++++++++++++++++- src/mbgl/mtl/drawable_impl.hpp | 1 + src/mbgl/shaders/mtl/shader_program.cpp | 14 +++++++++++++- 6 files changed, 57 insertions(+), 4 deletions(-) diff --git a/include/mbgl/shaders/mtl/shader_program.hpp b/include/mbgl/shaders/mtl/shader_program.hpp index 88a37fa63..d67d8262c 100644 --- a/include/mbgl/shaders/mtl/shader_program.hpp +++ b/include/mbgl/shaders/mtl/shader_program.hpp @@ -62,7 +62,8 @@ public: MTLRenderPipelineStatePtr getRenderPipelineState(const gfx::Renderable&, const MTLVertexDescriptorPtr&, - const gfx::ColorMode& colorMode) const; + const gfx::ColorMode& colorMode, + const std::optional reuseHash) const; std::optional getSamplerLocation(const size_t id) const override; @@ -87,6 +88,8 @@ protected: VertexAttributeArray vertexAttributes; VertexAttributeArray instanceAttributes; std::array, shaders::maxTextureCountPerShader> textureBindings; + + mutable mbgl::unordered_map renderPipelineStateCache; }; } // namespace mtl diff --git a/src/mbgl/gfx/color_mode.hpp b/src/mbgl/gfx/color_mode.hpp index 578a681a2..29f282568 100644 --- a/src/mbgl/gfx/color_mode.hpp +++ b/src/mbgl/gfx/color_mode.hpp @@ -3,6 +3,7 @@ #include #include #include +#include namespace mbgl { namespace gfx { @@ -58,6 +59,18 @@ public: static ColorMode additive() { return {Add{ColorBlendFactorType::One, ColorBlendFactorType::One}, {}, {true, true, true, true}}; } + + std::size_t hash() const { + return mbgl::util::hash(blendFunction.which(), + blendColor.r, + blendColor.g, + blendColor.b, + blendColor.a, + mask.r, + mask.g, + mask.b, + mask.a); + } }; constexpr bool operator!=(const ColorMode::Mask& a, const ColorMode::Mask& b) { diff --git a/src/mbgl/mtl/context.cpp b/src/mbgl/mtl/context.cpp index 9b26cd404..b6470ec13 100644 --- a/src/mbgl/mtl/context.cpp +++ b/src/mbgl/mtl/context.cpp @@ -23,6 +23,7 @@ #include #include #include +#include #include #include @@ -361,7 +362,14 @@ bool Context::renderTileClippingMasks(gfx::RenderPass& renderPass, // Create a render pipeline state, telling Metal how to render the primitives const auto& renderPassDescriptor = mtlRenderPass.getDescriptor(); - if (auto state = mtlShader.getRenderPipelineState(renderable, vertDesc, colorMode)) { + const std::size_t hash = mbgl::util::hash(ShaderClass::attributes[0].index, + 0, + MTL::VertexFormatShort2, + vertexSize, + MTL::VertexStepFunctionPerVertex, + 1); + if (auto state = mtlShader.getRenderPipelineState( + renderable, vertDesc, colorMode, mbgl::util::hash(colorMode.hash(), hash))) { clipMaskPipelineState = std::move(state); } } diff --git a/src/mbgl/mtl/drawable.cpp b/src/mbgl/mtl/drawable.cpp index b305ba036..71b06bd03 100644 --- a/src/mbgl/mtl/drawable.cpp +++ b/src/mbgl/mtl/drawable.cpp @@ -18,6 +18,7 @@ #include #include #include +#include #include @@ -210,7 +211,11 @@ void Drawable::draw(PaintParameters& parameters) const { encoder->setFrontFacingWinding(mapWindingMode(cullMode.winding)); if (!impl->pipelineState) { - impl->pipelineState = shaderMTL.getRenderPipelineState(renderable, impl->vertexDesc, getColorMode()); + impl->pipelineState = shaderMTL.getRenderPipelineState( + renderable, + impl->vertexDesc, + getColorMode(), + mbgl::util::hash(getColorMode().hash(), impl->vertexDescHash)); } if (impl->pipelineState) { encoder->setRenderPipelineState(impl->pipelineState.get()); @@ -563,6 +568,9 @@ void Drawable::upload(gfx::UploadPass& uploadPass_) { if (impl->attributeBindings != attributeBindings_) { impl->attributeBindings = std::move(attributeBindings_); + // hash + std::size_t hash{0}; + // Create a layout descriptor for each attribute auto vertDesc = NS::RetainPtr(MTL::VertexDescriptor::vertexDescriptor()); @@ -595,10 +603,18 @@ void Drawable::upload(gfx::UploadPass& uploadPass_) { vertDesc->attributes()->setObject(attribDesc.get(), index); vertDesc->layouts()->setObject(layoutDesc.get(), index); + mbgl::util::hash_combine(hash, + mbgl::util::hash(index, + binding->attribute.offset, + binding->attribute.dataType, + binding->vertexStride, + static_cast(binding->vertexBufferResource))); + index += 1; } impl->vertexDesc = std::move(vertDesc); + impl->vertexDescHash = hash; impl->pipelineState.reset(); } } diff --git a/src/mbgl/mtl/drawable_impl.hpp b/src/mbgl/mtl/drawable_impl.hpp index 2958b00f8..0ed0ca717 100644 --- a/src/mbgl/mtl/drawable_impl.hpp +++ b/src/mbgl/mtl/drawable_impl.hpp @@ -36,6 +36,7 @@ public: std::vector segments; MTLVertexDescriptorPtr vertexDesc; + std::size_t vertexDescHash{0}; /* std::vector textures; diff --git a/src/mbgl/shaders/mtl/shader_program.cpp b/src/mbgl/shaders/mtl/shader_program.cpp index 46fb4670a..1528fc862 100644 --- a/src/mbgl/shaders/mtl/shader_program.cpp +++ b/src/mbgl/shaders/mtl/shader_program.cpp @@ -83,7 +83,14 @@ ShaderProgram::~ShaderProgram() noexcept = default; MTLRenderPipelineStatePtr ShaderProgram::getRenderPipelineState(const gfx::Renderable& renderable, const MTLVertexDescriptorPtr& vertexDescriptor, - const gfx::ColorMode& colorMode) const { + const gfx::ColorMode& colorMode, + const std::optional reuseHash) const { + if (reuseHash.has_value()) { + // we'd like to reuse a previous value + if (auto it = renderPipelineStateCache.find(reuseHash.value()); it != renderPipelineStateCache.end()) + return it->second; + } + auto pool = NS::TransferPtr(NS::AutoreleasePool::alloc()->init()); const auto& renderableResource = renderable.getResource(); @@ -165,6 +172,11 @@ MTLRenderPipelineStatePtr ShaderProgram::getRenderPipelineState(const gfx::Rende assert(false); } + if (reuseHash.has_value()) { + // store the value for future reuse + renderPipelineStateCache[reuseHash.value()] = rps; + } + return rps; }