Topic/metal cache (#1704)

This commit is contained in:
Tim Sylvester
2023-10-02 09:47:17 -07:00
committed by GitHub
parent 59a5edb1ea
commit 44b5af7c4a
7 changed files with 112 additions and 81 deletions

View File

@@ -134,7 +134,7 @@ public:
bool getEnableStencil() const { return enableStencil; }
/// Set stencil usage
void setEnableStencil(bool value) { enableStencil = value; }
virtual void setEnableStencil(bool value) { enableStencil = value; }
/// not used for anything yet
DrawPriority getDrawPriority() const { return drawPriority; }
@@ -142,19 +142,19 @@ public:
/// Whether to enable depth testing
bool getEnableDepth() { return enableDepth; }
void setEnableDepth(bool value) { enableDepth = value; }
virtual void setEnableDepth(bool value) { enableDepth = value; }
/// Determines depth range within the layer for 2D drawables
int32_t getSubLayerIndex() const { return subLayerIndex; }
/// Set sub-layer index
void setSubLayerIndex(int32_t value) { subLayerIndex = value; }
virtual void setSubLayerIndex(int32_t value) { subLayerIndex = value; }
/// Depth writability for 2D drawables
DepthMaskType getDepthType() const { return depthType; }
/// Set depth type
void setDepthType(DepthMaskType value) { depthType = value; }
virtual void setDepthType(DepthMaskType value) { depthType = value; }
/// Uses 3D depth mode
bool getIs3D() const { return is3D; }

View File

@@ -4,8 +4,6 @@
#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>
@@ -59,6 +57,11 @@ public:
void setShader(gfx::ShaderProgramBasePtr) override;
void setEnableStencil(bool) override;
void setEnableDepth(bool) override;
void setSubLayerIndex(int32_t) override;
void setDepthType(gfx::DepthMaskType) override;
protected:
// For testing only.
Drawable(std::unique_ptr<Impl>);
@@ -76,12 +79,6 @@ protected:
class Impl;
const std::unique_ptr<Impl> impl;
gfx::AttributeBindingArray attributeBindings;
mutable MTLRenderPipelineStatePtr pipelineState;
mutable std::optional<gfx::RenderPassDescriptor> renderPassDescriptor;
};
} // namespace mtl

View File

@@ -23,7 +23,7 @@ public:
virtual const mbgl::mtl::RendererBackend& getBackend() const = 0;
virtual const mbgl::mtl::MTLCommandBufferPtr& getCommandBuffer() const = 0;
virtual mbgl::mtl::MTLBlitPassDescriptorPtr getUploadPassDescriptor() const = 0;
virtual mbgl::mtl::MTLRenderPassDescriptorPtr getRenderPassDescriptor() const = 0;
virtual const mbgl::mtl::MTLRenderPassDescriptorPtr& getRenderPassDescriptor() const = 0;
};
} // namespace mtl

View File

@@ -69,8 +69,12 @@ public:
return NS::TransferPtr(MTL::BlitPassDescriptor::alloc()->init());
}
mbgl::mtl::MTLRenderPassDescriptorPtr getRenderPassDescriptor() const override {
return NS::RetainPtr((__bridge MTL::RenderPassDescriptor*)mtlView.currentRenderPassDescriptor);
const mbgl::mtl::MTLRenderPassDescriptorPtr& getRenderPassDescriptor() const override {
if (!cachedRenderPassDescriptor) {
auto* mtlDesc = mtlView.currentRenderPassDescriptor;
cachedRenderPassDescriptor = NS::RetainPtr((__bridge MTL::RenderPassDescriptor*)mtlDesc);
}
return cachedRenderPassDescriptor;
}
void swap() override {
@@ -83,6 +87,8 @@ public:
commandBuffer = nil;
commandBufferPtr.reset();
cachedRenderPassDescriptor.reset();
}
mbgl::Size framebufferSize() {
@@ -94,6 +100,7 @@ public:
private:
MLNMapViewMetalImpl& backend;
mbgl::mtl::MTLCommandBufferPtr commandBufferPtr;
mutable mbgl::mtl::MTLRenderPassDescriptorPtr cachedRenderPassDescriptor;
public:
MLNMapViewImplDelegate* delegate = nil;

View File

@@ -123,12 +123,32 @@ MTL::Winding mapWindingMode(const gfx::CullFaceWindingType mode) {
} // namespace
void Drawable::setColorMode(const gfx::ColorMode& value) {
pipelineState.reset();
impl->pipelineState.reset();
gfx::Drawable::setColorMode(value);
}
void Drawable::setEnableStencil(bool value) {
gfx::Drawable::setEnableStencil(value);
impl->depthStencilState.reset();
}
void Drawable::setEnableDepth(bool value) {
gfx::Drawable::setEnableDepth(value);
impl->depthStencilState.reset();
}
void Drawable::setSubLayerIndex(int32_t value) {
gfx::Drawable::setSubLayerIndex(value);
impl->depthStencilState.reset();
}
void Drawable::setDepthType(gfx::DepthMaskType value) {
gfx::Drawable::setDepthType(value);
impl->depthStencilState.reset();
}
void Drawable::setShader(gfx::ShaderProgramBasePtr value) {
pipelineState.reset();
impl->pipelineState.reset();
gfx::Drawable::setShader(value);
}
@@ -151,13 +171,12 @@ void Drawable::draw(PaintParameters& parameters) const {
return;
}
if (renderPassDescriptor.has_value() && renderPass.getDescriptor() != renderPassDescriptor.value()) {
pipelineState.reset();
const auto& descriptor = renderPass.getDescriptor();
if (impl->renderPassDescriptor && descriptor != *impl->renderPassDescriptor) {
impl->pipelineState.reset();
}
renderPassDescriptor.emplace(gfx::RenderPassDescriptor{renderPass.getDescriptor().renderable,
renderPass.getDescriptor().clearColor,
renderPass.getDescriptor().clearDepth,
renderPass.getDescriptor().clearStencil});
impl->renderPassDescriptor.emplace(gfx::RenderPassDescriptor{
descriptor.renderable, descriptor.clearColor, descriptor.clearDepth, descriptor.clearStencil});
const auto& shaderMTL = static_cast<const ShaderProgram&>(*shader);
@@ -165,23 +184,6 @@ void Drawable::draw(PaintParameters& parameters) const {
const auto debugGroup = parameters.encoder->createDebugGroup(debugLabel(*this));
#endif
/*
context.setDepthMode(getIs3D() ? parameters.depthModeFor3D()
: parameters.depthModeForSublayer(getSubLayerIndex(), getDepthType()));
// force disable depth test for debugging
// context.setDepthMode({gfx::DepthFunctionType::Always, gfx::DepthMaskType::ReadOnly, {0,1}});
// For 3D mode, stenciling is handled by the layer group
if (!is3D) {
context.setStencilMode(makeStencilMode(parameters));
}
context.setColorMode(getColorMode());
context.setCullFaceMode(getCullFaceMode());
*/
bindAttributes(renderPass);
bindUniformBuffers(renderPass);
bindTextures(renderPass);
@@ -207,11 +209,11 @@ void Drawable::draw(PaintParameters& parameters) const {
encoder->setCullMode(cullMode.enabled ? mapCullMode(cullMode.side) : MTL::CullModeNone);
encoder->setFrontFacingWinding(mapWindingMode(cullMode.winding));
if (!pipelineState) {
pipelineState = shaderMTL.getRenderPipelineState(renderPassDescriptor, impl->vertexDesc, getColorMode());
if (!impl->pipelineState) {
impl->pipelineState = shaderMTL.getRenderPipelineState(renderPassDescriptor, impl->vertexDesc, getColorMode());
}
if (pipelineState) {
encoder->setRenderPipelineState(pipelineState.get());
if (impl->pipelineState) {
encoder->setRenderPipelineState(impl->pipelineState.get());
} else {
assert(!"Failed to create render pipeline state");
return;
@@ -219,12 +221,30 @@ void Drawable::draw(PaintParameters& parameters) const {
// For 3D mode, stenciling is handled by the layer group
if (!is3D) {
const auto depthMode = parameters.depthModeForSublayer(getSubLayerIndex(), getDepthType());
const auto stencilMode = enableStencil ? parameters.stencilModeForClipping(tileID->toUnwrapped())
: gfx::StencilMode::disabled();
if (auto depthStencilState = context.makeDepthStencilState(depthMode, stencilMode, renderPass)) {
encoder->setDepthStencilState(depthStencilState.get());
encoder->setStencilReferenceValue(stencilMode.ref);
std::optional<gfx::StencilMode> newStencilMode;
// If we have a stencil state, we may be able to reuse it, if the tile masks haven't changed.
// We assume that only the reference value needs to be compared.
if (impl->depthStencilState && enableStencil) {
newStencilMode = parameters.stencilModeForClipping(tileID->toUnwrapped());
if (newStencilMode->ref != impl->previousStencilMode.ref) {
// No, need to rebuild it
impl->depthStencilState.reset();
}
}
if (!impl->depthStencilState) {
if (enableStencil && !newStencilMode) {
newStencilMode = parameters.stencilModeForClipping(tileID->toUnwrapped());
}
const auto depthMode = parameters.depthModeForSublayer(getSubLayerIndex(), getDepthType());
const auto stencilMode = enableStencil ? parameters.stencilModeForClipping(tileID->toUnwrapped())
: gfx::StencilMode::disabled();
impl->depthStencilState = context.makeDepthStencilState(depthMode, stencilMode, renderPass);
impl->previousStencilMode = *newStencilMode;
}
if (impl->depthStencilState) {
encoder->setDepthStencilState(impl->depthStencilState.get());
encoder->setStencilReferenceValue(impl->previousStencilMode.ref);
}
}
@@ -266,7 +286,7 @@ void Drawable::draw(PaintParameters& parameters) const {
assert(mlSegment.indexOffset + mlSegment.indexLength <= indexBufferLength);
assert(static_cast<std::size_t>(maxIndex) < mlSegment.vertexLength);
for (const auto& binding : attributeBindings) {
for (const auto& binding : impl->attributeBindings) {
if (binding) {
if (const auto buffer = getMetalBuffer(binding ? binding->vertexBufferResource : nullptr)) {
assert((maxIndex + mlSegment.vertexOffset) * binding->vertexStride <= buffer->length());
@@ -348,7 +368,7 @@ void Drawable::bindAttributes(const RenderPass& renderPass) const {
const auto& encoder = renderPass.getMetalEncoder();
NS::UInteger attributeIndex = 0;
for (const auto& binding : attributeBindings) {
for (const auto& binding : impl->attributeBindings) {
if (const auto buffer = getMetalBuffer(binding ? binding->vertexBufferResource : nullptr)) {
assert(binding->vertexStride * impl->vertexCount <= getBufferSize(binding->vertexBufferResource));
encoder->setVertexBuffer(buffer, /*offset=*/0, attributeIndex);
@@ -363,7 +383,7 @@ void Drawable::unbindAttributes(const RenderPass& renderPass) const {
const auto& encoder = renderPass.getMetalEncoder();
NS::UInteger attributeIndex = 0;
for (const auto& binding : attributeBindings) {
for (const auto& binding : impl->attributeBindings) {
encoder->setVertexBuffer(nullptr, /*offset=*/0, attributeIndex);
attributeIndex += 1;
}
@@ -558,14 +578,14 @@ void Drawable::upload(gfx::UploadPass& uploadPass_) {
impl->vertexAttributes.visitAttributes(
[](const auto&, gfx::VertexAttribute& attrib) { attrib.setDirty(false); });
if (attributeBindings != attributeBindings_) {
attributeBindings = attributeBindings_;
if (impl->attributeBindings != attributeBindings_) {
impl->attributeBindings = attributeBindings_;
// Create a layout descriptor for each attribute
auto vertDesc = NS::RetainPtr(MTL::VertexDescriptor::vertexDescriptor());
NS::UInteger index = 0;
for (auto& binding : attributeBindings) {
for (auto& binding : impl->attributeBindings) {
if (!binding) {
assert("Missing attribute binding");
continue;
@@ -595,7 +615,7 @@ void Drawable::upload(gfx::UploadPass& uploadPass_) {
}
impl->vertexDesc = std::move(vertDesc);
pipelineState.reset();
impl->pipelineState.reset();
}
}

View File

@@ -8,6 +8,7 @@
#include <mbgl/gfx/uniform_buffer.hpp>
#include <mbgl/gfx/vertex_attribute.hpp>
#include <mbgl/mtl/mtl_fwd.hpp>
#include <mbgl/mtl/render_pass.hpp>
#include <mbgl/mtl/uniform_buffer.hpp>
#include <mbgl/mtl/upload_pass.hpp>
#include <mbgl/programs/segment.hpp>
@@ -55,6 +56,15 @@ public:
StringIdentity idVertexAttrName = StringIndexer::get("a_pos");
gfx::UniqueVertexBufferResource noBindingBuffer;
gfx::AttributeBindingArray attributeBindings;
MTLRenderPipelineStatePtr pipelineState;
std::optional<gfx::RenderPassDescriptor> renderPassDescriptor;
MTLDepthStencilStatePtr depthStencilState;
gfx::StencilMode previousStencilMode;
};
struct Drawable::DrawSegment final : public gfx::Drawable::DrawSegment {

View File

@@ -157,6 +157,22 @@ void PaintParameters::clearTileClippingMasks() {
}
}
namespace {
const auto clipMaskStencilMode = gfx::StencilMode{
/*.test=*/gfx::StencilMode::Always(),
/*.ref=*/0,
/*.mask=*/0b11111111,
/*.fail=*/gfx::StencilOpType::Keep,
/*.depthFail=*/gfx::StencilOpType::Keep,
/*.pass=*/gfx::StencilOpType::Replace,
};
const auto clipMaskDepthMode = gfx::DepthMode{
.func = gfx::DepthFunctionType::Always,
.mask = gfx::DepthMaskType::ReadOnly,
.range = {0, 1},
};
} // namespace
template <typename TIter>
void PaintParameters::renderTileClippingMasks(TIter beg, TIter end, GetTileIDFunc<TIter>&& f, bool clear) {
if (tileIDsIdentical(beg, end, f, tileClippingMaskIDs)) {
@@ -238,32 +254,13 @@ void PaintParameters::renderTileClippingMasks(TIter beg, TIter end, GetTileIDFun
// gfx::CullFaceMode::disabled();
encoder->setCullMode(MTL::CullModeNone);
auto stencilDescriptor = NS::TransferPtr(MTL::StencilDescriptor::alloc()->init());
if (!stencilDescriptor) {
if (auto depthStencilState = mtlContext.makeDepthStencilState(
clipMaskDepthMode, clipMaskStencilMode, mtlRenderPass)) {
encoder->setDepthStencilState(depthStencilState.get());
} else {
assert(!"Failed to create depth-stencil state");
return;
}
stencilDescriptor->setStencilCompareFunction(MTL::CompareFunction::CompareFunctionAlways);
stencilDescriptor->setStencilFailureOperation(MTL::StencilOperation::StencilOperationKeep);
stencilDescriptor->setDepthFailureOperation(MTL::StencilOperation::StencilOperationKeep);
stencilDescriptor->setDepthStencilPassOperation(MTL::StencilOperation::StencilOperationReplace);
stencilDescriptor->setReadMask(0);
stencilDescriptor->setWriteMask(0b11111111);
auto depthStencilDescriptor = NS::TransferPtr(MTL::DepthStencilDescriptor::alloc()->init());
if (!depthStencilDescriptor) {
return;
}
depthStencilDescriptor->setDepthCompareFunction(MTL::CompareFunction::CompareFunctionAlways);
depthStencilDescriptor->setDepthWriteEnabled(false);
depthStencilDescriptor->setFrontFaceStencil(stencilDescriptor.get());
depthStencilDescriptor->setBackFaceStencil(stencilDescriptor.get());
auto& device = mtlContext.getBackend().getDevice();
auto depthStencilState = NS::TransferPtr(device->newDepthStencilState(depthStencilDescriptor.get()));
if (!depthStencilState) {
return;
}
encoder->setDepthStencilState(depthStencilState.get());
// Create a render pipeline state, telling Metal how to render the primitives
const auto& renderPassDescriptor = mtlRenderPass.getDescriptor();