Combine multiple segments into a drawable when sortFeaturesByKey is not used (#2060)

This commit is contained in:
Tim Sylvester
2024-01-30 08:02:05 -08:00
committed by GitHub
parent c4f852b3f4
commit bf15332c5e
2 changed files with 50 additions and 16 deletions

View File

@@ -24,6 +24,9 @@
#include <simd/simd.h>
#include <cassert>
#if !defined(NDEBUG)
#include <sstream>
#endif
namespace mbgl {
namespace mtl {
@@ -72,11 +75,16 @@ MTL::PrimitiveType getPrimitiveType(const gfx::DrawModeType type) noexcept {
#if !defined(NDEBUG)
std::string debugLabel(const gfx::Drawable& drawable) {
std::string result = drawable.getName();
std::ostringstream oss;
oss << drawable.getID().id() << "/" << drawable.getName() << "/tile=";
if (const auto& tileID = drawable.getTileID()) {
result.append("/tile=").append(util::toString(*tileID));
oss << util::toString(*tileID);
} else {
oss << "(none)";
}
return result;
return oss.str();
}
#endif // !defined(NDEBUG)

View File

@@ -88,15 +88,14 @@ struct RenderableSegment {
const LayerRenderData& renderData_,
const SymbolBucket::PaintProperties& bucketPaintProperties_,
float sortKey_,
const SymbolType type_,
const uint8_t overscaledZ_ = 0)
const SymbolType type_)
: segment(segment_),
tile(tile_),
renderData(renderData_),
bucketPaintProperties(bucketPaintProperties_),
sortKey(sortKey_),
type(type_),
overscaledZ(overscaledZ_) {}
overscaledZ(tile.getOverscaledTileID().overscaledZ) {}
SegmentWrapper segment;
const RenderTile& tile;
@@ -129,6 +128,19 @@ struct RenderableSegment {
}
};
struct SegmentGroup {
// A reference to the first or only segment
RenderableSegment renderable;
// A reference to multiple segments, or none
SegmentVectorWrapper segments;
bool operator<(const SegmentGroup& other) const { return renderable < other.renderable; }
};
namespace {
const SegmentVector<SymbolTextAttributes> emptySegmentVector;
}
#if MLN_LEGACY_RENDERER
template <typename DrawFn>
@@ -1038,7 +1050,7 @@ void RenderSymbolLayer::update(gfx::ShaderRegistry& shaders,
}
const bool sortFeaturesByKey = !impl_cast(baseImpl).layout.get<SymbolSortKey>().isUndefined();
std::multiset<RenderableSegment> renderableSegments;
std::multiset<SegmentGroup> renderableSegments;
std::unique_ptr<gfx::DrawableBuilder> builder;
const auto currentZoom = static_cast<float>(state.getZoom());
@@ -1169,13 +1181,20 @@ void RenderSymbolLayer::update(gfx::ShaderRegistry& shaders,
}
float serialKey = 1.0f;
auto addRenderables = [&, it = renderableSegments.begin()](const SymbolBucket::Buffer& buffer,
const SymbolType type) mutable {
for (const auto& segment : buffer.segments) {
const auto key = sortFeaturesByKey ? segment.sortKey : (serialKey += 1.0);
assert(segment.vertexOffset + segment.vertexLength <= buffer.vertices().elements());
it = renderableSegments.emplace_hint(
it, std::ref(segment), tile, renderData, bucketPaintProperties, key, type, tileID.overscaledZ);
auto addRenderables = [&](const SymbolBucket::Buffer& buffer, const SymbolType type) mutable {
if (sortFeaturesByKey) {
// Features need to be rendered in a specific order, so we add each segment individually
for (const auto& segment : buffer.segments) {
assert(segment.vertexOffset + segment.vertexLength <= buffer.vertices().elements());
renderableSegments.emplace(SegmentGroup{
{segment, tile, renderData, bucketPaintProperties, segment.sortKey, type}, emptySegmentVector});
}
} else if (!buffer.segments.empty()) {
// Features can be rendered in the order produced, and as grouped by the bucket
const auto& firstSeg = buffer.segments.front();
renderableSegments.emplace(SegmentGroup{
{firstSeg, tile, renderData, bucketPaintProperties, serialKey, type}, buffer.segments});
serialKey += 1.0;
}
};
@@ -1208,7 +1227,10 @@ void RenderSymbolLayer::update(gfx::ShaderRegistry& shaders,
};
std::unordered_map<UnwrappedTileID, TileInfo> tileCache;
for (auto& renderable : renderableSegments) {
for (auto& group : renderableSegments) {
const auto& renderable = group.renderable;
const auto& segments = group.segments.get();
const auto isText = (renderable.type == SymbolType::Text);
const auto sdfIcons = (renderable.type == SymbolType::IconSDF);
@@ -1320,7 +1342,11 @@ void RenderSymbolLayer::update(gfx::ShaderRegistry& shaders,
builder->setDrawableName(layerPrefix + std::string(suffix));
builder->setVertexAttributes(attribs);
builder->setSegments(gfx::Triangles(), buffer.sharedTriangles, &renderable.segment.get(), 1);
if (segments.empty()) {
builder->setSegments(gfx::Triangles(), buffer.sharedTriangles, &renderable.segment.get(), 1);
} else {
builder->setSegments(gfx::Triangles(), buffer.sharedTriangles, segments.data(), segments.size());
}
builder->flush(context);