Merge branch 'topic/metal-sep21' into main (#1695)

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: Tim Sylvester <tim@wetdogweather.com>
Co-authored-by: Bart Louwers <bart@emeel.net>
Co-authored-by: Alex Cristici <alex.cristici@gmail.com>
Co-authored-by: Stefan Karschti <stefan.karschti@gmail.com>
Co-authored-by: Alex Cristici <alex@skoon.energy>
Co-authored-by: Bart Louwers <bart.louwers@gmail.com>
Co-authored-by: Wei Chen <alanchenboy@gmail.com>
Co-authored-by: Siarhei Fedartsou <siarhei.fedartsou@gmail.com>
Co-authored-by: tdcosta100 <tdcosta100@gmail.com>
This commit is contained in:
mwilsnd
2023-10-02 09:22:19 -04:00
committed by GitHub
parent 34a2097bdd
commit f4d3cb6b69
48 changed files with 754 additions and 576 deletions

View File

@@ -11,6 +11,7 @@
#include <mbgl/gfx/cull_face_mode.hpp>
#include <mbgl/math/angles.hpp>
#include <mbgl/style/layers/raster_layer_impl.hpp>
#include <mbgl/util/logging.hpp>
#if MLN_DRAWABLE_RENDERER
#include <mbgl/renderer/layers/raster_layer_tweaker.hpp>
@@ -53,7 +54,10 @@ void RenderRasterLayer::evaluate(const PropertyEvaluationParameters& parameters)
evaluatedProperties = std::move(properties);
#if MLN_DRAWABLE_RENDERER
updateLayerTweaker();
if (layerGroup) {
auto newTweaker = std::make_shared<RasterLayerTweaker>(getID(), evaluatedProperties);
replaceTweaker(layerTweaker, std::move(newTweaker), {layerGroup, imageLayerGroup});
}
#endif
}
@@ -247,19 +251,6 @@ static const StringIdentity idTexturePosAttribName = StringIndexer::get("a_textu
static const StringIdentity idTexImage0Name = StringIndexer::get("u_image0");
static const StringIdentity idTexImage1Name = StringIndexer::get("u_image1");
void RenderRasterLayer::updateLayerTweaker() {
if (layerGroup || imageLayerGroup) {
tweaker = std::make_shared<RasterLayerTweaker>(getID(), evaluatedProperties);
tweaker->enableOverdrawInspector(overdrawInspector);
if (layerGroup) {
layerGroup->setLayerTweaker(tweaker);
}
if (imageLayerGroup) {
imageLayerGroup->setLayerTweaker(tweaker);
}
}
}
void RenderRasterLayer::update(gfx::ShaderRegistry& shaders,
gfx::Context& context,
const TransformState& /*state*/,
@@ -278,22 +269,28 @@ void RenderRasterLayer::update(gfx::ShaderRegistry& shaders,
return;
}
auto renderPass = RenderPass::Translucent;
constexpr auto renderPass = RenderPass::Translucent;
if (!rasterShader) {
rasterShader = context.getGenericShader(shaders, "RasterShader");
if (!rasterShader) {
return;
}
rasterSampler0 = rasterShader->getSamplerLocation(idTexImage0Name);
rasterSampler1 = rasterShader->getSamplerLocation(idTexImage1Name);
}
const bool overdraw = !!(updateParameters->debugOptions & MapDebugOptions::Overdraw);
if (overdrawInspector != overdraw) {
overdrawInspector = overdraw;
if (tweaker) {
tweaker->enableOverdrawInspector(overdrawInspector);
if (!layerTweaker) {
layerTweaker = std::make_shared<RasterLayerTweaker>(getID(), evaluatedProperties);
if (layerGroup) {
layerGroup->addLayerTweaker(layerTweaker);
}
if (imageLayerGroup) {
imageLayerGroup->addLayerTweaker(layerTweaker);
}
}
layerTweaker->enableOverdrawInspector(!!(updateParameters->debugOptions & MapDebugOptions::Overdraw));
if (!staticDataVertices) {
staticDataVertices = std::make_shared<RasterVertexVector>(RenderStaticData::rasterVertices());
@@ -305,61 +302,65 @@ void RenderRasterLayer::update(gfx::ShaderRegistry& shaders,
staticDataSegments = std::make_shared<RasterSegmentVector>(RenderStaticData::rasterSegments());
}
const auto& evaluated = static_cast<const RasterLayerProperties&>(*evaluatedProperties).evaluated;
RasterProgram::Binders paintAttributeData{evaluated, 0};
const gfx::TextureFilterType filter = evaluated.get<RasterResampling>() == RasterResamplingType::Nearest
? gfx::TextureFilterType::Nearest
: gfx::TextureFilterType::Linear;
auto createBuilder = [&context, &renderPass, this]() -> std::unique_ptr<gfx::DrawableBuilder> {
std::unique_ptr<gfx::DrawableBuilder> builder{context.createDrawableBuilder("raster")};
const auto createBuilder = [&] {
auto builder = context.createDrawableBuilder("raster");
builder->setShader(rasterShader);
builder->setRenderPass(renderPass);
builder->setSubLayerIndex(0);
builder->setDepthType((renderPass == RenderPass::Opaque) ? gfx::DepthMaskType::ReadWrite
: gfx::DepthMaskType::ReadOnly);
builder->setDepthType(gfx::DepthMaskType::ReadOnly);
builder->setColorMode(gfx::ColorMode::alphaBlended());
builder->setCullFaceMode(gfx::CullFaceMode::disabled());
builder->setVertexAttrNameId(idPosAttribName);
return builder;
};
auto setTextures = [&context, &filter, this](std::unique_ptr<gfx::DrawableBuilder>& builder,
const RasterBucket& bucket) {
// textures
auto location0 = rasterShader->getSamplerLocation(idTexImage0Name);
if (location0.has_value()) {
std::shared_ptr<gfx::Texture2D> tex0 = context.createTexture2D();
tex0->setImage(bucket.image);
tex0->setSamplerConfiguration({filter, gfx::TextureWrapType::Clamp, gfx::TextureWrapType::Clamp});
builder->setTexture(tex0, location0.value());
}
auto location1 = rasterShader->getSamplerLocation(idTexImage1Name);
if (location1.has_value()) {
std::shared_ptr<gfx::Texture2D> tex1 = context.createTexture2D();
tex1->setImage(bucket.image);
tex1->setSamplerConfiguration({filter, gfx::TextureWrapType::Clamp, gfx::TextureWrapType::Clamp});
builder->setTexture(tex1, location1.value());
const auto setTextures = [&](gfx::UniqueDrawableBuilder& builder, RasterBucket& bucket) {
if (bucket.image && (rasterSampler0 || rasterSampler1)) {
if (!bucket.texture2d) {
if (auto tex = context.createTexture2D()) {
tex->setImage(bucket.image);
bucket.texture2d = std::move(tex);
}
}
if (bucket.texture2d) {
const auto& evaluated = static_cast<const RasterLayerProperties&>(*evaluatedProperties).evaluated;
const bool nearest = evaluated.get<RasterResampling>() == RasterResamplingType::Nearest;
const auto filter = nearest ? gfx::TextureFilterType::Nearest : gfx::TextureFilterType::Linear;
bucket.texture2d->setSamplerConfiguration(
{filter, gfx::TextureWrapType::Clamp, gfx::TextureWrapType::Clamp});
if (rasterSampler0) {
builder->setTexture(bucket.texture2d, *rasterSampler0);
}
if (rasterSampler1) {
builder->setTexture(bucket.texture2d, *rasterSampler1);
}
}
}
};
auto buildVertexData = [this](std::unique_ptr<gfx::DrawableBuilder>& builder, const RasterBucket& bucket) {
RasterVertexVectorPtr vertices = staticDataVertices;
TriangleIndexVectorPtr indices = staticDataIndices;
const RasterSegmentVector* segments = staticDataSegments.get();
// Build vertex attributes and apply them to a drawable or a builder.
// Populates a drawable xor a drawable builder for creates and updates, respectively.
// Returns false if the drawable must be re-created.
const auto buildVertexData =
[this](const gfx::UniqueDrawableBuilder& builder, gfx::Drawable* drawable, const RasterBucket& bucket) {
// The bucket only fills in geometry for masked tiles,
// otherwise the standard tile extent geometry should be used.
const bool shared = (!bucket.sharedVertices->empty() && !bucket.sharedTriangles->empty() &&
!bucket.segments.empty());
const auto& vertices = shared ? bucket.sharedVertices : staticDataVertices;
const auto& indices = shared ? bucket.sharedTriangles : staticDataIndices;
const auto* segments = shared ? &bucket.segments : staticDataSegments.get();
if (!bucket.vertices.empty() && !bucket.indices.empty() && !bucket.segments.empty()) {
vertices = bucket.sharedVertices;
indices = bucket.sharedTriangles;
segments = &bucket.segments;
}
// The bucket may later add, remove, or change masking. In that case, the tile's
// shared data and segments are not updated, and it needs to be re-created.
if (drawable && (bucket.sharedVertices->getDirty() || bucket.sharedTriangles->getDirty())) {
return false;
}
// attributes
{
gfx::VertexAttributeArray vertexAttrs;
if (auto& attr = vertexAttrs.add(idPosAttribName)) {
attr->setSharedRawData(vertices,
offsetof(RasterLayoutVertex, a1),
@@ -376,109 +377,128 @@ void RenderRasterLayer::update(gfx::ShaderRegistry& shaders,
gfx::AttributeDataType::Short2);
}
builder->setVertexAttributes(std::move(vertexAttrs));
assert(!!drawable ^ !!builder);
if (drawable) {
drawable->setVertexAttributes(std::move(vertexAttrs));
} else if (builder) {
builder->setVertexAttributes(std::move(vertexAttrs));
builder->setRawVertices({}, vertices->elements(), gfx::AttributeDataType::Short2);
builder->setSegments(gfx::Triangles(), indices, segments->data(), segments->size());
}
return true;
};
gfx::UniqueDrawableBuilder builder;
if (imageData) {
// TODO: Can we avoid rebuilding drawables each time in this case as well?
if (imageLayerGroup) {
stats.drawablesRemoved += imageLayerGroup->clearDrawables();
}
builder->setRawVertices({}, vertices->elements(), gfx::AttributeDataType::Short2);
builder->setSegments(gfx::Triangles(), indices, segments->data(), segments->size());
};
auto buildDrawables = [&setTextures, &buildVertexData](std::unique_ptr<gfx::DrawableBuilder>& builder,
const RasterBucket& bucket) {
buildVertexData(builder, bucket);
setTextures(builder, bucket);
};
auto updateTileDrawables = [&](std::unique_ptr<gfx::DrawableBuilder>& builder,
auto* tileLayerGroup,
const auto& tileID,
const RasterBucket& bucket) {
// TODO: check for oportunity to skip
buildVertexData(builder, bucket);
tileLayerGroup->visitDrawables(renderPass, tileID, [&](gfx::Drawable& drawable) {
for (auto& tex : drawable.getTextures()) {
builder->setTexture(tex.second, tex.first);
}
});
};
if (imageData) {
RasterBucket& bucket = *imageData->bucket;
if (!bucket.vertices.empty()) {
if (imageLayerGroup) {
stats.drawablesRemoved += imageLayerGroup->clearDrawables();
} else {
if (!imageLayerGroup) {
// Set up a layer group
imageLayerGroup = context.createLayerGroup(layerIndex, /*initialCapacity=*/64, getID());
imageLayerGroup->addLayerTweaker(layerTweaker);
activateLayerGroup(imageLayerGroup, isRenderable, changes);
updateLayerTweaker();
}
auto builder = createBuilder();
// Create a drawable for each transformation
// TODO: Share textures
builder = createBuilder();
for (const auto& matrix_ : imageData->matrices) {
buildDrawables(builder, bucket);
buildVertexData(builder, /*drawable=*/nullptr, bucket);
setTextures(builder, bucket);
// finish
builder->flush();
for (auto& drawable : builder->clearDrawables()) {
drawable->setData(std::make_unique<gfx::ImageDrawableData>(matrix_));
drawable->setLayerTweaker(layerTweaker);
imageLayerGroup->addDrawable(std::move(drawable));
++stats.drawablesAdded;
}
}
}
} else if (renderTiles) {
// Remove existing drawables that are no longer in the cover set
if (layerGroup) {
stats.drawablesRemoved += layerGroup->removeDrawablesIf([&](gfx::Drawable& drawable) {
// Has this tile dropped out of the cover set?
return drawable.getTileID() && !hasRenderTile(*drawable.getTileID());
});
stats.drawablesRemoved += layerGroup->removeDrawablesIf(
[&](gfx::Drawable& drawable) { return drawable.getTileID() && !hasRenderTile(*drawable.getTileID()); });
} else {
// Set up a tile layer group
if (auto layerGroup_ = context.createTileLayerGroup(layerIndex, /*initialCapacity=*/64, getID())) {
layerGroup_->addLayerTweaker(layerTweaker);
setLayerGroup(std::move(layerGroup_), changes);
updateLayerTweaker();
}
}
auto* tileLayerGroup = static_cast<TileLayerGroup*>(layerGroup.get());
auto builder = createBuilder();
for (const RenderTile& tile : *renderTiles) {
const auto& tileID = tile.getOverscaledTileID();
const auto* bucket_ = tile.getBucket(*baseImpl);
auto* bucket_ = tile.getBucket(*baseImpl);
if (!bucket_ || !bucket_->hasData()) {
removeTile(renderPass, tileID);
continue;
}
const auto& bucket = static_cast<const RasterBucket&>(*bucket_);
bool cleared = false;
auto& bucket = static_cast<RasterBucket&>(*bucket_);
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.
// If the bucket data has changed, rebuild the drawables.
const bool bucketSharedData = (!bucket.vertices.empty() && !bucket.indices.empty() &&
!bucket.segments.empty());
const bool bucketDirty = bucketSharedData && (bucket.vertices.getDirty() || bucket.indices.getDirty());
if (bucketDirty) {
// Note, vertex/index dirty flags will be reset when those buffers are uploaded.
removeTile(renderPass, tileID);
cleared = true;
} else if (setRenderTileBucketID(tileID, bucket.getID())) {
// Bucket ID changed, we need to rebuild the drawables
removeTile(renderPass, tileID);
cleared = true;
}
setRenderTileBucketID(tileID, bucket.getID());
if (tileLayerGroup->getDrawableCount(renderPass, tileID) > 0) {
// re-create drawable geometry and pass texture
updateTileDrawables(builder, tileLayerGroup, tileID, bucket);
if (!cleared) {
// Update existing drawables
bool geometryChanged = false;
const auto updated = tileLayerGroup->visitDrawables(renderPass, tileID, [&](gfx::Drawable& drawable) {
gfx::UniqueDrawableBuilder none;
if (!geometryChanged && !buildVertexData(none, &drawable, bucket)) {
// Masking changed, need to rebuild this tile
geometryChanged = true;
}
});
// erase current drawable
removeTile(renderPass, tileID);
} else if (bucket.image) {
// build new drawable for this tile
buildDrawables(builder, bucket);
if (geometryChanged) {
removeTile(renderPass, tileID);
cleared = true;
} else if (0 < updated) {
// If we modified drawables without removing them, we're done with this tile.
continue;
}
}
// Otherwise, create new ones.
if (!builder) {
builder = createBuilder();
}
if (bucket.image && builder->getTextures().size() == 0) {
setTextures(builder, bucket);
};
buildVertexData(builder, /*drawable=*/nullptr, bucket);
// finish
builder->flush();
for (auto& drawable : builder->clearDrawables()) {
drawable->setTileID(tileID);
drawable->setLayerTweaker(layerTweaker);
tileLayerGroup->addDrawable(renderPass, tileID, std::move(drawable));
++stats.drawablesAdded;
}