diff --git a/include/mbgl/gfx/drawable.hpp b/include/mbgl/gfx/drawable.hpp index 65fa80778..b13a93b75 100644 --- a/include/mbgl/gfx/drawable.hpp +++ b/include/mbgl/gfx/drawable.hpp @@ -68,7 +68,7 @@ public: const gfx::ShaderProgramBasePtr& getShader() const { return shader; } /// Set the shader to be used - void setShader(gfx::ShaderProgramBasePtr value) { shader = std::move(value); } + virtual void setShader(gfx::ShaderProgramBasePtr value) { shader = std::move(value); } /// The pass on which we'll be rendered mbgl::RenderPass getRenderPass() const { return renderPass; } @@ -181,7 +181,7 @@ public: const gfx::ColorMode& getColorMode() const; /// Set color mode - void setColorMode(const gfx::ColorMode&); + virtual void setColorMode(const gfx::ColorMode&); /// Get the vertex attributes that override default values in the shader program virtual const gfx::VertexAttributeArray& getVertexAttributes() const = 0; diff --git a/include/mbgl/gfx/renderable.hpp b/include/mbgl/gfx/renderable.hpp index 62052fa25..dd95dc123 100644 --- a/include/mbgl/gfx/renderable.hpp +++ b/include/mbgl/gfx/renderable.hpp @@ -38,6 +38,8 @@ public: virtual void wait() {} + bool operator!=(const Renderable& other) const { return resource.get() != other.resource.get(); } + protected: Size size; std::unique_ptr resource; diff --git a/include/mbgl/mtl/drawable.hpp b/include/mbgl/mtl/drawable.hpp index 0d2c7f64c..c2e96608d 100644 --- a/include/mbgl/mtl/drawable.hpp +++ b/include/mbgl/mtl/drawable.hpp @@ -4,6 +4,8 @@ #include #include #include +#include +#include #include @@ -53,6 +55,10 @@ public: void upload(gfx::UploadPass&); + void setColorMode(const gfx::ColorMode&) override; + + void setShader(gfx::ShaderProgramBasePtr) override; + protected: // For testing only. Drawable(std::unique_ptr); @@ -72,6 +78,10 @@ protected: const std::unique_ptr impl; gfx::AttributeBindingArray attributeBindings; + + mutable MTLRenderPipelineStatePtr pipelineState; + + mutable std::optional renderPassDescriptor; }; } // namespace mtl diff --git a/platform/ios/benchmark/locations.cpp b/platform/ios/benchmark/locations.cpp index 9f53877e4..a546bdd7f 100644 --- a/platform/ios/benchmark/locations.cpp +++ b/platform/ios/benchmark/locations.cpp @@ -4,6 +4,7 @@ namespace mbgl { namespace bench { const std::vector locations = { + { "boston", -71.07766, 42.36513, 16, 0.0 }, { "paris", 2.3411, 48.8664, 11, 0.0 }, { "paris2", 2.3516, 48.8356, 13, 273.8 }, { "alps", 10.6107, 46.9599, 6, 0.0 }, diff --git a/src/mbgl/gfx/render_pass.hpp b/src/mbgl/gfx/render_pass.hpp index b65eea4cc..41abcbfdd 100644 --- a/src/mbgl/gfx/render_pass.hpp +++ b/src/mbgl/gfx/render_pass.hpp @@ -2,20 +2,24 @@ #include #include +#include #include namespace mbgl { namespace gfx { -class Renderable; - class RenderPassDescriptor { public: Renderable& renderable; std::optional clearColor; std::optional clearDepth; std::optional clearStencil; + + bool operator!=(const RenderPassDescriptor& other) const { + return other.clearColor != clearColor || other.clearDepth != clearDepth || other.clearStencil != clearStencil || + other.renderable != renderable; + } }; class RenderPass { diff --git a/src/mbgl/mtl/drawable.cpp b/src/mbgl/mtl/drawable.cpp index 19beb4305..2caaaf3b6 100644 --- a/src/mbgl/mtl/drawable.cpp +++ b/src/mbgl/mtl/drawable.cpp @@ -122,6 +122,16 @@ MTL::Winding mapWindingMode(const gfx::CullFaceWindingType mode) { } // namespace +void Drawable::setColorMode(const gfx::ColorMode& value) { + pipelineState.reset(); + gfx::Drawable::setColorMode(value); +} + +void Drawable::setShader(gfx::ShaderProgramBasePtr value) { + pipelineState.reset(); + gfx::Drawable::setShader(value); +} + void Drawable::draw(PaintParameters& parameters) const { if (isCustom) { return; @@ -141,6 +151,14 @@ void Drawable::draw(PaintParameters& parameters) const { return; } + if (renderPassDescriptor.has_value() && renderPass.getDescriptor() != renderPassDescriptor.value()) { + pipelineState.reset(); + } + renderPassDescriptor.emplace(gfx::RenderPassDescriptor{renderPass.getDescriptor().renderable, + renderPass.getDescriptor().clearColor, + renderPass.getDescriptor().clearDepth, + renderPass.getDescriptor().clearStencil}); + const auto& shaderMTL = static_cast(*shader); #if !defined(NDEBUG) @@ -189,8 +207,11 @@ void Drawable::draw(PaintParameters& parameters) const { encoder->setCullMode(cullMode.enabled ? mapCullMode(cullMode.side) : MTL::CullModeNone); encoder->setFrontFacingWinding(mapWindingMode(cullMode.winding)); - if (auto state = shaderMTL.getRenderPipelineState(renderPassDescriptor, impl->vertexDesc, getColorMode())) { - encoder->setRenderPipelineState(state.get()); + if (!pipelineState) { + pipelineState = shaderMTL.getRenderPipelineState(renderPassDescriptor, impl->vertexDesc, getColorMode()); + } + if (pipelineState) { + encoder->setRenderPipelineState(pipelineState.get()); } else { assert(!"Failed to create render pipeline state"); return; @@ -522,53 +543,58 @@ void Drawable::upload(gfx::UploadPass& uploadPass_) { // Apply drawable values to shader defaults std::vector> vertexBuffers; - attributeBindings = uploadPass.buildAttributeBindings(impl->vertexCount, - impl->vertexType, - /*vertexAttributeIndex=*/-1, - /*vertexData=*/{}, - shader->getVertexAttributes(), - impl->vertexAttributes, - usage, - vertexBuffers); + auto attributeBindings_ = uploadPass.buildAttributeBindings(impl->vertexCount, + impl->vertexType, + /*vertexAttributeIndex=*/-1, + /*vertexData=*/{}, + shader->getVertexAttributes(), + impl->vertexAttributes, + usage, + vertexBuffers); impl->attributeBuffers = std::move(vertexBuffers); impl->vertexAttributes.visitAttributes( [](const auto&, gfx::VertexAttribute& attrib) { attrib.setDirty(false); }); - // Create a layout descriptor for each attribute - auto vertDesc = NS::RetainPtr(MTL::VertexDescriptor::vertexDescriptor()); + if (attributeBindings != attributeBindings_) { + attributeBindings = attributeBindings_; - NS::UInteger index = 0; - for (auto& binding : attributeBindings) { - if (!binding) { - assert("Missing attribute binding"); - continue; + // Create a layout descriptor for each attribute + auto vertDesc = NS::RetainPtr(MTL::VertexDescriptor::vertexDescriptor()); + + NS::UInteger index = 0; + for (auto& binding : attributeBindings) { + if (!binding) { + assert("Missing attribute binding"); + continue; + } + + if (!binding->vertexBufferResource && !impl->noBindingBuffer) { + impl->noBindingBuffer = uploadPass.createVertexBufferResource( + nullptr, 64, gfx::BufferUsageType::StaticDraw); + } + + auto attribDesc = NS::TransferPtr(MTL::VertexAttributeDescriptor::alloc()->init()); + attribDesc->setBufferIndex(index); + attribDesc->setOffset(static_cast(binding->attribute.offset)); + attribDesc->setFormat(mtlVertexTypeOf(binding->attribute.dataType)); + assert(binding->vertexStride > 0); + + auto layoutDesc = NS::TransferPtr(MTL::VertexBufferLayoutDescriptor::alloc()->init()); + layoutDesc->setStride(static_cast(binding->vertexStride)); + layoutDesc->setStepFunction(binding->vertexBufferResource ? MTL::VertexStepFunctionPerVertex + : MTL::VertexStepFunctionConstant); + layoutDesc->setStepRate(binding->vertexBufferResource ? 1 : 0); + + vertDesc->attributes()->setObject(attribDesc.get(), index); + vertDesc->layouts()->setObject(layoutDesc.get(), index); + + index += 1; } - if (!binding->vertexBufferResource && !impl->noBindingBuffer) { - impl->noBindingBuffer = uploadPass.createVertexBufferResource( - nullptr, 64, gfx::BufferUsageType::StaticDraw); - } - - auto attribDesc = NS::TransferPtr(MTL::VertexAttributeDescriptor::alloc()->init()); - attribDesc->setBufferIndex(index); - attribDesc->setOffset(static_cast(binding->attribute.offset)); - attribDesc->setFormat(mtlVertexTypeOf(binding->attribute.dataType)); - assert(binding->vertexStride > 0); - - auto layoutDesc = NS::TransferPtr(MTL::VertexBufferLayoutDescriptor::alloc()->init()); - layoutDesc->setStride(static_cast(binding->vertexStride)); - layoutDesc->setStepFunction(binding->vertexBufferResource ? MTL::VertexStepFunctionPerVertex - : MTL::VertexStepFunctionConstant); - layoutDesc->setStepRate(binding->vertexBufferResource ? 1 : 0); - - vertDesc->attributes()->setObject(attribDesc.get(), index); - vertDesc->layouts()->setObject(layoutDesc.get(), index); - - index += 1; + impl->vertexDesc = std::move(vertDesc); + pipelineState.reset(); } - - impl->vertexDesc = std::move(vertDesc); } const bool texturesNeedUpload = std::any_of(