Cache metal pipeline state (#1658)

Co-authored-by: Alex Cristici <alex.cristici@gmail.com>
This commit is contained in:
Stefan Karschti
2023-09-21 16:31:10 +03:00
committed by GitHub
parent 19f05e4c66
commit 2e36dcfcb4
6 changed files with 87 additions and 44 deletions

View File

@@ -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;

View File

@@ -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<RenderableResource> resource;

View File

@@ -4,6 +4,8 @@
#include <mbgl/gfx/draw_mode.hpp>
#include <mbgl/mtl/upload_pass.hpp>
#include <mbgl/programs/segment.hpp>
#include <mbgl/mtl/mtl_fwd.hpp>
#include <mbgl/mtl/render_pass.hpp>
#include <memory>
@@ -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<Impl>);
@@ -72,6 +78,10 @@ protected:
const std::unique_ptr<Impl> impl;
gfx::AttributeBindingArray attributeBindings;
mutable MTLRenderPipelineStatePtr pipelineState;
mutable std::optional<gfx::RenderPassDescriptor> renderPassDescriptor;
};
} // namespace mtl

View File

@@ -4,6 +4,7 @@ namespace mbgl {
namespace bench {
const std::vector<Location> 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 },

View File

@@ -2,20 +2,24 @@
#include <mbgl/gfx/debug_group.hpp>
#include <mbgl/util/color.hpp>
#include <mbgl/gfx/renderable.hpp>
#include <cstdint>
namespace mbgl {
namespace gfx {
class Renderable;
class RenderPassDescriptor {
public:
Renderable& renderable;
std::optional<Color> clearColor;
std::optional<float> clearDepth;
std::optional<int32_t> clearStencil;
bool operator!=(const RenderPassDescriptor& other) const {
return other.clearColor != clearColor || other.clearDepth != clearDepth || other.clearStencil != clearStencil ||
other.renderable != renderable;
}
};
class RenderPass {

View File

@@ -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<const ShaderProgram&>(*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<std::unique_ptr<gfx::VertexBufferResource>> 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<NS::UInteger>(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<NS::UInteger>(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<NS::UInteger>(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<NS::UInteger>(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(