diff --git a/src/mbgl/gl/drawable_gl.cpp b/src/mbgl/gl/drawable_gl.cpp index e172d54d8..71a7b2c44 100644 --- a/src/mbgl/gl/drawable_gl.cpp +++ b/src/mbgl/gl/drawable_gl.cpp @@ -46,7 +46,10 @@ void DrawableGL::draw(PaintParameters& parameters) const { // force disable depth test for debugging // context.setDepthMode({gfx::DepthFunctionType::Always, gfx::DepthMaskType::ReadOnly, {0,1}}); - context.setStencilMode(makeStencilMode(parameters)); + // For 3D mode, stenciling is handled by the layer group + if (!is3D) { + context.setStencilMode(makeStencilMode(parameters)); + } context.setColorMode(getColorMode()); context.setCullFaceMode(getCullFaceMode()); @@ -211,9 +214,7 @@ gfx::ColorMode DrawableGL::makeColorMode(PaintParameters& parameters) const { gfx::StencilMode DrawableGL::makeStencilMode(PaintParameters& parameters) const { if (enableStencil) { - if (is3D) { - return parameters.stencilModeFor3D(); - } else if (tileID) { + if (!is3D && tileID) { return parameters.stencilModeForClipping(tileID->toUnwrapped()); } assert(false); diff --git a/src/mbgl/gl/layer_group_gl.cpp b/src/mbgl/gl/layer_group_gl.cpp index 324f6d5a1..ea01eebeb 100644 --- a/src/mbgl/gl/layer_group_gl.cpp +++ b/src/mbgl/gl/layer_group_gl.cpp @@ -46,6 +46,14 @@ void TileLayerGroupGL::render(RenderOrchestrator&, PaintParameters& parameters) return; } + auto& context = static_cast(parameters.context); + + // `stencilModeFor3D` uses a different stencil mask value each time its called, so if the + // drawables in this layer use 3D stencil mode, we need to set it up here so that all the + // drawables end up using the same mode value. + bool stencil3d = false; + gfx::StencilMode stencilMode3d; + if (getDrawableCount()) { #if !defined(NDEBUG) const auto label_clip = getName() + (getName().empty() ? "" : "-") + "tile-clip-masks"; @@ -55,12 +63,23 @@ void TileLayerGroupGL::render(RenderOrchestrator&, PaintParameters& parameters) // Collect the tile IDs relevant to stenciling and update the stencil buffer, if necessary. std::set tileIDs; observeDrawables([&](const gfx::Drawable& drawable) { - if (drawable.getEnabled() && !drawable.getIs3D() && drawable.getEnableStencil() && drawable.getTileID() && - drawable.hasRenderPass(parameters.pass)) { - tileIDs.emplace(drawable.getTileID()->toUnwrapped()); + if (drawable.getEnabled() && drawable.getEnableStencil() && drawable.hasRenderPass(parameters.pass)) { + if (drawable.getIs3D()) { + stencil3d = true; + } + if (!stencil3d && drawable.getTileID()) { + tileIDs.emplace(drawable.getTileID()->toUnwrapped()); + } } }); - parameters.renderTileClippingMasks(tileIDs); + + // If we're doing 3D stenciling, set up the single-value stencil mask. + // If we're doing 2D stenciling, render each tile with a different value. + if (stencil3d) { + stencilMode3d = parameters.stencilModeFor3D(); + } else { + parameters.renderTileClippingMasks(tileIDs); + } } #if !defined(NDEBUG) @@ -86,6 +105,10 @@ void TileLayerGroupGL::render(RenderOrchestrator&, PaintParameters& parameters) tweaker->execute(drawable, parameters); } + if (stencil3d) { + context.setStencilMode(drawable.getEnableStencil() ? stencilMode3d : gfx::StencilMode::disabled()); + } + drawable.draw(parameters); }); }