Files
MapLibreParticleLab/src/mbgl/renderer/retained_underlay_cache.cpp
tei 8b9ab30322
Some checks failed
validate-scripts / validate-scripts (push) Has been cancelled
feat: add retained underlay render cache poc
2026-09-21 22:53:00 +09:00

150 lines
6.2 KiB
C++

#include <mbgl/renderer/retained_underlay_cache.hpp>
#include <mbgl/gfx/color_mode.hpp>
#include <mbgl/gfx/context.hpp>
#include <mbgl/gfx/cull_face_mode.hpp>
#include <mbgl/gfx/drawable_builder.hpp>
#include <mbgl/gfx/offscreen_texture.hpp>
#include <mbgl/gfx/render_pass.hpp>
#include <mbgl/gfx/upload_pass.hpp>
#include <mbgl/gfx/vertex_attribute.hpp>
#include <mbgl/particle/renderer_debug_counters.hpp>
#include <mbgl/renderer/buckets/heatmap_bucket.hpp>
#include <mbgl/renderer/layer_group.hpp>
#include <mbgl/renderer/paint_parameters.hpp>
#include <mbgl/renderer/render_orchestrator.hpp>
#include <mbgl/renderer/render_static_data.hpp>
#include <mbgl/shaders/shader_defines.hpp>
namespace mbgl {
namespace {
constexpr auto CompositeShaderName = "RetainedUnderlayCompositeShader";
}
RetainedUnderlayCache::RetainedUnderlayCache() = default;
RetainedUnderlayCache::~RetainedUnderlayCache() = default;
RetainedUnderlayDecision RetainedUnderlayCache::evaluate(const std::optional<RetainedUnderlayKey>& nextKey,
bool supported,
const char* fallbackReason) {
if (!nextKey) return RetainedUnderlayDecision::Disabled;
if (!supported) {
++fallbackCount;
particle::incrementRendererDebugCounter(particle::RendererDebugCounter::RetainedUnderlayFallback);
invalidate(fallbackReason ? fallbackReason : "unsupported");
return RetainedUnderlayDecision::Fallback;
}
if (!key || *key != *nextKey) {
const char* reason = !key ? "first-frame" : (key->viewport != nextKey->viewport ? "viewport" : "camera-or-boundary");
invalidate(reason);
key = nextKey;
}
if (valid) {
++reuseCount;
particle::incrementRendererDebugCounter(particle::RendererDebugCounter::RetainedUnderlayReuse);
return RetainedUnderlayDecision::Reuse;
}
return RetainedUnderlayDecision::Build;
}
bool RetainedUnderlayCache::prepareResources(gfx::Context& context,
gfx::ShaderRegistry& shaders,
const RetainedUnderlayKey& nextKey) {
try {
if (!offscreenTexture || offscreenTexture->getSize() != nextKey.viewport) {
offscreenTexture = context.createOffscreenTexture(
nextKey.viewport, gfx::TextureChannelDataType::UnsignedByte, true, true);
compositeLayerGroup.reset();
}
if (!offscreenTexture || !offscreenTexture->isRenderable()) return false;
return compositeLayerGroup || rebuildComposite(context, shaders);
} catch (...) {
return false;
}
}
bool RetainedUnderlayCache::rebuildComposite(gfx::Context& context, gfx::ShaderRegistry& shaders) {
auto shader = context.getGenericShader(shaders, CompositeShaderName);
auto group = context.createLayerGroup(0, 1, "retained-underlay-composite");
if (!shader || !group || !offscreenTexture) return false;
auto vertices = std::make_shared<gfx::VertexVector<HeatmapTextureLayoutVertex>>(
RenderStaticData::heatmapTextureVertices());
auto attributes = context.createVertexAttributeArray();
if (const auto& attribute = attributes->set(shaders::idRetainedUnderlayCompositePosVertexAttribute)) {
attribute->setSharedRawData(vertices,
offsetof(HeatmapTextureLayoutVertex, a1),
0,
sizeof(HeatmapTextureLayoutVertex),
gfx::AttributeDataType::Short2);
}
auto builder = context.createDrawableBuilder("retained-underlay-composite");
builder->setShader(std::move(shader));
builder->setEnableDepth(false);
builder->setColorMode(gfx::ColorMode::alphaBlended());
builder->setCullFaceMode(gfx::CullFaceMode::disabled());
builder->setRenderPass(RenderPass::Translucent);
builder->setVertexAttributes(std::move(attributes));
builder->setRawVertices({}, vertices->elements(), gfx::AttributeDataType::Short2);
auto segments = RenderStaticData::heatmapTextureSegments();
builder->setSegments(gfx::Triangles(),
RenderStaticData::quadTriangleIndices().vector(),
segments.data(),
segments.size());
builder->setTexture(offscreenTexture->getTexture(), shaders::idRetainedUnderlayCompositeTexture);
builder->flush(context);
for (auto& drawable : builder->clearDrawables()) group->addDrawable(std::move(drawable));
compositeLayerGroup = std::move(group);
return !compositeLayerGroup->empty();
}
void RetainedUnderlayCache::upload(gfx::UploadPass& uploadPass) {
if (compositeLayerGroup) compositeLayerGroup->upload(uploadPass);
}
void RetainedUnderlayCache::beginBuild(PaintParameters& parameters) {
parameters.renderPass = parameters.encoder->createRenderPass(
"retained static underlay",
{.renderable = *offscreenTexture,
.clearColor = Color{0.0f, 0.0f, 0.0f, 0.0f},
.clearDepth = 1.0f,
.clearStencil = 0});
#if MLN_RENDER_BACKEND_OPENGL
parameters.updateStencilBufferAvailability();
#endif
}
void RetainedUnderlayCache::finishBuild(PaintParameters& parameters) {
parameters.renderPass.reset();
parameters.encoder->present(*offscreenTexture);
}
void RetainedUnderlayCache::composite(RenderOrchestrator& orchestrator, PaintParameters& parameters) {
if (!compositeLayerGroup) return;
parameters.pass = RenderPass::Translucent;
parameters.currentLayer = 0;
compositeLayerGroup->render(orchestrator, parameters);
}
void RetainedUnderlayCache::markBuildSucceeded() {
valid = true;
++buildCount;
particle::incrementRendererDebugCounter(particle::RendererDebugCounter::RetainedUnderlayBuild);
}
void RetainedUnderlayCache::markBuildFailed(const char* reason) {
++fallbackCount;
particle::incrementRendererDebugCounter(particle::RendererDebugCounter::RetainedUnderlayFallback);
invalidate(reason);
}
void RetainedUnderlayCache::invalidate(const char* reason) {
valid = false;
lastInvalidationReason = reason ? reason : "unknown";
particle::incrementRendererDebugCounter(particle::RendererDebugCounter::RetainedUnderlayInvalidation);
}
} // namespace mbgl