Files
MapLibreParticleLab/src/mbgl/renderer/layers/render_line_layer.cpp
Alex Cristici 61a6b66435 UBO by index instead of map (#1980)
Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
2024-01-31 22:02:05 +02:00

802 lines
37 KiB
C++

#include <mbgl/renderer/layers/render_line_layer.hpp>
#include <mbgl/geometry/feature_index.hpp>
#include <mbgl/geometry/line_atlas.hpp>
#include <mbgl/gfx/cull_face_mode.hpp>
#include <mbgl/programs/line_program.hpp>
#include <mbgl/programs/programs.hpp>
#include <mbgl/renderer/buckets/line_bucket.hpp>
#include <mbgl/renderer/image_manager.hpp>
#include <mbgl/renderer/paint_parameters.hpp>
#include <mbgl/renderer/render_source.hpp>
#include <mbgl/renderer/render_tile.hpp>
#include <mbgl/renderer/tile_render_data.hpp>
#include <mbgl/renderer/upload_parameters.hpp>
#include <mbgl/style/expression/image.hpp>
#include <mbgl/style/layers/line_layer_impl.hpp>
#include <mbgl/tile/geometry_tile.hpp>
#include <mbgl/tile/tile.hpp>
#include <mbgl/util/convert.hpp>
#include <mbgl/util/intersection_tests.hpp>
#include <mbgl/util/logging.hpp>
#include <mbgl/util/math.hpp>
#if MLN_DRAWABLE_RENDERER
#include <mbgl/gfx/drawable_atlases_tweaker.hpp>
#include <mbgl/gfx/drawable_builder.hpp>
#include <mbgl/gfx/line_drawable_data.hpp>
#include <mbgl/renderer/layer_group.hpp>
#include <mbgl/renderer/layers/line_layer_tweaker.hpp>
#include <mbgl/renderer/update_parameters.hpp>
#include <mbgl/shaders/line_layer_ubo.hpp>
#include <mbgl/shaders/shader_program_base.hpp>
#include <mbgl/util/string_indexer.hpp>
#endif
namespace mbgl {
using namespace style;
using namespace shaders;
namespace {
inline const LineLayer::Impl& impl_cast(const Immutable<style::Layer::Impl>& impl) {
assert(impl->getTypeInfo() == LineLayer::Impl::staticTypeInfo());
return static_cast<const LineLayer::Impl&>(*impl);
}
#if MLN_DRAWABLE_RENDERER
const StringIdentity idVertexAttribName = stringIndexer().get("a_pos_normal");
const StringIdentity idDataAttribName = stringIndexer().get("a_data");
#endif // MLN_DRAWABLE_RENDERER
} // namespace
RenderLineLayer::RenderLineLayer(Immutable<style::LineLayer::Impl> _impl)
: RenderLayer(makeMutable<LineLayerProperties>(std::move(_impl))),
unevaluated(impl_cast(baseImpl).paint.untransitioned()),
colorRamp(std::make_shared<PremultipliedImage>(Size(256, 1))) {}
RenderLineLayer::~RenderLineLayer() = default;
void RenderLineLayer::transition(const TransitionParameters& parameters) {
unevaluated = impl_cast(baseImpl).paint.transitioned(parameters, std::move(unevaluated));
updateColorRamp();
}
void RenderLineLayer::evaluate(const PropertyEvaluationParameters& parameters) {
auto properties = makeMutable<LineLayerProperties>(staticImmutableCast<LineLayer::Impl>(baseImpl),
parameters.getCrossfadeParameters(),
unevaluated.evaluate(parameters));
auto& evaluated = properties->evaluated;
passes = (evaluated.get<style::LineOpacity>().constantOr(1.0) > 0 &&
evaluated.get<style::LineColor>().constantOr(Color::black()).a > 0 &&
evaluated.get<style::LineWidth>().constantOr(1.0) > 0)
? RenderPass::Translucent
: RenderPass::None;
properties->renderPasses = mbgl::underlying_type(passes);
evaluatedProperties = std::move(properties);
#if MLN_DRAWABLE_RENDERER
if (layerTweaker) {
layerTweaker->updateProperties(evaluatedProperties);
}
#endif
}
bool RenderLineLayer::hasTransition() const {
return unevaluated.hasTransition();
}
bool RenderLineLayer::hasCrossfade() const {
return getCrossfade<LineLayerProperties>(evaluatedProperties).t != 1;
}
void RenderLineLayer::prepare(const LayerPrepareParameters& params) {
RenderLayer::prepare(params);
for (const RenderTile& tile : *renderTiles) {
const LayerRenderData* renderData = tile.getLayerRenderData(*baseImpl);
if (!renderData) continue;
const auto& evaluated = getEvaluated<LineLayerProperties>(renderData->layerProperties);
if (evaluated.get<LineDasharray>().from.empty()) continue;
const auto& bucket = static_cast<const LineBucket&>(*renderData->bucket);
const LinePatternCap cap = bucket.layout.get<LineCap>() == LineCapType::Round ? LinePatternCap::Round
: LinePatternCap::Square;
// Ensures that the dash data gets added to the atlas.
params.lineAtlas.getDashPatternTexture(
evaluated.get<LineDasharray>().from, evaluated.get<LineDasharray>().to, cap);
}
}
#if MLN_LEGACY_RENDERER
void RenderLineLayer::upload(gfx::UploadPass& uploadPass) {
if (!unevaluated.get<LineGradient>().getValue().isUndefined() && !colorRampTexture) {
colorRampTexture = uploadPass.createTexture(*colorRamp);
}
}
void RenderLineLayer::render(PaintParameters& parameters) {
assert(renderTiles);
if (parameters.pass == RenderPass::Opaque) {
return;
}
if (!parameters.shaders.getLegacyGroup().populate(lineProgram)) return;
if (!parameters.shaders.getLegacyGroup().populate(lineGradientProgram)) return;
if (!parameters.shaders.getLegacyGroup().populate(lineSDFProgram)) return;
if (!parameters.shaders.getLegacyGroup().populate(linePatternProgram)) return;
parameters.renderTileClippingMasks(renderTiles);
for (const RenderTile& tile : *renderTiles) {
const LayerRenderData* renderData = getRenderDataForPass(tile, parameters.pass);
if (!renderData) {
continue;
}
auto& bucket = static_cast<LineBucket&>(*renderData->bucket);
const auto& evaluated = getEvaluated<LineLayerProperties>(renderData->layerProperties);
const auto& crossfade = getCrossfade<LineLayerProperties>(renderData->layerProperties);
auto draw = [&](auto& programInstance,
auto&& uniformValues,
const std::optional<ImagePosition>& patternPositionA,
const std::optional<ImagePosition>& patternPositionB,
auto&& textureBindings) {
const auto& paintPropertyBinders = bucket.paintPropertyBinders.at(getID());
paintPropertyBinders.setPatternParameters(patternPositionA, patternPositionB, crossfade);
const auto allUniformValues = programInstance.computeAllUniformValues(
std::forward<decltype(uniformValues)>(uniformValues),
paintPropertyBinders,
evaluated,
static_cast<float>(parameters.state.getZoom()));
const auto allAttributeBindings = programInstance.computeAllAttributeBindings(
*bucket.vertexBuffer, paintPropertyBinders, evaluated);
checkRenderability(parameters, programInstance.activeBindingCount(allAttributeBindings));
programInstance.draw(parameters.context,
*parameters.renderPass,
gfx::Triangles(),
parameters.depthModeForSublayer(0, gfx::DepthMaskType::ReadOnly),
parameters.stencilModeForClipping(tile.id),
parameters.colorModeForRenderPass(),
gfx::CullFaceMode::disabled(),
*bucket.indexBuffer,
bucket.segments,
allUniformValues,
allAttributeBindings,
std::forward<decltype(textureBindings)>(textureBindings),
getID());
};
if (!evaluated.get<LineDasharray>().from.empty()) {
const LinePatternCap cap = bucket.layout.get<LineCap>() == LineCapType::Round ? LinePatternCap::Round
: LinePatternCap::Square;
const auto& dashPatternTexture = parameters.lineAtlas.getDashPatternTexture(
evaluated.get<LineDasharray>().from, evaluated.get<LineDasharray>().to, cap);
draw(*lineSDFProgram,
LineSDFProgram::layoutUniformValues(evaluated,
parameters.pixelRatio,
tile,
parameters.state,
parameters.pixelsToGLUnits,
dashPatternTexture.getFrom(),
dashPatternTexture.getTo(),
crossfade,
static_cast<float>(dashPatternTexture.getSize().width)),
{},
{},
LineSDFProgram::TextureBindings{
dashPatternTexture.textureBinding(),
});
} else if (!unevaluated.get<LinePattern>().isUndefined()) {
const auto& linePatternValue = evaluated.get<LinePattern>().constantOr(Faded<expression::Image>{"", ""});
const Size& texsize = tile.getIconAtlasTexture()->getSize();
std::optional<ImagePosition> posA = tile.getPattern(linePatternValue.from.id());
std::optional<ImagePosition> posB = tile.getPattern(linePatternValue.to.id());
draw(*linePatternProgram,
LinePatternProgram::layoutUniformValues(evaluated,
tile,
parameters.state,
parameters.pixelsToGLUnits,
parameters.pixelRatio,
texsize,
crossfade),
posA,
posB,
LinePatternProgram::TextureBindings{
tile.getIconAtlasTextureBinding(gfx::TextureFilterType::Linear),
});
} else if (!unevaluated.get<LineGradient>().getValue().isUndefined()) {
assert(colorRampTexture);
draw(*lineGradientProgram,
LineGradientProgram::layoutUniformValues(
evaluated, tile, parameters.state, parameters.pixelsToGLUnits, parameters.pixelRatio),
{},
{},
LineGradientProgram::TextureBindings{
textures::image::Value{colorRampTexture->getResource(), gfx::TextureFilterType::Linear},
});
} else {
draw(*lineProgram,
LineProgram::layoutUniformValues(
evaluated, tile, parameters.state, parameters.pixelsToGLUnits, parameters.pixelRatio),
{},
{},
LineProgram::TextureBindings{});
}
}
}
#endif // MLN_LEGACY_RENDERER
namespace {
GeometryCollection offsetLine(const GeometryCollection& rings, double offset) {
assert(offset != 0.0f);
assert(!rings.empty());
GeometryCollection newRings;
newRings.reserve(rings.size());
const Point<double> zero(0, 0);
for (const auto& ring : rings) {
newRings.emplace_back();
auto& newRing = newRings.back();
newRing.reserve(ring.size());
for (auto i = ring.begin(); i != ring.end(); ++i) {
auto& p = *i;
Point<double> aToB = i == ring.begin() ? zero : util::perp(util::unit(convertPoint<double>(p - *(i - 1))));
Point<double> bToC = i + 1 == ring.end() ? zero
: util::perp(util::unit(convertPoint<double>(*(i + 1) - p)));
Point<double> extrude = util::unit(aToB + bToC);
const double cosHalfAngle = extrude.x * bToC.x + extrude.y * bToC.y;
extrude *= (cosHalfAngle != 0) ? (1.0 / cosHalfAngle) : 0;
newRing.emplace_back(convertPoint<int16_t>(extrude * offset) + p);
}
}
return newRings;
}
} // namespace
bool RenderLineLayer::queryIntersectsFeature(const GeometryCoordinates& queryGeometry,
const GeometryTileFeature& feature,
const float zoom,
const TransformState& transformState,
const float pixelsToTileUnits,
const mat4&,
const FeatureState& featureState) const {
const auto& evaluated = static_cast<const LineLayerProperties&>(*evaluatedProperties).evaluated;
// Translate query geometry
auto translatedQueryGeometry = FeatureIndex::translateQueryGeometry(queryGeometry,
evaluated.get<style::LineTranslate>(),
evaluated.get<style::LineTranslateAnchor>(),
static_cast<float>(transformState.getBearing()),
pixelsToTileUnits);
// Evaluate function
auto offset = evaluated.get<style::LineOffset>().evaluate(
feature, zoom, featureState, style::LineOffset::defaultValue()) *
pixelsToTileUnits;
// Test intersection
const auto halfWidth = static_cast<float>(getLineWidth(feature, zoom, featureState) / 2.0 * pixelsToTileUnits);
// Apply offset to geometry
if (offset != 0.0f && !feature.getGeometries().empty()) {
return util::polygonIntersectsBufferedMultiLine(
translatedQueryGeometry.value_or(queryGeometry), offsetLine(feature.getGeometries(), offset), halfWidth);
}
return util::polygonIntersectsBufferedMultiLine(
translatedQueryGeometry.value_or(queryGeometry), feature.getGeometries(), halfWidth);
}
void RenderLineLayer::updateColorRamp() {
const style::ColorRampPropertyValue colorValue = unevaluated.get<LineGradient>().getValue();
if (!colorRamp || !applyColorRamp(colorValue, *colorRamp)) {
return;
}
colorRampTexture = std::nullopt;
#if MLN_DRAWABLE_RENDERER
if (colorRampTexture2D) {
colorRampTexture2D.reset();
// delete all gradient drawables
if (layerGroup) {
stats.drawablesRemoved += layerGroup->getDrawableCount();
layerGroup->clearDrawables();
}
}
#endif
}
float RenderLineLayer::getLineWidth(const GeometryTileFeature& feature,
const float zoom,
const FeatureState& featureState) const {
const auto& evaluated = static_cast<const LineLayerProperties&>(*evaluatedProperties).evaluated;
float lineWidth = evaluated.get<style::LineWidth>().evaluate(
feature, zoom, featureState, style::LineWidth::defaultValue());
float gapWidth = evaluated.get<style::LineGapWidth>().evaluate(
feature, zoom, featureState, style::LineGapWidth::defaultValue());
if (gapWidth) {
return gapWidth + 2 * lineWidth;
} else {
return lineWidth;
}
}
#if MLN_DRAWABLE_RENDERER
static const StringIdentity idLineImageUniformName = stringIndexer().get("u_image");
void RenderLineLayer::update(gfx::ShaderRegistry& shaders,
gfx::Context& context,
const TransformState& state,
const std::shared_ptr<UpdateParameters>&,
[[maybe_unused]] const RenderTree& renderTree,
[[maybe_unused]] UniqueChangeRequestVec& changes) {
std::unique_lock<std::mutex> guard(mutex);
if (!renderTiles || renderTiles->empty()) {
removeAllDrawables();
return;
}
// Set up a layer group
if (!layerGroup) {
if (auto layerGroup_ = context.createTileLayerGroup(layerIndex, /*initialCapacity=*/64, getID())) {
setLayerGroup(std::move(layerGroup_), changes);
} else {
return;
}
}
auto* tileLayerGroup = static_cast<TileLayerGroup*>(layerGroup.get());
if (!layerTweaker) {
layerTweaker = std::make_shared<LineLayerTweaker>(getID(), evaluatedProperties);
layerGroup->addLayerTweaker(layerTweaker);
}
if (!lineShaderGroup) {
lineShaderGroup = shaders.getShaderGroup("LineShader");
}
if (!lineGradientShaderGroup) {
lineGradientShaderGroup = shaders.getShaderGroup("LineGradientShader");
}
if (!linePatternShaderGroup) {
linePatternShaderGroup = shaders.getShaderGroup("LinePatternShader");
}
if (!lineSDFShaderGroup) {
lineSDFShaderGroup = shaders.getShaderGroup("LineSDFShader");
}
const RenderPass renderPass = static_cast<RenderPass>(evaluatedProperties->renderPasses &
~mbgl::underlying_type(RenderPass::Opaque));
stats.drawablesRemoved += tileLayerGroup->removeDrawablesIf([&](gfx::Drawable& drawable) {
// If the render pass has changed or the tile has dropped out of the cover set, remove it.
const auto& tileID = drawable.getTileID();
if (drawable.getRenderPass() != passes || (tileID && !hasRenderTile(*tileID))) {
return true;
}
return false;
});
auto createLineBuilder = [&](const std::string& name,
gfx::ShaderPtr shader) -> std::unique_ptr<gfx::DrawableBuilder> {
std::unique_ptr<gfx::DrawableBuilder> builder = context.createDrawableBuilder(name);
builder->setShader(std::static_pointer_cast<gfx::ShaderProgramBase>(shader));
builder->setRenderPass(renderPass);
builder->setSubLayerIndex(0);
builder->setDepthType(gfx::DepthMaskType::ReadOnly);
builder->setColorMode(renderPass == RenderPass::Translucent ? gfx::ColorMode::alphaBlended()
: gfx::ColorMode::unblended());
builder->setCullFaceMode(gfx::CullFaceMode::disabled());
builder->setEnableStencil(true);
builder->setVertexAttrNameId(idVertexAttribName);
return builder;
};
auto addAttributes =
[&](gfx::DrawableBuilder& builder, const LineBucket& bucket, gfx::VertexAttributeArrayPtr&& vertexAttrs) {
const auto vertexCount = bucket.vertices.elements();
builder.setRawVertices({}, vertexCount, gfx::AttributeDataType::Short4);
if (const auto& attr = vertexAttrs->add(idVertexAttribName)) {
attr->setSharedRawData(bucket.sharedVertices,
offsetof(LineLayoutVertex, a1),
/*vertexOffset=*/0,
sizeof(LineLayoutVertex),
gfx::AttributeDataType::Short2);
}
if (const auto& attr = vertexAttrs->add(idDataAttribName)) {
attr->setSharedRawData(bucket.sharedVertices,
offsetof(LineLayoutVertex, a2),
/*vertexOffset=*/0,
sizeof(LineLayoutVertex),
gfx::AttributeDataType::UByte4);
}
builder.setVertexAttributes(std::move(vertexAttrs));
};
auto setSegments = [&](std::unique_ptr<gfx::DrawableBuilder>& builder, const LineBucket& bucket) {
builder->setSegments(gfx::Triangles(), bucket.sharedTriangles, bucket.segments.data(), bucket.segments.size());
};
tileLayerGroup->setStencilTiles(renderTiles);
mbgl::unordered_set<StringIdentity> propertiesAsUniforms;
for (const RenderTile& tile : *renderTiles) {
const auto& tileID = tile.getOverscaledTileID();
const LayerRenderData* renderData = getRenderDataForPass(tile, renderPass);
if (!renderData) {
removeTile(renderPass, tileID);
continue;
}
auto& bucket = static_cast<LineBucket&>(*renderData->bucket);
if (!bucket.sharedTriangles->elements()) {
removeTile(renderPass, tileID);
continue;
}
const auto& paintPropertyBinders = bucket.paintPropertyBinders.at(getID());
const auto& evaluated = getEvaluated<LineLayerProperties>(renderData->layerProperties);
const auto& crossfade = getCrossfade<LineLayerProperties>(renderData->layerProperties);
const auto prevBucketID = getRenderTileBucketID(tileID);
if (prevBucketID != util::SimpleIdentity::Empty && prevBucketID != bucket.getID()) {
// This tile was previously set up from a different bucket, drop and re-create any drawables for it.
removeTile(renderPass, tileID);
}
setRenderTileBucketID(tileID, bucket.getID());
// interpolation UBOs
const float zoom = static_cast<float>(state.getZoom());
std::optional<LineInterpolationUBO> lineInterpolationUBO = std::nullopt;
std::optional<LineGradientInterpolationUBO> lineGradientInterpolationUBO = std::nullopt;
std::optional<LinePatternInterpolationUBO> linePatternInterpolationUBO = std::nullopt;
std::optional<LineSDFInterpolationUBO> lineSDFInterpolationUBO = std::nullopt;
auto getLineInterpolationUBO = [&]() -> const LineInterpolationUBO& {
if (!lineInterpolationUBO) {
lineInterpolationUBO = {
/*color_t =*/std::get<0>(paintPropertyBinders.get<LineColor>()->interpolationFactor(zoom)),
/*blur_t =*/std::get<0>(paintPropertyBinders.get<LineBlur>()->interpolationFactor(zoom)),
/*opacity_t =*/std::get<0>(paintPropertyBinders.get<LineOpacity>()->interpolationFactor(zoom)),
/*gapwidth_t =*/std::get<0>(paintPropertyBinders.get<LineGapWidth>()->interpolationFactor(zoom)),
/*offset_t =*/std::get<0>(paintPropertyBinders.get<LineOffset>()->interpolationFactor(zoom)),
/*width_t =*/std::get<0>(paintPropertyBinders.get<LineWidth>()->interpolationFactor(zoom)),
0,
0};
}
return *lineInterpolationUBO;
};
auto getLineGradientInterpolationUBO = [&]() -> const LineGradientInterpolationUBO& {
if (!lineGradientInterpolationUBO) {
lineGradientInterpolationUBO = {
/*blur_t =*/std::get<0>(paintPropertyBinders.get<LineBlur>()->interpolationFactor(zoom)),
/*opacity_t =*/std::get<0>(paintPropertyBinders.get<LineOpacity>()->interpolationFactor(zoom)),
/*gapwidth_t =*/std::get<0>(paintPropertyBinders.get<LineGapWidth>()->interpolationFactor(zoom)),
/*offset_t =*/std::get<0>(paintPropertyBinders.get<LineOffset>()->interpolationFactor(zoom)),
/*width_t =*/std::get<0>(paintPropertyBinders.get<LineWidth>()->interpolationFactor(zoom)),
0,
0,
0};
}
return *lineGradientInterpolationUBO;
};
auto getLinePatternInterpolationUBO = [&]() -> const LinePatternInterpolationUBO& {
if (!linePatternInterpolationUBO) {
linePatternInterpolationUBO = {
/*blur_t =*/std::get<0>(paintPropertyBinders.get<LineBlur>()->interpolationFactor(zoom)),
/*opacity_t =*/std::get<0>(paintPropertyBinders.get<LineOpacity>()->interpolationFactor(zoom)),
/*offset_t =*/std::get<0>(paintPropertyBinders.get<LineOffset>()->interpolationFactor(zoom)),
/*gapwidth_t =*/std::get<0>(paintPropertyBinders.get<LineGapWidth>()->interpolationFactor(zoom)),
/*width_t =*/std::get<0>(paintPropertyBinders.get<LineWidth>()->interpolationFactor(zoom)),
/*pattern_from_t =*/std::get<0>(paintPropertyBinders.get<LinePattern>()->interpolationFactor(zoom)),
/*pattern_to_t =*/std::get<1>(paintPropertyBinders.get<LinePattern>()->interpolationFactor(zoom)),
0};
}
return *linePatternInterpolationUBO;
};
auto getLineSDFInterpolationUBO = [&]() -> const LineSDFInterpolationUBO& {
if (!lineSDFInterpolationUBO) {
lineSDFInterpolationUBO = {
/*color_t =*/std::get<0>(paintPropertyBinders.get<LineColor>()->interpolationFactor(zoom)),
/*blur_t =*/std::get<0>(paintPropertyBinders.get<LineBlur>()->interpolationFactor(zoom)),
/*opacity_t =*/std::get<0>(paintPropertyBinders.get<LineOpacity>()->interpolationFactor(zoom)),
/*gapwidth_t =*/std::get<0>(paintPropertyBinders.get<LineGapWidth>()->interpolationFactor(zoom)),
/*offset_t =*/std::get<0>(paintPropertyBinders.get<LineOffset>()->interpolationFactor(zoom)),
/*width_t =*/std::get<0>(paintPropertyBinders.get<LineWidth>()->interpolationFactor(zoom)),
/*floorwidth_t =*/
std::get<0>(paintPropertyBinders.get<LineFloorWidth>()->interpolationFactor(zoom)),
0};
}
return *lineSDFInterpolationUBO;
};
// tile dependent properties UBOs:
std::optional<LinePatternTilePropertiesUBO> linePatternTilePropertiesUBO = std::nullopt;
const auto& linePatternValue = evaluated.get<LinePattern>().constantOr(Faded<expression::Image>{"", ""});
const std::optional<ImagePosition> patternPosA = tile.getPattern(linePatternValue.from.id());
const std::optional<ImagePosition> patternPosB = tile.getPattern(linePatternValue.to.id());
auto getLinePatternTilePropertiesUBO = [&]() -> const LinePatternTilePropertiesUBO& {
if (!linePatternTilePropertiesUBO) {
linePatternTilePropertiesUBO = {
/*pattern_from =*/patternPosA ? util::cast<float>(patternPosA->tlbr()) : std::array<float, 4>{0},
/*pattern_to =*/patternPosB ? util::cast<float>(patternPosB->tlbr()) : std::array<float, 4>{0}};
}
return *linePatternTilePropertiesUBO;
};
auto updateExisting = [&](gfx::Drawable& drawable) {
if (drawable.getLayerTweaker() != layerTweaker) {
// This drawable was produced on a previous style/bucket, and should not be updated.
return false;
}
auto& drawableUniforms = drawable.mutableUniformBuffers();
const LineLayerTweaker::LineType type = static_cast<LineLayerTweaker::LineType>(drawable.getType());
switch (type) {
case LineLayerTweaker::LineType::Simple: {
drawableUniforms.createOrUpdate(idLineInterpolationUBO, &getLineInterpolationUBO(), context);
} break;
case LineLayerTweaker::LineType::Gradient: {
drawableUniforms.createOrUpdate(
idLineGradientInterpolationUBO, &getLineGradientInterpolationUBO(), context);
} break;
case LineLayerTweaker::LineType::Pattern: {
drawableUniforms.createOrUpdate(
idLinePatternInterpolationUBO, &getLinePatternInterpolationUBO(), context);
drawableUniforms.createOrUpdate(
idLinePatternTilePropertiesUBO, &getLinePatternTilePropertiesUBO(), context);
} break;
case LineLayerTweaker::LineType::SDF: {
drawableUniforms.createOrUpdate(idLineSDFInterpolationUBO, &getLineSDFInterpolationUBO(), context);
} break;
default: {
using namespace std::string_literals;
Log::Error(Event::General,
"RenderLineLayer: unknown line type: "s + std::to_string(mbgl::underlying_type(type)));
} break;
}
return true;
};
if (updateTile(renderPass, tileID, std::move(updateExisting))) {
continue;
}
if (!evaluated.get<LineDasharray>().from.empty()) {
if (!lineSDFShaderGroup) {
continue;
}
// dash array line (SDF)
propertiesAsUniforms.clear();
auto vertexAttrs = context.createVertexAttributeArray();
vertexAttrs->readDataDrivenPaintProperties<LineColor,
LineBlur,
LineOpacity,
LineGapWidth,
LineOffset,
LineWidth,
LineFloorWidth>(
paintPropertyBinders, evaluated, propertiesAsUniforms);
auto shader = lineSDFShaderGroup->getOrCreateShader(context, propertiesAsUniforms);
if (!shader) {
continue;
}
auto builder = createLineBuilder("lineSDF", std::move(shader));
// vertices, attributes and segments
addAttributes(*builder, bucket, std::move(vertexAttrs));
setSegments(builder, bucket);
// finish
builder->flush(context);
const LinePatternCap cap = bucket.layout.get<LineCap>() == LineCapType::Round ? LinePatternCap::Round
: LinePatternCap::Square;
for (auto& drawable : builder->clearDrawables()) {
drawable->setType(mbgl::underlying_type(LineLayerTweaker::LineType::SDF));
drawable->setTileID(tileID);
drawable->setLayerTweaker(layerTweaker);
drawable->setData(std::make_unique<gfx::LineDrawableData>(cap));
drawable->mutableUniformBuffers().createOrUpdate(
idLineSDFInterpolationUBO, &getLineSDFInterpolationUBO(), context);
tileLayerGroup->addDrawable(renderPass, tileID, std::move(drawable));
++stats.drawablesAdded;
}
} else if (!unevaluated.get<LinePattern>().isUndefined()) {
if (!linePatternShaderGroup) {
continue;
}
// pattern line
paintPropertyBinders.setPatternParameters(patternPosA, patternPosB, crossfade);
propertiesAsUniforms.clear();
auto vertexAttrs = context.createVertexAttributeArray();
vertexAttrs->readDataDrivenPaintProperties<LineBlur,
LineOpacity,
LineOffset,
LineGapWidth,
LineWidth,
LinePattern>(
paintPropertyBinders, evaluated, propertiesAsUniforms);
auto shader = linePatternShaderGroup->getOrCreateShader(context, propertiesAsUniforms);
if (!shader) {
continue;
}
auto builder = createLineBuilder("linePattern", std::move(shader));
// vertices and attributes
addAttributes(*builder, bucket, std::move(vertexAttrs));
// texture
if (const auto& atlases = tile.getAtlasTextures(); atlases && atlases->icon) {
if (!iconTweaker) {
iconTweaker = std::make_shared<gfx::DrawableAtlasesTweaker>(
atlases,
0,
idLineImageUniformName,
/*isText*/ false,
/*sdfIcons*/ true, // to force linear filter
/*rotationAlignment_*/ AlignmentType::Auto,
/*iconScaled*/ false,
/*textSizeIsZoomConstant_*/ false);
}
builder->addTweaker(iconTweaker);
setSegments(builder, bucket);
builder->flush(context);
for (auto& drawable : builder->clearDrawables()) {
drawable->setType(mbgl::underlying_type(LineLayerTweaker::LineType::Pattern));
drawable->setTileID(tileID);
drawable->setLayerTweaker(layerTweaker);
drawable->mutableUniformBuffers().createOrUpdate(
idLinePatternInterpolationUBO, &getLinePatternInterpolationUBO(), context);
drawable->mutableUniformBuffers().createOrUpdate(
idLinePatternTilePropertiesUBO, &getLinePatternTilePropertiesUBO(), context);
tileLayerGroup->addDrawable(renderPass, tileID, std::move(drawable));
++stats.drawablesAdded;
}
}
} else if (!unevaluated.get<LineGradient>().getValue().isUndefined()) {
if (!lineGradientShaderGroup) {
continue;
}
// gradient line
propertiesAsUniforms.clear();
auto vertexAttrs = context.createVertexAttributeArray();
vertexAttrs->readDataDrivenPaintProperties<LineBlur, LineOpacity, LineGapWidth, LineOffset, LineWidth>(
paintPropertyBinders, evaluated, propertiesAsUniforms);
auto shader = lineGradientShaderGroup->getOrCreateShader(context, propertiesAsUniforms);
if (!shader) {
continue;
}
auto builder = createLineBuilder("lineGradient", std::move(shader));
// vertices and attributes
addAttributes(*builder, bucket, std::move(vertexAttrs));
// texture
if (const auto samplerLocation = builder->getShader()->getSamplerLocation(idLineImageUniformName)) {
if (!colorRampTexture2D && colorRamp->valid()) {
// create texture. to be reused for all the tiles of the layer
colorRampTexture2D = context.createTexture2D();
colorRampTexture2D->setImage(colorRamp);
colorRampTexture2D->setSamplerConfiguration(
{gfx::TextureFilterType::Linear, gfx::TextureWrapType::Clamp, gfx::TextureWrapType::Clamp});
}
if (colorRampTexture2D) {
builder->setTexture(colorRampTexture2D, samplerLocation.value());
// segments
setSegments(builder, bucket);
// finish
builder->flush(context);
for (auto& drawable : builder->clearDrawables()) {
drawable->setType(mbgl::underlying_type(LineLayerTweaker::LineType::Gradient));
drawable->setTileID(tileID);
drawable->setLayerTweaker(layerTweaker);
drawable->mutableUniformBuffers().createOrUpdate(
idLineGradientInterpolationUBO, &getLineGradientInterpolationUBO(), context);
tileLayerGroup->addDrawable(renderPass, tileID, std::move(drawable));
++stats.drawablesAdded;
}
}
}
} else {
if (!lineShaderGroup) {
continue;
}
// simple line
propertiesAsUniforms.clear();
auto vertexAttrs = context.createVertexAttributeArray();
vertexAttrs
->readDataDrivenPaintProperties<LineColor, LineBlur, LineOpacity, LineGapWidth, LineOffset, LineWidth>(
paintPropertyBinders, evaluated, propertiesAsUniforms);
auto shader = lineShaderGroup->getOrCreateShader(context, propertiesAsUniforms);
if (!shader) {
continue;
}
auto builder = createLineBuilder("line", std::move(shader));
// vertices, attributes and segments
addAttributes(*builder, bucket, std::move(vertexAttrs));
setSegments(builder, bucket);
// finish
builder->flush(context);
for (auto& drawable : builder->clearDrawables()) {
drawable->setType(mbgl::underlying_type(LineLayerTweaker::LineType::Simple));
drawable->setTileID(tileID);
drawable->setLayerTweaker(layerTweaker);
drawable->mutableUniformBuffers().createOrUpdate(
idLineInterpolationUBO, &getLineInterpolationUBO(), context);
tileLayerGroup->addDrawable(renderPass, tileID, std::move(drawable));
++stats.drawablesAdded;
}
}
}
}
#endif
} // namespace mbgl