Handle the case where styles update without a bucket change, fixing `… (#1874)

This commit is contained in:
Tim Sylvester
2023-11-17 09:44:00 -08:00
committed by GitHub
parent b01c6270d4
commit 4150c8b851
9 changed files with 97 additions and 62 deletions

View File

@@ -365,13 +365,14 @@ void RenderCircleLayer::update(gfx::ShaderRegistry& shaders,
auto updateExisting = [&](gfx::Drawable& drawable) {
if (drawable.getLayerTweaker() != layerTweaker) {
// This drawable was produced on a previous style/bucket, and should not be updated.
return;
return false;
}
auto& uniforms = drawable.mutableUniformBuffers();
uniforms.createOrUpdate(idCircleInterpolateUBOName, &interpolateUBO, context);
return true;
};
if (0 < tileLayerGroup->visitDrawables(renderPass, tileID, std::move(updateExisting))) {
if (updateTile(renderPass, tileID, std::move(updateExisting))) {
continue;
}

View File

@@ -404,24 +404,18 @@ void RenderFillExtrusionLayer::update(gfx::ShaderRegistry& shaders,
};
// If we already have drawables for this tile, update them.
if (tileLayerGroup->getDrawableCount(drawPass, tileID) > 0) {
// Just update the drawables we already created
tileLayerGroup->visitDrawables(drawPass, tileID, [&](gfx::Drawable& drawable) {
if (drawable.getLayerTweaker() != layerTweaker) {
// This drawable was produced on a previous style/bucket, and should not be updated.
return;
}
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& uniforms = drawable.mutableUniformBuffers();
uniforms.createOrUpdate(
FillExtrusionLayerTweaker::idFillExtrusionTilePropsUBOName, &tilePropsUBO, context);
uniforms.createOrUpdate(
FillExtrusionLayerTweaker::idFillExtrusionInterpolateUBOName, &interpUBO, context);
});
continue;
}
if (!shaderGroup) {
auto& uniforms = drawable.mutableUniformBuffers();
uniforms.createOrUpdate(FillExtrusionLayerTweaker::idFillExtrusionTilePropsUBOName, &tilePropsUBO, context);
uniforms.createOrUpdate(FillExtrusionLayerTweaker::idFillExtrusionInterpolateUBOName, &interpUBO, context);
return true;
};
if (updateTile(drawPass, tileID, std::move(updateExisting))) {
continue;
}

View File

@@ -518,7 +518,7 @@ void RenderFillLayer::update(gfx::ShaderRegistry& shaders,
auto updateExisting = [&](gfx::Drawable& drawable) {
if (drawable.getLayerTweaker() != layerTweaker) {
// This drawable was produced on a previous style/bucket, and should not be updated.
return;
return false;
}
auto& uniforms = drawable.mutableUniformBuffers();
@@ -539,8 +539,9 @@ void RenderFillLayer::update(gfx::ShaderRegistry& shaders,
}
drawable.setVertexAttributes(vertexAttrs);
return true;
};
if (0 < tileLayerGroup->visitDrawables(renderPass, tileID, std::move(updateExisting))) {
if (updateTile(renderPass, tileID, std::move(updateExisting))) {
continue;
}

View File

@@ -491,7 +491,7 @@ void RenderHillshadeLayer::update(gfx::ShaderRegistry& shaders,
// Only current drawables are updated, ones produced for
// a previous style retain the attribute values for that style.
if (drawable.getLayerTweaker() != layerTweaker) {
return;
return false;
}
drawable.setVertexAttributes(std::move(hillshadeVertexAttrs));
@@ -516,8 +516,9 @@ void RenderHillshadeLayer::update(gfx::ShaderRegistry& shaders,
if (hillshadeImageLocation) {
drawable.setTexture(bucket.renderTarget->getTexture(), *hillshadeImageLocation);
}
return true;
};
if (0 < tileLayerGroup->visitDrawables(renderPass, tileID, std::move(updateExisting))) {
if (updateTile(renderPass, tileID, std::move(updateExisting))) {
continue;
}

View File

@@ -537,11 +537,10 @@ void RenderLineLayer::update(gfx::ShaderRegistry& shaders,
/*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}};
// update existing drawables
tileLayerGroup->visitDrawables(renderPass, tileID, [&](gfx::Drawable& drawable) {
auto updateExisting = [&](gfx::Drawable& drawable) {
if (drawable.getLayerTweaker() != layerTweaker) {
// This drawable was produced on a previous style/bucket, and should not be updated.
return;
return false;
}
const auto& shader = drawable.getShader();
@@ -572,9 +571,9 @@ void RenderLineLayer::update(gfx::ShaderRegistry& shaders,
}
// TODO: vertex attributes or `propertiesAsUniforms` updated, is that needed?
});
if (tileLayerGroup->getDrawableCount(renderPass, tileID) > 0) {
return true;
};
if (updateTile(renderPass, tileID, std::move(updateExisting))) {
continue;
}

View File

@@ -466,20 +466,26 @@ void RenderRasterLayer::update(gfx::ShaderRegistry& shaders,
if (!cleared) {
// Update existing drawables
bool geometryChanged = false;
const auto updated = tileLayerGroup->visitDrawables(renderPass, tileID, [&](gfx::Drawable& drawable) {
auto updateExisting = [&](gfx::Drawable& drawable) {
// Only current drawables are updated, ones produced for
// a previous style retain the attribute values for that style.
if (drawable.getLayerTweaker() != layerTweaker) {
return false;
}
gfx::UniqueDrawableBuilder none;
if (!geometryChanged && !buildVertexData(none, &drawable, bucket)) {
// Masking changed, need to rebuild this tile
geometryChanged = true;
}
});
if (geometryChanged) {
removeTile(renderPass, tileID);
// cleared = true;
} else if (0 < updated) {
return true;
};
if (updateTile(renderPass, tileID, std::move(updateExisting))) {
// If we modified drawables without removing them, we're done with this tile.
continue;
} else if (geometryChanged) {
// If the geometry has changed, the drawable needs to be re-built
removeTile(renderPass, tileID);
}
}

View File

@@ -1148,35 +1148,34 @@ void RenderSymbolLayer::update(gfx::ShaderRegistry& shaders,
};
// If we already have drawables for this tile, update them.
if (tileLayerGroup->getDrawableCount(passes, tileID) > 0) {
gfx::UniformBufferPtr textInterpUBO, iconInterpUBO;
// Just update the drawables we already created
gfx::UniformBufferPtr textInterpUBO, iconInterpUBO;
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;
}
// Just update the drawables we already created
tileLayerGroup->visitDrawables(passes, tileID, [&](gfx::Drawable& drawable) {
if (drawable.getLayerTweaker() != layerTweaker) {
// This drawable was produced on a previous style/bucket, and should not be updated.
return;
}
propertiesAsUniforms.clear();
propertiesAsUniforms.clear();
const auto& evaluated = getEvaluated<SymbolLayerProperties>(renderData.layerProperties);
updateTileDrawable(drawable,
context,
bucket,
bucketPaintProperties,
evaluated,
state,
textInterpUBO,
iconInterpUBO,
propertiesAsUniforms);
// We assume that the properties-as-uniforms doesn't change without the style changing.
// That would require updating the shader as well.
[[maybe_unused]] const auto& drawData = static_cast<gfx::SymbolDrawableData&>(*drawable.getData());
assert(drawData.propertiesAsUniforms == toMap(propertiesAsUniforms));
});
const auto& evaluated = getEvaluated<SymbolLayerProperties>(renderData.layerProperties);
updateTileDrawable(drawable,
context,
bucket,
bucketPaintProperties,
evaluated,
state,
textInterpUBO,
iconInterpUBO,
propertiesAsUniforms);
// We assume that the properties-as-uniforms doesn't change without the style changing.
// That would require updating the shader as well.
[[maybe_unused]] const auto& drawData = static_cast<gfx::SymbolDrawableData&>(*drawable.getData());
assert(drawData.propertiesAsUniforms == toMap(propertiesAsUniforms));
return true;
};
if (updateTile(passes, tileID, std::move(updateExisting))) {
// re-create collision drawables
if (collisionTileLayerGroup) {
collisionTileLayerGroup->removeDrawables(passes, tileID);

View File

@@ -166,6 +166,30 @@ const LayerRenderData* RenderLayer::getRenderDataForPass(const RenderTile& tile,
}
#if MLN_DRAWABLE_RENDERER
bool RenderLayer::updateTile(RenderPass renderPass,
const OverscaledTileID& tileID,
std::function<bool(gfx::Drawable&)> update) {
bool anyUpdated = false;
if (const auto tileGroup = static_cast<TileLayerGroup*>(layerGroup.get())) {
bool unUpdatedDrawables = false;
tileGroup->visitDrawables(renderPass, tileID, [&](gfx::Drawable& drawable) {
if (update(drawable)) {
anyUpdated = true;
} else {
unUpdatedDrawables = true;
}
});
// If any are updated, the caller shouldn't add new ones.
// If none are updated and some were skipped, remove those.
// This is to handle the case that the style layer changes but the bucket is not re-created.
if (!anyUpdated && unUpdatedDrawables) {
removeTile(renderPass, tileID);
}
}
return anyUpdated;
}
std::size_t RenderLayer::removeTile(RenderPass renderPass, const OverscaledTileID& tileID) {
if (const auto tileGroup = static_cast<TileLayerGroup*>(layerGroup.get())) {
const auto n = tileGroup->removeDrawables(renderPass, tileID).size();

View File

@@ -209,6 +209,16 @@ protected:
/// Change the layer index on a layer group associated with this layer
void changeLayerIndex(const LayerGroupBasePtr&, int32_t newLayerIndex, UniqueChangeRequestVec&);
/// Update the drawables for a tile.
/// @param renderPass The pass to consider
/// @param tileID The tile to consider
/// @param updateFunction A function that updates a single drawable. Should return true if the drawable
/// was updated or false if it was skipped because it's for a previous style.
/// @return true if drawables were updated
bool updateTile(RenderPass renderPass,
const OverscaledTileID& tileID,
std::function<bool(gfx::Drawable&)> updateFunction);
/// Remove all drawables for the tile from the layer group
/// @return The number of drawables actually removed.
virtual std::size_t removeTile(RenderPass, const OverscaledTileID&);