diff --git a/include/mbgl/gfx/drawable.hpp b/include/mbgl/gfx/drawable.hpp index be68a343e..621e16f8f 100644 --- a/include/mbgl/gfx/drawable.hpp +++ b/include/mbgl/gfx/drawable.hpp @@ -143,7 +143,7 @@ public: void setDrawPriority(DrawPriority value) { drawPriority = value; } /// Whether to enable depth testing - bool getEnableDepth() { return enableDepth; } + bool getEnableDepth() const { return enableDepth; } virtual void setEnableDepth(bool value) { enableDepth = value; } /// Determines depth range within the layer for 2D drawables diff --git a/include/mbgl/mtl/tile_layer_group.hpp b/include/mbgl/mtl/tile_layer_group.hpp index d24198d32..58b15d4e3 100644 --- a/include/mbgl/mtl/tile_layer_group.hpp +++ b/include/mbgl/mtl/tile_layer_group.hpp @@ -1,7 +1,12 @@ #pragma once +#include #include +#include + +#include + namespace mbgl { namespace mtl { @@ -17,6 +22,8 @@ public: void render(RenderOrchestrator&, PaintParameters&) override; protected: + std::optional stateNone; + std::optional stateDepth; }; } // namespace mtl diff --git a/src/mbgl/mtl/drawable.cpp b/src/mbgl/mtl/drawable.cpp index 79a5caed8..d0883842c 100644 --- a/src/mbgl/mtl/drawable.cpp +++ b/src/mbgl/mtl/drawable.cpp @@ -235,7 +235,9 @@ void Drawable::draw(PaintParameters& parameters) const { if (enableStencil && !newStencilMode) { newStencilMode = parameters.stencilModeForClipping(tileID->toUnwrapped()); } - const auto depthMode = parameters.depthModeForSublayer(getSubLayerIndex(), getDepthType()); + const auto depthMode = getEnableDepth() + ? parameters.depthModeForSublayer(getSubLayerIndex(), getDepthType()) + : gfx::DepthMode::disabled(); const auto stencilMode = enableStencil ? parameters.stencilModeForClipping(tileID->toUnwrapped()) : gfx::StencilMode::disabled(); impl->depthStencilState = context.makeDepthStencilState(depthMode, stencilMode, renderable); diff --git a/src/mbgl/mtl/tile_layer_group.cpp b/src/mbgl/mtl/tile_layer_group.cpp index adb334d8e..678b8953b 100644 --- a/src/mbgl/mtl/tile_layer_group.cpp +++ b/src/mbgl/mtl/tile_layer_group.cpp @@ -74,15 +74,49 @@ void TileLayerGroup::render(RenderOrchestrator&, PaintParameters& parameters) { // If we're doing 3D stenciling and have any features to draw, set up the single-value stencil mask. // If we're doing 2D stenciling and have any drawables with tile IDs, render each tile into the stencil buffer with // a different value. - MTLDepthStencilStatePtr stateWithStencil, stateWithoutStencil; + // We can keep the depth-based descriptors, but the stencil-based ones can change + // every time, as a new value is assigned in each call to `stencilModeFor3D`. + std::optional stateStencil, stateDepthStencil; + std::function getDepthStencilState; if (features3d) { + // If we're using group-wide states, build only the ones that actually get used + getDepthStencilState = [&](bool depth, bool stencil) -> const MTLDepthStencilStatePtr& { + if (depth) { + // We assume this doesn't change over the lifetime of a layer group. + const auto depthMode = parameters.depthModeFor3D(); + if (stencil) { + if (!stateDepthStencil.has_value()) { + stateDepthStencil = context.makeDepthStencilState(depthMode, stencilMode3d, renderable); + } + return *stateDepthStencil; + } else { + if (!stateDepth) { + stateDepth = context.makeDepthStencilState(depthMode, gfx::StencilMode::disabled(), renderable); + } + return *stateDepth; + } + } else { + if (stencil) { + if (!stateStencil.has_value()) { + stateStencil = context.makeDepthStencilState( + gfx::DepthMode::disabled(), stencilMode3d, renderable); + } + return *stateStencil; + } else { + if (!stateNone) { + stateNone = context.makeDepthStencilState( + gfx::DepthMode::disabled(), gfx::StencilMode::disabled(), renderable); + } + return *stateNone; + } + } + }; + const auto depthMode = parameters.depthModeFor3D(); if (stencil3d) { stencilMode3d = parameters.stencilModeFor3D(); - stateWithStencil = context.makeDepthStencilState(depthMode, stencilMode3d, renderable); encoder->setStencilReferenceValue(stencilMode3d.ref); } - stateWithoutStencil = context.makeDepthStencilState(depthMode, gfx::StencilMode::disabled(), renderable); } else if (stencilTiles && !stencilTiles->empty()) { parameters.renderTileClippingMasks(stencilTiles); } @@ -100,7 +134,7 @@ void TileLayerGroup::render(RenderOrchestrator&, PaintParameters& parameters) { // stencil mode for features with stencil enabled or disable stenciling. // 2D drawables will set their own stencil mode within `draw`. if (features3d) { - const auto& state = drawable.getEnableStencil() ? stateWithStencil : stateWithoutStencil; + const auto state = getDepthStencilState(drawable.getEnableDepth(), drawable.getEnableStencil()); renderPass.setDepthStencilState(state); } diff --git a/src/mbgl/renderer/layer_tweaker.cpp b/src/mbgl/renderer/layer_tweaker.cpp index 426fd57b3..b39b25c75 100644 --- a/src/mbgl/renderer/layer_tweaker.cpp +++ b/src/mbgl/renderer/layer_tweaker.cpp @@ -44,8 +44,9 @@ mat4 LayerTweaker::getTileMatrix(const UnwrappedTileID& tileID, : parameters.transformParams.projMatrix); #if !MLN_RENDER_BACKEND_OPENGL - // Offset the projection matrix NDC depth range for the drawable's layer and sublayer. - if (!drawable.getIs3D()) { + // If this drawable is participating in depth testing, offset the + // projection matrix NDC depth range for the drawable's layer and sublayer. + if (!drawable.getIs3D() && drawable.getEnableDepth()) { projMatrix[14] -= ((1 + drawable.getLayerIndex()) * PaintParameters::numSublayers - drawable.getSubLayerIndex()) * PaintParameters::depthEpsilon;