diff --git a/CMakeLists.txt b/CMakeLists.txt index 3a3bbb6bc..1848a6bbc 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -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 diff --git a/bazel/core.bzl b/bazel/core.bzl index 52dfa662d..86fcd4373 100644 --- a/bazel/core.bzl +++ b/bazel/core.bzl @@ -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", diff --git a/include/mbgl/gfx/drawable.hpp b/include/mbgl/gfx/drawable.hpp index fb58f562c..b54740048 100644 --- a/include/mbgl/gfx/drawable.hpp +++ b/include/mbgl/gfx/drawable.hpp @@ -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(); } diff --git a/include/mbgl/gfx/drawable_builder.hpp b/include/mbgl/gfx/drawable_builder.hpp index 91a702506..51b2c322b 100644 --- a/include/mbgl/gfx/drawable_builder.hpp +++ b/include/mbgl/gfx/drawable_builder.hpp @@ -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); diff --git a/include/mbgl/gl/render_target_gl.hpp b/include/mbgl/gl/render_target_gl.hpp new file mode 100644 index 000000000..0a3c2c0e7 --- /dev/null +++ b/include/mbgl/gl/render_target_gl.hpp @@ -0,0 +1,29 @@ +#pragma once + +#include +#include +#include +#include +#include + +namespace mbgl { +namespace gl { + +class Context; +using UniqueFramebufferPtr = std::shared_ptr; + +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 diff --git a/include/mbgl/renderer/change_request.hpp b/include/mbgl/renderer/change_request.hpp index 064287cbc..ff36bf999 100644 --- a/include/mbgl/renderer/change_request.hpp +++ b/include/mbgl/renderer/change_request.hpp @@ -11,11 +11,13 @@ class ChangeRequest; class LayerGroupBase; class TileLayerGroup; class RenderOrchestrator; +class RenderTarget; using ChangeRequestPtr = std::shared_ptr; using UniqueChangeRequest = std::unique_ptr; using UniqueChangeRequestVec = std::vector; using LayerGroupBasePtr = std::shared_ptr; +using RenderTargetPtr = std::shared_ptr; 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 diff --git a/include/mbgl/renderer/render_target.hpp b/include/mbgl/renderer/render_target.hpp new file mode 100644 index 000000000..6c1713777 --- /dev/null +++ b/include/mbgl/renderer/render_target.hpp @@ -0,0 +1,45 @@ +#pragma once + +#include +#include +#include + +namespace mbgl { + +namespace gfx { +class Texture2D; +class UploadPass; +using Texture2DPtr = std::shared_ptr; +} // namespace gfx + +class LayerGroupBase; +class PaintParameters; +class RenderOrchestrator; +class RenderTree; + +using LayerGroupBasePtr = std::shared_ptr; + +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 observeLayerGroups(std::function) const; + + virtual void upload(gfx::UploadPass& uploadPass) = 0; + virtual void render(RenderOrchestrator&, const RenderTree&, PaintParameters&) = 0; + +protected: + gfx::Texture2DPtr texture; + using LayerGroupMap = std::map; + LayerGroupMap layerGroupsByLayerIndex; +}; + +} // namespace mbgl diff --git a/include/mbgl/shaders/gl/drawable_heatmap.hpp b/include/mbgl/shaders/gl/drawable_heatmap.hpp new file mode 100644 index 000000000..b46ddf2e1 --- /dev/null +++ b/include/mbgl/shaders/gl/drawable_heatmap.hpp @@ -0,0 +1,127 @@ +// Generated code, do not modify this file! +#pragma once +#include + +namespace mbgl { +namespace shaders { + +template <> +struct ShaderSource { + 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 diff --git a/include/mbgl/shaders/gl/drawable_heatmap_texture.hpp b/include/mbgl/shaders/gl/drawable_heatmap_texture.hpp new file mode 100644 index 000000000..ba4ad4459 --- /dev/null +++ b/include/mbgl/shaders/gl/drawable_heatmap_texture.hpp @@ -0,0 +1,52 @@ +// Generated code, do not modify this file! +#pragma once +#include + +namespace mbgl { +namespace shaders { + +template <> +struct ShaderSource { + 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 diff --git a/include/mbgl/shaders/shader_manifest.hpp b/include/mbgl/shaders/shader_manifest.hpp index f1d3d974a..f2acb593a 100644 --- a/include/mbgl/shaders/shader_manifest.hpp +++ b/include/mbgl/shaders/shader_manifest.hpp @@ -14,6 +14,8 @@ #include #include #include +#include +#include #include #include #include diff --git a/include/mbgl/shaders/shader_source.hpp b/include/mbgl/shaders/shader_source.hpp index 08607a680..df63ef01e 100644 --- a/include/mbgl/shaders/shader_source.hpp +++ b/include/mbgl/shaders/shader_source.hpp @@ -20,11 +20,14 @@ enum class BuiltIn { LineShader, FillPatternShader, FillOutlinePatternShader, + HeatmapShader, + HeatmapTextureShader, RasterShader, SymbolIconShader, SymbolSDFTextShader, SymbolSDFIconShader, SymbolTextAndIconShader, + Prelude, BackgroundProgram, BackgroundPatternProgram, diff --git a/shaders/drawable.heatmap.fragment.glsl b/shaders/drawable.heatmap.fragment.glsl new file mode 100644 index 000000000..4c501fca7 --- /dev/null +++ b/shaders/drawable.heatmap.fragment.glsl @@ -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 +} diff --git a/shaders/drawable.heatmap.vertex.glsl b/shaders/drawable.heatmap.vertex.glsl new file mode 100644 index 000000000..539651b11 --- /dev/null +++ b/shaders/drawable.heatmap.vertex.glsl @@ -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; +} diff --git a/shaders/drawable.heatmap_texture.fragment.glsl b/shaders/drawable.heatmap_texture.fragment.glsl new file mode 100644 index 000000000..5113da190 --- /dev/null +++ b/shaders/drawable.heatmap_texture.fragment.glsl @@ -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 +} diff --git a/shaders/drawable.heatmap_texture.vertex.glsl b/shaders/drawable.heatmap_texture.vertex.glsl new file mode 100644 index 000000000..fa6a2edad --- /dev/null +++ b/shaders/drawable.heatmap_texture.vertex.glsl @@ -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; +} diff --git a/shaders/manifest.json b/shaders/manifest.json index 74f6fc18d..e8236edf7 100644 --- a/shaders/manifest.json +++ b/shaders/manifest.json @@ -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", diff --git a/src/mbgl/gfx/context.hpp b/src/mbgl/gfx/context.hpp index f78efb658..44a7257c8 100644 --- a/src/mbgl/gfx/context.hpp +++ b/src/mbgl/gfx/context.hpp @@ -24,8 +24,10 @@ class ProgramParameters; #if MLN_DRAWABLE_RENDERER class TileLayerGroup; class LayerGroup; +class RenderTarget; using TileLayerGroupPtr = std::shared_ptr; using LayerGroupPtr = std::shared_ptr; +using RenderTargetPtr = std::shared_ptr; #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 }; diff --git a/src/mbgl/gfx/drawable.cpp b/src/mbgl/gfx/drawable.cpp index 44207af28..5612affb0 100644 --- a/src/mbgl/gfx/drawable.cpp +++ b/src/mbgl/gfx/drawable.cpp @@ -1,5 +1,6 @@ #include +#include #include #include #include @@ -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; } diff --git a/src/mbgl/gfx/drawable_builder.cpp b/src/mbgl/gfx/drawable_builder.cpp index b9806b8f2..5020084db 100644 --- a/src/mbgl/gfx/drawable_builder.cpp +++ b/src/mbgl/gfx/drawable_builder.cpp @@ -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); diff --git a/src/mbgl/gfx/drawable_builder_impl.hpp b/src/mbgl/gfx/drawable_builder_impl.hpp index a3c62d5e9..a321dac03 100644 --- a/src/mbgl/gfx/drawable_builder_impl.hpp +++ b/src/mbgl/gfx/drawable_builder_impl.hpp @@ -1,4 +1,5 @@ #include +#include #include #include #include @@ -21,6 +22,7 @@ struct DrawableBuilder::Impl { std::vector> segments; AttributeDataType rawVerticesType = static_cast(-1); + gfx::ColorMode colorMode = gfx::ColorMode::disabled(); gfx::CullFaceMode cullFaceMode = gfx::CullFaceMode::disabled(); }; diff --git a/src/mbgl/gl/context.cpp b/src/mbgl/gl/context.cpp index ac8316088..6ba3ab758 100644 --- a/src/mbgl/gl/context.cpp +++ b/src/mbgl/gl/context.cpp @@ -21,6 +21,7 @@ #include #include #include +#include #include #include #include @@ -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 emptyAttributes(0); + std::vector emptyProperties(0); return std::static_pointer_cast( - 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(*this); } + +RenderTargetPtr Context::createRenderTarget(const Size size, const gfx::TextureChannelDataType type) { + return std::make_shared(*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(color).getTextureID(), + 0)); + checkFramebuffer(); + return fbo; +} #endif void Context::clear(std::optional color, std::optional depth, std::optional stencil) { diff --git a/src/mbgl/gl/context.hpp b/src/mbgl/gl/context.hpp index e96587eda..ae1b0bdad 100644 --- a/src/mbgl/gl/context.hpp +++ b/src/mbgl/gl/context.hpp @@ -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: diff --git a/src/mbgl/gl/drawable_gl.cpp b/src/mbgl/gl/drawable_gl.cpp index 01e4039e4..9c88ab449 100644 --- a/src/mbgl/gl/drawable_gl.cpp +++ b/src/mbgl/gl/drawable_gl.cpp @@ -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(); diff --git a/src/mbgl/gl/render_target_gl.cpp b/src/mbgl/gl/render_target_gl.cpp new file mode 100644 index 000000000..e319f5f00 --- /dev/null +++ b/src/mbgl/gl/render_target_gl.cpp @@ -0,0 +1,85 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +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(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(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 diff --git a/src/mbgl/gl/renderer_backend.cpp b/src/mbgl/gl/renderer_backend.cpp index 67ccb1bf6..202613ad0 100644 --- a/src/mbgl/gl/renderer_backend.cpp +++ b/src/mbgl/gl/renderer_backend.cpp @@ -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, diff --git a/src/mbgl/gl/texture2d.cpp b/src/mbgl/gl/texture2d.cpp index 322ae84d1..8e0919e72 100644 --- a/src/mbgl/gl/texture2d.cpp +++ b/src/mbgl/gl/texture2d.cpp @@ -93,7 +93,7 @@ void Texture2D::createStorage(const void* data) noexcept { context.pixelStoreUnpack = {1}; MBGL_CHECK_ERROR(glTexImage2D(GL_TEXTURE_2D, 0, - Enum::to(pixelFormat), + Enum::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 { diff --git a/src/mbgl/renderer/change_request.cpp b/src/mbgl/renderer/change_request.cpp index cb7afb872..09e526e07 100644 --- a/src/mbgl/renderer/change_request.cpp +++ b/src/mbgl/renderer/change_request.cpp @@ -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 diff --git a/src/mbgl/renderer/layers/heatmap_layer_tweaker.cpp b/src/mbgl/renderer/layers/heatmap_layer_tweaker.cpp new file mode 100644 index 000000000..abafd4d43 --- /dev/null +++ b/src/mbgl/renderer/layers/heatmap_layer_tweaker.cpp @@ -0,0 +1,76 @@ +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +namespace mbgl { + +using namespace style; + +struct alignas(16) HeatmapDrawableUBO { + std::array matrix; + float extrude_scale; + std::array 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(*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().constantOr(HeatmapWeight::defaultValue()), + /* .radius = */ evaluated.get().constantOr(HeatmapRadius::defaultValue()), + /* .intensity = */ evaluated.get(), + /* .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(matrix), + /* .extrude_scale = */ tileID.pixelsToTileUnits(1.0f, static_cast(parameters.state.getZoom())), + /* .padding = */ {0}}; + + drawable.mutableUniformBuffers().createOrUpdate(HeatmapDrawableUBOName, &drawableUBO, parameters.context); + }); +} + +} // namespace mbgl diff --git a/src/mbgl/renderer/layers/heatmap_layer_tweaker.hpp b/src/mbgl/renderer/layers/heatmap_layer_tweaker.hpp new file mode 100644 index 000000000..d912f98e6 --- /dev/null +++ b/src/mbgl/renderer/layers/heatmap_layer_tweaker.hpp @@ -0,0 +1,25 @@ +#pragma once + +#include + +namespace mbgl { + +/** + Heatmap layer specific tweaker + */ +class HeatmapLayerTweaker : public LayerTweaker { +public: + HeatmapLayerTweaker(Immutable properties) + : LayerTweaker(properties){}; + +public: + ~HeatmapLayerTweaker() override = default; + + void execute(LayerGroupBase&, const RenderTree&, const PaintParameters&) override; + +protected: + gfx::UniformBufferPtr paintParamsUniformBuffer; + gfx::UniformBufferPtr evaluatedPropsUniformBuffer; +}; + +} // namespace mbgl diff --git a/src/mbgl/renderer/layers/heatmap_texture_layer_tweaker.cpp b/src/mbgl/renderer/layers/heatmap_texture_layer_tweaker.cpp new file mode 100644 index 000000000..4a7941dca --- /dev/null +++ b/src/mbgl/renderer/layers/heatmap_texture_layer_tweaker.cpp @@ -0,0 +1,55 @@ +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +namespace mbgl { + +using namespace style; + +struct alignas(16) HeatmapTextureDrawableUBO { + std::array matrix; + std::array 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(*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(viewportMat), + /* .world = */ {static_cast(size.width), static_cast(size.height)}, + /* .opacity = */ evaluated.get(), + /* .padding = */ 0}; + + drawable.mutableUniformBuffers().createOrUpdate( + HeatmapTextureDrawableUBOName, &drawableUBO, parameters.context); + }); +} + +} // namespace mbgl diff --git a/src/mbgl/renderer/layers/heatmap_texture_layer_tweaker.hpp b/src/mbgl/renderer/layers/heatmap_texture_layer_tweaker.hpp new file mode 100644 index 000000000..0e6e58db1 --- /dev/null +++ b/src/mbgl/renderer/layers/heatmap_texture_layer_tweaker.hpp @@ -0,0 +1,23 @@ +#pragma once + +#include + +namespace mbgl { + +/** + Heatmap texture layer specific tweaker + */ +class HeatmapTextureLayerTweaker : public LayerTweaker { +public: + HeatmapTextureLayerTweaker(Immutable properties) + : LayerTweaker(properties){}; + +public: + ~HeatmapTextureLayerTweaker() override = default; + + void execute(LayerGroupBase&, const RenderTree&, const PaintParameters&) override; + +protected: +}; + +} // namespace mbgl diff --git a/src/mbgl/renderer/layers/render_background_layer.cpp b/src/mbgl/renderer/layers/render_background_layer.cpp index 96532327b..0cf966cce 100644 --- a/src/mbgl/renderer/layers/render_background_layer.cpp +++ b/src/mbgl/renderer/layers/render_background_layer.cpp @@ -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; diff --git a/src/mbgl/renderer/layers/render_circle_layer.cpp b/src/mbgl/renderer/layers/render_circle_layer.cpp index 4fefa6aa7..1ce33aa21 100644 --- a/src/mbgl/renderer/layers/render_circle_layer.cpp +++ b/src/mbgl/renderer/layers/render_circle_layer.cpp @@ -390,6 +390,7 @@ void RenderCircleLayer::update(gfx::ShaderRegistry& shaders, circleBuilder->setShader(std::static_pointer_cast(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); diff --git a/src/mbgl/renderer/layers/render_fill_layer.cpp b/src/mbgl/renderer/layers/render_fill_layer.cpp index 71c5b56c5..152ec185a 100644 --- a/src/mbgl/renderer/layers/render_fill_layer.cpp +++ b/src/mbgl/renderer/layers/render_fill_layer.cpp @@ -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().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); diff --git a/src/mbgl/renderer/layers/render_heatmap_layer.cpp b/src/mbgl/renderer/layers/render_heatmap_layer.cpp index 5b140c93e..13244fcf9 100644 --- a/src/mbgl/renderer/layers/render_heatmap_layer.cpp +++ b/src/mbgl/renderer/layers/render_heatmap_layer.cpp @@ -5,15 +5,25 @@ #include #include #include -#include #include #include +#include #include #include -#include #include #include +#if MLN_DRAWABLE_RENDERER +#include +#include +#include +#include +#include +#include +#include +#include +#endif + namespace mbgl { using namespace style; @@ -29,8 +39,9 @@ inline const HeatmapLayer::Impl& impl_cast(const Immutable& impl) { RenderHeatmapLayer::RenderHeatmapLayer(Immutable _impl) : RenderLayer(makeMutable(std::move(_impl))), - unevaluated(impl_cast(baseImpl).paint.untransitioned()), - colorRamp({256, 1}) {} + unevaluated(impl_cast(baseImpl).paint.untransitioned()) { + colorRamp = std::make_shared(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(evaluatedProperties)); + } + if (layerGroup) { + layerGroup->setLayerTweaker(std::make_shared(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(i) / length); - colorRamp.data[i + 0] = static_cast(std::floor(color.r * 255.f)); - colorRamp.data[i + 1] = static_cast(std::floor(color.g * 255.f)); - colorRamp.data[i + 2] = static_cast(std::floor(color.b * 255.f)); - colorRamp.data[i + 3] = static_cast(std::floor(color.a * 255.f)); + (*colorRamp).data[i + 0] = static_cast(std::floor(color.r * 255.f)); + (*colorRamp).data[i + 1] = static_cast(std::floor(color.g * 255.f)); + (*colorRamp).data[i + 2] = static_cast(std::floor(color.b * 255.f)); + (*colorRamp).data[i + 3] = static_cast(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(renderTarget_)); + } else { + // The RenderTree is informing us we should not render anything + changes.emplace_back(std::make_unique(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(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 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 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(evaluatedProperties)); + renderTarget->addLayerGroup(tileLayerGroup, /*canReplace=*/true); + } + + if (renderTarget->getTexture()->getSize() != size) { + renderTarget->getTexture()->setSize(size); + } + + auto* tileLayerGroup = static_cast(renderTarget->getLayerGroup(0).get()); + + if (!heatmapShaderGroup) { + heatmapShaderGroup = shaders.getShaderGroup(HeatmapShaderGroupName); + } + if (!heatmapShaderGroup) { + removeAllDrawables(); + return; + } + + std::unordered_set 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 heatmapBuilder; + std::vector 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(*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(*renderData->bucket); + const auto& paintPropertyBinders = bucket.paintPropertyBinders.at(getID()); + + float zoom = static_cast(state.getZoom()); + const HeatmapInterpolateUBO interpolateUBO = { + /* .weight_t = */ std::get<0>(paintPropertyBinders.get()->interpolationFactor(zoom)), + /* .radius_t = */ std::get<0>(paintPropertyBinders.get()->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( + paintPropertyBinders, evaluated); + + auto heatmapShader = heatmapShaderGroup->getOrCreateShader(context, propertiesAsUniforms); + if (!heatmapShader) { + continue; + } + + std::vector> rawVerts; + const auto buildVertices = [&]() { + const std::vector>>::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(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(evaluatedProperties)); + setLayerGroup(std::move(layerGroup_), changes); + } + + auto* textureLayerGroup = static_cast(layerGroup.get()); + + if (!heatmapTextureShader) { + heatmapTextureShader = context.getGenericShader(shaders, HeatmapTextureShaderGroupName); + } + if (!heatmapTextureShader) { + removeAllDrawables(); + return; + } + + textureLayerGroup->clearDrawables(); + + std::unique_ptr heatmapTextureBuilder; + + std::vector> textureRawVerts; + const auto buildTextureVertices = [&]() { + const std::vector>>::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 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 diff --git a/src/mbgl/renderer/layers/render_heatmap_layer.hpp b/src/mbgl/renderer/layers/render_heatmap_layer.hpp index b9e9da4cf..ead422eb9 100644 --- a/src/mbgl/renderer/layers/render_heatmap_layer.hpp +++ b/src/mbgl/renderer/layers/render_heatmap_layer.hpp @@ -16,6 +16,17 @@ public: explicit RenderHeatmapLayer(Immutable); ~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 colorRamp; std::unique_ptr renderTexture; std::optional colorRampTexture; SegmentVector segments; @@ -48,6 +67,12 @@ private: std::shared_ptr heatmapProgram; std::shared_ptr heatmapTextureProgram; #endif + +#if MLN_DRAWABLE_RENDERER + gfx::ShaderGroupPtr heatmapShaderGroup; + gfx::ShaderProgramBasePtr heatmapTextureShader; + RenderTargetPtr renderTarget; +#endif }; } // namespace mbgl diff --git a/src/mbgl/renderer/layers/render_line_layer.cpp b/src/mbgl/renderer/layers/render_line_layer.cpp index dee5923b0..18b2476c7 100644 --- a/src/mbgl/renderer/layers/render_line_layer.cpp +++ b/src/mbgl/renderer/layers/render_line_layer.cpp @@ -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"); diff --git a/src/mbgl/renderer/layers/render_raster_layer.cpp b/src/mbgl/renderer/layers/render_raster_layer.cpp index c526ca071..e8d6c10f9 100644 --- a/src/mbgl/renderer/layers/render_raster_layer.cpp +++ b/src/mbgl/renderer/layers/render_raster_layer.cpp @@ -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"); diff --git a/src/mbgl/renderer/layers/render_symbol_layer.cpp b/src/mbgl/renderer/layers/render_symbol_layer.cpp index 156103fb8..7546b3740 100644 --- a/src/mbgl/renderer/layers/render_symbol_layer.cpp +++ b/src/mbgl/renderer/layers/render_symbol_layer.cpp @@ -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); } diff --git a/src/mbgl/renderer/render_layer.hpp b/src/mbgl/renderer/render_layer.hpp index 1c80c2816..d8cac6b47 100644 --- a/src/mbgl/renderer/render_layer.hpp +++ b/src/mbgl/renderer/render_layer.hpp @@ -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: diff --git a/src/mbgl/renderer/render_orchestrator.cpp b/src/mbgl/renderer/render_orchestrator.cpp index f89ec5086..2cbddf30d 100644 --- a/src/mbgl/renderer/render_orchestrator.cpp +++ b/src/mbgl/renderer/render_orchestrator.cpp @@ -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 f) { + for (auto& renderTarget : renderTargets) { + f(*renderTarget); + } +} + +void RenderOrchestrator::observeRenderTargets(std::function 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) { diff --git a/src/mbgl/renderer/render_orchestrator.hpp b/src/mbgl/renderer/render_orchestrator.hpp index b169ef057..d6e9b7b73 100644 --- a/src/mbgl/renderer/render_orchestrator.hpp +++ b/src/mbgl/renderer/render_orchestrator.hpp @@ -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 f); + void observeRenderTargets(std::function f) const; #endif const ZoomHistory& getZoomHistory() const { return zoomHistory; } @@ -195,6 +200,8 @@ private: using LayerGroupMap = std::map; LayerGroupMap layerGroupsByLayerIndex; bool layerGroupOrderDirty = false; + + std::vector renderTargets; #endif }; diff --git a/src/mbgl/renderer/render_static_data.cpp b/src/mbgl/renderer/render_static_data.cpp index 5ab35fb47..6e0eec20d 100644 --- a/src/mbgl/renderer/render_static_data.cpp +++ b/src/mbgl/renderer/render_static_data.cpp @@ -21,7 +21,7 @@ gfx::IndexVector RenderStaticData::quadTriangleIndices() { return result; } -static gfx::IndexVector tileLineStripIndices() { +gfx::IndexVector RenderStaticData::tileLineStripIndices() { gfx::IndexVector result; result.emplace_back(0); result.emplace_back(1); @@ -31,7 +31,7 @@ static gfx::IndexVector tileLineStripIndices() { return result; } -static gfx::VertexVector rasterVertices() { +gfx::VertexVector RenderStaticData::rasterVertices() { gfx::VertexVector 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 rasterVertices() { return result; } -static gfx::VertexVector heatmapTextureVertices() { +gfx::VertexVector RenderStaticData::heatmapTextureVertices() { gfx::VertexVector result; result.emplace_back(HeatmapTextureProgram::layoutVertex({0, 0})); result.emplace_back(HeatmapTextureProgram::layoutVertex({1, 0})); diff --git a/src/mbgl/renderer/render_static_data.hpp b/src/mbgl/renderer/render_static_data.hpp index fbce51eb8..9e2fb5b6d 100644 --- a/src/mbgl/renderer/render_static_data.hpp +++ b/src/mbgl/renderer/render_static_data.hpp @@ -31,14 +31,17 @@ public: std::optional quadTriangleIndexBuffer; std::optional tileBorderIndexBuffer; + static gfx::VertexVector> tileVertices(); + static gfx::IndexVector quadTriangleIndices(); + static gfx::IndexVector tileLineStripIndices(); + static gfx::VertexVector rasterVertices(); + static gfx::VertexVector heatmapTextureVertices(); + static SegmentVector tileTriangleSegments(); static SegmentVector tileBorderSegments(); static SegmentVector rasterSegments(); static SegmentVector heatmapTextureSegments(); - static gfx::IndexVector quadTriangleIndices(); - static gfx::VertexVector> tileVertices(); - std::optional> depthRenderbuffer; bool has3D = false; bool uploaded = false; diff --git a/src/mbgl/renderer/render_target.cpp b/src/mbgl/renderer/render_target.cpp new file mode 100644 index 000000000..e0ee3d659 --- /dev/null +++ b/src/mbgl/renderer/render_target.cpp @@ -0,0 +1,63 @@ +#include + +#include +#include + +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 f) { + for (auto& pair : layerGroupsByLayerIndex) { + if (pair.second) { + f(*pair.second); + } + } +} + +void RenderTarget::observeLayerGroups(std::function f) const { + for (const auto& pair : layerGroupsByLayerIndex) { + if (pair.second) { + f(*pair.second); + } + } +} + +} // namespace mbgl diff --git a/src/mbgl/renderer/renderer_impl.cpp b/src/mbgl/renderer/renderer_impl.cpp index 375cb3d90..34c07b11c 100644 --- a/src/mbgl/renderer/renderer_impl.cpp +++ b/src/mbgl/renderer/renderer_impl.cpp @@ -21,6 +21,7 @@ #include #include #include +#include #include #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