Metal debug lines (#1888)

This commit is contained in:
Stefan Karschti
2023-11-28 07:51:18 +02:00
committed by GitHub
parent 634ce8089b
commit 178454bdba
2 changed files with 223 additions and 73 deletions

View File

@@ -159,6 +159,8 @@ void Renderer::Impl::render(const RenderTree& renderTree,
// Tweakers are run in the upload pass so they can set up uniforms.
orchestrator.visitLayerGroups(
[&](LayerGroupBase& layerGroup) { layerGroup.runTweakers(renderTree, parameters); });
orchestrator.visitDebugLayerGroups(
[&](LayerGroupBase& layerGroup) { layerGroup.runTweakers(renderTree, parameters); });
// Update the debug layer groups
orchestrator.updateDebugLayerGroups(renderTree, parameters);
@@ -324,7 +326,12 @@ void Renderer::Impl::render(const RenderTree& renderTree,
{
const auto debugGroup(parameters.renderPass->createDebugGroup("debug"));
orchestrator.visitDebugLayerGroups([&](LayerGroupBase& layerGroup) {
visitLayerGroupDrawables(layerGroup, [&](gfx::Drawable& drawable) { drawable.draw(parameters); });
visitLayerGroupDrawables(layerGroup, [&](gfx::Drawable& drawable) {
for (const auto& tweaker : drawable.getTweakers()) {
tweaker->execute(drawable, parameters);
}
drawable.draw(parameters);
});
});
}
};

View File

@@ -19,6 +19,12 @@
#include <mbgl/shaders/shader_program_base.hpp>
#include <mbgl/util/convert.hpp>
#include <mbgl/util/string_indexer.hpp>
#include <mbgl/tile/geojson_tile_data.hpp>
#include <mbgl/gfx/polyline_generator.hpp>
#include <mbgl/style/types.hpp>
#include <mbgl/shaders/line_layer_ubo.hpp>
#include <mbgl/gfx/drawable_tweaker.hpp>
#include <mbgl/renderer/layer_tweaker.hpp>
#include <unordered_set>
#endif
@@ -49,26 +55,59 @@ void TileSourceRenderItem::updateDebugDrawables(DebugLayerGroupMap& debugLayerGr
return;
}
// initialize
auto& context = parameters.context;
const auto renderPass = RenderPass::None;
auto& shaders = *parameters.staticData.shaders;
// initialize debug builder
constexpr auto DebugShaderName = "DebugShader";
gfx::ShaderProgramBasePtr debugShader = context.getGenericShader(shaders, std::string(DebugShaderName));
if (!debugShader) {
return;
}
// create a builder
static const StringIdentity idVertexAttribName = stringIndexer().get("a_pos");
static const StringIdentity idDebugUBOName = stringIndexer().get("DebugUBO");
std::unique_ptr<gfx::DrawableBuilder> builder = context.createDrawableBuilder("debug-builder");
builder->setShader(debugShader);
builder->setRenderPass(renderPass);
builder->setEnableDepth(false);
builder->setColorMode(gfx::ColorMode::unblended());
builder->setCullFaceMode(gfx::CullFaceMode::disabled());
builder->setVertexAttrNameId(idVertexAttribName);
std::unique_ptr<gfx::DrawableBuilder> debugBuilder = [&]() -> std::unique_ptr<gfx::DrawableBuilder> {
auto builder = context.createDrawableBuilder("debug-builder");
builder->setShader(debugShader);
builder->setRenderPass(renderPass);
builder->setEnableDepth(false);
builder->setColorMode(gfx::ColorMode::unblended());
builder->setCullFaceMode(gfx::CullFaceMode::disabled());
builder->setVertexAttrNameId(idVertexAttribName);
return builder;
}();
#if MLN_RENDER_BACKEND_METAL
// initialize polyline builder
gfx::ShaderPtr polylineShader;
const auto createPolylineShader = [&]() -> gfx::ShaderPtr {
gfx::ShaderGroupPtr shaderGroup = shaders.getShaderGroup("LineShader");
const mbgl::unordered_set<StringIdentity> propertiesAsUniforms{
stringIndexer().get("a_color"),
stringIndexer().get("a_blur"),
stringIndexer().get("a_opacity"),
stringIndexer().get("a_gapwidth"),
stringIndexer().get("a_offset"),
stringIndexer().get("a_width"),
};
return shaderGroup->getOrCreateShader(context, propertiesAsUniforms);
};
std::unique_ptr<gfx::DrawableBuilder> polylineBuilder;
const auto createPolylineBuilder = [&](gfx::ShaderPtr shader) -> std::unique_ptr<gfx::DrawableBuilder> {
std::unique_ptr<gfx::DrawableBuilder> builder = context.createDrawableBuilder("debug-polyline-builder");
builder->setShader(std::static_pointer_cast<gfx::ShaderProgramBase>(shader));
builder->setRenderPass(renderPass);
builder->setEnableDepth(false);
builder->setColorMode(gfx::ColorMode::alphaBlended());
builder->setCullFaceMode(gfx::CullFaceMode::disabled());
builder->setVertexAttrNameId(idVertexAttribName);
return builder;
};
#endif
// add or get the layer group for a debug type
const auto addOrGetLayerGroupForType = [&debugLayerGroups, &context](
@@ -87,9 +126,7 @@ void TileSourceRenderItem::updateDebugDrawables(DebugLayerGroupMap& debugLayerGr
// build a set of tiles to cover
std::unordered_set<OverscaledTileID> newTiles;
for (auto& tile : *renderTiles) {
if (tile.getNeedsRendering()) {
newTiles.insert(tile.getOverscaledTileID());
}
newTiles.insert(tile.getOverscaledTileID());
}
// create texture. to be reused for all the tiles of the debug layers
@@ -118,7 +155,7 @@ void TileSourceRenderItem::updateDebugDrawables(DebugLayerGroupMap& debugLayerGr
return updatedCount;
};
// function to add drawable
// function to add lines drawable
const auto addDrawable = [&](TileLayerGroup* tileLayerGroup,
const OverscaledTileID& tileID,
const DebugUBO& debugUBO,
@@ -132,14 +169,14 @@ void TileSourceRenderItem::updateDebugDrawables(DebugLayerGroupMap& debugLayerGr
return v.a1;
});
builder->addVertices(verts, 0, verts.size());
builder->setSegments(mode, indexes, segments.data(), segments.size());
debugBuilder->addVertices(verts, 0, verts.size());
debugBuilder->setSegments(mode, indexes, segments.data(), segments.size());
// texture
builder->setTexture(texture, samplerLocation.value());
debugBuilder->setTexture(texture, samplerLocation.value());
// finish
builder->flush();
for (auto& drawable : builder->clearDrawables()) {
debugBuilder->flush();
for (auto& drawable : debugBuilder->clearDrawables()) {
drawable->setTileID(tileID);
auto& uniforms = drawable->mutableUniformBuffers();
uniforms.createOrUpdate(idDebugUBOName, &debugUBO, context);
@@ -148,6 +185,112 @@ void TileSourceRenderItem::updateDebugDrawables(DebugLayerGroupMap& debugLayerGr
}
};
#if MLN_RENDER_BACKEND_METAL
// function to add polylines drawable
const auto addPolylineDrawable = [&](TileLayerGroup* tileLayerGroup, const RenderTile& tile) {
class PolylineDrawableTweaker : public gfx::DrawableTweaker {
public:
PolylineDrawableTweaker(const shaders::LinePropertiesUBO& properties)
: linePropertiesUBO(properties) {}
~PolylineDrawableTweaker() override = default;
void init(gfx::Drawable&) override{};
void execute(gfx::Drawable& drawable, const PaintParameters& parameters) override {
if (!drawable.getTileID().has_value()) {
return;
}
const UnwrappedTileID tileID = drawable.getTileID()->toUnwrapped();
const auto zoom = parameters.state.getZoom();
mat4 tileMatrix;
parameters.state.matrixFor(/*out*/ tileMatrix, tileID);
const auto matrix = LayerTweaker::getTileMatrix(
tileID, parameters, {{0, 0}}, style::TranslateAnchorType::Viewport, false, false, false);
static const StringIdentity idLineUBOName = stringIndexer().get("LineUBO");
const shaders::LineUBO lineUBO{
/*matrix = */ util::cast<float>(matrix),
/*units_to_pixels = */ {1.0f / parameters.pixelsToGLUnits[0], 1.0f / parameters.pixelsToGLUnits[1]},
/*ratio = */ 1.0f / tileID.pixelsToTileUnits(1.0f, zoom),
/*device_pixel_ratio = */ parameters.pixelRatio};
static const StringIdentity idLinePropertiesUBOName = stringIndexer().get("LinePropertiesUBO");
static const StringIdentity idLineInterpolationUBOName = stringIndexer().get("LineInterpolationUBO");
const shaders::LineInterpolationUBO lineInterpolationUBO{/*color_t =*/0.f,
/*blur_t =*/0.f,
/*opacity_t =*/0.f,
/*gapwidth_t =*/0.f,
/*offset_t =*/0.f,
/*width_t =*/0.f,
0,
0};
auto& uniforms = drawable.mutableUniformBuffers();
uniforms.createOrUpdate(idLineUBOName, &lineUBO, parameters.context);
uniforms.createOrUpdate(idLinePropertiesUBOName, &linePropertiesUBO, parameters.context);
uniforms.createOrUpdate(idLineInterpolationUBOName, &lineInterpolationUBO, parameters.context);
static const StringIdentity idExpressionInputsUBOName = stringIndexer().get("ExpressionInputsUBO");
const auto expressionUBO = LayerTweaker::buildExpressionUBO(zoom, parameters.frameCount);
uniforms.createOrUpdate(idExpressionInputsUBOName, &expressionUBO, parameters.context);
static const StringIdentity idLinePermutationUBOName = stringIndexer().get("LinePermutationUBO");
const shaders::LinePermutationUBO permutationUBO = {
/* .color = */ {/*.source=*/shaders::AttributeSource::Constant, /*.expression=*/{}},
/* .blur = */ {/*.source=*/shaders::AttributeSource::Constant, /*.expression=*/{}},
/* .opacity = */ {/*.source=*/shaders::AttributeSource::Constant, /*.expression=*/{}},
/* .gapwidth = */ {/*.source=*/shaders::AttributeSource::Constant, /*.expression=*/{}},
/* .offset = */ {/*.source=*/shaders::AttributeSource::Constant, /*.expression=*/{}},
/* .width = */ {/*.source=*/shaders::AttributeSource::Constant, /*.expression=*/{}},
/* .floorwidth = */ {/*.source=*/shaders::AttributeSource::Constant, /*.expression=*/{}},
/* .pattern_from = */ {/*.source=*/shaders::AttributeSource::Constant, /*.expression=*/{}},
/* .pattern_to = */ {/*.source=*/shaders::AttributeSource::Constant, /*.expression=*/{}},
/* .overdrawInspector = */ false,
/* .pad = */ 0,
0,
0,
0};
uniforms.createOrUpdate(idLinePermutationUBOName, &permutationUBO, parameters.context);
};
private:
shaders::LinePropertiesUBO linePropertiesUBO;
};
GeometryCoordinates coords{{0, 0}, {util::EXTENT, 0}, {util::EXTENT, util::EXTENT}, {0, util::EXTENT}, {0, 0}};
gfx::PolylineGeneratorOptions options;
options.type = FeatureType::Polygon;
if (!polylineShader) polylineShader = createPolylineShader();
if (!polylineBuilder) {
polylineBuilder = createPolylineBuilder(polylineShader);
}
polylineBuilder->addPolyline(coords, options);
// create line tweaker
const shaders::LinePropertiesUBO linePropertiesUBO{/*color*/ Color::red(),
/*blur*/ 0.f,
/*opacity*/ 1.f,
/*gapwidth*/ 0.f,
/*offset*/ 0.f,
/*width*/ 4.f,
0,
0,
0};
auto tweaker = std::make_shared<PolylineDrawableTweaker>(linePropertiesUBO);
// finish
polylineBuilder->flush();
for (auto& drawable : polylineBuilder->clearDrawables()) {
drawable->setTileID(tile.getOverscaledTileID());
drawable->addTweaker(tweaker);
tileLayerGroup->addDrawable(renderPass, tile.getOverscaledTileID(), std::move(drawable));
}
};
#endif
// Timestamps or Parse Status
if (parameters.debugOptions & (MapDebugOptions::Timestamps | MapDebugOptions::ParseStatus)) {
TileLayerGroup* outlineLayerGroup = static_cast<TileLayerGroup*>(
@@ -164,42 +307,40 @@ void TileSourceRenderItem::updateDebugDrawables(DebugLayerGroupMap& debugLayerGr
// add new drawables and update existing ones
for (auto& tile : *renderTiles) {
if (tile.getNeedsRendering()) {
const auto tileID = tile.getOverscaledTileID();
const auto& debugBucket = tile.debugBucket;
if (!debugBucket) continue;
const auto tileID = tile.getOverscaledTileID();
const auto& debugBucket = tile.debugBucket;
if (!debugBucket) continue;
const DebugUBO outlineUBO{/*matrix = */ util::cast<float>(tile.matrix),
/*color = */ Color::white(),
/*overlay_scale = */ 1.0f,
0,
0,
0};
if (0 == updateDrawables(outlineLayerGroup, tileID, outlineUBO)) {
addDrawable(outlineLayerGroup,
tileID,
outlineUBO,
gfx::Lines(4.0f * parameters.pixelRatio),
debugBucket->vertices.vector(),
debugBucket->indices.vector(),
debugBucket->segments);
}
const DebugUBO outlineUBO{/*matrix = */ util::cast<float>(tile.matrix),
/*color = */ Color::white(),
/*overlay_scale = */ 1.0f,
0,
0,
0};
if (0 == updateDrawables(outlineLayerGroup, tileID, outlineUBO)) {
addDrawable(outlineLayerGroup,
tileID,
outlineUBO,
gfx::Lines(4.0f * parameters.pixelRatio),
debugBucket->vertices.vector(),
debugBucket->indices.vector(),
debugBucket->segments);
}
const DebugUBO textUBO{/*matrix = */ util::cast<float>(tile.matrix),
/*color = */ Color::black(),
/*overlay_scale = */ 1.0f,
0,
0,
0};
if (0 == updateDrawables(textLayerGroup, tileID, textUBO)) {
addDrawable(textLayerGroup,
tileID,
textUBO,
gfx::Lines(2.0f * parameters.pixelRatio),
debugBucket->vertices.vector(),
debugBucket->indices.vector(),
debugBucket->segments);
}
const DebugUBO textUBO{/*matrix = */ util::cast<float>(tile.matrix),
/*color = */ Color::black(),
/*overlay_scale = */ 1.0f,
0,
0,
0};
if (0 == updateDrawables(textLayerGroup, tileID, textUBO) && tile.getNeedsRendering()) {
addDrawable(textLayerGroup,
tileID,
textUBO,
gfx::Lines(2.0f * parameters.pixelRatio),
debugBucket->vertices.vector(),
debugBucket->indices.vector(),
debugBucket->segments);
}
}
} else {
@@ -223,26 +364,28 @@ void TileSourceRenderItem::updateDebugDrawables(DebugLayerGroupMap& debugLayerGr
auto indexes = RenderStaticData::tileLineStripIndices().vector();
auto segments = RenderStaticData::tileBorderSegments();
for (auto& tile : *renderTiles) {
if (tile.getNeedsRendering()) {
const auto tileID = tile.getOverscaledTileID();
const auto& debugBucket = tile.debugBucket;
if (!debugBucket) continue;
const auto tileID = tile.getOverscaledTileID();
const auto& debugBucket = tile.debugBucket;
if (!debugBucket) continue;
const DebugUBO debugUBO{/*matrix = */ util::cast<float>(tile.matrix),
/*color = */ Color::red(),
/*overlay_scale = */ 1.0f,
0,
0,
0};
if (0 == updateDrawables(tileLayerGroup, tileID, debugUBO)) {
addDrawable(tileLayerGroup,
tileID,
debugUBO,
gfx::LineStrip(4.0f * parameters.pixelRatio),
vertices,
indexes,
segments);
}
const DebugUBO debugUBO{/*matrix = */ util::cast<float>(tile.matrix),
/*color = */ Color::red(),
/*overlay_scale = */ 1.0f,
0,
0,
0};
if (0 == updateDrawables(tileLayerGroup, tileID, debugUBO) && tile.getNeedsRendering()) {
#if MLN_RENDER_BACKEND_METAL
addPolylineDrawable(tileLayerGroup, tile);
#else
addDrawable(tileLayerGroup,
tileID,
debugUBO,
gfx::LineStrip(4.0f * parameters.pixelRatio),
vertices,
indexes,
segments);
#endif
}
}
} else {