Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Bug/stencil tiles #1871

Merged
merged 5 commits into from
Nov 16, 2023
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions include/mbgl/renderer/layer_group.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,12 @@ namespace mbgl {
class LayerGroupBase;
class PaintParameters;
class RenderOrchestrator;
class RenderTile;
class RenderTree;
class TileLayerGroup;

using LayerGroupBasePtr = std::shared_ptr<LayerGroupBase>;
using RenderTiles = std::shared_ptr<const std::vector<std::reference_wrapper<const RenderTile>>>;

namespace gfx {
class Context;
Expand Down Expand Up @@ -127,9 +129,15 @@ class TileLayerGroup : public LayerGroupBase {

std::size_t clearDrawables() override;

void setStencilTiles(RenderTiles);

protected:
struct Impl;
std::unique_ptr<Impl> impl;

// When stencil clipping is enabled for the layer, this is the set
// of tile IDs that need to be rendered to the stencil buffer.
RenderTiles stencilTiles;
};

/**
Expand Down
29 changes: 12 additions & 17 deletions src/mbgl/gl/layer_group_gl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -62,31 +62,26 @@ void TileLayerGroupGL::render(RenderOrchestrator&, PaintParameters& parameters)
const auto debugGroupClip = parameters.encoder->createDebugGroup(label_clip.c_str());
#endif

// Collect the tile IDs relevant to stenciling and update the stencil buffer, if necessary.
std::set<UnwrappedTileID> tileIDs;
visitDrawables([&](const gfx::Drawable& drawable) {
if (!drawable.getEnabled() || !drawable.hasRenderPass(parameters.pass)) {
return;
}
if (drawable.getIs3D()) {
features3d = true;
if (drawable.getEnableStencil()) {
stencil3d = true;
// If we're using stencil clipping, we need to handle 3D features separately
if (stencilTiles && !stencilTiles->empty()) {
visitDrawables([&](const gfx::Drawable& drawable) {
if (drawable.getEnabled() && drawable.getIs3D() && drawable.hasRenderPass(parameters.pass)) {
features3d = true;
if (drawable.getEnableStencil()) {
stencil3d = true;
}
}
}
if (!features3d && drawable.getEnableStencil() && drawable.getTileID()) {
tileIDs.emplace(drawable.getTileID()->toUnwrapped());
}
});
});
}

// 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.
if (features3d) {
stencilMode3d = stencil3d ? parameters.stencilModeFor3D() : gfx::StencilMode::disabled();
} else if (!tileIDs.empty()) {
parameters.renderTileClippingMasks(tileIDs);
} else if (stencilTiles && !stencilTiles->empty()) {
parameters.renderTileClippingMasks(stencilTiles);
}
}

Expand Down
40 changes: 14 additions & 26 deletions src/mbgl/mtl/tile_layer_group.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -55,37 +55,25 @@ void TileLayerGroup::render(RenderOrchestrator&, PaintParameters& parameters) {
bool stencil3d = false;
gfx::StencilMode stencilMode3d;

// Collect the tile IDs relevant to stenciling and update the stencil buffer, if necessary.
std::set<UnwrappedTileID> tileIDs;
std::size_t numEnabled = 0;
visitDrawables([&](const gfx::Drawable& drawable) {
if (!drawable.getEnabled() || !drawable.hasRenderPass(parameters.pass)) {
return;
}
numEnabled += 1;
if (drawable.getIs3D()) {
features3d = true;
if (drawable.getEnableStencil()) {
stencil3d = true;
// If we're using stencil clipping, we need to handle 3D features separately
if (stencilTiles && !stencilTiles->empty()) {
visitDrawables([&](const gfx::Drawable& drawable) {
if (drawable.getEnabled() && drawable.getIs3D() && drawable.hasRenderPass(parameters.pass)) {
features3d = true;
if (drawable.getEnableStencil()) {
stencil3d = true;
}
}
}
if (!features3d && drawable.getEnableStencil() && drawable.getTileID()) {
tileIDs.emplace(drawable.getTileID()->toUnwrapped());
}
});

if (!numEnabled) {
return;
});
}

#if !defined(NDEBUG)
const auto debugGroupRender = parameters.encoder->createDebugGroup(getName() + "-render");
#endif

// 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.
// 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;
if (features3d) {
const auto depthMode = parameters.depthModeFor3D();
Expand All @@ -95,8 +83,8 @@ void TileLayerGroup::render(RenderOrchestrator&, PaintParameters& parameters) {
encoder->setStencilReferenceValue(stencilMode3d.ref);
}
stateWithoutStencil = context.makeDepthStencilState(depthMode, gfx::StencilMode::disabled(), renderable);
} else if (!tileIDs.empty()) {
parameters.renderTileClippingMasks(tileIDs);
} else if (stencilTiles && !stencilTiles->empty()) {
parameters.renderTileClippingMasks(stencilTiles);
}

visitDrawables([&](gfx::Drawable& drawable) {
Expand Down
12 changes: 5 additions & 7 deletions src/mbgl/renderer/layers/render_background_layer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -204,10 +204,6 @@ void RenderBackgroundLayer::prepare(const LayerPrepareParameters& params) {
addPatternIfNeeded(evaluated.get<BackgroundPattern>().from.id(), params);
addPatternIfNeeded(evaluated.get<BackgroundPattern>().to.id(), params);
}

#if MLN_DRAWABLE_RENDERER
updateRenderTileIDs();
#endif // MLN_DRAWABLE_RENDERER
}

#if MLN_DRAWABLE_RENDERER
Expand Down Expand Up @@ -290,9 +286,11 @@ void RenderBackgroundLayer::update(gfx::ShaderRegistry& shaders,

std::unique_ptr<gfx::DrawableBuilder> builder;

tileLayerGroup->visitDrawables([&](gfx::Drawable& drawable) -> bool {
// Has this tile dropped out of the cover set?
return (!drawable.getTileID() || hasRenderTile(*drawable.getTileID()));
// Remove drawables for tiles that are no longer in the cover set.
// (Note that `RenderTiles` is empty, and this layer does not use it)
tileLayerGroup->removeDrawablesIf([&](gfx::Drawable& drawable) -> bool {
return drawable.getTileID() &&
(std::find(tileCover.begin(), tileCover.end(), *drawable.getTileID()) == tileCover.end());
});

// For each tile in the cover set, add a tile drawable if one doesn't already exist.
Expand Down
3 changes: 2 additions & 1 deletion src/mbgl/renderer/layers/render_fill_extrusion_layer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -347,6 +347,8 @@ void RenderFillExtrusionLayer::update(gfx::ShaderRegistry& shaders,
return;
}

tileLayerGroup->setStencilTiles(renderTiles);

std::unordered_set<StringIdentity> propertiesAsUniforms;
for (const RenderTile& tile : *renderTiles) {
const auto& tileID = tile.getOverscaledTileID();
Expand Down Expand Up @@ -448,7 +450,6 @@ void RenderFillExtrusionLayer::update(gfx::ShaderRegistry& shaders,
if (auto builder = context.createDrawableBuilder(layerPrefix + "depth")) {
builder->setShader(shader);
builder->setIs3D(true);
builder->setEnableStencil(false);
builder->setEnableColor(false);
builder->setRenderPass(drawPass);
builder->setCullFaceMode(gfx::CullFaceMode::backCCW());
Expand Down
12 changes: 8 additions & 4 deletions src/mbgl/renderer/layers/render_fill_layer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -364,6 +364,8 @@ void RenderFillLayer::update(gfx::ShaderRegistry& shaders,
return tileID && !hasRenderTile(*tileID);
});

tileLayerGroup->setStencilTiles(renderTiles);

std::unordered_set<StringIdentity> propertiesAsUniforms;
for (const RenderTile& tile : *renderTiles) {
const auto& tileID = tile.getOverscaledTileID();
Expand Down Expand Up @@ -559,11 +561,13 @@ void RenderFillLayer::update(gfx::ShaderRegistry& shaders,

if (!fillBuilder && fillShader) {
if (auto builder = context.createDrawableBuilder(layerPrefix + "fill")) {
// Only write opaque fills to the depth buffer, matching `fillRenderPass` in legacy rendering
const bool opaque = (evaluated.get<FillColor>().constantOr(Color()).a >= 1.0f &&
evaluated.get<FillOpacity>().constantOr(0) >= 1.0f);

commonInit(*builder);
builder->setDepthType((renderPass == RenderPass::Opaque) ? gfx::DepthMaskType::ReadWrite
: gfx::DepthMaskType::ReadOnly);
builder->setColorMode(renderPass == RenderPass::Translucent ? gfx::ColorMode::alphaBlended()
: gfx::ColorMode::unblended());
builder->setDepthType(opaque ? gfx::DepthMaskType::ReadWrite : gfx::DepthMaskType::ReadOnly);
builder->setColorMode(opaque ? gfx::ColorMode::unblended() : gfx::ColorMode::alphaBlended());
builder->setSubLayerIndex(1);
builder->setRenderPass(renderPass);
fillBuilder = std::move(builder);
Expand Down
2 changes: 0 additions & 2 deletions src/mbgl/renderer/layers/render_heatmap_layer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -435,7 +435,6 @@ void RenderHeatmapLayer::update(gfx::ShaderRegistry& shaders,
heatmapBuilder->setEnableDepth(false);
heatmapBuilder->setColorMode(gfx::ColorMode::additive());
heatmapBuilder->setCullFaceMode(gfx::CullFaceMode::disabled());
heatmapBuilder->setEnableStencil(false);
heatmapBuilder->setRenderPass(renderPass);
heatmapBuilder->setVertexAttributes(std::move(heatmapVertexAttrs));
heatmapBuilder->setRawVertices({}, vertexCount, gfx::AttributeDataType::Short2);
Expand Down Expand Up @@ -509,7 +508,6 @@ void RenderHeatmapLayer::update(gfx::ShaderRegistry& shaders,
heatmapTextureBuilder->setEnableDepth(false);
heatmapTextureBuilder->setColorMode(gfx::ColorMode::alphaBlended());
heatmapTextureBuilder->setCullFaceMode(gfx::CullFaceMode::disabled());
heatmapTextureBuilder->setEnableStencil(false);
heatmapTextureBuilder->setRenderPass(renderPass);
heatmapTextureBuilder->setVertexAttributes(std::move(textureVertexAttrs));
heatmapTextureBuilder->setRawVertices({}, textureVertexCount, gfx::AttributeDataType::Short2);
Expand Down
2 changes: 2 additions & 0 deletions src/mbgl/renderer/layers/render_line_layer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -461,6 +461,8 @@ void RenderLineLayer::update(gfx::ShaderRegistry& shaders,
builder->setSegments(gfx::Triangles(), bucket.sharedTriangles, bucket.segments.data(), bucket.segments.size());
};

tileLayerGroup->setStencilTiles(renderTiles);

std::unordered_set<StringIdentity> propertiesAsUniforms;
for (const RenderTile& tile : *renderTiles) {
const auto& tileID = tile.getOverscaledTileID();
Expand Down
2 changes: 0 additions & 2 deletions src/mbgl/renderer/layers/render_symbol_layer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1055,7 +1055,6 @@ void RenderSymbolLayer::update(gfx::ShaderRegistry& shaders,

std::unique_ptr<gfx::DrawableBuilder> collisionBuilder = context.createDrawableBuilder(layerCollisionPrefix);
collisionBuilder->setSubLayerIndex(0);
collisionBuilder->setEnableStencil(false);
collisionBuilder->setEnableDepth(false);
collisionBuilder->setRenderPass(passes);
collisionBuilder->setCullFaceMode(gfx::CullFaceMode::disabled());
Expand Down Expand Up @@ -1316,7 +1315,6 @@ void RenderSymbolLayer::update(gfx::ShaderRegistry& shaders,
if (!builder) {
builder = context.createDrawableBuilder(layerPrefix);
builder->setSubLayerIndex(0);
builder->setEnableStencil(false);
builder->setRenderPass(passes);
builder->setCullFaceMode(gfx::CullFaceMode::disabled());
builder->setDepthType(gfx::DepthMaskType::ReadOnly);
Expand Down
65 changes: 27 additions & 38 deletions src/mbgl/renderer/paint_parameters.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,9 @@

using TileMaskIDMap = std::map<UnwrappedTileID, int32_t>;

// `std::includes` adapted to extract tile IDs from arbitrary collection iterators
// `std::includes` adapted to extract tile IDs from arbitrary collection iterators.
// This is needed because, although it accepts iterators of different types, they must be:
// "...such that an object of type InputIt can be dereferenced and then implicitly converted to both of them.​"
template <class I1, class I2>
bool includes(I1 beg1, const I1 end1, I2 beg2, const I2 end2, const GetTileIDFunc<I2>& unwrap) {
for (; beg2 != end2; ++beg1) {
Expand All @@ -118,25 +120,20 @@
return true;
}

const UnwrappedTileID& unwrap(const RenderTiles::element_type::value_type& iter) {
return iter.get().id;
}

// Check whether the given set of tile IDs is a subset of the ones already rendered
template <typename TIter>
bool tileIDsCovered(TIter beg, TIter end, GetTileIDFunc<TIter>& unwrap, const TileMaskIDMap& idMap) {
if (idMap.size() < static_cast<std::size_t>(std::distance(beg, end))) {
bool tileIDsCovered(const RenderTiles& tiles, const TileMaskIDMap& idMap) {
if (idMap.size() < tiles->size()) {
return false;
}
assert(std::is_sorted(beg, end, [=](const auto& a, const auto& b) { return unwrap(a) < unwrap(b); }));
return includes(idMap.cbegin(), idMap.cend(), beg, end, unwrap);
assert(std::is_sorted(
tiles->begin(), tiles->end(), [=](const auto& a, const auto& b) { return unwrap(a) < unwrap(b); }));
return includes(idMap.cbegin(), idMap.cend(), tiles->cbegin(), tiles->cend(), &unwrap);
}

#if MLN_LEGACY_RENDERER
const UnwrappedTileID& unwrapRenderTiles(const RenderTiles::element_type::value_type& iter) {
return iter.get().id;
}
#else // !MLN_LEGACY_RENDERER
const UnwrappedTileID& unwrapIdentity(const UnwrappedTileID& value) {
return value;
}
#endif // MLN_LEGACY_RENDERER
} // namespace

void PaintParameters::clearStencil() {
Expand Down Expand Up @@ -164,35 +161,21 @@
#endif
}

#if MLN_LEGACY_RENDERER
void PaintParameters::renderTileClippingMasks(const RenderTiles& renderTiles) {
renderTileClippingMasks((*renderTiles).cbegin(), (*renderTiles).cend(), &unwrapRenderTiles);
}
#else // !MLN_LEGACY_RENDERER
void PaintParameters::renderTileClippingMasks(const std::set<UnwrappedTileID>& tileIDs) {
renderTileClippingMasks(tileIDs.cbegin(), tileIDs.cend(), &unwrapIdentity);
}
#endif // MLN_LEGACY_RENDERER

void PaintParameters::clearTileClippingMasks() {
if (!tileClippingMaskIDs.empty()) {
clearStencil();
if (!renderTiles) {
return;
}
}

template <typename TIter>
void PaintParameters::renderTileClippingMasks(TIter beg, TIter end, GetTileIDFunc<TIter> unwrap) {
if (!renderPass) {
assert(false);
return;
}

if (tileIDsCovered(beg, end, unwrap, tileClippingMaskIDs)) {
if (tileIDsCovered(renderTiles, tileClippingMaskIDs)) {
// The current stencil mask is for this source already; no need to draw another one.
return;
}

const auto count = std::distance(beg, end);
const auto count = renderTiles->size();
if (nextStencilID + count > maxStencilValue) {
// we'll run out of fresh IDs so we need to clear and start from scratch
clearStencil();
Expand All @@ -201,8 +184,8 @@
#if MLN_RENDER_BACKEND_METAL
// Assign a stencil ID and build a UBO for each tile in the set
std::vector<shaders::ClipUBO> tileUBOs;
for (auto i = beg; i != end; ++i) {
const auto& tileID = unwrap(*i);
for (const auto& tileRef : *renderTiles) {
const auto& tileID = tileRef.get().id;

const int32_t stencilID = nextStencilID;
const auto result = tileClippingMaskIDs.insert(std::make_pair(tileID, stencilID));
Expand All @@ -215,7 +198,7 @@
}

if (tileUBOs.empty()) {
tileUBOs.reserve(std::distance(beg, end));
tileUBOs.reserve(count);
}

tileUBOs.emplace_back(shaders::ClipUBO{/*.matrix=*/util::cast<float>(matrixForTile(tileID)),
Expand Down Expand Up @@ -248,8 +231,8 @@
const style::Properties<>::PossiblyEvaluated properties{};
const ClippingMaskProgram::Binders paintAttributeData(properties, 0);

for (auto i = beg; i != end; ++i) {
const auto& tileID = unwrap(*i);
for (const auto& tileRef : *renderTiles) {
const auto& tileID = tileRef.get().id;

const int32_t stencilID = nextStencilID;
const auto result = tileClippingMaskIDs.insert(std::make_pair(tileID, stencilID));
Expand Down Expand Up @@ -290,6 +273,12 @@
#endif // MLN_RENDER_BACKEND_METAL
}

void PaintParameters::clearTileClippingMasks() {
if (!tileClippingMaskIDs.empty()) {
clearStencil();

Check warning on line 278 in src/mbgl/renderer/paint_parameters.cpp

View check run for this annotation

Codecov / codecov/patch

src/mbgl/renderer/paint_parameters.cpp#L276-L278

Added lines #L276 - L278 were not covered by tests
}
}

Check warning on line 280 in src/mbgl/renderer/paint_parameters.cpp

View check run for this annotation

Codecov / codecov/patch

src/mbgl/renderer/paint_parameters.cpp#L280

Added line #L280 was not covered by tests

gfx::StencilMode PaintParameters::stencilModeForClipping(const UnwrappedTileID& tileID) const {
auto it = tileClippingMaskIDs.find(tileID);
assert(it != tileClippingMaskIDs.end());
Expand Down
4 changes: 0 additions & 4 deletions src/mbgl/renderer/paint_parameters.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -95,11 +95,7 @@ class PaintParameters {

// Stencil handling
public:
#if MLN_LEGACY_RENDERER
void renderTileClippingMasks(const RenderTiles&);
#else
void renderTileClippingMasks(const std::set<UnwrappedTileID>&);
#endif // MLN_LEGACY_RENDERER

/// Clear any tile masks and the stencil buffer, if necessary
void clearTileClippingMasks();
Expand Down
1 change: 0 additions & 1 deletion src/mbgl/renderer/sources/render_tile_source.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,6 @@ void TileSourceRenderItem::updateDebugDrawables(DebugLayerGroupMap& debugLayerGr
builder->setEnableDepth(false);
builder->setColorMode(gfx::ColorMode::unblended());
builder->setCullFaceMode(gfx::CullFaceMode::disabled());
builder->setEnableStencil(false);
builder->setVertexAttrNameId(idVertexAttribName);

// add or get the layer group for a debug type
Expand Down
Loading
Loading