Heatmap layer (#1230)

Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
This commit is contained in:
Alex Cristici
2023-07-03 16:50:10 +03:00
committed by Bart Louwers
parent e631bc3c42
commit 813ddb024a
46 changed files with 1247 additions and 26 deletions

View File

@@ -148,6 +148,7 @@ if(MLN_DRAWABLE_RENDERER)
${PROJECT_SOURCE_DIR}/include/mbgl/renderer/change_request.hpp
${PROJECT_SOURCE_DIR}/include/mbgl/renderer/layer_group.hpp
${PROJECT_SOURCE_DIR}/include/mbgl/renderer/layer_tweaker.hpp
${PROJECT_SOURCE_DIR}/include/mbgl/renderer/render_target.hpp
${PROJECT_SOURCE_DIR}/include/mbgl/shaders/shader_program_base.hpp
${PROJECT_SOURCE_DIR}/include/mbgl/shaders/mtl/shader_program_mtl.hpp
${PROJECT_SOURCE_DIR}/include/mbgl/util/identity.hpp
@@ -159,6 +160,7 @@ if(MLN_DRAWABLE_RENDERER)
${PROJECT_SOURCE_DIR}/include/mbgl/gl/drawable_gl_builder.hpp
${PROJECT_SOURCE_DIR}/include/mbgl/gl/drawable_gl_tweaker.hpp
${PROJECT_SOURCE_DIR}/include/mbgl/gl/layer_group_gl.hpp
${PROJECT_SOURCE_DIR}/include/mbgl/gl/render_target_gl.hpp
${PROJECT_SOURCE_DIR}/include/mbgl/gl/uniform_block_gl.hpp
${PROJECT_SOURCE_DIR}/include/mbgl/gl/uniform_buffer_gl.hpp
${PROJECT_SOURCE_DIR}/include/mbgl/gl/vertex_attribute_gl.hpp
@@ -590,6 +592,10 @@ list(APPEND SRC_FILES
${PROJECT_SOURCE_DIR}/src/mbgl/renderer/layers/circle_layer_tweaker.hpp
${PROJECT_SOURCE_DIR}/src/mbgl/renderer/layers/fill_layer_tweaker.cpp
${PROJECT_SOURCE_DIR}/src/mbgl/renderer/layers/fill_layer_tweaker.hpp
${PROJECT_SOURCE_DIR}/src/mbgl/renderer/layers/heatmap_layer_tweaker.cpp
${PROJECT_SOURCE_DIR}/src/mbgl/renderer/layers/heatmap_layer_tweaker.hpp
${PROJECT_SOURCE_DIR}/src/mbgl/renderer/layers/heatmap_texture_layer_tweaker.cpp
${PROJECT_SOURCE_DIR}/src/mbgl/renderer/layers/heatmap_texture_layer_tweaker.hpp
${PROJECT_SOURCE_DIR}/src/mbgl/renderer/layers/raster_layer_tweaker.cpp
${PROJECT_SOURCE_DIR}/src/mbgl/renderer/layers/raster_layer_tweaker.hpp
${PROJECT_SOURCE_DIR}/src/mbgl/renderer/layers/render_background_layer.cpp
@@ -631,6 +637,7 @@ list(APPEND SRC_FILES
${PROJECT_SOURCE_DIR}/src/mbgl/renderer/render_source_observer.hpp
${PROJECT_SOURCE_DIR}/src/mbgl/renderer/render_static_data.cpp
${PROJECT_SOURCE_DIR}/src/mbgl/renderer/render_static_data.hpp
${PROJECT_SOURCE_DIR}/src/mbgl/renderer/render_target.cpp
${PROJECT_SOURCE_DIR}/src/mbgl/renderer/render_tile.cpp
${PROJECT_SOURCE_DIR}/src/mbgl/renderer/render_tile.hpp
${PROJECT_SOURCE_DIR}/src/mbgl/renderer/render_tree.hpp
@@ -1007,6 +1014,8 @@ if(MLN_WITH_OPENGL)
${PROJECT_SOURCE_DIR}/include/mbgl/shaders/gl/drawable_line_sdf.hpp
${PROJECT_SOURCE_DIR}/include/mbgl/shaders/gl/drawable_fill_outline_pattern.hpp
${PROJECT_SOURCE_DIR}/include/mbgl/shaders/gl/drawable_fill_pattern.hpp
${PROJECT_SOURCE_DIR}/include/mbgl/shaders/gl/drawable_heatmap.hpp
${PROJECT_SOURCE_DIR}/include/mbgl/shaders/gl/drawable_heatmap_texture.hpp
${PROJECT_SOURCE_DIR}/include/mbgl/shaders/gl/drawable_raster.hpp
${PROJECT_SOURCE_DIR}/include/mbgl/shaders/gl/drawable_symbol_icon.hpp
${PROJECT_SOURCE_DIR}/include/mbgl/shaders/gl/drawable_symbol_sdf_text.hpp
@@ -1069,6 +1078,7 @@ if(MLN_WITH_OPENGL)
${PROJECT_SOURCE_DIR}/src/mbgl/gl/render_custom_layer.hpp
${PROJECT_SOURCE_DIR}/src/mbgl/gl/render_pass.cpp
${PROJECT_SOURCE_DIR}/src/mbgl/gl/render_pass.hpp
${PROJECT_SOURCE_DIR}/src/mbgl/gl/render_target_gl.cpp
${PROJECT_SOURCE_DIR}/src/mbgl/gl/renderbuffer_resource.hpp
${PROJECT_SOURCE_DIR}/src/mbgl/gl/renderer_backend.cpp
${PROJECT_SOURCE_DIR}/src/mbgl/gl/state.hpp

View File

@@ -849,6 +849,8 @@ MLN_OPENGL_HEADERS = [
"include/mbgl/shaders/gl/drawable_line_pattern.hpp",
"include/mbgl/shaders/gl/drawable_line_sdf.hpp",
"include/mbgl/shaders/gl/drawable_line.hpp",
"include/mbgl/shaders/gl/drawable_heatmap.hpp",
"include/mbgl/shaders/gl/drawable_heatmap_texture.hpp",
"include/mbgl/shaders/gl/drawable_raster.hpp",
"include/mbgl/shaders/gl/drawable_symbol_icon.hpp",
"include/mbgl/shaders/gl/drawable_symbol_sdf_text.hpp",
@@ -892,12 +894,17 @@ MLN_DRAWABLES_SOURCE = [
"src/mbgl/renderer/layer_group.cpp",
"src/mbgl/renderer/tile_layer_group.cpp",
"src/mbgl/renderer/layer_tweaker.cpp",
"src/mbgl/renderer/render_target.cpp",
"src/mbgl/renderer/layers/background_layer_tweaker.cpp",
"src/mbgl/renderer/layers/background_layer_tweaker.hpp",
"src/mbgl/renderer/layers/circle_layer_tweaker.cpp",
"src/mbgl/renderer/layers/circle_layer_tweaker.hpp",
"src/mbgl/renderer/layers/fill_layer_tweaker.cpp",
"src/mbgl/renderer/layers/fill_layer_tweaker.hpp",
"src/mbgl/renderer/layers/heatmap_layer_tweaker.cpp",
"src/mbgl/renderer/layers/heatmap_layer_tweaker.hpp",
"src/mbgl/renderer/layers/heatmap_texture_layer_tweaker.cpp",
"src/mbgl/renderer/layers/heatmap_texture_layer_tweaker.hpp",
"src/mbgl/renderer/layers/line_layer_tweaker.cpp",
"src/mbgl/renderer/layers/line_layer_tweaker.hpp",
"src/mbgl/renderer/layers/raster_layer_tweaker.cpp",
@@ -913,6 +920,7 @@ MLN_DRAWABLES_SOURCE = [
"src/mbgl/gl/drawable_gl_impl.hpp",
"src/mbgl/gl/drawable_gl_tweaker.cpp",
"src/mbgl/gl/layer_group_gl.cpp",
"src/mbgl/gl/render_target_gl.cpp",
"src/mbgl/gl/texture2d.cpp",
"src/mbgl/gl/uniform_block_gl.cpp",
"src/mbgl/gl/uniform_buffer_gl.cpp",
@@ -932,6 +940,7 @@ MLN_DRAWABLES_HEADERS = [
"include/mbgl/renderer/change_request.hpp",
"include/mbgl/renderer/layer_group.hpp",
"include/mbgl/renderer/layer_tweaker.hpp",
"include/mbgl/renderer/render_target.hpp",
"include/mbgl/shaders/shader_program_base.hpp",
"include/mbgl/shaders/mtl/shader_program_mtl.hpp",
"include/mbgl/util/identity.hpp",
@@ -941,6 +950,7 @@ MLN_DRAWABLES_HEADERS = [
"include/mbgl/gl/drawable_gl_builder.hpp",
"include/mbgl/gl/drawable_gl_tweaker.hpp",
"include/mbgl/gl/layer_group_gl.hpp",
"include/mbgl/gl/render_target_gl.hpp",
"include/mbgl/gl/uniform_block_gl.hpp",
"include/mbgl/gl/uniform_buffer_gl.hpp",
"include/mbgl/gl/vertex_attribute_gl.hpp",

View File

@@ -22,6 +22,7 @@ enum class RenderPass : uint8_t;
namespace gfx {
class ColorMode;
class CullFaceMode;
enum class DepthMaskType : bool;
class DrawableTweaker;
@@ -134,6 +135,9 @@ public:
const gfx::CullFaceMode& getCullFaceMode() const;
void setCullFaceMode(const gfx::CullFaceMode&);
const gfx::ColorMode& getColorMode() const;
void setColorMode(const gfx::ColorMode&);
/// Get the number of vertexes
std::size_t getVertexCount() const { return getVertexAttributes().getMaxCount(); }

View File

@@ -76,6 +76,9 @@ public:
DepthMaskType getDepthType() const { return depthType; }
void setDepthType(DepthMaskType value) { depthType = value; }
const gfx::ColorMode& getColorMode() const;
void setColorMode(const gfx::ColorMode& value);
const gfx::CullFaceMode& getCullFaceMode() const;
void setCullFaceMode(const gfx::CullFaceMode& value);

View File

@@ -0,0 +1,29 @@
#pragma once
#include <mbgl/renderer/render_target.hpp>
#include <mbgl/gfx/types.hpp>
#include <mbgl/gl/object.hpp>
#include <mbgl/gl/types.hpp>
#include <mbgl/util/size.hpp>
namespace mbgl {
namespace gl {
class Context;
using UniqueFramebufferPtr = std::shared_ptr<UniqueFramebuffer>;
class RenderTargetGL final : public RenderTarget {
public:
RenderTargetGL(Context& context, const Size size, const gfx::TextureChannelDataType type);
~RenderTargetGL() override;
void upload(gfx::UploadPass& uploadPass) override;
void render(RenderOrchestrator&, const RenderTree&, PaintParameters&) override;
private:
Context& glContext;
UniqueFramebufferPtr framebuffer;
};
} // namespace gl
} // namespace mbgl

View File

@@ -11,11 +11,13 @@ class ChangeRequest;
class LayerGroupBase;
class TileLayerGroup;
class RenderOrchestrator;
class RenderTarget;
using ChangeRequestPtr = std::shared_ptr<ChangeRequest>;
using UniqueChangeRequest = std::unique_ptr<ChangeRequest>;
using UniqueChangeRequestVec = std::vector<UniqueChangeRequest>;
using LayerGroupBasePtr = std::shared_ptr<LayerGroupBase>;
using RenderTargetPtr = std::shared_ptr<RenderTarget>;
namespace gfx {
class Drawable;
@@ -89,4 +91,30 @@ protected:
int32_t newLayerIndex;
};
/**
Add a new render target to the scene
*/
class AddRenderTargetRequest : public ChangeRequest {
public:
AddRenderTargetRequest(RenderTargetPtr renderTarget_);
void execute(RenderOrchestrator &) override;
protected:
RenderTargetPtr renderTarget;
};
/**
Remove a render target from the scene
*/
class RemoveRenderTargetRequest : public ChangeRequest {
public:
RemoveRenderTargetRequest(const RenderTargetPtr &renderTarget_);
void execute(RenderOrchestrator &) override;
protected:
const RenderTargetPtr &renderTarget;
};
} // namespace mbgl

View File

@@ -0,0 +1,45 @@
#pragma once
#include <string>
#include <memory>
#include <map>
namespace mbgl {
namespace gfx {
class Texture2D;
class UploadPass;
using Texture2DPtr = std::shared_ptr<Texture2D>;
} // namespace gfx
class LayerGroupBase;
class PaintParameters;
class RenderOrchestrator;
class RenderTree;
using LayerGroupBasePtr = std::shared_ptr<LayerGroupBase>;
class RenderTarget {
public:
virtual ~RenderTarget() = default;
void setTexture(const gfx::Texture2DPtr& texture_) { texture = std::move(texture_); };
const gfx::Texture2DPtr& getTexture() const { return texture; };
bool addLayerGroup(LayerGroupBasePtr, bool replace);
bool removeLayerGroup(const int32_t layerIndex);
size_t numLayerGroups() const noexcept;
const LayerGroupBasePtr& getLayerGroup(const int32_t layerIndex) const;
void observeLayerGroups(std::function<void(LayerGroupBase&)>);
void observeLayerGroups(std::function<void(const LayerGroupBase&)>) const;
virtual void upload(gfx::UploadPass& uploadPass) = 0;
virtual void render(RenderOrchestrator&, const RenderTree&, PaintParameters&) = 0;
protected:
gfx::Texture2DPtr texture;
using LayerGroupMap = std::map<int32_t, LayerGroupBasePtr>;
LayerGroupMap layerGroupsByLayerIndex;
};
} // namespace mbgl

View File

@@ -0,0 +1,127 @@
// Generated code, do not modify this file!
#pragma once
#include <mbgl/shaders/shader_source.hpp>
namespace mbgl {
namespace shaders {
template <>
struct ShaderSource<BuiltIn::HeatmapShader, gfx::Backend::Type::OpenGL> {
static constexpr const char* name = "HeatmapShader";
static constexpr const char* vertex = R"(layout (location = 0) in vec2 a_pos;
out vec2 v_extrude;
layout (std140) uniform HeatmapDrawableUBO {
highp mat4 u_matrix;
highp float u_extrude_scale;
lowp float pad1_;
lowp vec2 pad2_;
};
layout (std140) uniform HeatmapEvaluatedPropsUBO {
highp float u_weight;
highp float u_radius;
highp float u_intensity;
lowp float pad0_;
};
layout (std140) uniform HeatmapInterpolateUBO {
lowp float u_weight_t;
lowp float u_radius_t;
lowp vec2 pad3_;
};
#ifndef HAS_UNIFORM_u_weight
layout (location = 1) in highp vec2 a_weight;
out highp float weight;
#endif
#ifndef HAS_UNIFORM_u_radius
layout (location = 2) in mediump vec2 a_radius;
#endif
// Effective "0" in the kernel density texture to adjust the kernel size to;
// this empirically chosen number minimizes artifacts on overlapping kernels
// for typical heatmap cases (assuming clustered source)
const highp float ZERO = 1.0 / 255.0 / 16.0;
// Gaussian kernel coefficient: 1 / sqrt(2 * PI)
#define GAUSS_COEF 0.3989422804014327
void main(void) {
#ifndef HAS_UNIFORM_u_weight
weight = unpack_mix_vec2(a_weight, u_weight_t);
#else
highp float weight = u_weight;
#endif
#ifndef HAS_UNIFORM_u_radius
mediump float radius = unpack_mix_vec2(a_radius, u_radius_t);
#else
mediump float radius = u_radius;
#endif
// unencode the extrusion vector that we snuck into the a_pos vector
vec2 unscaled_extrude = vec2(mod(a_pos, 2.0) * 2.0 - 1.0);
// This 'extrude' comes in ranging from [-1, -1], to [1, 1]. We'll use
// it to produce the vertices of a square mesh framing the point feature
// we're adding to the kernel density texture. We'll also pass it as
// a varying, so that the fragment shader can determine the distance of
// each fragment from the point feature.
// Before we do so, we need to scale it up sufficiently so that the
// kernel falls effectively to zero at the edge of the mesh.
// That is, we want to know S such that
// weight * u_intensity * GAUSS_COEF * exp(-0.5 * 3.0^2 * S^2) == ZERO
// Which solves to:
// S = sqrt(-2.0 * log(ZERO / (weight * u_intensity * GAUSS_COEF))) / 3.0
float S = sqrt(-2.0 * log(ZERO / weight / u_intensity / GAUSS_COEF)) / 3.0;
// Pass the varying in units of radius
v_extrude = S * unscaled_extrude;
// Scale by radius and the zoom-based scale factor to produce actual
// mesh position
vec2 extrude = v_extrude * radius * u_extrude_scale;
// multiply a_pos by 0.5, since we had it * 2 in order to sneak
// in extrusion data
vec4 pos = vec4(floor(a_pos * 0.5) + extrude, 0, 1);
gl_Position = u_matrix * pos;
}
)";
static constexpr const char* fragment = R"(in vec2 v_extrude;
layout (std140) uniform HeatmapEvaluatedPropsUBO {
highp float u_weight;
highp float u_radius;
highp float u_intensity;
lowp float pad0_;
};
#ifndef HAS_UNIFORM_u_weight
in highp float weight;
#endif
// Gaussian kernel coefficient: 1 / sqrt(2 * PI)
#define GAUSS_COEF 0.3989422804014327
void main() {
#ifdef HAS_UNIFORM_u_weight
highp float weight = u_weight;
#endif
// Kernel density estimation with a Gaussian kernel of size 5x5
float d = -0.5 * 3.0 * 3.0 * dot(v_extrude, v_extrude);
float val = weight * u_intensity * GAUSS_COEF * exp(d);
fragColor = vec4(val, 1.0, 1.0, 1.0);
#ifdef OVERDRAW_INSPECTOR
fragColor = vec4(1.0);
#endif
}
)";
};
} // namespace shaders
} // namespace mbgl

View File

@@ -0,0 +1,52 @@
// Generated code, do not modify this file!
#pragma once
#include <mbgl/shaders/shader_source.hpp>
namespace mbgl {
namespace shaders {
template <>
struct ShaderSource<BuiltIn::HeatmapTextureShader, gfx::Backend::Type::OpenGL> {
static constexpr const char* name = "HeatmapTextureShader";
static constexpr const char* vertex = R"(layout (location = 0) in vec2 a_pos;
out vec2 v_pos;
layout (std140) uniform HeatmapTextureDrawableUBO {
highp mat4 u_matrix;
highp vec2 u_world;
highp float u_opacity;
lowp float pad0_;
};
void main() {
gl_Position = u_matrix * vec4(a_pos * u_world, 0, 1);
v_pos.x = a_pos.x;
v_pos.y = 1.0 - a_pos.y;
}
)";
static constexpr const char* fragment = R"(in vec2 v_pos;
uniform sampler2D u_image;
uniform sampler2D u_color_ramp;
layout (std140) uniform HeatmapTextureDrawableUBO {
highp mat4 u_matrix;
highp vec2 u_world;
highp float u_opacity;
lowp float pad0_;
};
void main() {
float t = texture(u_image, v_pos).r;
vec4 color = texture(u_color_ramp, vec2(t, 0.5));
fragColor = color * u_opacity;
#ifdef OVERDRAW_INSPECTOR
fragColor = vec4(0.0);
#endif
}
)";
};
} // namespace shaders
} // namespace mbgl

View File

@@ -14,6 +14,8 @@
#include <mbgl/shaders/gl/drawable_line.hpp>
#include <mbgl/shaders/gl/drawable_fill_pattern.hpp>
#include <mbgl/shaders/gl/drawable_fill_outline_pattern.hpp>
#include <mbgl/shaders/gl/drawable_heatmap.hpp>
#include <mbgl/shaders/gl/drawable_heatmap_texture.hpp>
#include <mbgl/shaders/gl/drawable_raster.hpp>
#include <mbgl/shaders/gl/drawable_symbol_icon.hpp>
#include <mbgl/shaders/gl/drawable_symbol_sdf_icon.hpp>

View File

@@ -20,11 +20,14 @@ enum class BuiltIn {
LineShader,
FillPatternShader,
FillOutlinePatternShader,
HeatmapShader,
HeatmapTextureShader,
RasterShader,
SymbolIconShader,
SymbolSDFTextShader,
SymbolSDFIconShader,
SymbolTextAndIconShader,
Prelude,
BackgroundProgram,
BackgroundPatternProgram,

View File

@@ -0,0 +1,27 @@
in vec2 v_extrude;
layout (std140) uniform HeatmapEvaluatedPropsUBO {
highp float u_weight;
highp float u_radius;
highp float u_intensity;
lowp float pad0_;
};
#pragma mapbox: define highp float weight
// Gaussian kernel coefficient: 1 / sqrt(2 * PI)
#define GAUSS_COEF 0.3989422804014327
void main() {
#pragma mapbox: initialize highp float weight
// Kernel density estimation with a Gaussian kernel of size 5x5
float d = -0.5 * 3.0 * 3.0 * dot(v_extrude, v_extrude);
float val = weight * u_intensity * GAUSS_COEF * exp(d);
fragColor = vec4(val, 1.0, 1.0, 1.0);
#ifdef OVERDRAW_INSPECTOR
fragColor = vec4(1.0);
#endif
}

View File

@@ -0,0 +1,67 @@
layout (location = 0) in vec2 a_pos;
out vec2 v_extrude;
layout (std140) uniform HeatmapDrawableUBO {
highp mat4 u_matrix;
highp float u_extrude_scale;
lowp float pad1_;
lowp vec2 pad2_;
};
layout (std140) uniform HeatmapEvaluatedPropsUBO {
highp float u_weight;
highp float u_radius;
highp float u_intensity;
lowp float pad0_;
};
layout (std140) uniform HeatmapInterpolateUBO {
lowp float u_weight_t;
lowp float u_radius_t;
lowp vec2 pad3_;
};
#pragma mapbox: define highp float weight
#pragma mapbox: define mediump float radius
// Effective "0" in the kernel density texture to adjust the kernel size to;
// this empirically chosen number minimizes artifacts on overlapping kernels
// for typical heatmap cases (assuming clustered source)
const highp float ZERO = 1.0 / 255.0 / 16.0;
// Gaussian kernel coefficient: 1 / sqrt(2 * PI)
#define GAUSS_COEF 0.3989422804014327
void main(void) {
#pragma mapbox: initialize highp float weight
#pragma mapbox: initialize mediump float radius
// unencode the extrusion vector that we snuck into the a_pos vector
vec2 unscaled_extrude = vec2(mod(a_pos, 2.0) * 2.0 - 1.0);
// This 'extrude' comes in ranging from [-1, -1], to [1, 1]. We'll use
// it to produce the vertices of a square mesh framing the point feature
// we're adding to the kernel density texture. We'll also pass it as
// a varying, so that the fragment shader can determine the distance of
// each fragment from the point feature.
// Before we do so, we need to scale it up sufficiently so that the
// kernel falls effectively to zero at the edge of the mesh.
// That is, we want to know S such that
// weight * u_intensity * GAUSS_COEF * exp(-0.5 * 3.0^2 * S^2) == ZERO
// Which solves to:
// S = sqrt(-2.0 * log(ZERO / (weight * u_intensity * GAUSS_COEF))) / 3.0
float S = sqrt(-2.0 * log(ZERO / weight / u_intensity / GAUSS_COEF)) / 3.0;
// Pass the varying in units of radius
v_extrude = S * unscaled_extrude;
// Scale by radius and the zoom-based scale factor to produce actual
// mesh position
vec2 extrude = v_extrude * radius * u_extrude_scale;
// multiply a_pos by 0.5, since we had it * 2 in order to sneak
// in extrusion data
vec4 pos = vec4(floor(a_pos * 0.5) + extrude, 0, 1);
gl_Position = u_matrix * pos;
}

View File

@@ -0,0 +1,20 @@
in vec2 v_pos;
uniform sampler2D u_image;
uniform sampler2D u_color_ramp;
layout (std140) uniform HeatmapTextureDrawableUBO {
highp mat4 u_matrix;
highp vec2 u_world;
highp float u_opacity;
lowp float pad0_;
};
void main() {
float t = texture(u_image, v_pos).r;
vec4 color = texture(u_color_ramp, vec2(t, 0.5));
fragColor = color * u_opacity;
#ifdef OVERDRAW_INSPECTOR
fragColor = vec4(0.0);
#endif
}

View File

@@ -0,0 +1,16 @@
layout (location = 0) in vec2 a_pos;
out vec2 v_pos;
layout (std140) uniform HeatmapTextureDrawableUBO {
highp mat4 u_matrix;
highp vec2 u_world;
highp float u_opacity;
lowp float pad0_;
};
void main() {
gl_Position = u_matrix * vec4(a_pos * u_world, 0, 1);
v_pos.x = a_pos.x;
v_pos.y = 1.0 - a_pos.y;
}

View File

@@ -76,6 +76,20 @@
"glsl_frag": "drawable.fill_outline_pattern.fragment.glsl",
"uses_ubos": true
},
{
"name": "HeatmapShader",
"header": "drawable_heatmap",
"glsl_vert": "drawable.heatmap.vertex.glsl",
"glsl_frag": "drawable.heatmap.fragment.glsl",
"uses_ubos": true
},
{
"name": "HeatmapTextureShader",
"header": "drawable_heatmap_texture",
"glsl_vert": "drawable.heatmap_texture.vertex.glsl",
"glsl_frag": "drawable.heatmap_texture.fragment.glsl",
"uses_ubos": true
},
{
"name": "RasterShader",
"header": "drawable_raster",

View File

@@ -24,8 +24,10 @@ class ProgramParameters;
#if MLN_DRAWABLE_RENDERER
class TileLayerGroup;
class LayerGroup;
class RenderTarget;
using TileLayerGroupPtr = std::shared_ptr<TileLayerGroup>;
using LayerGroupPtr = std::shared_ptr<LayerGroup>;
using RenderTargetPtr = std::shared_ptr<RenderTarget>;
#endif
namespace gfx {
@@ -137,6 +139,9 @@ public:
/// Create a texture
virtual Texture2DPtr createTexture2D() = 0;
/// Create a render target
virtual RenderTargetPtr createRenderTarget(const Size size, const TextureChannelDataType type) = 0;
#endif
};

View File

@@ -1,5 +1,6 @@
#include <mbgl/gfx/drawable.hpp>
#include <mbgl/gfx/color_mode.hpp>
#include <mbgl/gfx/cull_face_mode.hpp>
#include <mbgl/gfx/types.hpp>
#include <mbgl/renderer/render_pass.hpp>
@@ -8,6 +9,7 @@ namespace mbgl {
namespace gfx {
struct Drawable::Impl {
gfx::ColorMode colorMode = gfx::ColorMode::disabled();
gfx::CullFaceMode cullFaceMode = gfx::CullFaceMode::disabled();
};
@@ -19,6 +21,14 @@ Drawable::Drawable(std::string name_)
Drawable::~Drawable() = default;
const gfx::ColorMode& Drawable::getColorMode() const {
return impl->colorMode;
}
void Drawable::setColorMode(const gfx::ColorMode& value) {
impl->colorMode = value;
}
const gfx::CullFaceMode& Drawable::getCullFaceMode() const {
return impl->cullFaceMode;
}

View File

@@ -16,6 +16,13 @@ DrawableBuilder::DrawableBuilder(std::string name_)
DrawableBuilder::~DrawableBuilder() = default;
const gfx::ColorMode& DrawableBuilder::getColorMode() const {
return impl->colorMode;
}
void DrawableBuilder::setColorMode(const gfx::ColorMode& value) {
impl->colorMode = value;
}
const gfx::CullFaceMode& DrawableBuilder::getCullFaceMode() const {
return impl->cullFaceMode;
}
@@ -40,6 +47,7 @@ void DrawableBuilder::flush() {
draw->setDrawPriority(drawPriority);
draw->setSubLayerIndex(subLayerIndex);
draw->setDepthType(depthType);
draw->setColorMode(impl->colorMode);
draw->setCullFaceMode(impl->cullFaceMode);
draw->setShader(shader);
draw->setTextures(textures);

View File

@@ -1,4 +1,5 @@
#include <mbgl/gfx/attribute.hpp>
#include <mbgl/gfx/color_mode.hpp>
#include <mbgl/gfx/cull_face_mode.hpp>
#include <mbgl/gfx/index_vector.hpp>
#include <mbgl/gfx/vertex_vector.hpp>
@@ -21,6 +22,7 @@ struct DrawableBuilder::Impl {
std::vector<std::unique_ptr<Drawable::DrawSegment>> segments;
AttributeDataType rawVerticesType = static_cast<AttributeDataType>(-1);
gfx::ColorMode colorMode = gfx::ColorMode::disabled();
gfx::CullFaceMode cullFaceMode = gfx::CullFaceMode::disabled();
};

View File

@@ -21,6 +21,7 @@
#include <mbgl/gl/drawable_gl_builder.hpp>
#include <mbgl/gl/drawable_gl_tweaker.hpp>
#include <mbgl/gl/layer_group_gl.hpp>
#include <mbgl/gl/render_target_gl.hpp>
#include <mbgl/gl/uniform_buffer_gl.hpp>
#include <mbgl/gl/texture2d.hpp>
#include <mbgl/shaders/gl/shader_program_gl.hpp>
@@ -472,9 +473,9 @@ gfx::UniformBufferPtr Context::createUniformBuffer(const void* data, std::size_t
}
gfx::ShaderProgramBasePtr Context::getGenericShader(gfx::ShaderRegistry& shaders, const std::string& name) {
std::vector<std::string> emptyAttributes(0);
std::vector<std::string> emptyProperties(0);
return std::static_pointer_cast<gfx::ShaderProgramBase>(
shaders.getShaderGroup(name)->getOrCreateShader(*this, emptyAttributes));
shaders.getShaderGroup(name)->getOrCreateShader(*this, emptyProperties));
}
TileLayerGroupPtr Context::createTileLayerGroup(int32_t layerIndex, std::size_t initialCapacity, std::string name) {
@@ -488,6 +489,22 @@ LayerGroupPtr Context::createLayerGroup(int32_t layerIndex, std::size_t initialC
gfx::Texture2DPtr Context::createTexture2D() {
return std::make_shared<gl::Texture2D>(*this);
}
RenderTargetPtr Context::createRenderTarget(const Size size, const gfx::TextureChannelDataType type) {
return std::make_shared<gl::RenderTargetGL>(*this, size, type);
}
UniqueFramebuffer Context::createFramebuffer(const gfx::Texture2D& color) {
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));
checkFramebuffer();
return fbo;
}
#endif
void Context::clear(std::optional<mbgl::Color> color, std::optional<float> depth, std::optional<int32_t> stencil) {

View File

@@ -118,6 +118,10 @@ public:
LayerGroupPtr createLayerGroup(int32_t layerIndex, std::size_t initialCapacity, std::string name) override;
gfx::Texture2DPtr createTexture2D() override;
RenderTargetPtr createRenderTarget(const Size size, const gfx::TextureChannelDataType type) override;
UniqueFramebuffer createFramebuffer(const gfx::Texture2D& color);
#endif
private:

View File

@@ -47,7 +47,7 @@ void DrawableGL::draw(const PaintParameters& parameters) const {
context.setStencilMode(gfx::StencilMode::disabled());
}
context.setColorMode(parameters.colorModeForRenderPass());
context.setColorMode(getColorMode());
context.setCullFaceMode(getCullFaceMode());
bindUniformBuffers();

View File

@@ -0,0 +1,85 @@
#include <mbgl/gl/render_target_gl.hpp>
#include <mbgl/gl/context.hpp>
#include <mbgl/gl/defines.hpp>
#include <mbgl/gl/framebuffer.hpp>
#include <mbgl/platform/gl_functions.hpp>
#include <mbgl/renderer/layer_tweaker.hpp>
#include <mbgl/renderer/paint_parameters.hpp>
#include <mbgl/renderer/render_orchestrator.hpp>
#include <mbgl/renderer/render_static_data.hpp>
#include <mbgl/renderer/render_tree.hpp>
#include <mbgl/util/logging.hpp>
#include <cassert>
namespace mbgl {
namespace gl {
using namespace platform;
RenderTargetGL::RenderTargetGL(Context& context, const Size size, const gfx::TextureChannelDataType type)
: glContext(context) {
texture = glContext.createTexture2D();
texture->setSize(size);
texture->setFormat(gfx::TexturePixelType::RGBA, type);
texture->setSamplerConfiguration(
{gfx::TextureFilterType::Linear, gfx::TextureWrapType::Clamp, gfx::TextureWrapType::Clamp});
}
RenderTargetGL::~RenderTargetGL() {
if (framebuffer) {
MBGL_CHECK_ERROR(glDeleteFramebuffers(1, &framebuffer->get()));
framebuffer.reset();
}
}
void RenderTargetGL::upload(gfx::UploadPass& uploadPass) {
observeLayerGroups(([&](LayerGroupBase& layerGroup) { layerGroup.upload(uploadPass); }));
}
void RenderTargetGL::render(RenderOrchestrator& orchestrator,
const RenderTree& renderTree,
PaintParameters& parameters) {
texture->create();
if (!framebuffer) {
framebuffer = std::make_shared<UniqueFramebuffer>(glContext.createFramebuffer(*texture));
}
glContext.bindFramebuffer = *framebuffer;
glContext.activeTextureUnit = 0;
glContext.scissorTest = false;
glContext.viewport = {0, 0, texture->getSize()};
glContext.clear(Color{0.0f, 0.0f, 0.0f, 1.0f}, {}, {});
// Run layer tweakers to update any dynamic elements
observeLayerGroups([&](LayerGroupBase& layerGroup) {
if (layerGroup.getLayerTweaker()) {
layerGroup.getLayerTweaker()->execute(layerGroup, renderTree, parameters);
}
});
// draw layer groups, opaque pass
parameters.pass = RenderPass::Opaque;
parameters.currentLayer = 0;
parameters.depthRangeSize = 1 - (numLayerGroups() + 2) * parameters.numSublayers * PaintParameters::depthEpsilon;
observeLayerGroups([&](LayerGroupBase& layerGroup) {
layerGroup.render(orchestrator, parameters);
parameters.currentLayer++;
});
// draw layer groups, translucent pass
parameters.pass = RenderPass::Translucent;
parameters.currentLayer = static_cast<int32_t>(numLayerGroups()) - 1;
parameters.depthRangeSize = 1 - (numLayerGroups() + 2) * parameters.numSublayers * PaintParameters::depthEpsilon;
observeLayerGroups([&](LayerGroupBase& layerGroup) {
layerGroup.render(orchestrator, parameters);
if (parameters.currentLayer != 0) {
parameters.currentLayer--;
}
});
}
} // namespace gl
} // namespace mbgl

View File

@@ -104,6 +104,8 @@ void RendererBackend::initShaders(gfx::ShaderRegistry& shaders, const ProgramPar
shaders::BuiltIn::LineGradientShader,
shaders::BuiltIn::FillOutlinePatternShader,
shaders::BuiltIn::FillPatternShader,
shaders::BuiltIn::HeatmapShader,
shaders::BuiltIn::HeatmapTextureShader,
shaders::BuiltIn::RasterShader,
shaders::BuiltIn::SymbolIconShader,
shaders::BuiltIn::SymbolSDFTextShader,

View File

@@ -93,7 +93,7 @@ void Texture2D::createStorage(const void* data) noexcept {
context.pixelStoreUnpack = {1};
MBGL_CHECK_ERROR(glTexImage2D(GL_TEXTURE_2D,
0,
Enum<gfx::TexturePixelType>::to(pixelFormat),
Enum<gfx::TexturePixelType>::sizedFor(pixelFormat, channelType),
size.width,
size.height,
0,
@@ -105,8 +105,12 @@ void Texture2D::createStorage(const void* data) noexcept {
}
void Texture2D::create() noexcept {
createObject();
createStorage();
if (!textureResource) {
createObject();
}
if (storageDirty) {
createStorage();
}
}
platform::GLuint Texture2D::getTextureID() const noexcept {

View File

@@ -29,4 +29,18 @@ void UpdateLayerGroupIndexRequest::execute(RenderOrchestrator &orchestrator) {
orchestrator.markLayerGroupOrderDirty();
}
AddRenderTargetRequest::AddRenderTargetRequest(RenderTargetPtr renderTarget_)
: renderTarget(std::move(renderTarget_)) {}
void AddRenderTargetRequest::execute(RenderOrchestrator &orchestrator) {
orchestrator.addRenderTarget(std::move(renderTarget));
}
RemoveRenderTargetRequest::RemoveRenderTargetRequest(const RenderTargetPtr &renderTarget_)
: renderTarget(renderTarget_) {}
void RemoveRenderTargetRequest::execute(RenderOrchestrator &orchestrator) {
orchestrator.removeRenderTarget(renderTarget);
}
} // namespace mbgl

View File

@@ -0,0 +1,76 @@
#include <mbgl/renderer/layers/heatmap_layer_tweaker.hpp>
#include <mbgl/gfx/context.hpp>
#include <mbgl/gfx/drawable.hpp>
#include <mbgl/renderer/layer_group.hpp>
#include <mbgl/renderer/paint_parameters.hpp>
#include <mbgl/renderer/render_static_data.hpp>
#include <mbgl/renderer/render_tree.hpp>
#include <mbgl/style/layers/heatmap_layer_properties.hpp>
#include <mbgl/util/convert.hpp>
namespace mbgl {
using namespace style;
struct alignas(16) HeatmapDrawableUBO {
std::array<float, 4 * 4> matrix;
float extrude_scale;
std::array<float, 3> padding;
};
static_assert(sizeof(HeatmapDrawableUBO) % 16 == 0);
struct alignas(16) HeatmapEvaluatedPropsUBO {
float weight;
float radius;
float intensity;
float padding;
};
static_assert(sizeof(HeatmapEvaluatedPropsUBO) % 16 == 0);
static constexpr std::string_view HeatmapDrawableUBOName = "HeatmapDrawableUBO";
static constexpr std::string_view HeatmapEvaluatedPropsUBOName = "HeatmapEvaluatedPropsUBO";
void HeatmapLayerTweaker::execute(LayerGroupBase& layerGroup,
const RenderTree& renderTree,
const PaintParameters& parameters) {
const auto& evaluated = static_cast<const HeatmapLayerProperties&>(*evaluatedProperties).evaluated;
if (layerGroup.empty()) {
return;
}
#if !defined(NDEBUG)
const auto label = layerGroup.getName() + "-update-uniforms";
const auto debugGroup = parameters.encoder->createDebugGroup(label.c_str());
#endif
if (!evaluatedPropsUniformBuffer) {
HeatmapEvaluatedPropsUBO evaluatedPropsUBO = {
/* .weight = */ evaluated.get<HeatmapWeight>().constantOr(HeatmapWeight::defaultValue()),
/* .radius = */ evaluated.get<HeatmapRadius>().constantOr(HeatmapRadius::defaultValue()),
/* .intensity = */ evaluated.get<HeatmapIntensity>(),
/* .padding = */ 0};
evaluatedPropsUniformBuffer = parameters.context.createUniformBuffer(&evaluatedPropsUBO,
sizeof(evaluatedPropsUBO));
}
layerGroup.observeDrawables([&](gfx::Drawable& drawable) {
drawable.mutableUniformBuffers().addOrReplace(HeatmapEvaluatedPropsUBOName, evaluatedPropsUniformBuffer);
if (!drawable.getTileID()) {
return;
}
const UnwrappedTileID tileID = drawable.getTileID()->toUnwrapped();
const auto matrix = getTileMatrix(
tileID, renderTree, parameters.state, {0.f, 0.f}, TranslateAnchorType::Viewport, false);
HeatmapDrawableUBO drawableUBO = {
/* .matrix = */ util::cast<float>(matrix),
/* .extrude_scale = */ tileID.pixelsToTileUnits(1.0f, static_cast<float>(parameters.state.getZoom())),
/* .padding = */ {0}};
drawable.mutableUniformBuffers().createOrUpdate(HeatmapDrawableUBOName, &drawableUBO, parameters.context);
});
}
} // namespace mbgl

View File

@@ -0,0 +1,25 @@
#pragma once
#include <mbgl/renderer/layer_tweaker.hpp>
namespace mbgl {
/**
Heatmap layer specific tweaker
*/
class HeatmapLayerTweaker : public LayerTweaker {
public:
HeatmapLayerTweaker(Immutable<style::LayerProperties> properties)
: LayerTweaker(properties){};
public:
~HeatmapLayerTweaker() override = default;
void execute(LayerGroupBase&, const RenderTree&, const PaintParameters&) override;
protected:
gfx::UniformBufferPtr paintParamsUniformBuffer;
gfx::UniformBufferPtr evaluatedPropsUniformBuffer;
};
} // namespace mbgl

View File

@@ -0,0 +1,55 @@
#include <mbgl/renderer/layers/heatmap_texture_layer_tweaker.hpp>
#include <mbgl/gfx/context.hpp>
#include <mbgl/gfx/drawable.hpp>
#include <mbgl/renderer/layer_group.hpp>
#include <mbgl/renderer/paint_parameters.hpp>
#include <mbgl/renderer/render_static_data.hpp>
#include <mbgl/renderer/render_tree.hpp>
#include <mbgl/style/layers/heatmap_layer_properties.hpp>
#include <mbgl/util/convert.hpp>
namespace mbgl {
using namespace style;
struct alignas(16) HeatmapTextureDrawableUBO {
std::array<float, 4 * 4> matrix;
std::array<float, 2> world;
float opacity;
float padding;
};
static_assert(sizeof(HeatmapTextureDrawableUBO) % 16 == 0);
static constexpr std::string_view HeatmapTextureDrawableUBOName = "HeatmapTextureDrawableUBO";
void HeatmapTextureLayerTweaker::execute(LayerGroupBase& layerGroup,
[[maybe_unused]] const RenderTree& renderTree,
const PaintParameters& parameters) {
const auto& evaluated = static_cast<const HeatmapLayerProperties&>(*evaluatedProperties).evaluated;
if (layerGroup.empty()) {
return;
}
#if !defined(NDEBUG)
const auto label = layerGroup.getName() + "-update-uniforms";
const auto debugGroup = parameters.encoder->createDebugGroup(label.c_str());
#endif
layerGroup.observeDrawables([&](gfx::Drawable& drawable) {
const auto& size = parameters.staticData.backendSize;
mat4 viewportMat;
matrix::ortho(viewportMat, 0, size.width, size.height, 0, 0, 1);
HeatmapTextureDrawableUBO drawableUBO = {
/* .matrix = */ util::cast<float>(viewportMat),
/* .world = */ {static_cast<float>(size.width), static_cast<float>(size.height)},
/* .opacity = */ evaluated.get<HeatmapOpacity>(),
/* .padding = */ 0};
drawable.mutableUniformBuffers().createOrUpdate(
HeatmapTextureDrawableUBOName, &drawableUBO, parameters.context);
});
}
} // namespace mbgl

View File

@@ -0,0 +1,23 @@
#pragma once
#include <mbgl/renderer/layer_tweaker.hpp>
namespace mbgl {
/**
Heatmap texture layer specific tweaker
*/
class HeatmapTextureLayerTweaker : public LayerTweaker {
public:
HeatmapTextureLayerTweaker(Immutable<style::LayerProperties> properties)
: LayerTweaker(properties){};
public:
~HeatmapTextureLayerTweaker() override = default;
void execute(LayerGroupBase&, const RenderTree&, const PaintParameters&) override;
protected:
};
} // namespace mbgl

View File

@@ -306,6 +306,8 @@ void RenderBackgroundLayer::update(gfx::ShaderRegistry& shaders,
builder->setRenderPass(drawPasses);
builder->setShader(curShader);
builder->setDepthType(gfx::DepthMaskType::ReadWrite);
builder->setColorMode(drawPasses == RenderPass::Translucent ? gfx::ColorMode::alphaBlended()
: gfx::ColorMode::unblended());
}
auto verticesCopy = rawVertices;

View File

@@ -390,6 +390,7 @@ void RenderCircleLayer::update(gfx::ShaderRegistry& shaders,
circleBuilder->setShader(std::static_pointer_cast<gfx::ShaderProgramBase>(circleShader));
circleBuilder->setDepthType((renderPass == RenderPass::Opaque) ? gfx::DepthMaskType::ReadWrite
: gfx::DepthMaskType::ReadOnly);
circleBuilder->setColorMode(gfx::ColorMode::alphaBlended());
circleBuilder->setCullFaceMode(gfx::CullFaceMode::disabled());
circleBuilder->setRenderPass(renderPass);

View File

@@ -457,6 +457,8 @@ void RenderFillLayer::update(gfx::ShaderRegistry& shaders,
commonInit(*builder);
builder->setDepthType((renderPass == RenderPass::Opaque) ? gfx::DepthMaskType::ReadWrite
: gfx::DepthMaskType::ReadOnly);
builder->setColorMode(renderPass == RenderPass::Translucent ? gfx::ColorMode::alphaBlended()
: gfx::ColorMode::unblended());
builder->setSubLayerIndex(0);
builder->setRenderPass(renderPass);
fillBuilder = std::move(builder);
@@ -467,6 +469,7 @@ void RenderFillLayer::update(gfx::ShaderRegistry& shaders,
commonInit(*builder);
builder->setLineWidth(2.0f);
builder->setDepthType(gfx::DepthMaskType::ReadOnly);
builder->setColorMode(gfx::ColorMode::alphaBlended());
builder->setSubLayerIndex(unevaluated.get<FillOutlineColor>().isUndefined() ? 2 : 0);
builder->setRenderPass(RenderPass::Translucent);
outlineBuilder = std::move(builder);
@@ -512,6 +515,7 @@ void RenderFillLayer::update(gfx::ShaderRegistry& shaders,
if (auto builder = context.createDrawableBuilder(layerPrefix + "fill-pattern")) {
commonInit(*builder);
builder->setDepthType(gfx::DepthMaskType::ReadWrite);
builder->setColorMode(gfx::ColorMode::alphaBlended());
builder->setSubLayerIndex(1);
builder->setRenderPass(RenderPass::Translucent);
patternBuilder = std::move(builder);
@@ -522,6 +526,7 @@ void RenderFillLayer::update(gfx::ShaderRegistry& shaders,
commonInit(*builder);
builder->setLineWidth(2.0f);
builder->setDepthType(gfx::DepthMaskType::ReadOnly);
builder->setColorMode(gfx::ColorMode::alphaBlended());
builder->setSubLayerIndex(2);
builder->setRenderPass(RenderPass::Translucent);
outlinePatternBuilder = std::move(builder);

View File

@@ -5,15 +5,25 @@
#include <mbgl/renderer/render_static_data.hpp>
#include <mbgl/programs/programs.hpp>
#include <mbgl/tile/tile.hpp>
#include <mbgl/style/layers/heatmap_layer.hpp>
#include <mbgl/style/layers/heatmap_layer_impl.hpp>
#include <mbgl/geometry/feature_index.hpp>
#include <mbgl/gfx/context.hpp>
#include <mbgl/gfx/cull_face_mode.hpp>
#include <mbgl/gfx/render_pass.hpp>
#include <mbgl/gfx/context.hpp>
#include <mbgl/util/math.hpp>
#include <mbgl/util/intersection_tests.hpp>
#if MLN_DRAWABLE_RENDERER
#include <mbgl/renderer/layers/heatmap_layer_tweaker.hpp>
#include <mbgl/renderer/layers/heatmap_texture_layer_tweaker.hpp>
#include <mbgl/renderer/layer_group.hpp>
#include <mbgl/renderer/render_target.hpp>
#include <mbgl/shaders/shader_program_base.hpp>
#include <mbgl/gfx/drawable_builder.hpp>
#include <mbgl/gfx/shader_group.hpp>
#include <mbgl/gfx/shader_registry.hpp>
#endif
namespace mbgl {
using namespace style;
@@ -29,8 +39,9 @@ inline const HeatmapLayer::Impl& impl_cast(const Immutable<Layer::Impl>& impl) {
RenderHeatmapLayer::RenderHeatmapLayer(Immutable<HeatmapLayer::Impl> _impl)
: RenderLayer(makeMutable<HeatmapLayerProperties>(std::move(_impl))),
unevaluated(impl_cast(baseImpl).paint.untransitioned()),
colorRamp({256, 1}) {}
unevaluated(impl_cast(baseImpl).paint.untransitioned()) {
colorRamp = std::make_shared<PremultipliedImage>(Size(256, 1));
}
RenderHeatmapLayer::~RenderHeatmapLayer() = default;
@@ -47,6 +58,15 @@ void RenderHeatmapLayer::evaluate(const PropertyEvaluationParameters& parameters
: RenderPass::None;
properties->renderPasses = mbgl::underlying_type(passes);
evaluatedProperties = std::move(properties);
#if MLN_DRAWABLE_RENDERER
if (renderTarget) {
renderTarget->getLayerGroup(0)->setLayerTweaker(std::make_shared<HeatmapLayerTweaker>(evaluatedProperties));
}
if (layerGroup) {
layerGroup->setLayerTweaker(std::make_shared<HeatmapTextureLayerTweaker>(evaluatedProperties));
}
#endif
}
bool RenderHeatmapLayer::hasTransition() const {
@@ -59,7 +79,7 @@ bool RenderHeatmapLayer::hasCrossfade() const {
void RenderHeatmapLayer::upload(gfx::UploadPass& uploadPass) {
if (!colorRampTexture) {
colorRampTexture = uploadPass.createTexture(colorRamp, gfx::TextureChannelDataType::UnsignedByte);
colorRampTexture = uploadPass.createTexture(*colorRamp, gfx::TextureChannelDataType::UnsignedByte);
}
}
@@ -180,14 +200,14 @@ void RenderHeatmapLayer::updateColorRamp() {
colorValue = HeatmapLayer::getDefaultHeatmapColor();
}
const auto length = colorRamp.bytes();
const auto length = (*colorRamp).bytes();
for (uint32_t i = 0; i < length; i += 4) {
const auto color = colorValue.evaluate(static_cast<double>(i) / length);
colorRamp.data[i + 0] = static_cast<uint8_t>(std::floor(color.r * 255.f));
colorRamp.data[i + 1] = static_cast<uint8_t>(std::floor(color.g * 255.f));
colorRamp.data[i + 2] = static_cast<uint8_t>(std::floor(color.b * 255.f));
colorRamp.data[i + 3] = static_cast<uint8_t>(std::floor(color.a * 255.f));
(*colorRamp).data[i + 0] = static_cast<uint8_t>(std::floor(color.r * 255.f));
(*colorRamp).data[i + 1] = static_cast<uint8_t>(std::floor(color.g * 255.f));
(*colorRamp).data[i + 2] = static_cast<uint8_t>(std::floor(color.b * 255.f));
(*colorRamp).data[i + 3] = static_cast<uint8_t>(std::floor(color.a * 255.f));
}
if (colorRampTexture) {
@@ -209,4 +229,266 @@ bool RenderHeatmapLayer::queryIntersectsFeature(const GeometryCoordinates& query
return false;
}
#if MLN_DRAWABLE_RENDERER
void activateRenderTarget(const RenderTargetPtr& renderTarget_, bool activate, UniqueChangeRequestVec& changes) {
if (renderTarget_) {
if (activate) {
// The RenderTree has determined this render target should be included in the renderable set for a frame
changes.emplace_back(std::make_unique<AddRenderTargetRequest>(renderTarget_));
} else {
// The RenderTree is informing us we should not render anything
changes.emplace_back(std::make_unique<RemoveRenderTargetRequest>(renderTarget_));
}
}
}
void RenderHeatmapLayer::markLayerRenderable(bool willRender, UniqueChangeRequestVec& changes) {
RenderLayer::markLayerRenderable(willRender, changes);
activateRenderTarget(renderTarget, willRender, changes);
}
void RenderHeatmapLayer::removeTile(RenderPass renderPass, const OverscaledTileID& tileID) {
auto* tileLayerGroup = static_cast<TileLayerGroup*>(renderTarget->getLayerGroup(0).get());
stats.drawablesRemoved += tileLayerGroup->removeDrawables(renderPass, tileID).size();
}
void RenderHeatmapLayer::removeAllDrawables() {
RenderLayer::removeAllDrawables();
if (renderTarget) {
stats.drawablesRemoved += renderTarget->getLayerGroup(0)->getDrawableCount();
renderTarget->getLayerGroup(0)->clearDrawables();
}
}
struct alignas(16) HeatmapInterpolateUBO {
float weight_t;
float radius_t;
std::array<float, 2> padding;
};
static_assert(sizeof(HeatmapInterpolateUBO) % 16 == 0);
static const std::string HeatmapShaderGroupName = "HeatmapShader";
static const std::string HeatmapTextureShaderGroupName = "HeatmapTextureShader";
static constexpr std::string_view HeatmapInterpolateUBOName = "HeatmapInterpolateUBO";
void RenderHeatmapLayer::update(gfx::ShaderRegistry& shaders,
gfx::Context& context,
const TransformState& state,
[[maybe_unused]] const RenderTree& renderTree,
[[maybe_unused]] UniqueChangeRequestVec& changes) {
std::unique_lock<std::mutex> guard(mutex);
if (!renderTiles || renderTiles->empty()) {
removeAllDrawables();
return;
}
const auto& viewportSize = state.getSize();
const auto size = Size{viewportSize.width / 2, viewportSize.height / 2};
// Set up a render target
if (!renderTarget) {
renderTarget = context.createRenderTarget(size, gfx::TextureChannelDataType::HalfFloat);
if (!renderTarget) {
return;
}
activateRenderTarget(renderTarget, isRenderable, changes);
// Set up tile layer group
auto tileLayerGroup = context.createTileLayerGroup(0, /*initialCapacity=*/64, getID());
if (!tileLayerGroup) {
return;
}
tileLayerGroup->setLayerTweaker(std::make_shared<HeatmapLayerTweaker>(evaluatedProperties));
renderTarget->addLayerGroup(tileLayerGroup, /*canReplace=*/true);
}
if (renderTarget->getTexture()->getSize() != size) {
renderTarget->getTexture()->setSize(size);
}
auto* tileLayerGroup = static_cast<TileLayerGroup*>(renderTarget->getLayerGroup(0).get());
if (!heatmapShaderGroup) {
heatmapShaderGroup = shaders.getShaderGroup(HeatmapShaderGroupName);
}
if (!heatmapShaderGroup) {
removeAllDrawables();
return;
}
std::unordered_set<OverscaledTileID> newTileIDs(renderTiles->size());
std::transform(renderTiles->begin(),
renderTiles->end(),
std::inserter(newTileIDs, newTileIDs.begin()),
[](const auto& renderTile) -> OverscaledTileID { return renderTile.get().getOverscaledTileID(); });
std::unique_ptr<gfx::DrawableBuilder> heatmapBuilder;
std::vector<gfx::DrawablePtr> newTiles;
gfx::VertexAttributeArray heatmapVertexAttrs;
auto renderPass = RenderPass::Translucent;
if (!(mbgl::underlying_type(renderPass) & evaluatedProperties->renderPasses)) {
return;
}
tileLayerGroup->observeDrawables([&](gfx::UniqueDrawable& drawable) {
const auto tileID = drawable->getTileID();
if (tileID && newTileIDs.find(*tileID) == newTileIDs.end()) {
// remove it
drawable.reset();
++stats.drawablesRemoved;
}
});
const auto& evaluated = static_cast<const HeatmapLayerProperties&>(*evaluatedProperties).evaluated;
for (const RenderTile& tile : *renderTiles) {
const auto& tileID = tile.getOverscaledTileID();
const LayerRenderData* renderData = getRenderDataForPass(tile, renderPass);
if (!renderData) {
removeTile(renderPass, tileID);
continue;
}
auto& bucket = static_cast<HeatmapBucket&>(*renderData->bucket);
const auto& paintPropertyBinders = bucket.paintPropertyBinders.at(getID());
float zoom = static_cast<float>(state.getZoom());
const HeatmapInterpolateUBO interpolateUBO = {
/* .weight_t = */ std::get<0>(paintPropertyBinders.get<HeatmapWeight>()->interpolationFactor(zoom)),
/* .radius_t = */ std::get<0>(paintPropertyBinders.get<HeatmapRadius>()->interpolationFactor(zoom)),
/* .padding = */ {0}};
tileLayerGroup->observeDrawables(renderPass, tileID, [&](gfx::Drawable& drawable) {
drawable.mutableUniformBuffers().createOrUpdate(HeatmapInterpolateUBOName, &interpolateUBO, context);
});
if (tileLayerGroup->getDrawableCount(renderPass, tileID) > 0) {
continue;
}
heatmapVertexAttrs.clear();
auto propertiesAsUniforms = heatmapVertexAttrs.readDataDrivenPaintProperties<HeatmapWeight, HeatmapRadius>(
paintPropertyBinders, evaluated);
auto heatmapShader = heatmapShaderGroup->getOrCreateShader(context, propertiesAsUniforms);
if (!heatmapShader) {
continue;
}
std::vector<std::array<int16_t, 2>> rawVerts;
const auto buildVertices = [&]() {
const std::vector<gfx::VertexVector<gfx::detail::VertexType<gfx::AttributeType<int16_t, 2>>>::Vertex>&
verts = bucket.vertices.vector();
if (rawVerts.size() < verts.size()) {
rawVerts.resize(verts.size());
std::transform(verts.begin(), verts.end(), rawVerts.begin(), [](const auto& x) { return x.a1; });
}
};
heatmapBuilder = context.createDrawableBuilder("heatmap");
heatmapBuilder->setShader(std::static_pointer_cast<gfx::ShaderProgramBase>(heatmapShader));
heatmapBuilder->setDepthType((renderPass == RenderPass::Opaque) ? gfx::DepthMaskType::ReadWrite
: gfx::DepthMaskType::ReadOnly);
heatmapBuilder->setColorMode(gfx::ColorMode::additive());
heatmapBuilder->setCullFaceMode(gfx::CullFaceMode::disabled());
heatmapBuilder->setRenderPass(renderPass);
heatmapBuilder->setVertexAttributes(heatmapVertexAttrs);
buildVertices();
heatmapBuilder->addVertices(rawVerts, 0, rawVerts.size());
heatmapBuilder->setSegments(
gfx::Triangles(), bucket.triangles.vector(), bucket.segments.data(), bucket.segments.size());
heatmapBuilder->flush();
for (auto& drawable : heatmapBuilder->clearDrawables()) {
drawable->setTileID(tileID);
drawable->mutableUniformBuffers().createOrUpdate(HeatmapInterpolateUBOName, &interpolateUBO, context);
tileLayerGroup->addDrawable(renderPass, tileID, std::move(drawable));
++stats.drawablesAdded;
}
}
// Set up texture layer group
if (!layerGroup) {
auto layerGroup_ = context.createLayerGroup(layerIndex, /*initialCapacity=*/1, getID());
if (!layerGroup_) {
return;
}
layerGroup_->setLayerTweaker(std::make_shared<HeatmapTextureLayerTweaker>(evaluatedProperties));
setLayerGroup(std::move(layerGroup_), changes);
}
auto* textureLayerGroup = static_cast<LayerGroup*>(layerGroup.get());
if (!heatmapTextureShader) {
heatmapTextureShader = context.getGenericShader(shaders, HeatmapTextureShaderGroupName);
}
if (!heatmapTextureShader) {
removeAllDrawables();
return;
}
textureLayerGroup->clearDrawables();
std::unique_ptr<gfx::DrawableBuilder> heatmapTextureBuilder;
std::vector<std::array<int16_t, 2>> textureRawVerts;
const auto buildTextureVertices = [&]() {
const std::vector<gfx::VertexVector<gfx::detail::VertexType<gfx::AttributeType<int16_t, 2>>>::Vertex> verts =
RenderStaticData::heatmapTextureVertices().vector();
if (textureRawVerts.size() < verts.size()) {
textureRawVerts.resize(verts.size());
std::transform(verts.begin(), verts.end(), textureRawVerts.begin(), [](const auto& x) { return x.a1; });
}
};
heatmapTextureBuilder = context.createDrawableBuilder("heatmapTexture");
heatmapTextureBuilder->setShader(heatmapTextureShader);
heatmapTextureBuilder->setDepthType((renderPass == RenderPass::Opaque) ? gfx::DepthMaskType::ReadWrite
: gfx::DepthMaskType::ReadOnly);
heatmapTextureBuilder->setColorMode(gfx::ColorMode::alphaBlended());
heatmapTextureBuilder->setCullFaceMode(gfx::CullFaceMode::disabled());
heatmapTextureBuilder->setRenderPass(renderPass);
buildTextureVertices();
heatmapTextureBuilder->addVertices(textureRawVerts, 0, textureRawVerts.size());
if (segments.empty()) {
segments = RenderStaticData::heatmapTextureSegments();
}
heatmapTextureBuilder->setSegments(
gfx::Triangles(), RenderStaticData::quadTriangleIndices().vector(), segments.data(), segments.size());
auto imageLocation = heatmapTextureShader->getSamplerLocation("u_image");
if (imageLocation.has_value()) {
heatmapTextureBuilder->setTexture(renderTarget->getTexture(), imageLocation.value());
}
auto colorRampLocation = heatmapTextureShader->getSamplerLocation("u_color_ramp");
if (colorRampLocation.has_value()) {
std::shared_ptr<gfx::Texture2D> texture = context.createTexture2D();
texture->setImage(colorRamp);
texture->setSamplerConfiguration(
{gfx::TextureFilterType::Linear, gfx::TextureWrapType::Clamp, gfx::TextureWrapType::Clamp});
heatmapTextureBuilder->setTexture(texture, colorRampLocation.value());
}
heatmapTextureBuilder->flush();
for (auto& drawable : heatmapTextureBuilder->clearDrawables()) {
textureLayerGroup->addDrawable(std::move(drawable));
++stats.drawablesAdded;
}
}
#endif // MLN_DRAWABLE_RENDERER
} // namespace mbgl

View File

@@ -16,6 +16,17 @@ public:
explicit RenderHeatmapLayer(Immutable<style::HeatmapLayer::Impl>);
~RenderHeatmapLayer() override;
#if MLN_DRAWABLE_RENDERER
void markLayerRenderable(bool willRender, UniqueChangeRequestVec& changes) override;
/// Generate any changes needed by the layer
void update(gfx::ShaderRegistry&,
gfx::Context&,
const TransformState&,
const RenderTree&,
UniqueChangeRequestVec&) override;
#endif
private:
void transition(const TransitionParameters&) override;
void evaluate(const PropertyEvaluationParameters&) override;
@@ -36,9 +47,17 @@ private:
const FeatureState&) const override;
void updateColorRamp();
#if MLN_DRAWABLE_RENDERER
/// Remove all drawables for the tile from the layer group
void removeTile(RenderPass, const OverscaledTileID&) override;
/// Remove all the drawables for tiles
void removeAllDrawables() override;
#endif
// Paint properties
style::HeatmapPaintProperties::Unevaluated unevaluated;
PremultipliedImage colorRamp;
std::shared_ptr<PremultipliedImage> colorRamp;
std::unique_ptr<gfx::OffscreenTexture> renderTexture;
std::optional<gfx::Texture> colorRampTexture;
SegmentVector<HeatmapTextureAttributes> segments;
@@ -48,6 +67,12 @@ private:
std::shared_ptr<HeatmapProgram> heatmapProgram;
std::shared_ptr<HeatmapTextureProgram> heatmapTextureProgram;
#endif
#if MLN_DRAWABLE_RENDERER
gfx::ShaderGroupPtr heatmapShaderGroup;
gfx::ShaderProgramBasePtr heatmapTextureShader;
RenderTargetPtr renderTarget;
#endif
};
} // namespace mbgl

View File

@@ -466,6 +466,8 @@ void RenderLineLayer::update(gfx::ShaderRegistry& shaders,
builder->setRenderPass(renderPass);
builder->setSubLayerIndex(0);
builder->setDepthType(gfx::DepthMaskType::ReadOnly);
builder->setColorMode(renderPass == RenderPass::Translucent ? gfx::ColorMode::alphaBlended()
: gfx::ColorMode::unblended());
builder->setCullFaceMode(gfx::CullFaceMode::disabled());
builder->setNeedsStencil(true);
builder->setVertexAttrName("a_pos_normal");

View File

@@ -260,6 +260,7 @@ void RenderRasterLayer::update(gfx::ShaderRegistry& shaders,
builder->setSubLayerIndex(0);
builder->setDepthType((renderPass == RenderPass::Opaque) ? gfx::DepthMaskType::ReadWrite
: gfx::DepthMaskType::ReadOnly);
builder->setColorMode(gfx::ColorMode::alphaBlended());
builder->setCullFaceMode(gfx::CullFaceMode::disabled());
builder->setVertexAttrName("a_pos");

View File

@@ -1003,7 +1003,8 @@ void RenderSymbolLayer::update(gfx::ShaderRegistry& shaders,
builder->setRenderPass(passes);
builder->setCullFaceMode(gfx::CullFaceMode::disabled());
builder->setDepthType(gfx::DepthMaskType::ReadOnly);
builder->setCullFaceMode(gfx::CullFaceMode::disabled());
builder->setColorMode(passes == RenderPass::Translucent ? gfx::ColorMode::alphaBlended()
: gfx::ColorMode::unblended());
builder->setVertexAttrName(posOffsetAttribName);
}

View File

@@ -197,10 +197,10 @@ protected:
void activateLayerGroup(const LayerGroupBasePtr&, bool activate, UniqueChangeRequestVec& changes);
/// Remove all drawables for the tile from the layer group
void removeTile(RenderPass, const OverscaledTileID&);
virtual void removeTile(RenderPass, const OverscaledTileID&);
/// Remove all the drawables for tiles
void removeAllDrawables();
virtual void removeAllDrawables();
#endif
protected:

View File

@@ -897,6 +897,38 @@ void RenderOrchestrator::processChanges() {
void RenderOrchestrator::markLayerGroupOrderDirty() {
layerGroupOrderDirty = true;
}
bool RenderOrchestrator::addRenderTarget(RenderTargetPtr renderTarget) {
auto it = std::find(renderTargets.begin(), renderTargets.end(), renderTarget);
if (it == renderTargets.end()) {
renderTargets.emplace_back(renderTarget);
return true;
} else {
return false;
}
}
bool RenderOrchestrator::removeRenderTarget(const RenderTargetPtr& renderTarget) {
auto it = std::find(renderTargets.begin(), renderTargets.end(), renderTarget);
if (it != renderTargets.end()) {
renderTargets.erase(it);
return true;
} else {
return false;
}
}
void RenderOrchestrator::observeRenderTargets(std::function<void(RenderTarget&)> f) {
for (auto& renderTarget : renderTargets) {
f(*renderTarget);
}
}
void RenderOrchestrator::observeRenderTargets(std::function<void(const RenderTarget&)> f) const {
for (const auto& renderTarget : renderTargets) {
f(*renderTarget);
}
}
#endif // MLN_DRAWABLE_RENDERER
void RenderOrchestrator::onGlyphsError(const FontStack& fontStack, const GlyphRange& glyphRange, std::exception_ptr error) {

View File

@@ -116,6 +116,11 @@ public:
void processChanges();
/// @brief Indicate that the orchestrator needs to re-sort layer groups when processing changes
void markLayerGroupOrderDirty();
bool addRenderTarget(RenderTargetPtr);
bool removeRenderTarget(const RenderTargetPtr&);
void observeRenderTargets(std::function<void(RenderTarget&)> f);
void observeRenderTargets(std::function<void(const RenderTarget&)> f) const;
#endif
const ZoomHistory& getZoomHistory() const { return zoomHistory; }
@@ -195,6 +200,8 @@ private:
using LayerGroupMap = std::map<int32_t, LayerGroupBasePtr>;
LayerGroupMap layerGroupsByLayerIndex;
bool layerGroupOrderDirty = false;
std::vector<RenderTargetPtr> renderTargets;
#endif
};

View File

@@ -21,7 +21,7 @@ gfx::IndexVector<gfx::Triangles> RenderStaticData::quadTriangleIndices() {
return result;
}
static gfx::IndexVector<gfx::LineStrip> tileLineStripIndices() {
gfx::IndexVector<gfx::LineStrip> RenderStaticData::tileLineStripIndices() {
gfx::IndexVector<gfx::LineStrip> result;
result.emplace_back(0);
result.emplace_back(1);
@@ -31,7 +31,7 @@ static gfx::IndexVector<gfx::LineStrip> tileLineStripIndices() {
return result;
}
static gfx::VertexVector<RasterLayoutVertex> rasterVertices() {
gfx::VertexVector<RasterLayoutVertex> RenderStaticData::rasterVertices() {
gfx::VertexVector<RasterLayoutVertex> result;
result.emplace_back(RasterProgram::layoutVertex({0, 0}, {0, 0}));
result.emplace_back(RasterProgram::layoutVertex({util::EXTENT, 0}, {util::EXTENT, 0}));
@@ -40,7 +40,7 @@ static gfx::VertexVector<RasterLayoutVertex> rasterVertices() {
return result;
}
static gfx::VertexVector<HeatmapTextureLayoutVertex> heatmapTextureVertices() {
gfx::VertexVector<HeatmapTextureLayoutVertex> RenderStaticData::heatmapTextureVertices() {
gfx::VertexVector<HeatmapTextureLayoutVertex> result;
result.emplace_back(HeatmapTextureProgram::layoutVertex({0, 0}));
result.emplace_back(HeatmapTextureProgram::layoutVertex({1, 0}));

View File

@@ -31,14 +31,17 @@ public:
std::optional<gfx::IndexBuffer> quadTriangleIndexBuffer;
std::optional<gfx::IndexBuffer> tileBorderIndexBuffer;
static gfx::VertexVector<gfx::Vertex<PositionOnlyLayoutAttributes>> tileVertices();
static gfx::IndexVector<gfx::Triangles> quadTriangleIndices();
static gfx::IndexVector<gfx::LineStrip> tileLineStripIndices();
static gfx::VertexVector<RasterLayoutVertex> rasterVertices();
static gfx::VertexVector<HeatmapTextureLayoutVertex> heatmapTextureVertices();
static SegmentVector<BackgroundAttributes> tileTriangleSegments();
static SegmentVector<DebugAttributes> tileBorderSegments();
static SegmentVector<RasterAttributes> rasterSegments();
static SegmentVector<HeatmapTextureAttributes> heatmapTextureSegments();
static gfx::IndexVector<gfx::Triangles> quadTriangleIndices();
static gfx::VertexVector<gfx::Vertex<PositionOnlyLayoutAttributes>> tileVertices();
std::optional<gfx::Renderbuffer<gfx::RenderbufferPixelType::Depth>> depthRenderbuffer;
bool has3D = false;
bool uploaded = false;

View File

@@ -0,0 +1,63 @@
#include <mbgl/renderer/render_target.hpp>
#include <mbgl/gfx/context.hpp>
#include <mbgl/renderer/layer_group.hpp>
namespace mbgl {
bool RenderTarget::addLayerGroup(LayerGroupBasePtr layerGroup, const bool replace) {
const auto index = layerGroup->getLayerIndex();
const auto result = layerGroupsByLayerIndex.insert(std::make_pair(index, LayerGroupBasePtr{}));
if (result.second) {
// added
result.first->second = std::move(layerGroup);
return true;
} else {
// not added
if (replace) {
result.first->second = std::move(layerGroup);
return true;
} else {
return false;
}
}
}
bool RenderTarget::removeLayerGroup(const int32_t layerIndex) {
const auto hit = layerGroupsByLayerIndex.find(layerIndex);
if (hit != layerGroupsByLayerIndex.end()) {
layerGroupsByLayerIndex.erase(hit);
return true;
} else {
return false;
}
}
size_t RenderTarget::numLayerGroups() const noexcept {
return layerGroupsByLayerIndex.size();
}
static const LayerGroupBasePtr no_group;
const LayerGroupBasePtr& RenderTarget::getLayerGroup(const int32_t layerIndex) const {
const auto hit = layerGroupsByLayerIndex.find(layerIndex);
return (hit == layerGroupsByLayerIndex.end()) ? no_group : hit->second;
}
void RenderTarget::observeLayerGroups(std::function<void(LayerGroupBase&)> f) {
for (auto& pair : layerGroupsByLayerIndex) {
if (pair.second) {
f(*pair.second);
}
}
}
void RenderTarget::observeLayerGroups(std::function<void(const LayerGroupBase&)> f) const {
for (const auto& pair : layerGroupsByLayerIndex) {
if (pair.second) {
f(*pair.second);
}
}
}
} // namespace mbgl

View File

@@ -21,6 +21,7 @@
#include <mbgl/gfx/drawable_tweaker.hpp>
#include <mbgl/gl/drawable_gl.hpp>
#include <mbgl/renderer/layer_tweaker.hpp>
#include <mbgl/renderer/render_target.hpp>
#include <mbgl/shaders/gl/shader_program_gl.hpp>
#endif
@@ -142,6 +143,9 @@ void Renderer::Impl::render(const RenderTree& renderTree) {
#if MLN_DRAWABLE_RENDERER
// Give the layers a chance to upload
orchestrator.observeLayerGroups([&](LayerGroupBase& layerGroup) { layerGroup.upload(*uploadPass); });
// Give the render targets a chance to upload
orchestrator.observeRenderTargets([&](RenderTarget& renderTarget) { renderTarget.upload(*uploadPass); });
#endif
}
@@ -176,6 +180,12 @@ void Renderer::Impl::render(const RenderTree& renderTree) {
#endif
}
#if MLN_DRAWABLE_RENDERER
// draw render targets
orchestrator.observeRenderTargets(
[&](RenderTarget& renderTarget) { renderTarget.render(orchestrator, renderTree, parameters); });
#endif
// - CLEAR
// -------------------------------------------------------------------------------------
// Renders the backdrop of the OpenGL view. This also paints in areas where