feat: add retained underlay render cache poc
Some checks failed
validate-scripts / validate-scripts (push) Has been cancelled
Some checks failed
validate-scripts / validate-scripts (push) Has been cancelled
This commit is contained in:
@@ -180,6 +180,8 @@ list(APPEND SRC_FILES
|
||||
${PROJECT_SOURCE_DIR}/src/mbgl/gfx/uniform_buffer.cpp
|
||||
${PROJECT_SOURCE_DIR}/src/mbgl/gfx/vertex_attribute.cpp
|
||||
${PROJECT_SOURCE_DIR}/src/mbgl/renderer/render_target.cpp
|
||||
${PROJECT_SOURCE_DIR}/src/mbgl/renderer/retained_underlay_cache.cpp
|
||||
${PROJECT_SOURCE_DIR}/src/mbgl/renderer/retained_underlay_cache.hpp
|
||||
${PROJECT_SOURCE_DIR}/src/mbgl/renderer/change_request.cpp
|
||||
${PROJECT_SOURCE_DIR}/src/mbgl/renderer/layer_group.cpp
|
||||
${PROJECT_SOURCE_DIR}/src/mbgl/renderer/tile_layer_group.cpp
|
||||
|
||||
@@ -48,6 +48,7 @@ list(APPEND
|
||||
${PROJECT_SOURCE_DIR}/include/mbgl/shaders/mtl/line.hpp
|
||||
${PROJECT_SOURCE_DIR}/include/mbgl/shaders/mtl/location_indicator.hpp
|
||||
${PROJECT_SOURCE_DIR}/include/mbgl/shaders/mtl/particle_gpu_validation.hpp
|
||||
${PROJECT_SOURCE_DIR}/include/mbgl/shaders/mtl/retained_underlay_composite.hpp
|
||||
${PROJECT_SOURCE_DIR}/include/mbgl/shaders/mtl/raster.hpp
|
||||
${PROJECT_SOURCE_DIR}/include/mbgl/shaders/mtl/shader_group.hpp
|
||||
${PROJECT_SOURCE_DIR}/include/mbgl/shaders/mtl/shader_program.hpp
|
||||
@@ -92,6 +93,7 @@ list(APPEND
|
||||
${PROJECT_SOURCE_DIR}/src/mbgl/shaders/mtl/line.cpp
|
||||
${PROJECT_SOURCE_DIR}/src/mbgl/shaders/mtl/location_indicator.cpp
|
||||
${PROJECT_SOURCE_DIR}/src/mbgl/shaders/mtl/particle_gpu_validation.cpp
|
||||
${PROJECT_SOURCE_DIR}/src/mbgl/shaders/mtl/retained_underlay_composite.cpp
|
||||
${PROJECT_SOURCE_DIR}/src/mbgl/shaders/mtl/raster.cpp
|
||||
${PROJECT_SOURCE_DIR}/src/mbgl/shaders/mtl/symbol.cpp
|
||||
${PROJECT_SOURCE_DIR}/src/mbgl/shaders/mtl/widevector.cpp
|
||||
|
||||
@@ -37,6 +37,7 @@ list(APPEND
|
||||
${PROJECT_SOURCE_DIR}/include/mbgl/shaders/gl/fill_extrusion_pattern_instanced.hpp
|
||||
${PROJECT_SOURCE_DIR}/include/mbgl/shaders/gl/heatmap.hpp
|
||||
${PROJECT_SOURCE_DIR}/include/mbgl/shaders/gl/heatmap_texture.hpp
|
||||
${PROJECT_SOURCE_DIR}/include/mbgl/shaders/gl/retained_underlay_composite.hpp
|
||||
${PROJECT_SOURCE_DIR}/include/mbgl/shaders/gl/hillshade_prepare.hpp
|
||||
${PROJECT_SOURCE_DIR}/include/mbgl/shaders/gl/hillshade.hpp
|
||||
${PROJECT_SOURCE_DIR}/include/mbgl/shaders/gl/color_relief.hpp
|
||||
|
||||
@@ -82,6 +82,10 @@ public:
|
||||
virtual void reduceMemoryUsage() = 0;
|
||||
|
||||
virtual std::unique_ptr<OffscreenTexture> createOffscreenTexture(Size, TextureChannelDataType) = 0;
|
||||
virtual std::unique_ptr<OffscreenTexture> createOffscreenTexture(Size,
|
||||
TextureChannelDataType,
|
||||
bool,
|
||||
bool) = 0;
|
||||
|
||||
template <RenderbufferPixelType pixelType>
|
||||
Renderbuffer<pixelType> createRenderbuffer(const Size size) {
|
||||
|
||||
@@ -106,7 +106,10 @@ public:
|
||||
|
||||
void setDirtyState() override;
|
||||
|
||||
std::unique_ptr<gfx::OffscreenTexture> createOffscreenTexture(Size, gfx::TextureChannelDataType, bool, bool);
|
||||
std::unique_ptr<gfx::OffscreenTexture> createOffscreenTexture(Size,
|
||||
gfx::TextureChannelDataType,
|
||||
bool,
|
||||
bool) override;
|
||||
|
||||
std::unique_ptr<gfx::OffscreenTexture> createOffscreenTexture(Size, gfx::TextureChannelDataType) override;
|
||||
|
||||
|
||||
@@ -22,6 +22,13 @@ enum class RendererDebugCounter : uint8_t {
|
||||
TrailTargetCreateOrResize,
|
||||
V4ProjectionMaterialize,
|
||||
FieldWindowRevision,
|
||||
FullRendererFrame,
|
||||
RetainedUnderlayBuild,
|
||||
RetainedUnderlayReuse,
|
||||
RetainedUnderlayFallback,
|
||||
RetainedUnderlayInvalidation,
|
||||
RetainedUnderlayStaticGroupDraw,
|
||||
RetainedDynamicGroupDraw,
|
||||
Count,
|
||||
};
|
||||
|
||||
@@ -40,6 +47,13 @@ struct RendererDebugCounterSnapshot {
|
||||
uint64_t trailTargetCreateOrResize = 0;
|
||||
uint64_t v4ProjectionMaterialize = 0;
|
||||
uint64_t fieldWindowRevision = 0;
|
||||
uint64_t fullRendererFrame = 0;
|
||||
uint64_t retainedUnderlayBuild = 0;
|
||||
uint64_t retainedUnderlayReuse = 0;
|
||||
uint64_t retainedUnderlayFallback = 0;
|
||||
uint64_t retainedUnderlayInvalidation = 0;
|
||||
uint64_t retainedUnderlayStaticGroupDraw = 0;
|
||||
uint64_t retainedDynamicGroupDraw = 0;
|
||||
};
|
||||
|
||||
inline std::atomic_uint64_t* rendererDebugCounterStorage() {
|
||||
@@ -59,7 +73,10 @@ inline RendererDebugCounterSnapshot rendererDebugCounterSnapshot() {
|
||||
values[6].load(std::memory_order_relaxed), values[7].load(std::memory_order_relaxed),
|
||||
values[8].load(std::memory_order_relaxed), values[9].load(std::memory_order_relaxed),
|
||||
values[10].load(std::memory_order_relaxed), values[11].load(std::memory_order_relaxed),
|
||||
values[12].load(std::memory_order_relaxed)};
|
||||
values[12].load(std::memory_order_relaxed), values[13].load(std::memory_order_relaxed),
|
||||
values[14].load(std::memory_order_relaxed), values[15].load(std::memory_order_relaxed),
|
||||
values[16].load(std::memory_order_relaxed), values[17].load(std::memory_order_relaxed),
|
||||
values[18].load(std::memory_order_relaxed), values[19].load(std::memory_order_relaxed)};
|
||||
}
|
||||
#else
|
||||
inline void incrementRendererDebugCounter(RendererDebugCounter) {}
|
||||
|
||||
29
include/mbgl/shaders/gl/retained_underlay_composite.hpp
Normal file
29
include/mbgl/shaders/gl/retained_underlay_composite.hpp
Normal file
@@ -0,0 +1,29 @@
|
||||
// Generated code, do not modify this file!
|
||||
#pragma once
|
||||
#include <mbgl/shaders/shader_source.hpp>
|
||||
|
||||
namespace mbgl {
|
||||
namespace shaders {
|
||||
|
||||
template <>
|
||||
struct ShaderSource<BuiltIn::RetainedUnderlayCompositeShader, gfx::Backend::Type::OpenGL> {
|
||||
static constexpr const char* name = "RetainedUnderlayCompositeShader";
|
||||
static constexpr const char* vertex = R"(layout (location = 0) in vec2 a_pos;
|
||||
out vec2 v_uv;
|
||||
|
||||
void main() {
|
||||
gl_Position = vec4(a_pos.x * 2.0 - 1.0, 1.0 - a_pos.y * 2.0, 0.0, 1.0);
|
||||
v_uv = vec2(a_pos.x, 1.0 - a_pos.y);
|
||||
}
|
||||
)";
|
||||
static constexpr const char* fragment = R"(in vec2 v_uv;
|
||||
uniform sampler2D u_image;
|
||||
|
||||
void main() {
|
||||
fragColor = texture(u_image, v_uv);
|
||||
}
|
||||
)";
|
||||
};
|
||||
|
||||
} // namespace shaders
|
||||
} // namespace mbgl
|
||||
@@ -156,6 +156,13 @@ struct ShaderInfo<BuiltIn::ParticleGpuValidationShader, gfx::Backend::Type::Open
|
||||
static const std::vector<TextureInfo> textures;
|
||||
};
|
||||
|
||||
template <>
|
||||
struct ShaderInfo<BuiltIn::RetainedUnderlayCompositeShader, gfx::Backend::Type::OpenGL> {
|
||||
static const std::vector<AttributeInfo> attributes;
|
||||
static const std::vector<UniformBlockInfo> uniformBlocks;
|
||||
static const std::vector<TextureInfo> textures;
|
||||
};
|
||||
|
||||
template <>
|
||||
struct ShaderInfo<BuiltIn::HillshadePrepareShader, gfx::Backend::Type::OpenGL> {
|
||||
static const std::vector<AttributeInfo> attributes;
|
||||
|
||||
34
include/mbgl/shaders/mtl/retained_underlay_composite.hpp
Normal file
34
include/mbgl/shaders/mtl/retained_underlay_composite.hpp
Normal file
@@ -0,0 +1,34 @@
|
||||
#pragma once
|
||||
|
||||
#include <mbgl/shaders/shader_source.hpp>
|
||||
#include <mbgl/shaders/mtl/shader_program.hpp>
|
||||
|
||||
namespace mbgl::shaders {
|
||||
|
||||
template <>
|
||||
struct ShaderSource<BuiltIn::RetainedUnderlayCompositeShader, gfx::Backend::Type::Metal> {
|
||||
static constexpr auto name = "RetainedUnderlayCompositeShader";
|
||||
static constexpr auto vertexMainFunction = "vertexMain";
|
||||
static constexpr auto fragmentMainFunction = "fragmentMain";
|
||||
static const std::array<AttributeInfo, 1> attributes;
|
||||
static constexpr std::array<AttributeInfo, 0> instanceAttributes{};
|
||||
static const std::array<TextureInfo, 1> textures;
|
||||
static constexpr auto prelude = R"()";
|
||||
static constexpr auto source = R"(
|
||||
struct VertexStage { short2 pos [[attribute(0)]]; };
|
||||
struct FragmentStage { float4 position [[position, invariant]]; float2 uv; };
|
||||
|
||||
FragmentStage vertex vertexMain(thread const VertexStage in [[stage_in]]) {
|
||||
const float2 p = float2(in.pos);
|
||||
return { .position = float4(p.x * 2.0 - 1.0, 1.0 - p.y * 2.0, 0.0, 1.0), .uv = p };
|
||||
}
|
||||
|
||||
half4 fragment fragmentMain(FragmentStage in [[stage_in]],
|
||||
texture2d<float, access::sample> image [[texture(0)]],
|
||||
sampler imageSampler [[sampler(0)]]) {
|
||||
return half4(image.sample(imageSampler, in.uv));
|
||||
}
|
||||
)";
|
||||
};
|
||||
|
||||
} // namespace mbgl::shaders
|
||||
@@ -347,6 +347,11 @@ enum {
|
||||
particleGpuValidationTextureCount
|
||||
};
|
||||
|
||||
enum {
|
||||
idRetainedUnderlayCompositeTexture,
|
||||
retainedUnderlayCompositeTextureCount
|
||||
};
|
||||
|
||||
enum {
|
||||
idHillshadeImageTexture,
|
||||
hillshadeTextureCount
|
||||
@@ -392,6 +397,7 @@ static constexpr uint32_t maxTextureCountPerShader = std::max({static_cast<uint3
|
||||
static_cast<uint32_t>(fillExtrusionTextureCount),
|
||||
static_cast<uint32_t>(heatmapTextureCount),
|
||||
static_cast<uint32_t>(particleGpuValidationTextureCount),
|
||||
static_cast<uint32_t>(retainedUnderlayCompositeTextureCount),
|
||||
static_cast<uint32_t>(hillshadeTextureCount),
|
||||
static_cast<uint32_t>(colorReliefTextureCount),
|
||||
static_cast<uint32_t>(lineTextureCount),
|
||||
@@ -410,6 +416,11 @@ enum {
|
||||
particleGpuValidationVertexAttributeCount
|
||||
};
|
||||
|
||||
enum {
|
||||
idRetainedUnderlayCompositePosVertexAttribute,
|
||||
retainedUnderlayCompositeVertexAttributeCount
|
||||
};
|
||||
|
||||
enum {
|
||||
idCirclePosVertexAttribute,
|
||||
|
||||
|
||||
@@ -25,6 +25,7 @@
|
||||
#include <mbgl/shaders/gl/heatmap.hpp>
|
||||
#include <mbgl/shaders/gl/heatmap_texture.hpp>
|
||||
#include <mbgl/shaders/gl/particle_gpu_validation.hpp>
|
||||
#include <mbgl/shaders/gl/retained_underlay_composite.hpp>
|
||||
#include <mbgl/shaders/gl/hillshade_prepare.hpp>
|
||||
#include <mbgl/shaders/gl/color_relief.hpp>
|
||||
#include <mbgl/shaders/gl/hillshade.hpp>
|
||||
|
||||
@@ -31,6 +31,7 @@ enum class BuiltIn {
|
||||
HeatmapShader,
|
||||
HeatmapTextureShader,
|
||||
ParticleGpuValidationShader,
|
||||
RetainedUnderlayCompositeShader,
|
||||
HillshadePrepareShader,
|
||||
ColorReliefShader,
|
||||
HillshadeShader,
|
||||
|
||||
@@ -106,7 +106,10 @@ public:
|
||||
|
||||
void setDirtyState() override {}
|
||||
|
||||
std::unique_ptr<gfx::OffscreenTexture> createOffscreenTexture(Size, gfx::TextureChannelDataType, bool, bool);
|
||||
std::unique_ptr<gfx::OffscreenTexture> createOffscreenTexture(Size,
|
||||
gfx::TextureChannelDataType,
|
||||
bool,
|
||||
bool) override;
|
||||
|
||||
std::unique_ptr<gfx::OffscreenTexture> createOffscreenTexture(Size, gfx::TextureChannelDataType) override;
|
||||
|
||||
|
||||
@@ -43,7 +43,10 @@ public:
|
||||
void reduceMemoryUsage() override;
|
||||
|
||||
// Resource creation
|
||||
std::unique_ptr<gfx::OffscreenTexture> createOffscreenTexture(Size, gfx::TextureChannelDataType, bool, bool);
|
||||
std::unique_ptr<gfx::OffscreenTexture> createOffscreenTexture(Size,
|
||||
gfx::TextureChannelDataType,
|
||||
bool,
|
||||
bool) override;
|
||||
std::unique_ptr<gfx::OffscreenTexture> createOffscreenTexture(Size, gfx::TextureChannelDataType) override;
|
||||
std::unique_ptr<gfx::CommandEncoder> createCommandEncoder() override;
|
||||
gfx::VertexAttributeArrayPtr createVertexAttributeArray() const override;
|
||||
|
||||
@@ -151,6 +151,13 @@
|
||||
"glsl_frag": "particle_gpu_validation.fragment.glsl",
|
||||
"uses_ubos": true
|
||||
},
|
||||
{
|
||||
"name": "RetainedUnderlayCompositeShader",
|
||||
"header": "retained_underlay_composite",
|
||||
"glsl_vert": "retained_underlay_composite.vertex.glsl",
|
||||
"glsl_frag": "retained_underlay_composite.fragment.glsl",
|
||||
"uses_ubos": true
|
||||
},
|
||||
{
|
||||
"name": "HillshadePrepareShader",
|
||||
"header": "hillshade_prepare",
|
||||
|
||||
6
shaders/retained_underlay_composite.fragment.glsl
Normal file
6
shaders/retained_underlay_composite.fragment.glsl
Normal file
@@ -0,0 +1,6 @@
|
||||
in vec2 v_uv;
|
||||
uniform sampler2D u_image;
|
||||
|
||||
void main() {
|
||||
fragColor = texture(u_image, v_uv);
|
||||
}
|
||||
7
shaders/retained_underlay_composite.vertex.glsl
Normal file
7
shaders/retained_underlay_composite.vertex.glsl
Normal file
@@ -0,0 +1,7 @@
|
||||
layout (location = 0) in vec2 a_pos;
|
||||
out vec2 v_uv;
|
||||
|
||||
void main() {
|
||||
gl_Position = vec4(a_pos.x * 2.0 - 1.0, 1.0 - a_pos.y * 2.0, 0.0, 1.0);
|
||||
v_uv = vec2(a_pos.x, 1.0 - a_pos.y);
|
||||
}
|
||||
@@ -436,7 +436,15 @@ std::unique_ptr<gfx::OffscreenTexture> Context::createOffscreenTexture(const Siz
|
||||
const gfx::TextureChannelDataType type) {
|
||||
MLN_TRACE_FUNC();
|
||||
|
||||
return std::make_unique<gl::OffscreenTexture>(*this, size, type);
|
||||
return std::make_unique<gl::OffscreenTexture>(*this, size, type, false, false);
|
||||
}
|
||||
|
||||
std::unique_ptr<gfx::OffscreenTexture> Context::createOffscreenTexture(const Size size,
|
||||
const gfx::TextureChannelDataType type,
|
||||
const bool depth,
|
||||
const bool stencil) {
|
||||
MLN_TRACE_FUNC();
|
||||
return std::make_unique<gl::OffscreenTexture>(*this, size, type, depth, stencil);
|
||||
}
|
||||
|
||||
std::unique_ptr<gfx::DrawScopeResource> Context::createDrawScopeResource() {
|
||||
@@ -611,6 +619,24 @@ Framebuffer Context::createFramebuffer(const gfx::Texture2D& color) {
|
||||
return {color.getSize(), std::move(fbo)};
|
||||
}
|
||||
|
||||
Framebuffer Context::createFramebuffer(
|
||||
const gfx::Texture2D& color,
|
||||
const gfx::Renderbuffer<gfx::RenderbufferPixelType::DepthStencil>& depthStencil) {
|
||||
if (color.getSize() != depthStencil.getSize()) {
|
||||
throw std::runtime_error("Renderbuffer size mismatch");
|
||||
}
|
||||
auto fbo = createFramebuffer();
|
||||
bindFramebuffer = fbo;
|
||||
MBGL_CHECK_ERROR(glFramebufferTexture2D(GL_FRAMEBUFFER,
|
||||
GL_COLOR_ATTACHMENT0,
|
||||
GL_TEXTURE_2D,
|
||||
static_cast<const gl::Texture2D&>(color).getTextureID(),
|
||||
0));
|
||||
bindDepthStencilRenderbuffer(depthStencil);
|
||||
checkFramebuffer();
|
||||
return {color.getSize(), std::move(fbo)};
|
||||
}
|
||||
|
||||
gfx::VertexAttributeArrayPtr Context::createVertexAttributeArray() const {
|
||||
return std::make_shared<VertexAttributeArrayGL>();
|
||||
}
|
||||
|
||||
@@ -134,6 +134,8 @@ public:
|
||||
RenderTargetPtr createRenderTarget(const Size size, const gfx::TextureChannelDataType type) override;
|
||||
|
||||
Framebuffer createFramebuffer(const gfx::Texture2D& color);
|
||||
Framebuffer createFramebuffer(const gfx::Texture2D& color,
|
||||
const gfx::Renderbuffer<gfx::RenderbufferPixelType::DepthStencil>&);
|
||||
|
||||
gfx::VertexAttributeArrayPtr createVertexAttributeArray() const override;
|
||||
|
||||
@@ -212,6 +214,10 @@ private:
|
||||
|
||||
public:
|
||||
std::unique_ptr<gfx::OffscreenTexture> createOffscreenTexture(Size, gfx::TextureChannelDataType) override;
|
||||
std::unique_ptr<gfx::OffscreenTexture> createOffscreenTexture(Size,
|
||||
gfx::TextureChannelDataType,
|
||||
bool,
|
||||
bool) override;
|
||||
|
||||
private:
|
||||
std::unique_ptr<gfx::RenderbufferResource> createRenderbufferResource(gfx::RenderbufferPixelType,
|
||||
|
||||
@@ -8,7 +8,11 @@ namespace gl {
|
||||
|
||||
class OffscreenTextureResource final : public gl::RenderableResource {
|
||||
public:
|
||||
OffscreenTextureResource(gl::Context& context_, const Size size_, const gfx::TextureChannelDataType type_)
|
||||
OffscreenTextureResource(gl::Context& context_,
|
||||
const Size size_,
|
||||
const gfx::TextureChannelDataType type_,
|
||||
bool depth,
|
||||
bool stencil)
|
||||
: context(context_),
|
||||
size(size_),
|
||||
type(type_) {
|
||||
@@ -19,6 +23,10 @@ public:
|
||||
texture->setSamplerConfiguration({.filter = gfx::TextureFilterType::Linear,
|
||||
.wrapU = gfx::TextureWrapType::Clamp,
|
||||
.wrapV = gfx::TextureWrapType::Clamp});
|
||||
if (depth || stencil) {
|
||||
depthStencil = std::make_unique<gfx::Renderbuffer<gfx::RenderbufferPixelType::DepthStencil>>(
|
||||
context.createRenderbuffer<gfx::RenderbufferPixelType::DepthStencil>(size));
|
||||
}
|
||||
}
|
||||
|
||||
~OffscreenTextureResource() noexcept override = default;
|
||||
@@ -27,7 +35,8 @@ public:
|
||||
if (!framebuffer) {
|
||||
assert(texture);
|
||||
texture->create();
|
||||
framebuffer = context.createFramebuffer(*texture);
|
||||
framebuffer = depthStencil ? context.createFramebuffer(*texture, *depthStencil)
|
||||
: context.createFramebuffer(*texture);
|
||||
} else {
|
||||
context.bindFramebuffer = framebuffer->framebuffer;
|
||||
}
|
||||
@@ -54,10 +63,16 @@ private:
|
||||
gfx::Texture2DPtr texture;
|
||||
const gfx::TextureChannelDataType type;
|
||||
std::optional<gl::Framebuffer> framebuffer;
|
||||
std::unique_ptr<gfx::Renderbuffer<gfx::RenderbufferPixelType::DepthStencil>> depthStencil;
|
||||
};
|
||||
|
||||
OffscreenTexture::OffscreenTexture(gl::Context& context, const Size size_, const gfx::TextureChannelDataType type)
|
||||
: gfx::OffscreenTexture(size, std::make_unique<OffscreenTextureResource>(context, size_, type)) {}
|
||||
OffscreenTexture::OffscreenTexture(gl::Context& context,
|
||||
const Size size_,
|
||||
const gfx::TextureChannelDataType type,
|
||||
bool depth,
|
||||
bool stencil)
|
||||
: gfx::OffscreenTexture(
|
||||
size_, std::make_unique<OffscreenTextureResource>(context, size_, type, depth, stencil)) {}
|
||||
|
||||
bool OffscreenTexture::isRenderable() {
|
||||
try {
|
||||
|
||||
@@ -12,7 +12,9 @@ class OffscreenTexture final : public gfx::OffscreenTexture {
|
||||
public:
|
||||
OffscreenTexture(gl::Context&,
|
||||
Size size,
|
||||
gfx::TextureChannelDataType type = gfx::TextureChannelDataType::UnsignedByte);
|
||||
gfx::TextureChannelDataType type = gfx::TextureChannelDataType::UnsignedByte,
|
||||
bool depth = false,
|
||||
bool stencil = false);
|
||||
|
||||
bool isRenderable() override;
|
||||
|
||||
|
||||
@@ -136,6 +136,7 @@ void RendererBackend::initShaders(gfx::ShaderRegistry& shaders, const ProgramPar
|
||||
shaders::BuiltIn::HeatmapShader,
|
||||
shaders::BuiltIn::HeatmapTextureShader,
|
||||
shaders::BuiltIn::ParticleGpuValidationShader,
|
||||
shaders::BuiltIn::RetainedUnderlayCompositeShader,
|
||||
shaders::BuiltIn::HillshadePrepareShader,
|
||||
shaders::BuiltIn::HillshadeShader,
|
||||
shaders::BuiltIn::ColorReliefShader,
|
||||
|
||||
@@ -28,6 +28,7 @@
|
||||
#include <mbgl/shaders/mtl/line.hpp>
|
||||
#include <mbgl/shaders/mtl/location_indicator.hpp>
|
||||
#include <mbgl/shaders/mtl/particle_gpu_validation.hpp>
|
||||
#include <mbgl/shaders/mtl/retained_underlay_composite.hpp>
|
||||
#include <mbgl/shaders/mtl/raster.hpp>
|
||||
#include <mbgl/shaders/mtl/symbol.hpp>
|
||||
#include <mbgl/shaders/mtl/widevector.hpp>
|
||||
@@ -133,6 +134,7 @@ void RendererBackend::initShaders(gfx::ShaderRegistry& shaders, const ProgramPar
|
||||
shaders::BuiltIn::LocationIndicatorShader,
|
||||
shaders::BuiltIn::LocationIndicatorTexturedShader,
|
||||
shaders::BuiltIn::ParticleGpuValidationShader,
|
||||
shaders::BuiltIn::RetainedUnderlayCompositeShader,
|
||||
shaders::BuiltIn::RasterShader,
|
||||
shaders::BuiltIn::SymbolIconShader,
|
||||
shaders::BuiltIn::SymbolSDFShader,
|
||||
|
||||
@@ -44,6 +44,7 @@ private:
|
||||
|
||||
#ifndef MLN_DRAWABLE_LOCATION_INDICATOR
|
||||
void render(PaintParameters &) override;
|
||||
bool usesLegacyRendering() const override { return true; }
|
||||
#endif
|
||||
|
||||
void populateDynamicRenderFeatureIndex(DynamicFeatureIndex &) const override;
|
||||
|
||||
@@ -27,6 +27,7 @@ private:
|
||||
bool hasTransition() const override { return false; }
|
||||
bool hasCrossfade() const override { return false; }
|
||||
bool needsRepaint() const override;
|
||||
bool startsRetainedDynamicRange() const override { return true; }
|
||||
void prepare(const LayerPrepareParameters&) override;
|
||||
void markLayerRenderable(bool, UniqueChangeRequestVec&) override;
|
||||
void layerRemoved(UniqueChangeRequestVec&) override;
|
||||
|
||||
@@ -23,6 +23,7 @@ private:
|
||||
bool hasTransition() const override { return false; }
|
||||
bool hasCrossfade() const override { return false; }
|
||||
bool needsRepaint() const override;
|
||||
bool startsRetainedDynamicRange() const override { return true; }
|
||||
void prepare(const LayerPrepareParameters&) override;
|
||||
void markLayerRenderable(bool, UniqueChangeRequestVec&) override;
|
||||
void layerRemoved(UniqueChangeRequestVec&) override;
|
||||
|
||||
@@ -109,6 +109,14 @@ public:
|
||||
// Returns true when an active animated layer needs another MapLibre frame.
|
||||
virtual bool needsRepaint() const { return false; }
|
||||
|
||||
// Renderer-internal boundary for retained static-underlay rendering. This is
|
||||
// deliberately not exposed through the style or Host APIs.
|
||||
virtual bool startsRetainedDynamicRange() const { return false; }
|
||||
|
||||
// Only layers that still issue commands through RenderLayer::render() need
|
||||
// legacy ordering protection in the retained-underlay path.
|
||||
virtual bool usesLegacyRendering() const { return false; }
|
||||
|
||||
// Exceptional source-driven cleanup for a hidden layer. The default keeps
|
||||
// normal MapLibre hidden-layer lifecycle unchanged.
|
||||
virtual bool needsHiddenLayerSourceCleanup(const RenderSource&) const { return false; }
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
#include <mbgl/renderer/render_source.hpp>
|
||||
#include <mbgl/renderer/render_layer.hpp>
|
||||
#include <mbgl/renderer/render_static_data.hpp>
|
||||
#include <mbgl/renderer/retained_underlay_cache.hpp>
|
||||
#include <mbgl/renderer/render_tree.hpp>
|
||||
#include <mbgl/renderer/update_parameters.hpp>
|
||||
#include <mbgl/renderer/upload_parameters.hpp>
|
||||
@@ -364,6 +365,13 @@ std::unique_ptr<RenderTree> RenderOrchestrator::createRenderTree(
|
||||
// Track which layers are flagged for rendering
|
||||
std::vector<bool> updateList(orderedLayers.size());
|
||||
|
||||
RetainedDynamicBoundaryTracker boundaryTracker;
|
||||
for (std::size_t index = 0; index < orderedLayers.size(); ++index) {
|
||||
boundaryTracker.consider(static_cast<int32_t>(index),
|
||||
orderedLayers[index].get().startsRetainedDynamicRange());
|
||||
}
|
||||
retainedDynamicBoundary = boundaryTracker.value();
|
||||
|
||||
// Update all sources and initialize renderItems.
|
||||
for (const auto& sourceImpl : *sourceImpls) {
|
||||
MLN_TRACE_ZONE(update source);
|
||||
@@ -848,6 +856,22 @@ bool RenderOrchestrator::hasTransitions(TimePoint timePoint) const {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool RenderOrchestrator::retainedUnderlayIsStable(TimePoint timePoint, int32_t boundary) const {
|
||||
if (renderLight.hasTransition() || placementController.hasTransitions(timePoint)) return false;
|
||||
|
||||
const auto staticLayerCount = std::min<std::size_t>(
|
||||
boundary > 0 ? static_cast<std::size_t>(boundary) : 0, orderedLayers.size());
|
||||
for (std::size_t index = 0; index < staticLayerCount; ++index) {
|
||||
const auto& layer = orderedLayers[index].get();
|
||||
if (layer.hasTransition() || layer.needsRepaint()) return false;
|
||||
}
|
||||
|
||||
for (const auto& entry : renderSources) {
|
||||
if (entry.second->hasFadingTiles()) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool RenderOrchestrator::isLoaded() const {
|
||||
MLN_TRACE_FUNC();
|
||||
|
||||
|
||||
@@ -15,9 +15,11 @@
|
||||
#include <mbgl/renderer/image_manager_observer.hpp>
|
||||
#include <mbgl/text/placement.hpp>
|
||||
#include <mbgl/renderer/render_tree.hpp>
|
||||
#include <mbgl/renderer/retained_underlay_cache.hpp>
|
||||
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <optional>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
@@ -106,6 +108,8 @@ public:
|
||||
bool addLayerGroup(LayerGroupBasePtr);
|
||||
bool removeLayerGroup(const LayerGroupBasePtr&);
|
||||
size_t numLayerGroups() const noexcept;
|
||||
std::optional<int32_t> getRetainedDynamicBoundary() const noexcept { return retainedDynamicBoundary; }
|
||||
bool retainedUnderlayIsStable(TimePoint, int32_t boundary) const;
|
||||
void updateLayerIndex(LayerGroupBasePtr, int32_t newIndex);
|
||||
|
||||
template <typename Func /* void(LayerGroupBase&) */>
|
||||
@@ -121,6 +125,72 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
template <typename Func /* void(LayerGroupBase&, size_t originalOrdinal) */>
|
||||
void visitLayerGroupsBefore(int32_t boundary, Func f) {
|
||||
size_t ordinal = 0;
|
||||
for (auto& pair : layerGroupsByLayerIndex) {
|
||||
if (!retainedLayerGroupInRange(pair.first, boundary, RetainedLayerGroupRange::Before)) break;
|
||||
if (pair.second) {
|
||||
try {
|
||||
f(*pair.second, ordinal);
|
||||
} catch (...) {
|
||||
observer->onRenderError(std::current_exception());
|
||||
}
|
||||
}
|
||||
++ordinal;
|
||||
}
|
||||
}
|
||||
|
||||
template <typename Func /* void(LayerGroupBase&, size_t originalOrdinal) */>
|
||||
void visitLayerGroupsFrom(int32_t boundary, Func f) {
|
||||
size_t ordinal = static_cast<size_t>(std::distance(layerGroupsByLayerIndex.begin(),
|
||||
layerGroupsByLayerIndex.lower_bound(boundary)));
|
||||
for (auto it = layerGroupsByLayerIndex.lower_bound(boundary); it != layerGroupsByLayerIndex.end(); ++it) {
|
||||
if (!retainedLayerGroupInRange(it->first, boundary, RetainedLayerGroupRange::From)) continue;
|
||||
if (it->second) {
|
||||
try {
|
||||
f(*it->second, ordinal);
|
||||
} catch (...) {
|
||||
observer->onRenderError(std::current_exception());
|
||||
}
|
||||
}
|
||||
++ordinal;
|
||||
}
|
||||
}
|
||||
|
||||
template <typename Func /* void(LayerGroupBase&, size_t originalOrdinal) */>
|
||||
void visitLayerGroupsBeforeReversed(int32_t boundary, Func f) {
|
||||
auto end = layerGroupsByLayerIndex.lower_bound(boundary);
|
||||
size_t ordinal = static_cast<size_t>(std::distance(layerGroupsByLayerIndex.begin(), end));
|
||||
while (end != layerGroupsByLayerIndex.begin()) {
|
||||
--end;
|
||||
--ordinal;
|
||||
if (end->second) {
|
||||
try {
|
||||
f(*end->second, ordinal);
|
||||
} catch (...) {
|
||||
observer->onRenderError(std::current_exception());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <typename Func /* void(LayerGroupBase&, size_t originalOrdinal) */>
|
||||
void visitLayerGroupsFromReversed(int32_t boundary, Func f) {
|
||||
auto begin = layerGroupsByLayerIndex.lower_bound(boundary);
|
||||
size_t ordinal = layerGroupsByLayerIndex.size();
|
||||
for (auto it = layerGroupsByLayerIndex.rbegin(); it.base() != begin; ++it) {
|
||||
--ordinal;
|
||||
if (it->second) {
|
||||
try {
|
||||
f(*it->second, ordinal);
|
||||
} catch (...) {
|
||||
observer->onRenderError(std::current_exception());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <typename Func /* void(LayerGroupBase&) */>
|
||||
void visitLayerGroupsReversed(Func f) {
|
||||
for (auto rit = layerGroupsByLayerIndex.rbegin(); rit != layerGroupsByLayerIndex.rend(); ++rit) {
|
||||
@@ -241,6 +311,7 @@ private:
|
||||
|
||||
using LayerGroupMap = std::multimap<int32_t, LayerGroupBasePtr>;
|
||||
LayerGroupMap layerGroupsByLayerIndex;
|
||||
std::optional<int32_t> retainedDynamicBoundary;
|
||||
|
||||
std::vector<RenderTargetPtr> renderTargets;
|
||||
RenderItem::DebugLayerGroupMap debugLayerGroups;
|
||||
|
||||
@@ -23,6 +23,8 @@
|
||||
#include <mbgl/gfx/drawable_tweaker.hpp>
|
||||
#include <mbgl/renderer/layer_tweaker.hpp>
|
||||
#include <mbgl/renderer/render_target.hpp>
|
||||
#include <mbgl/renderer/retained_underlay_cache.hpp>
|
||||
#include <mbgl/particle/renderer_debug_counters.hpp>
|
||||
|
||||
#if MLN_RENDER_BACKEND_METAL
|
||||
#include <mbgl/mtl/renderer_backend.hpp>
|
||||
@@ -57,7 +59,8 @@ Renderer::Impl::Impl(gfx::RendererBackend& backend_,
|
||||
: orchestrator(!backend_.contextIsShared(), backend_.getThreadPool(), localFontFamily_),
|
||||
backend(backend_),
|
||||
observer(&nullObserver()),
|
||||
pixelRatio(pixelRatio_) {}
|
||||
pixelRatio(pixelRatio_),
|
||||
retainedUnderlayCache(std::make_unique<RetainedUnderlayCache>()) {}
|
||||
|
||||
Renderer::Impl::~Impl() {
|
||||
assert(gfx::BackendScope::exists());
|
||||
@@ -91,6 +94,7 @@ void Renderer::Impl::setObserver(RendererObserver* observer_) {
|
||||
|
||||
void Renderer::Impl::render(const RenderTree& renderTree, const std::shared_ptr<UpdateParameters>& updateParameters) {
|
||||
MLN_TRACE_FUNC();
|
||||
particle::incrementRendererDebugCounter(particle::RendererDebugCounter::FullRendererFrame);
|
||||
auto& context = backend.getContext();
|
||||
context.setObserver(this);
|
||||
|
||||
@@ -259,6 +263,58 @@ void Renderer::Impl::render(const RenderTree& renderTree, const std::shared_ptr<
|
||||
|
||||
orchestrator.processChanges();
|
||||
|
||||
std::optional<RetainedUnderlayKey> retainedKey;
|
||||
const auto retainedBoundary = orchestrator.getRetainedDynamicBoundary();
|
||||
size_t retainedStaticGroupCount = 0;
|
||||
if (retainedBoundary) {
|
||||
orchestrator.visitLayerGroupsBefore(*retainedBoundary,
|
||||
[&](LayerGroupBase&, size_t) { ++retainedStaticGroupCount; });
|
||||
mat4 cameraMatrix;
|
||||
state.getProjMatrix(cameraMatrix);
|
||||
retainedKey = RetainedUnderlayKey{size, *retainedBoundary, cameraMatrix};
|
||||
}
|
||||
bool legacyBelowBoundary = false;
|
||||
if (retainedBoundary) {
|
||||
for (const auto& item : layerRenderItems) {
|
||||
if (item.index < static_cast<uint32_t>(*retainedBoundary) && item.layer.get().usesLegacyRendering()) {
|
||||
legacyBelowBoundary = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
const bool retainedSupported = retainedBoundary && retainedStaticGroupCount > 0 &&
|
||||
renderTreeParameters.loaded && !renderTreeParameters.has3D &&
|
||||
renderTreeParameters.debugOptions == MapDebugOptions::NoDebug &&
|
||||
orchestrator.retainedUnderlayIsStable(renderTreeParameters.timePoint,
|
||||
*retainedBoundary) &&
|
||||
!renderTreeParameters.placementChanged &&
|
||||
renderTreeParameters.symbolFadeChange == 0.0f &&
|
||||
!legacyBelowBoundary;
|
||||
const char* retainedFallbackReason = !retainedBoundary ? "no-boundary"
|
||||
: retainedStaticGroupCount == 0 ? "empty-static-prefix"
|
||||
: !renderTreeParameters.loaded ? "style-not-loaded"
|
||||
: renderTreeParameters.has3D ? "3d"
|
||||
: renderTreeParameters.debugOptions != MapDebugOptions::NoDebug
|
||||
? "debug-options"
|
||||
: !orchestrator.retainedUnderlayIsStable(renderTreeParameters.timePoint,
|
||||
*retainedBoundary) ||
|
||||
renderTreeParameters.placementChanged ||
|
||||
renderTreeParameters.symbolFadeChange != 0.0f
|
||||
? "static-transition-or-placement"
|
||||
: legacyBelowBoundary ? "legacy-ordering"
|
||||
: nullptr;
|
||||
auto retainedDecision = retainedUnderlayCache->evaluate(retainedKey,
|
||||
retainedSupported,
|
||||
retainedFallbackReason);
|
||||
if ((retainedDecision == RetainedUnderlayDecision::Build ||
|
||||
retainedDecision == RetainedUnderlayDecision::Reuse) &&
|
||||
(!staticData->shaders || !retainedUnderlayCache->prepareResources(context, *staticData->shaders, *retainedKey))) {
|
||||
retainedUnderlayCache->markBuildFailed("resource-or-compositor");
|
||||
retainedDecision = RetainedUnderlayDecision::Fallback;
|
||||
}
|
||||
const bool useRetainedUnderlay = retainedDecision == RetainedUnderlayDecision::Build ||
|
||||
retainedDecision == RetainedUnderlayDecision::Reuse;
|
||||
|
||||
// Upload layer groups
|
||||
{
|
||||
const auto uploadPass = parameters.encoder->createUploadPass("layerGroup-upload",
|
||||
@@ -290,6 +346,7 @@ void Renderer::Impl::render(const RenderTree& renderTree, const std::shared_ptr<
|
||||
|
||||
// Upload the Debug layer group
|
||||
orchestrator.visitDebugLayerGroups([&](LayerGroupBase& layerGroup) { layerGroup.upload(*uploadPass); });
|
||||
if (useRetainedUnderlay) retainedUnderlayCache->upload(*uploadPass);
|
||||
}
|
||||
|
||||
const Size atlasSize = parameters.patternAtlas.getPixelSize();
|
||||
@@ -353,6 +410,32 @@ void Renderer::Impl::render(const RenderTree& renderTree, const std::shared_ptr<
|
||||
[&](RenderTarget& renderTarget) { renderTarget.render(orchestrator, renderTree, parameters); });
|
||||
};
|
||||
|
||||
const auto buildRetainedUnderlay = [&] {
|
||||
if (retainedDecision != RetainedUnderlayDecision::Build || !retainedBoundary) return;
|
||||
retainedUnderlayCache->beginBuild(parameters);
|
||||
context.bindGlobalUniformBuffers(*parameters.renderPass);
|
||||
parameters.depthRangeSize = 1 - (orchestrator.numLayerGroups() + 2) * PaintParameters::numSublayers *
|
||||
PaintParameters::depthEpsilon;
|
||||
parameters.pass = RenderPass::Opaque;
|
||||
orchestrator.visitLayerGroupsBeforeReversed(*retainedBoundary,
|
||||
[&](LayerGroupBase& layerGroup, size_t ordinal) {
|
||||
parameters.currentLayer = static_cast<uint32_t>(orchestrator.numLayerGroups() - 1 - ordinal);
|
||||
layerGroup.render(orchestrator, parameters);
|
||||
particle::incrementRendererDebugCounter(
|
||||
particle::RendererDebugCounter::RetainedUnderlayStaticGroupDraw);
|
||||
});
|
||||
parameters.pass = RenderPass::Translucent;
|
||||
orchestrator.visitLayerGroupsBefore(*retainedBoundary, [&](LayerGroupBase& layerGroup, size_t ordinal) {
|
||||
parameters.currentLayer = static_cast<uint32_t>(orchestrator.numLayerGroups() - 1 - ordinal);
|
||||
layerGroup.render(orchestrator, parameters);
|
||||
particle::incrementRendererDebugCounter(
|
||||
particle::RendererDebugCounter::RetainedUnderlayStaticGroupDraw);
|
||||
});
|
||||
context.unbindGlobalUniformBuffers(*parameters.renderPass);
|
||||
retainedUnderlayCache->finishBuild(parameters);
|
||||
retainedUnderlayCache->markBuildSucceeded();
|
||||
};
|
||||
|
||||
const auto commonClearPass = [&] {
|
||||
// - CLEAR
|
||||
// -------------------------------------------------------------------------------------
|
||||
@@ -386,11 +469,20 @@ void Renderer::Impl::render(const RenderTree& renderTree, const std::shared_ptr<
|
||||
PaintParameters::depthEpsilon;
|
||||
|
||||
// draw layer groups, opaque pass
|
||||
if (useRetainedUnderlay && retainedBoundary) {
|
||||
orchestrator.visitLayerGroupsFromReversed(*retainedBoundary,
|
||||
[&](LayerGroupBase& layerGroup, size_t ordinal) {
|
||||
parameters.currentLayer = static_cast<uint32_t>(orchestrator.numLayerGroups() - 1 - ordinal);
|
||||
layerGroup.render(orchestrator, parameters);
|
||||
particle::incrementRendererDebugCounter(particle::RendererDebugCounter::RetainedDynamicGroupDraw);
|
||||
});
|
||||
} else {
|
||||
parameters.currentLayer = 0;
|
||||
orchestrator.visitLayerGroupsReversed([&](LayerGroupBase& layerGroup) {
|
||||
layerGroup.render(orchestrator, parameters);
|
||||
parameters.currentLayer++;
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
const auto drawableTranslucentPass = [&] {
|
||||
@@ -400,6 +492,13 @@ void Renderer::Impl::render(const RenderTree& renderTree, const std::shared_ptr<
|
||||
PaintParameters::depthEpsilon;
|
||||
|
||||
// draw layer groups, translucent pass
|
||||
if (useRetainedUnderlay && retainedBoundary) {
|
||||
orchestrator.visitLayerGroupsFrom(*retainedBoundary, [&](LayerGroupBase& layerGroup, size_t ordinal) {
|
||||
parameters.currentLayer = static_cast<uint32_t>(orchestrator.numLayerGroups() - 1 - ordinal);
|
||||
layerGroup.render(orchestrator, parameters);
|
||||
particle::incrementRendererDebugCounter(particle::RendererDebugCounter::RetainedDynamicGroupDraw);
|
||||
});
|
||||
} else {
|
||||
parameters.currentLayer = static_cast<uint32_t>(orchestrator.numLayerGroups()) - 1;
|
||||
orchestrator.visitLayerGroups([&](LayerGroupBase& layerGroup) {
|
||||
layerGroup.render(orchestrator, parameters);
|
||||
@@ -407,6 +506,7 @@ void Renderer::Impl::render(const RenderTree& renderTree, const std::shared_ptr<
|
||||
parameters.currentLayer--;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Finally, render any legacy layers which have not been converted to drawables.
|
||||
// Note that they may be out of order, this is just a temporary fix for `RenderLocationIndicatorLayer` (#2216)
|
||||
@@ -439,8 +539,10 @@ void Renderer::Impl::render(const RenderTree& renderTree, const std::shared_ptr<
|
||||
drawable3DPass();
|
||||
}
|
||||
drawableTargetsPass();
|
||||
buildRetainedUnderlay();
|
||||
commonClearPass();
|
||||
context.bindGlobalUniformBuffers(*parameters.renderPass);
|
||||
if (useRetainedUnderlay) retainedUnderlayCache->composite(orchestrator, parameters);
|
||||
drawableOpaquePass();
|
||||
drawableTranslucentPass();
|
||||
drawableDebugOverlays();
|
||||
|
||||
@@ -16,6 +16,7 @@ namespace mbgl {
|
||||
class RendererObserver;
|
||||
class RenderStaticData;
|
||||
class RenderTree;
|
||||
class RetainedUnderlayCache;
|
||||
|
||||
namespace gfx {
|
||||
class RendererBackend;
|
||||
@@ -53,6 +54,7 @@ private:
|
||||
|
||||
const float pixelRatio;
|
||||
std::unique_ptr<RenderStaticData> staticData;
|
||||
std::unique_ptr<RetainedUnderlayCache> retainedUnderlayCache;
|
||||
gfx::DynamicTextureAtlasPtr dynamicTextureAtlas;
|
||||
bool styleLoaded = false;
|
||||
|
||||
|
||||
149
src/mbgl/renderer/retained_underlay_cache.cpp
Normal file
149
src/mbgl/renderer/retained_underlay_cache.cpp
Normal file
@@ -0,0 +1,149 @@
|
||||
#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
|
||||
85
src/mbgl/renderer/retained_underlay_cache.hpp
Normal file
85
src/mbgl/renderer/retained_underlay_cache.hpp
Normal file
@@ -0,0 +1,85 @@
|
||||
#pragma once
|
||||
|
||||
#include <mbgl/util/mat4.hpp>
|
||||
#include <mbgl/util/size.hpp>
|
||||
|
||||
#include <cstdint>
|
||||
#include <memory>
|
||||
#include <optional>
|
||||
#include <string>
|
||||
|
||||
namespace mbgl {
|
||||
|
||||
class LayerGroup;
|
||||
class PaintParameters;
|
||||
class RenderOrchestrator;
|
||||
|
||||
namespace gfx {
|
||||
class Context;
|
||||
class OffscreenTexture;
|
||||
class ShaderRegistry;
|
||||
class UploadPass;
|
||||
} // namespace gfx
|
||||
|
||||
struct RetainedUnderlayKey {
|
||||
Size viewport;
|
||||
int32_t boundary = 0;
|
||||
mat4 cameraMatrix{};
|
||||
|
||||
bool operator==(const RetainedUnderlayKey&) const = default;
|
||||
};
|
||||
|
||||
enum class RetainedUnderlayDecision : uint8_t { Disabled, Build, Reuse, Fallback };
|
||||
|
||||
class RetainedDynamicBoundaryTracker {
|
||||
public:
|
||||
void consider(int32_t layerIndex, bool candidate) {
|
||||
if (candidate && (!boundary || layerIndex < *boundary)) boundary = layerIndex;
|
||||
}
|
||||
std::optional<int32_t> value() const noexcept { return boundary; }
|
||||
|
||||
private:
|
||||
std::optional<int32_t> boundary;
|
||||
};
|
||||
|
||||
enum class RetainedLayerGroupRange : uint8_t { Before, From };
|
||||
inline bool retainedLayerGroupInRange(int32_t layerIndex, int32_t boundary, RetainedLayerGroupRange range) {
|
||||
return range == RetainedLayerGroupRange::Before ? layerIndex < boundary : layerIndex >= boundary;
|
||||
}
|
||||
|
||||
class RetainedUnderlayCache {
|
||||
public:
|
||||
RetainedUnderlayCache();
|
||||
~RetainedUnderlayCache();
|
||||
|
||||
RetainedUnderlayDecision evaluate(const std::optional<RetainedUnderlayKey>&, bool supported,
|
||||
const char* fallbackReason = nullptr);
|
||||
bool prepareResources(gfx::Context&, gfx::ShaderRegistry&, const RetainedUnderlayKey&);
|
||||
void upload(gfx::UploadPass&);
|
||||
void beginBuild(PaintParameters&);
|
||||
void finishBuild(PaintParameters&);
|
||||
void composite(RenderOrchestrator&, PaintParameters&);
|
||||
void markBuildSucceeded();
|
||||
void markBuildFailed(const char* reason);
|
||||
void invalidate(const char* reason);
|
||||
|
||||
bool isValid() const noexcept { return valid; }
|
||||
uint64_t getBuildCount() const noexcept { return buildCount; }
|
||||
uint64_t getReuseCount() const noexcept { return reuseCount; }
|
||||
uint64_t getFallbackCount() const noexcept { return fallbackCount; }
|
||||
const std::string& getLastInvalidationReason() const noexcept { return lastInvalidationReason; }
|
||||
|
||||
private:
|
||||
bool rebuildComposite(gfx::Context&, gfx::ShaderRegistry&);
|
||||
|
||||
std::optional<RetainedUnderlayKey> key;
|
||||
std::unique_ptr<gfx::OffscreenTexture> offscreenTexture;
|
||||
std::shared_ptr<LayerGroup> compositeLayerGroup;
|
||||
bool valid = false;
|
||||
uint64_t buildCount = 0;
|
||||
uint64_t reuseCount = 0;
|
||||
uint64_t fallbackCount = 0;
|
||||
std::string lastInvalidationReason;
|
||||
};
|
||||
|
||||
} // namespace mbgl
|
||||
@@ -304,6 +304,16 @@ const std::vector<TextureInfo> ParticleGpuValidationShaderInfo::textures = {
|
||||
TextureInfo{"u_state_texture", idParticleGpuValidationStateTexture},
|
||||
};
|
||||
|
||||
using RetainedUnderlayCompositeShaderInfo =
|
||||
ShaderInfo<BuiltIn::RetainedUnderlayCompositeShader, gfx::Backend::Type::OpenGL>;
|
||||
const std::vector<UniformBlockInfo> RetainedUnderlayCompositeShaderInfo::uniformBlocks = {};
|
||||
const std::vector<AttributeInfo> RetainedUnderlayCompositeShaderInfo::attributes = {
|
||||
AttributeInfo{"a_pos", idRetainedUnderlayCompositePosVertexAttribute},
|
||||
};
|
||||
const std::vector<TextureInfo> RetainedUnderlayCompositeShaderInfo::textures = {
|
||||
TextureInfo{"u_image", idRetainedUnderlayCompositeTexture},
|
||||
};
|
||||
|
||||
// Hillshade Prepare
|
||||
using HillshadePrepareShaderInfo = ShaderInfo<BuiltIn::HillshadePrepareShader, gfx::Backend::Type::OpenGL>;
|
||||
|
||||
|
||||
12
src/mbgl/shaders/mtl/retained_underlay_composite.cpp
Normal file
12
src/mbgl/shaders/mtl/retained_underlay_composite.cpp
Normal file
@@ -0,0 +1,12 @@
|
||||
#include <mbgl/shaders/mtl/retained_underlay_composite.hpp>
|
||||
#include <mbgl/shaders/shader_defines.hpp>
|
||||
|
||||
namespace mbgl::shaders {
|
||||
using Source = ShaderSource<BuiltIn::RetainedUnderlayCompositeShader, gfx::Backend::Type::Metal>;
|
||||
const std::array<AttributeInfo, 1> Source::attributes = {
|
||||
AttributeInfo{0, gfx::AttributeDataType::Short2, 0, idRetainedUnderlayCompositePosVertexAttribute},
|
||||
};
|
||||
const std::array<TextureInfo, 1> Source::textures = {
|
||||
TextureInfo{0, idRetainedUnderlayCompositeTexture},
|
||||
};
|
||||
} // namespace mbgl::shaders
|
||||
@@ -30,6 +30,7 @@ MBGL_DEFINE_ENUM(BuiltIn, {
|
||||
{BuiltIn::HeatmapShader, "HeatmapShader"},
|
||||
{BuiltIn::HeatmapTextureShader, "HeatmapTextureShader"},
|
||||
{BuiltIn::ParticleGpuValidationShader, "ParticleGpuValidationShader"},
|
||||
{BuiltIn::RetainedUnderlayCompositeShader, "RetainedUnderlayCompositeShader"},
|
||||
{BuiltIn::HillshadePrepareShader, "HillshadePrepareShader"},
|
||||
{BuiltIn::ColorReliefShader, "ColorReliefShader"},
|
||||
{BuiltIn::HillshadeShader, "HillshadeShader"},
|
||||
|
||||
@@ -27,6 +27,7 @@ add_library(
|
||||
${PROJECT_SOURCE_DIR}/test/plugin/plugin.test.cpp
|
||||
${PROJECT_SOURCE_DIR}/test/renderer/image_manager.test.cpp
|
||||
${PROJECT_SOURCE_DIR}/test/renderer/pattern_atlas.test.cpp
|
||||
${PROJECT_SOURCE_DIR}/test/renderer/retained_underlay_cache.test.cpp
|
||||
${PROJECT_SOURCE_DIR}/test/renderer/shader_registry.test.cpp
|
||||
$<$<BOOL:${MLN_WITH_WEBGPU}>:${PROJECT_SOURCE_DIR}/test/renderer/wgsl_preprocessor.test.cpp>
|
||||
${PROJECT_SOURCE_DIR}/test/sprite/sprite_loader.test.cpp
|
||||
|
||||
@@ -4,6 +4,10 @@
|
||||
|
||||
#include <mbgl/platform/gl_functions.hpp>
|
||||
|
||||
#if defined(__APPLE__)
|
||||
#include <TargetConditionals.h>
|
||||
#endif
|
||||
|
||||
using namespace mbgl::platform;
|
||||
|
||||
TEST(GLFunctions, OpenGLES) {
|
||||
@@ -253,8 +257,15 @@ TEST(GLFunctions, OpenGLES) {
|
||||
EXPECT_NE(glGetProgramBinary, nullptr);
|
||||
EXPECT_NE(glProgramBinary, nullptr);
|
||||
EXPECT_NE(glProgramParameteri, nullptr);
|
||||
#if defined(__APPLE__)
|
||||
#if TARGET_OS_IPHONE || TARGET_OS_SIMULATOR
|
||||
EXPECT_NE(glInvalidateFramebuffer, nullptr);
|
||||
EXPECT_NE(glInvalidateSubFramebuffer, nullptr);
|
||||
#endif
|
||||
#else
|
||||
EXPECT_NE(glInvalidateFramebuffer, nullptr);
|
||||
EXPECT_NE(glInvalidateSubFramebuffer, nullptr);
|
||||
#endif
|
||||
EXPECT_NE(glTexStorage2D, nullptr);
|
||||
EXPECT_NE(glTexStorage3D, nullptr);
|
||||
EXPECT_NE(glGetInternalformativ, nullptr);
|
||||
|
||||
89
test/renderer/retained_underlay_cache.test.cpp
Normal file
89
test/renderer/retained_underlay_cache.test.cpp
Normal file
@@ -0,0 +1,89 @@
|
||||
#include <mbgl/renderer/retained_underlay_cache.hpp>
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include <vector>
|
||||
|
||||
using namespace mbgl;
|
||||
|
||||
namespace {
|
||||
RetainedUnderlayKey key(Size size = {640, 480}, int32_t boundary = 4) {
|
||||
RetainedUnderlayKey result{size, boundary, {}};
|
||||
result.cameraMatrix[0] = 1.0;
|
||||
result.cameraMatrix[5] = 1.0;
|
||||
result.cameraMatrix[10] = 1.0;
|
||||
result.cameraMatrix[15] = 1.0;
|
||||
return result;
|
||||
}
|
||||
} // namespace
|
||||
|
||||
TEST(RetainedDynamicBoundary, SelectsFirstCandidate) {
|
||||
RetainedDynamicBoundaryTracker none;
|
||||
none.consider(0, false);
|
||||
none.consider(3, false);
|
||||
EXPECT_FALSE(none.value());
|
||||
|
||||
RetainedDynamicBoundaryTracker particleOnly;
|
||||
particleOnly.consider(5, true);
|
||||
EXPECT_EQ(particleOnly.value(), 5);
|
||||
|
||||
RetainedDynamicBoundaryTracker weatherAndParticle;
|
||||
weatherAndParticle.consider(7, true);
|
||||
weatherAndParticle.consider(2, true);
|
||||
EXPECT_EQ(weatherAndParticle.value(), 2);
|
||||
|
||||
RetainedDynamicBoundaryTracker particleAndWeather;
|
||||
particleAndWeather.consider(2, true);
|
||||
particleAndWeather.consider(7, true);
|
||||
EXPECT_EQ(particleAndWeather.value(), 2);
|
||||
}
|
||||
|
||||
TEST(RetainedLayerGroupRange, PreservesForwardReverseOriginalOrdinals) {
|
||||
const std::vector<int32_t> indices{0, 1, 3, 5, 8};
|
||||
std::vector<size_t> beforeForward;
|
||||
std::vector<size_t> fromForward;
|
||||
std::vector<size_t> beforeReverse;
|
||||
std::vector<size_t> fromReverse;
|
||||
for (size_t ordinal = 0; ordinal < indices.size(); ++ordinal) {
|
||||
if (retainedLayerGroupInRange(indices[ordinal], 5, RetainedLayerGroupRange::Before))
|
||||
beforeForward.push_back(ordinal);
|
||||
else
|
||||
fromForward.push_back(ordinal);
|
||||
}
|
||||
for (size_t ordinal = indices.size(); ordinal-- > 0;) {
|
||||
if (retainedLayerGroupInRange(indices[ordinal], 5, RetainedLayerGroupRange::Before))
|
||||
beforeReverse.push_back(ordinal);
|
||||
else
|
||||
fromReverse.push_back(ordinal);
|
||||
}
|
||||
EXPECT_EQ(beforeForward, (std::vector<size_t>{0, 1, 2}));
|
||||
EXPECT_EQ(fromForward, (std::vector<size_t>{3, 4}));
|
||||
EXPECT_EQ(beforeReverse, (std::vector<size_t>{2, 1, 0}));
|
||||
EXPECT_EQ(fromReverse, (std::vector<size_t>{4, 3}));
|
||||
}
|
||||
|
||||
TEST(RetainedUnderlayCache, BuildReuseAndInvalidation) {
|
||||
RetainedUnderlayCache cache;
|
||||
EXPECT_EQ(cache.evaluate(std::nullopt, false), RetainedUnderlayDecision::Disabled);
|
||||
EXPECT_EQ(cache.evaluate(key(), true), RetainedUnderlayDecision::Build);
|
||||
cache.markBuildSucceeded();
|
||||
EXPECT_EQ(cache.evaluate(key(), true), RetainedUnderlayDecision::Reuse);
|
||||
|
||||
EXPECT_EQ(cache.evaluate(key({800, 600}), true), RetainedUnderlayDecision::Build);
|
||||
EXPECT_EQ(cache.getLastInvalidationReason(), "viewport");
|
||||
cache.markBuildSucceeded();
|
||||
EXPECT_EQ(cache.evaluate(key({800, 600}, 6), true), RetainedUnderlayDecision::Build);
|
||||
EXPECT_EQ(cache.getLastInvalidationReason(), "camera-or-boundary");
|
||||
}
|
||||
|
||||
TEST(RetainedUnderlayCache, UnsupportedAndResourceFailureFallBackSafely) {
|
||||
RetainedUnderlayCache cache;
|
||||
EXPECT_EQ(cache.evaluate(key(), false, "3d"), RetainedUnderlayDecision::Fallback);
|
||||
EXPECT_EQ(cache.getLastInvalidationReason(), "3d");
|
||||
EXPECT_FALSE(cache.isValid());
|
||||
|
||||
EXPECT_EQ(cache.evaluate(key(), true), RetainedUnderlayDecision::Build);
|
||||
cache.markBuildFailed("resource-or-compositor");
|
||||
EXPECT_FALSE(cache.isValid());
|
||||
EXPECT_EQ(cache.getFallbackCount(), 2u);
|
||||
}
|
||||
Reference in New Issue
Block a user