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:
@@ -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;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user