Topic/metal cache (#1704)
This commit is contained in:
@@ -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; }
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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();
|
||||
|
||||
Reference in New Issue
Block a user