Merge branch 'topic/drawable-fixes' into topic/drawable (#1560)
Co-authored-by: Stefan Karschti <stefan.karschti@gmail.com> Co-authored-by: Alex Cristici <alex.cristici@gmail.com> Co-authored-by: Tim Sylvester <tim@wetdogweather.com> Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
This commit is contained in:
@@ -178,6 +178,7 @@ if(MLN_DRAWABLE_RENDERER)
|
||||
${PROJECT_SOURCE_DIR}/src/mbgl/gfx/image_drawable_data.hpp
|
||||
${PROJECT_SOURCE_DIR}/src/mbgl/gfx/line_drawable_data.hpp
|
||||
${PROJECT_SOURCE_DIR}/src/mbgl/gfx/symbol_drawable_data.hpp
|
||||
${PROJECT_SOURCE_DIR}/src/mbgl/gfx/collision_drawable_data.hpp
|
||||
${PROJECT_SOURCE_DIR}/src/mbgl/gfx/uniform_block.cpp
|
||||
${PROJECT_SOURCE_DIR}/src/mbgl/gfx/uniform_buffer.cpp
|
||||
${PROJECT_SOURCE_DIR}/src/mbgl/gfx/vertex_attribute.cpp
|
||||
@@ -209,6 +210,8 @@ if(MLN_DRAWABLE_RENDERER)
|
||||
${PROJECT_SOURCE_DIR}/src/mbgl/renderer/layers/raster_layer_tweaker.hpp
|
||||
${PROJECT_SOURCE_DIR}/src/mbgl/renderer/layers/symbol_layer_tweaker.cpp
|
||||
${PROJECT_SOURCE_DIR}/src/mbgl/renderer/layers/symbol_layer_tweaker.hpp
|
||||
${PROJECT_SOURCE_DIR}/src/mbgl/renderer/layers/collision_layer_tweaker.cpp
|
||||
${PROJECT_SOURCE_DIR}/src/mbgl/renderer/layers/collision_layer_tweaker.hpp
|
||||
${PROJECT_SOURCE_DIR}/src/mbgl/shaders/shader_program_base.cpp
|
||||
${PROJECT_SOURCE_DIR}/src/mbgl/shaders/mtl/shader_program_mtl.cpp
|
||||
${PROJECT_SOURCE_DIR}/src/mbgl/util/identity.cpp
|
||||
@@ -1003,6 +1006,9 @@ if(MLN_WITH_OPENGL)
|
||||
${PROJECT_SOURCE_DIR}/include/mbgl/shaders/gl/drawable_background.hpp
|
||||
${PROJECT_SOURCE_DIR}/include/mbgl/shaders/gl/drawable_background_pattern.hpp
|
||||
${PROJECT_SOURCE_DIR}/include/mbgl/shaders/gl/drawable_circle.hpp
|
||||
${PROJECT_SOURCE_DIR}/include/mbgl/shaders/gl/drawable_collision_box.hpp
|
||||
${PROJECT_SOURCE_DIR}/include/mbgl/shaders/gl/drawable_collision_circle.hpp
|
||||
${PROJECT_SOURCE_DIR}/include/mbgl/shaders/gl/drawable_debug.hpp
|
||||
${PROJECT_SOURCE_DIR}/include/mbgl/shaders/gl/drawable_fill.hpp
|
||||
${PROJECT_SOURCE_DIR}/include/mbgl/shaders/gl/drawable_fill_outline.hpp
|
||||
${PROJECT_SOURCE_DIR}/include/mbgl/shaders/gl/drawable_line.hpp
|
||||
|
||||
@@ -62,6 +62,9 @@ MLN_GENERATED_SHADER_HEADERS = [
|
||||
"include/mbgl/shaders/gl/drawable_background.hpp",
|
||||
"include/mbgl/shaders/gl/drawable_background_pattern.hpp",
|
||||
"include/mbgl/shaders/gl/drawable_circle.hpp",
|
||||
"include/mbgl/shaders/gl/drawable_collision_box.hpp",
|
||||
"include/mbgl/shaders/gl/drawable_collision_circle.hpp",
|
||||
"include/mbgl/shaders/gl/drawable_debug.hpp",
|
||||
"include/mbgl/shaders/gl/drawable_fill.hpp",
|
||||
"include/mbgl/shaders/gl/drawable_fill_outline.hpp",
|
||||
"include/mbgl/shaders/gl/drawable_fill_outline_pattern.hpp",
|
||||
@@ -896,6 +899,7 @@ MLN_DRAWABLES_SOURCE = [
|
||||
"src/mbgl/gfx/image_drawable_data.hpp",
|
||||
"src/mbgl/gfx/line_drawable_data.hpp",
|
||||
"src/mbgl/gfx/symbol_drawable_data.hpp",
|
||||
"src/mbgl/gfx/collision_drawable_data.hpp",
|
||||
"src/mbgl/gfx/uniform_block.cpp",
|
||||
"src/mbgl/gfx/uniform_buffer.cpp",
|
||||
"src/mbgl/gfx/vertex_attribute.cpp",
|
||||
@@ -926,6 +930,8 @@ MLN_DRAWABLES_SOURCE = [
|
||||
"src/mbgl/renderer/layers/raster_layer_tweaker.hpp",
|
||||
"src/mbgl/renderer/layers/symbol_layer_tweaker.cpp",
|
||||
"src/mbgl/renderer/layers/symbol_layer_tweaker.hpp",
|
||||
"src/mbgl/renderer/layers/collision_layer_tweaker.cpp",
|
||||
"src/mbgl/renderer/layers/collision_layer_tweaker.hpp",
|
||||
"src/mbgl/shaders/shader_program_base.cpp",
|
||||
"src/mbgl/shaders/mtl/shader_program_mtl.cpp",
|
||||
"src/mbgl/shaders/gl/shader_program_gl.cpp",
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
#include <mbgl/util/traits.hpp>
|
||||
#include <mbgl/gfx/texture2d.hpp>
|
||||
#include <mbgl/gfx/drawable_data.hpp>
|
||||
#include <mbgl/gfx/index_vector.hpp>
|
||||
|
||||
#include <cstdint>
|
||||
#include <memory>
|
||||
@@ -32,7 +33,6 @@ class VertexAttributeArray;
|
||||
|
||||
using DrawPriority = int64_t;
|
||||
using DrawableTweakerPtr = std::shared_ptr<DrawableTweaker>;
|
||||
using IndexVectorBasePtr = std::shared_ptr<IndexVectorBase>;
|
||||
using ShaderProgramBasePtr = std::shared_ptr<ShaderProgramBase>;
|
||||
using Texture2DPtr = std::shared_ptr<Texture2D>;
|
||||
|
||||
@@ -136,7 +136,11 @@ public:
|
||||
DrawPriority getDrawPriority() const { return drawPriority; }
|
||||
void setDrawPriority(DrawPriority value) { drawPriority = value; }
|
||||
|
||||
/// Get sub-layer index. Determines depth range within the layer for 2D drawables
|
||||
/// Whether to enable depth testing
|
||||
bool getEnableDepth() { return enableDepth; }
|
||||
void setEnableDepth(bool value) { enableDepth = value; }
|
||||
|
||||
/// Determines depth range within the layer for 2D drawables
|
||||
int32_t getSubLayerIndex() const { return subLayerIndex; }
|
||||
|
||||
/// Set sub-layer index
|
||||
@@ -227,6 +231,7 @@ protected:
|
||||
bool enabled = true;
|
||||
bool enableColor = true;
|
||||
bool enableStencil = false;
|
||||
bool enableDepth = true;
|
||||
bool is3D = false;
|
||||
bool isCustom = false;
|
||||
std::string name;
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
#pragma once
|
||||
|
||||
#include <mbgl/gfx/drawable_tweaker.hpp>
|
||||
#include <mbgl/style/types.hpp>
|
||||
#include <mbgl/renderer/layers/render_symbol_layer.hpp>
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
@@ -19,11 +21,22 @@ class Drawable;
|
||||
*/
|
||||
class DrawableAtlasesTweaker : public gfx::DrawableTweaker {
|
||||
public:
|
||||
DrawableAtlasesTweaker(TileAtlasTexturesPtr atlases_, std::string iconName_, std::string glyphName_, bool isText_)
|
||||
DrawableAtlasesTweaker(TileAtlasTexturesPtr atlases_,
|
||||
std::string iconName_,
|
||||
std::string glyphName_,
|
||||
bool isText_,
|
||||
const bool sdfIcons_,
|
||||
const style::AlignmentType rotationAlignment_,
|
||||
const bool iconScaled_,
|
||||
const bool textSizeIsZoomConstant_)
|
||||
: atlases(std::move(atlases_)),
|
||||
iconName(std::move(iconName_)),
|
||||
glyphName(std::move(glyphName_)),
|
||||
isText(isText_) {}
|
||||
isText(isText_),
|
||||
sdfIcons(sdfIcons_),
|
||||
rotationAlignment(rotationAlignment_),
|
||||
iconScaled(iconScaled_),
|
||||
textSizeIsZoomConstant(textSizeIsZoomConstant_) {}
|
||||
~DrawableAtlasesTweaker() override = default;
|
||||
|
||||
void init(Drawable&) override;
|
||||
@@ -31,12 +44,17 @@ public:
|
||||
void execute(Drawable&, const PaintParameters&) override;
|
||||
|
||||
protected:
|
||||
void setupTextures(Drawable&);
|
||||
void setupTextures(Drawable&, const bool);
|
||||
|
||||
TileAtlasTexturesPtr atlases;
|
||||
std::string iconName;
|
||||
std::string glyphName;
|
||||
bool isText;
|
||||
|
||||
const bool sdfIcons;
|
||||
const style::AlignmentType rotationAlignment;
|
||||
const bool iconScaled;
|
||||
const bool textSizeIsZoomConstant;
|
||||
};
|
||||
|
||||
} // namespace gfx
|
||||
|
||||
@@ -75,6 +75,10 @@ public:
|
||||
int32_t getSubLayerIndex() const { return subLayerIndex; }
|
||||
void setSubLayerIndex(int32_t value) { subLayerIndex = value; }
|
||||
|
||||
/// Whether to enable depth testing
|
||||
bool getEnableDepth() { return enableDepth; }
|
||||
void setEnableDepth(bool value) { enableDepth = value; }
|
||||
|
||||
/// Depth writability for 2D drawables
|
||||
DepthMaskType getDepthType() const { return depthType; }
|
||||
|
||||
@@ -204,6 +208,7 @@ protected:
|
||||
bool enabled = true;
|
||||
bool enableColor = true;
|
||||
bool enableStencil = false;
|
||||
bool enableDepth = true;
|
||||
bool is3D = false;
|
||||
float lineWidth = 1.0f;
|
||||
DrawPriority drawPriority = 0;
|
||||
|
||||
@@ -113,11 +113,6 @@ public:
|
||||
/// @see needsUpload
|
||||
virtual void upload() noexcept = 0;
|
||||
|
||||
/// @brief Get the underlying GL texture resource
|
||||
/// @note: Compat with legacy textures, to be refactored
|
||||
/// @return gfx::TextureResource
|
||||
virtual gfx::TextureResource& getResource() const = 0;
|
||||
|
||||
/// @brief Check whether the texture needs upload
|
||||
/// @return bool
|
||||
virtual bool needsUpload() const noexcept = 0;
|
||||
|
||||
@@ -225,16 +225,6 @@ public:
|
||||
/// @brief Clears the shared data
|
||||
void resetSharedRawData() { sharedRawData.reset(); }
|
||||
|
||||
/// Convert from the odd partially-normalized color component array produced by `Color::toArray` into normalized
|
||||
/// RGBA.
|
||||
static float4 colorAttrRGBA(const Color& color) {
|
||||
const auto components = color.toArray();
|
||||
return {static_cast<float>(components[0] / 255.0),
|
||||
static_cast<float>(components[1] / 255.0),
|
||||
static_cast<float>(components[2] / 255.0),
|
||||
static_cast<float>(components[3])};
|
||||
}
|
||||
|
||||
protected:
|
||||
VertexAttribute& operator=(const VertexAttribute&) = default;
|
||||
VertexAttribute& operator=(VertexAttribute&& other) {
|
||||
|
||||
@@ -40,11 +40,6 @@ public: // gfx::Texture2D
|
||||
void uploadSubRegion(const void* pixelData, const Size& size, uint16_t xOffset, uint16_t yOffset) noexcept override;
|
||||
void upload() noexcept override;
|
||||
|
||||
gfx::TextureResource& getResource() const override {
|
||||
assert(textureResource);
|
||||
return *textureResource;
|
||||
}
|
||||
|
||||
bool needsUpload() const noexcept override { return !!image; };
|
||||
|
||||
public:
|
||||
|
||||
@@ -20,7 +20,7 @@ uniform float u_camera_to_center_distance;
|
||||
out float v_placed;
|
||||
out float v_notUsed;
|
||||
out float v_radius;
|
||||
out vec2 v_extrude;
|
||||
out highp vec2 v_extrude;
|
||||
out vec2 v_extrude_scale;
|
||||
|
||||
void main() {
|
||||
@@ -49,7 +49,7 @@ void main() {
|
||||
in float v_placed;
|
||||
in float v_notUsed;
|
||||
in float v_radius;
|
||||
in vec2 v_extrude;
|
||||
in highp vec2 v_extrude;
|
||||
in vec2 v_extrude_scale;
|
||||
|
||||
void main() {
|
||||
|
||||
72
include/mbgl/shaders/gl/drawable_collision_box.hpp
Normal file
72
include/mbgl/shaders/gl/drawable_collision_box.hpp
Normal file
@@ -0,0 +1,72 @@
|
||||
// Generated code, do not modify this file!
|
||||
#pragma once
|
||||
#include <mbgl/shaders/shader_source.hpp>
|
||||
|
||||
namespace mbgl {
|
||||
namespace shaders {
|
||||
|
||||
template <>
|
||||
struct ShaderSource<BuiltIn::CollisionBoxShader, gfx::Backend::Type::OpenGL> {
|
||||
static constexpr const char* name = "CollisionBoxShader";
|
||||
static constexpr const char* vertex = R"(layout (location = 0) in vec2 a_pos;
|
||||
layout (location = 1) in vec2 a_anchor_pos;
|
||||
layout (location = 2) in vec2 a_extrude;
|
||||
layout (location = 3) in vec2 a_placed;
|
||||
layout (location = 4) in vec2 a_shift;
|
||||
|
||||
layout (std140) uniform CollisionBoxUBO {
|
||||
highp mat4 u_matrix;
|
||||
highp vec2 u_extrude_scale;
|
||||
highp float u_camera_to_center_distance;
|
||||
highp float pad1;
|
||||
};
|
||||
|
||||
out float v_placed;
|
||||
out float v_notUsed;
|
||||
|
||||
void main() {
|
||||
vec4 projectedPoint = u_matrix * vec4(a_anchor_pos, 0, 1);
|
||||
highp float camera_to_anchor_distance = projectedPoint.w;
|
||||
highp float collision_perspective_ratio = clamp(
|
||||
0.5 + 0.5 * (u_camera_to_center_distance / camera_to_anchor_distance),
|
||||
0.0, // Prevents oversized near-field boxes in pitched/overzoomed tiles
|
||||
4.0);
|
||||
|
||||
gl_Position = u_matrix * vec4(a_pos, 0.0, 1.0);
|
||||
gl_Position.xy += (a_extrude + a_shift) * u_extrude_scale * gl_Position.w * collision_perspective_ratio;
|
||||
|
||||
v_placed = a_placed.x;
|
||||
v_notUsed = a_placed.y;
|
||||
}
|
||||
)";
|
||||
static constexpr const char* fragment = R"(layout (std140) uniform CollisionBoxUBO {
|
||||
highp mat4 u_matrix;
|
||||
highp vec2 u_extrude_scale;
|
||||
highp float u_camera_to_center_distance;
|
||||
highp float pad1;
|
||||
};
|
||||
|
||||
in float v_placed;
|
||||
in float v_notUsed;
|
||||
|
||||
void main() {
|
||||
|
||||
float alpha = 0.5;
|
||||
|
||||
// Red = collision, hide label
|
||||
fragColor = vec4(1.0, 0.0, 0.0, 1.0) * alpha;
|
||||
|
||||
// Blue = no collision, label is showing
|
||||
if (v_placed > 0.5) {
|
||||
fragColor = vec4(0.0, 0.0, 1.0, 0.5) * alpha;
|
||||
}
|
||||
|
||||
if (v_notUsed > 0.5) {
|
||||
// This box not used, fade it out
|
||||
fragColor *= .1;
|
||||
}
|
||||
})";
|
||||
};
|
||||
|
||||
} // namespace shaders
|
||||
} // namespace mbgl
|
||||
93
include/mbgl/shaders/gl/drawable_collision_circle.hpp
Normal file
93
include/mbgl/shaders/gl/drawable_collision_circle.hpp
Normal file
@@ -0,0 +1,93 @@
|
||||
// Generated code, do not modify this file!
|
||||
#pragma once
|
||||
#include <mbgl/shaders/shader_source.hpp>
|
||||
|
||||
namespace mbgl {
|
||||
namespace shaders {
|
||||
|
||||
template <>
|
||||
struct ShaderSource<BuiltIn::CollisionCircleShader, gfx::Backend::Type::OpenGL> {
|
||||
static constexpr const char* name = "CollisionCircleShader";
|
||||
static constexpr const char* vertex = R"(layout (location = 0) in vec2 a_pos;
|
||||
layout (location = 1) in vec2 a_anchor_pos;
|
||||
layout (location = 2) in vec2 a_extrude;
|
||||
layout (location = 3) in vec2 a_placed;
|
||||
|
||||
layout (std140) uniform CollisionCircleUBO {
|
||||
highp mat4 u_matrix;
|
||||
highp vec2 u_extrude_scale;
|
||||
highp float u_camera_to_center_distance;
|
||||
highp float u_overscale_factor;
|
||||
};
|
||||
|
||||
out float v_placed;
|
||||
out float v_notUsed;
|
||||
out float v_radius;
|
||||
out highp vec2 v_extrude;
|
||||
out vec2 v_extrude_scale;
|
||||
|
||||
void main() {
|
||||
vec4 projectedPoint = u_matrix * vec4(a_anchor_pos, 0, 1);
|
||||
highp float camera_to_anchor_distance = projectedPoint.w;
|
||||
highp float collision_perspective_ratio = clamp(
|
||||
0.5 + 0.5 * (u_camera_to_center_distance / camera_to_anchor_distance),
|
||||
0.0, // Prevents oversized near-field circles in pitched/overzoomed tiles
|
||||
4.0);
|
||||
|
||||
gl_Position = u_matrix * vec4(a_pos, 0.0, 1.0);
|
||||
|
||||
highp float padding_factor = 1.2; // Pad the vertices slightly to make room for anti-alias blur
|
||||
gl_Position.xy += a_extrude * u_extrude_scale * padding_factor * gl_Position.w * collision_perspective_ratio;
|
||||
|
||||
v_placed = a_placed.x;
|
||||
v_notUsed = a_placed.y;
|
||||
v_radius = abs(a_extrude.y); // We don't pitch the circles, so both units of the extrusion vector are equal in magnitude to the radius
|
||||
|
||||
v_extrude = a_extrude * padding_factor;
|
||||
v_extrude_scale = u_extrude_scale * u_camera_to_center_distance * collision_perspective_ratio;
|
||||
}
|
||||
)";
|
||||
static constexpr const char* fragment = R"(layout (std140) uniform CollisionCircleUBO {
|
||||
highp mat4 u_matrix;
|
||||
highp vec2 u_extrude_scale;
|
||||
highp float u_camera_to_center_distance;
|
||||
highp float u_overscale_factor;
|
||||
};
|
||||
|
||||
in float v_placed;
|
||||
in float v_notUsed;
|
||||
in float v_radius;
|
||||
in highp vec2 v_extrude;
|
||||
in vec2 v_extrude_scale;
|
||||
|
||||
void main() {
|
||||
float alpha = 0.5;
|
||||
|
||||
// Red = collision, hide label
|
||||
vec4 color = vec4(1.0, 0.0, 0.0, 1.0) * alpha;
|
||||
|
||||
// Blue = no collision, label is showing
|
||||
if (v_placed > 0.5) {
|
||||
color = vec4(0.0, 0.0, 1.0, 0.5) * alpha;
|
||||
}
|
||||
|
||||
if (v_notUsed > 0.5) {
|
||||
// This box not used, fade it out
|
||||
color *= .2;
|
||||
}
|
||||
|
||||
float extrude_scale_length = length(v_extrude_scale);
|
||||
float extrude_length = length(v_extrude) * extrude_scale_length;
|
||||
float stroke_width = 15.0 * extrude_scale_length / u_overscale_factor;
|
||||
float radius = v_radius * extrude_scale_length;
|
||||
|
||||
float distance_to_edge = abs(extrude_length - radius);
|
||||
float opacity_t = smoothstep(-stroke_width, 0.0, -distance_to_edge);
|
||||
|
||||
fragColor = opacity_t * color;
|
||||
}
|
||||
)";
|
||||
};
|
||||
|
||||
} // namespace shaders
|
||||
} // namespace mbgl
|
||||
51
include/mbgl/shaders/gl/drawable_debug.hpp
Normal file
51
include/mbgl/shaders/gl/drawable_debug.hpp
Normal file
@@ -0,0 +1,51 @@
|
||||
// Generated code, do not modify this file!
|
||||
#pragma once
|
||||
#include <mbgl/shaders/shader_source.hpp>
|
||||
|
||||
namespace mbgl {
|
||||
namespace shaders {
|
||||
|
||||
template <>
|
||||
struct ShaderSource<BuiltIn::DebugShader, gfx::Backend::Type::OpenGL> {
|
||||
static constexpr const char* name = "DebugShader";
|
||||
static constexpr const char* vertex = R"(layout (location = 0) in vec2 a_pos;
|
||||
out vec2 v_uv;
|
||||
|
||||
layout (std140) uniform DebugUBO {
|
||||
highp mat4 u_matrix;
|
||||
highp vec4 u_color;
|
||||
highp float u_overlay_scale;
|
||||
highp float pad1;
|
||||
highp float pad2;
|
||||
highp float pad3;
|
||||
};
|
||||
|
||||
void main() {
|
||||
// This vertex shader expects a EXTENT x EXTENT quad,
|
||||
// The UV co-ordinates for the overlay texture can be calculated using that knowledge
|
||||
v_uv = a_pos / 8192.0;
|
||||
gl_Position = u_matrix * vec4(a_pos * u_overlay_scale, 0, 1);
|
||||
}
|
||||
)";
|
||||
static constexpr const char* fragment = R"(layout (std140) uniform DebugUBO {
|
||||
highp mat4 u_matrix;
|
||||
highp vec4 u_color;
|
||||
highp float u_overlay_scale;
|
||||
highp float pad1;
|
||||
highp float pad2;
|
||||
highp float pad3;
|
||||
};
|
||||
|
||||
uniform sampler2D u_overlay;
|
||||
|
||||
in vec2 v_uv;
|
||||
|
||||
void main() {
|
||||
vec4 overlay_color = texture(u_overlay, v_uv);
|
||||
fragColor = mix(u_color, overlay_color, overlay_color.a);
|
||||
}
|
||||
)";
|
||||
};
|
||||
|
||||
} // namespace shaders
|
||||
} // namespace mbgl
|
||||
@@ -6,6 +6,9 @@
|
||||
#include <mbgl/shaders/gl/drawable_background.hpp>
|
||||
#include <mbgl/shaders/gl/drawable_background_pattern.hpp>
|
||||
#include <mbgl/shaders/gl/drawable_circle.hpp>
|
||||
#include <mbgl/shaders/gl/drawable_collision_box.hpp>
|
||||
#include <mbgl/shaders/gl/drawable_collision_circle.hpp>
|
||||
#include <mbgl/shaders/gl/drawable_debug.hpp>
|
||||
#include <mbgl/shaders/gl/drawable_fill.hpp>
|
||||
#include <mbgl/shaders/gl/drawable_fill_outline.hpp>
|
||||
#include <mbgl/shaders/gl/drawable_line_gradient.hpp>
|
||||
|
||||
@@ -12,6 +12,9 @@ enum class BuiltIn {
|
||||
BackgroundShader,
|
||||
BackgroundPatternShader,
|
||||
CircleShader,
|
||||
CollisionBoxShader,
|
||||
CollisionCircleShader,
|
||||
DebugShader,
|
||||
FillShader,
|
||||
FillOutlineShader,
|
||||
LineGradientShader,
|
||||
@@ -31,7 +34,6 @@ enum class BuiltIn {
|
||||
SymbolSDFTextShader,
|
||||
SymbolSDFIconShader,
|
||||
SymbolTextAndIconShader,
|
||||
|
||||
Prelude,
|
||||
BackgroundProgram,
|
||||
BackgroundPatternProgram,
|
||||
|
||||
@@ -176,6 +176,23 @@ objc_library(
|
||||
],
|
||||
)
|
||||
|
||||
objc_library(
|
||||
name = "ios-benchapp",
|
||||
copts = MAPLIBRE_FLAGS,
|
||||
srcs = ["//platform/ios/benchmark:ios_benchmark_srcs"],
|
||||
hdrs = ["//platform/ios/benchmark:ios_benchmark_hdrs"],
|
||||
includes = [
|
||||
"darwin/app",
|
||||
"darwin/src",
|
||||
"ios/src",
|
||||
],
|
||||
visibility = ["//platform/ios:__pkg__"],
|
||||
deps = [
|
||||
":objc-headers",
|
||||
"//:mbgl-core",
|
||||
],
|
||||
)
|
||||
|
||||
sh_binary(
|
||||
name = "check-public-symbols",
|
||||
srcs = ["//platform/darwin:scripts/check-public-symbols.sh"],
|
||||
|
||||
@@ -84,14 +84,6 @@ android {
|
||||
}
|
||||
}
|
||||
}
|
||||
create("split") {
|
||||
dimension = "renderer"
|
||||
externalNativeBuild {
|
||||
cmake {
|
||||
arguments "-DMLN_LEGACY_RENDERER=ON", "-DMLN_DRAWABLE_RENDERER=ON", "-DMLN_RENDERER_SPLIT_VIEW=ON"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// build native libraries
|
||||
|
||||
@@ -431,6 +431,24 @@ ios_application(
|
||||
],
|
||||
)
|
||||
|
||||
ios_application(
|
||||
name = "BenchmarkApp",
|
||||
bundle_id = "{}.benchmark.app".format(BUNDLE_ID_PREFIX),
|
||||
families = [
|
||||
"iphone",
|
||||
"ipad",
|
||||
],
|
||||
infoplists = ["build/Info-benchmark.plist"],
|
||||
minimum_os_version = "12.0",
|
||||
provisioning_profile = "xcode_profile",
|
||||
resources = ["//platform/ios/benchmark:bundle_resources"],
|
||||
visibility = ["//visibility:public"],
|
||||
deps = [
|
||||
"//platform:ios-benchapp",
|
||||
"//platform:ios-sdk",
|
||||
],
|
||||
)
|
||||
|
||||
# Outputs a file with the size of MapLibre as a dynamic library in bytes
|
||||
genrule(
|
||||
name = "size",
|
||||
@@ -462,8 +480,39 @@ xcodeproj(
|
||||
},
|
||||
top_level_targets = [
|
||||
top_level_target(
|
||||
":App",
|
||||
target_environments = ["device", "simulator"],
|
||||
"App",
|
||||
target_environments = [
|
||||
"simulator",
|
||||
"device",
|
||||
],
|
||||
),
|
||||
top_level_target(
|
||||
"BenchmarkApp",
|
||||
target_environments = [
|
||||
"simulator",
|
||||
"device",
|
||||
],
|
||||
),
|
||||
top_level_target(
|
||||
"//render-test/ios:RenderTest",
|
||||
target_environments = [
|
||||
"simulator",
|
||||
"device",
|
||||
],
|
||||
),
|
||||
top_level_target(
|
||||
"//platform/ios/iosapp-UITests:uitest",
|
||||
target_environments = [
|
||||
"simulator",
|
||||
"device",
|
||||
],
|
||||
),
|
||||
top_level_target(
|
||||
"//platform/ios/test:ios_test",
|
||||
target_environments = [
|
||||
"simulator",
|
||||
"device",
|
||||
],
|
||||
),
|
||||
],
|
||||
xcode_configurations = {
|
||||
@@ -480,9 +529,9 @@ sh_binary(
|
||||
"Integration_Tests/Info.plist",
|
||||
"app/Info.plist",
|
||||
"bench_UITests/Info.plist",
|
||||
"benchmark/Info.plist",
|
||||
"framework/Info.plist",
|
||||
"framework/Info-static.plist",
|
||||
"//platform/ios/benchmark:Info.plist",
|
||||
"//platform/ios/iosapp-UITests:Info.plist",
|
||||
"//platform/ios/test:Info.plist",
|
||||
],
|
||||
|
||||
36
platform/ios/benchmark/BUILD.bazel
Normal file
36
platform/ios/benchmark/BUILD.bazel
Normal file
@@ -0,0 +1,36 @@
|
||||
filegroup(
|
||||
name = "ios_benchmark_srcs",
|
||||
srcs = [
|
||||
"main.m",
|
||||
"MBXBenchAppDelegate.m",
|
||||
"MBXBenchViewController.mm",
|
||||
"locations.cpp",
|
||||
],
|
||||
visibility = ["//platform:__pkg__"],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "ios_benchmark_hdrs",
|
||||
srcs = [
|
||||
"MBXBenchAppDelegate.h",
|
||||
"MBXBenchViewController.h",
|
||||
"locations.hpp",
|
||||
],
|
||||
visibility = ["//platform:__pkg__"],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "bundle_resources",
|
||||
srcs = glob([
|
||||
"benchmark/*.lproj/**",
|
||||
"benchmark/Assets.xcassets/**",
|
||||
"benchmark/assets/**/*.pbf",
|
||||
"benchmark/assets/**/*.json",
|
||||
"benchmark/assets/**/*.png",
|
||||
]),
|
||||
visibility = ["//platform/ios:__pkg__"],
|
||||
)
|
||||
|
||||
exports_files([
|
||||
"Info.plist",
|
||||
])
|
||||
@@ -1,4 +1,4 @@
|
||||
@import Mapbox;
|
||||
#import "Mapbox.h"
|
||||
|
||||
#import "MBXBenchAppDelegate.h"
|
||||
#import "MBXBenchViewController.h"
|
||||
|
||||
4
platform/ios/scripts/bazel-generate-plists.sh
Normal file → Executable file
4
platform/ios/scripts/bazel-generate-plists.sh
Normal file → Executable file
@@ -48,6 +48,8 @@ temp_info_static_plist="platform/ios/build/Info-static.plist"
|
||||
temp_info_plist="platform/ios/build/Info.plist"
|
||||
# Move and configure the app plist
|
||||
temp_app_info_plist="platform/ios/build/Info-app.plist"
|
||||
# Move and configure the BenchmarkApp plist
|
||||
temp_benchmark_info_plist="platform/ios/build/Info-benchmark.plist"
|
||||
|
||||
if [ ! -d platform/ios/build ]; then
|
||||
mkdir platform/ios/build
|
||||
@@ -56,6 +58,7 @@ fi
|
||||
cp platform/ios/framework/Info-static.plist "$temp_info_static_plist"
|
||||
cp platform/ios/framework/Info.plist "$temp_info_plist"
|
||||
cp platform/ios/app/Info.plist "$temp_app_info_plist"
|
||||
cp platform/ios/benchmark/Info.plist "$temp_benchmark_info_plist"
|
||||
|
||||
# Replace semver and hash
|
||||
plutil -replace MLNSemanticVersionString -string "$sem_version" "$temp_info_static_plist"
|
||||
@@ -67,6 +70,7 @@ plutil -replace MLNCommitHash -string "$hash" "$temp_info_plist"
|
||||
echo "Inserting MapLibre API key..."
|
||||
if [ "$token" ]; then
|
||||
plutil -replace MLNApiKey -string $token "$temp_app_info_plist"
|
||||
plutil -replace MLNApiKey -string $token "$temp_benchmark_info_plist"
|
||||
echo "API key insertion successful"
|
||||
else
|
||||
echo "Warning: Missing API key."
|
||||
|
||||
2
platform/ios/scripts/bazel-xcodeproj.sh
Normal file → Executable file
2
platform/ios/scripts/bazel-xcodeproj.sh
Normal file → Executable file
@@ -35,7 +35,7 @@ while [[ $# -gt 0 ]]; do
|
||||
;;
|
||||
--apikey)
|
||||
shift
|
||||
token="$1"
|
||||
args+=("--token" "$1")
|
||||
shift
|
||||
;;
|
||||
-*|--*)
|
||||
|
||||
@@ -25,7 +25,7 @@
|
||||
|
||||
NSFileManager *fileManager = [NSFileManager defaultManager];
|
||||
BOOL fileFound = [fileManager fileExistsAtPath: styleResult];
|
||||
XCTAssert(fileFound, @"Test result html '%@' doese not exit", styleResult);
|
||||
XCTAssert(fileFound, @"Test result html '%@' does not exit", styleResult);
|
||||
NSURL *styleURL = [NSURL fileURLWithPath:styleResult];
|
||||
XCTAttachment *attachment1URL = [XCTAttachment attachmentWithContentsOfFileAtURL: styleURL];
|
||||
XCTAssert(attachment1URL, @"Failed to attach test result '%@'", styleResult);
|
||||
@@ -33,7 +33,7 @@
|
||||
[self addAttachment:attachment1URL];
|
||||
|
||||
fileFound = [fileManager fileExistsAtPath: metricResult];
|
||||
XCTAssert(fileFound, @"Test result html '%@' doese not exit", metricResult);
|
||||
XCTAssert(fileFound, @"Test result html '%@' does not exit", metricResult);
|
||||
NSURL *metricURL = [NSURL fileURLWithPath:metricResult];
|
||||
XCTAttachment *attachment2URL = [XCTAttachment attachmentWithContentsOfFileAtURL: metricURL];
|
||||
XCTAssert(attachment2URL, @"Failed to attach test result '%@'", metricResult);
|
||||
|
||||
@@ -3,7 +3,7 @@ uniform float u_overscale_factor;
|
||||
in float v_placed;
|
||||
in float v_notUsed;
|
||||
in float v_radius;
|
||||
in vec2 v_extrude;
|
||||
in highp vec2 v_extrude;
|
||||
in vec2 v_extrude_scale;
|
||||
|
||||
void main() {
|
||||
|
||||
@@ -10,7 +10,7 @@ uniform float u_camera_to_center_distance;
|
||||
out float v_placed;
|
||||
out float v_notUsed;
|
||||
out float v_radius;
|
||||
out vec2 v_extrude;
|
||||
out highp vec2 v_extrude;
|
||||
out vec2 v_extrude_scale;
|
||||
|
||||
void main() {
|
||||
|
||||
27
shaders/drawable.collision_box.fragment.glsl
Normal file
27
shaders/drawable.collision_box.fragment.glsl
Normal file
@@ -0,0 +1,27 @@
|
||||
layout (std140) uniform CollisionBoxUBO {
|
||||
highp mat4 u_matrix;
|
||||
highp vec2 u_extrude_scale;
|
||||
highp float u_camera_to_center_distance;
|
||||
highp float pad1;
|
||||
};
|
||||
|
||||
in float v_placed;
|
||||
in float v_notUsed;
|
||||
|
||||
void main() {
|
||||
|
||||
float alpha = 0.5;
|
||||
|
||||
// Red = collision, hide label
|
||||
fragColor = vec4(1.0, 0.0, 0.0, 1.0) * alpha;
|
||||
|
||||
// Blue = no collision, label is showing
|
||||
if (v_placed > 0.5) {
|
||||
fragColor = vec4(0.0, 0.0, 1.0, 0.5) * alpha;
|
||||
}
|
||||
|
||||
if (v_notUsed > 0.5) {
|
||||
// This box not used, fade it out
|
||||
fragColor *= .1;
|
||||
}
|
||||
}
|
||||
30
shaders/drawable.collision_box.vertex.glsl
Normal file
30
shaders/drawable.collision_box.vertex.glsl
Normal file
@@ -0,0 +1,30 @@
|
||||
layout (location = 0) in vec2 a_pos;
|
||||
layout (location = 1) in vec2 a_anchor_pos;
|
||||
layout (location = 2) in vec2 a_extrude;
|
||||
layout (location = 3) in vec2 a_placed;
|
||||
layout (location = 4) in vec2 a_shift;
|
||||
|
||||
layout (std140) uniform CollisionBoxUBO {
|
||||
highp mat4 u_matrix;
|
||||
highp vec2 u_extrude_scale;
|
||||
highp float u_camera_to_center_distance;
|
||||
highp float pad1;
|
||||
};
|
||||
|
||||
out float v_placed;
|
||||
out float v_notUsed;
|
||||
|
||||
void main() {
|
||||
vec4 projectedPoint = u_matrix * vec4(a_anchor_pos, 0, 1);
|
||||
highp float camera_to_anchor_distance = projectedPoint.w;
|
||||
highp float collision_perspective_ratio = clamp(
|
||||
0.5 + 0.5 * (u_camera_to_center_distance / camera_to_anchor_distance),
|
||||
0.0, // Prevents oversized near-field boxes in pitched/overzoomed tiles
|
||||
4.0);
|
||||
|
||||
gl_Position = u_matrix * vec4(a_pos, 0.0, 1.0);
|
||||
gl_Position.xy += (a_extrude + a_shift) * u_extrude_scale * gl_Position.w * collision_perspective_ratio;
|
||||
|
||||
v_placed = a_placed.x;
|
||||
v_notUsed = a_placed.y;
|
||||
}
|
||||
39
shaders/drawable.collision_circle.fragment.glsl
Normal file
39
shaders/drawable.collision_circle.fragment.glsl
Normal file
@@ -0,0 +1,39 @@
|
||||
layout (std140) uniform CollisionCircleUBO {
|
||||
highp mat4 u_matrix;
|
||||
highp vec2 u_extrude_scale;
|
||||
highp float u_camera_to_center_distance;
|
||||
highp float u_overscale_factor;
|
||||
};
|
||||
|
||||
in float v_placed;
|
||||
in float v_notUsed;
|
||||
in float v_radius;
|
||||
in highp vec2 v_extrude;
|
||||
in vec2 v_extrude_scale;
|
||||
|
||||
void main() {
|
||||
float alpha = 0.5;
|
||||
|
||||
// Red = collision, hide label
|
||||
vec4 color = vec4(1.0, 0.0, 0.0, 1.0) * alpha;
|
||||
|
||||
// Blue = no collision, label is showing
|
||||
if (v_placed > 0.5) {
|
||||
color = vec4(0.0, 0.0, 1.0, 0.5) * alpha;
|
||||
}
|
||||
|
||||
if (v_notUsed > 0.5) {
|
||||
// This box not used, fade it out
|
||||
color *= .2;
|
||||
}
|
||||
|
||||
float extrude_scale_length = length(v_extrude_scale);
|
||||
float extrude_length = length(v_extrude) * extrude_scale_length;
|
||||
float stroke_width = 15.0 * extrude_scale_length / u_overscale_factor;
|
||||
float radius = v_radius * extrude_scale_length;
|
||||
|
||||
float distance_to_edge = abs(extrude_length - radius);
|
||||
float opacity_t = smoothstep(-stroke_width, 0.0, -distance_to_edge);
|
||||
|
||||
fragColor = opacity_t * color;
|
||||
}
|
||||
38
shaders/drawable.collision_circle.vertex.glsl
Normal file
38
shaders/drawable.collision_circle.vertex.glsl
Normal file
@@ -0,0 +1,38 @@
|
||||
layout (location = 0) in vec2 a_pos;
|
||||
layout (location = 1) in vec2 a_anchor_pos;
|
||||
layout (location = 2) in vec2 a_extrude;
|
||||
layout (location = 3) in vec2 a_placed;
|
||||
|
||||
layout (std140) uniform CollisionCircleUBO {
|
||||
highp mat4 u_matrix;
|
||||
highp vec2 u_extrude_scale;
|
||||
highp float u_camera_to_center_distance;
|
||||
highp float u_overscale_factor;
|
||||
};
|
||||
|
||||
out float v_placed;
|
||||
out float v_notUsed;
|
||||
out float v_radius;
|
||||
out highp vec2 v_extrude;
|
||||
out vec2 v_extrude_scale;
|
||||
|
||||
void main() {
|
||||
vec4 projectedPoint = u_matrix * vec4(a_anchor_pos, 0, 1);
|
||||
highp float camera_to_anchor_distance = projectedPoint.w;
|
||||
highp float collision_perspective_ratio = clamp(
|
||||
0.5 + 0.5 * (u_camera_to_center_distance / camera_to_anchor_distance),
|
||||
0.0, // Prevents oversized near-field circles in pitched/overzoomed tiles
|
||||
4.0);
|
||||
|
||||
gl_Position = u_matrix * vec4(a_pos, 0.0, 1.0);
|
||||
|
||||
highp float padding_factor = 1.2; // Pad the vertices slightly to make room for anti-alias blur
|
||||
gl_Position.xy += a_extrude * u_extrude_scale * padding_factor * gl_Position.w * collision_perspective_ratio;
|
||||
|
||||
v_placed = a_placed.x;
|
||||
v_notUsed = a_placed.y;
|
||||
v_radius = abs(a_extrude.y); // We don't pitch the circles, so both units of the extrusion vector are equal in magnitude to the radius
|
||||
|
||||
v_extrude = a_extrude * padding_factor;
|
||||
v_extrude_scale = u_extrude_scale * u_camera_to_center_distance * collision_perspective_ratio;
|
||||
}
|
||||
17
shaders/drawable.debug.fragment.glsl
Normal file
17
shaders/drawable.debug.fragment.glsl
Normal file
@@ -0,0 +1,17 @@
|
||||
layout (std140) uniform DebugUBO {
|
||||
highp mat4 u_matrix;
|
||||
highp vec4 u_color;
|
||||
highp float u_overlay_scale;
|
||||
highp float pad1;
|
||||
highp float pad2;
|
||||
highp float pad3;
|
||||
};
|
||||
|
||||
uniform sampler2D u_overlay;
|
||||
|
||||
in vec2 v_uv;
|
||||
|
||||
void main() {
|
||||
vec4 overlay_color = texture(u_overlay, v_uv);
|
||||
fragColor = mix(u_color, overlay_color, overlay_color.a);
|
||||
}
|
||||
18
shaders/drawable.debug.vertex.glsl
Normal file
18
shaders/drawable.debug.vertex.glsl
Normal file
@@ -0,0 +1,18 @@
|
||||
layout (location = 0) in vec2 a_pos;
|
||||
out vec2 v_uv;
|
||||
|
||||
layout (std140) uniform DebugUBO {
|
||||
highp mat4 u_matrix;
|
||||
highp vec4 u_color;
|
||||
highp float u_overlay_scale;
|
||||
highp float pad1;
|
||||
highp float pad2;
|
||||
highp float pad3;
|
||||
};
|
||||
|
||||
void main() {
|
||||
// This vertex shader expects a EXTENT x EXTENT quad,
|
||||
// The UV co-ordinates for the overlay texture can be calculated using that knowledge
|
||||
v_uv = a_pos / 8192.0;
|
||||
gl_Position = u_matrix * vec4(a_pos * u_overlay_scale, 0, 1);
|
||||
}
|
||||
@@ -20,6 +20,27 @@
|
||||
"glsl_frag": "drawable.circle.fragment.glsl",
|
||||
"uses_ubos": true
|
||||
},
|
||||
{
|
||||
"name": "CollisionBoxShader",
|
||||
"header": "drawable_collision_box",
|
||||
"glsl_vert": "drawable.collision_box.vertex.glsl",
|
||||
"glsl_frag": "drawable.collision_box.fragment.glsl",
|
||||
"uses_ubos": true
|
||||
},
|
||||
{
|
||||
"name": "CollisionCircleShader",
|
||||
"header": "drawable_collision_circle",
|
||||
"glsl_vert": "drawable.collision_circle.vertex.glsl",
|
||||
"glsl_frag": "drawable.collision_circle.fragment.glsl",
|
||||
"uses_ubos": true
|
||||
},
|
||||
{
|
||||
"name": "DebugShader",
|
||||
"header": "drawable_debug",
|
||||
"glsl_vert": "drawable.debug.vertex.glsl",
|
||||
"glsl_frag": "drawable.debug.fragment.glsl",
|
||||
"uses_ubos": true
|
||||
},
|
||||
{
|
||||
"name": "FillShader",
|
||||
"header": "drawable_fill",
|
||||
|
||||
@@ -222,24 +222,17 @@ void DashPatternTexture::upload(gfx::UploadPass& uploadPass) {
|
||||
#endif
|
||||
}
|
||||
|
||||
#if MLN_LEGACY_RENDERER
|
||||
gfx::TextureBinding DashPatternTexture::textureBinding() const {
|
||||
// The texture needs to have been uploaded already.
|
||||
#if MLN_DRAWABLE_RENDERER
|
||||
assert(std::holds_alternative<gfx::Texture2DPtr>(texture));
|
||||
return {std::get<gfx::Texture2DPtr>(texture)->getResource(),
|
||||
gfx::TextureFilterType::Linear,
|
||||
gfx::TextureMipMapType::No,
|
||||
gfx::TextureWrapType::Repeat,
|
||||
gfx::TextureWrapType::Clamp};
|
||||
#else
|
||||
assert(texture.is<gfx::Texture>());
|
||||
return {texture.get<gfx::Texture>().getResource(),
|
||||
gfx::TextureFilterType::Linear,
|
||||
gfx::TextureMipMapType::No,
|
||||
gfx::TextureWrapType::Repeat,
|
||||
gfx::TextureWrapType::Clamp};
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
#if MLN_DRAWABLE_RENDERER
|
||||
static const gfx::Texture2DPtr noTexture;
|
||||
|
||||
@@ -51,9 +51,10 @@ public:
|
||||
void upload(gfx::UploadPass&);
|
||||
|
||||
// Binds the atlas texture to the GPU, and uploads data if it is out of date.
|
||||
gfx::TextureBinding textureBinding() const;
|
||||
#if MLN_DRAWABLE_RENDERER
|
||||
const std::shared_ptr<gfx::Texture2D>& getTexture() const;
|
||||
#else
|
||||
gfx::TextureBinding textureBinding() const;
|
||||
#endif
|
||||
|
||||
// Returns the size of the texture image.
|
||||
|
||||
24
src/mbgl/gfx/collision_drawable_data.hpp
Normal file
24
src/mbgl/gfx/collision_drawable_data.hpp
Normal file
@@ -0,0 +1,24 @@
|
||||
#pragma once
|
||||
|
||||
#include <mbgl/gfx/drawable_data.hpp>
|
||||
#include <mbgl/style/types.hpp>
|
||||
|
||||
#include <memory>
|
||||
|
||||
namespace mbgl {
|
||||
namespace gfx {
|
||||
|
||||
struct CollisionDrawableData : public DrawableData {
|
||||
CollisionDrawableData(const std::array<float, 2> translate_, const style::TranslateAnchorType translateAnchor_)
|
||||
: translate(translate_),
|
||||
translateAnchor(translateAnchor_) {}
|
||||
~CollisionDrawableData() override = default;
|
||||
|
||||
std::array<float, 2> translate;
|
||||
style::TranslateAnchorType translateAnchor;
|
||||
};
|
||||
|
||||
using UniqueCollisionDrawableData = std::unique_ptr<CollisionDrawableData>;
|
||||
|
||||
} // namespace gfx
|
||||
} // namespace mbgl
|
||||
@@ -3,13 +3,22 @@
|
||||
#include <mbgl/gfx/drawable.hpp>
|
||||
#include <mbgl/renderer/tile_render_data.hpp>
|
||||
#include <mbgl/shaders/shader_program_base.hpp>
|
||||
#include <mbgl/renderer/paint_parameters.hpp>
|
||||
|
||||
namespace mbgl {
|
||||
namespace gfx {
|
||||
|
||||
void DrawableAtlasesTweaker::setupTextures(gfx::Drawable& drawable) {
|
||||
void DrawableAtlasesTweaker::setupTextures(gfx::Drawable& drawable, const bool linearFilterForIcons) {
|
||||
if (const auto& shader = drawable.getShader()) {
|
||||
if (const auto samplerLocation = shader->getSamplerLocation(glyphName)) {
|
||||
if (atlases) {
|
||||
atlases->glyph->setSamplerConfiguration(
|
||||
{TextureFilterType::Linear, TextureWrapType::Clamp, TextureWrapType::Clamp});
|
||||
atlases->icon->setSamplerConfiguration(
|
||||
{linearFilterForIcons ? TextureFilterType::Linear : TextureFilterType::Nearest,
|
||||
TextureWrapType::Clamp,
|
||||
TextureWrapType::Clamp});
|
||||
}
|
||||
if (const auto iconSamplerLocation = shader->getSamplerLocation(iconName)) {
|
||||
assert(*samplerLocation != *iconSamplerLocation);
|
||||
drawable.setTexture(atlases ? atlases->glyph : nullptr, *samplerLocation);
|
||||
@@ -22,11 +31,15 @@ void DrawableAtlasesTweaker::setupTextures(gfx::Drawable& drawable) {
|
||||
}
|
||||
|
||||
void DrawableAtlasesTweaker::init(gfx::Drawable& drawable) {
|
||||
setupTextures(drawable);
|
||||
setupTextures(drawable, true);
|
||||
}
|
||||
|
||||
void DrawableAtlasesTweaker::execute(gfx::Drawable& drawable, const PaintParameters&) {
|
||||
setupTextures(drawable);
|
||||
void DrawableAtlasesTweaker::execute(gfx::Drawable& drawable, const PaintParameters& parameters) {
|
||||
const bool transformed = rotationAlignment == style::AlignmentType::Map || parameters.state.getPitch() != 0;
|
||||
const bool linearFilterForIcons = isText ? (parameters.state.isChanging() || transformed || !textSizeIsZoomConstant)
|
||||
: (sdfIcons || parameters.state.isChanging() || iconScaled || transformed);
|
||||
|
||||
setupTextures(drawable, linearFilterForIcons);
|
||||
}
|
||||
|
||||
} // namespace gfx
|
||||
|
||||
@@ -52,6 +52,7 @@ void DrawableBuilder::flush() {
|
||||
draw->setRenderPass(renderPass);
|
||||
draw->setDrawPriority(drawPriority);
|
||||
draw->setSubLayerIndex(subLayerIndex);
|
||||
draw->setEnableDepth(enableDepth);
|
||||
draw->setDepthType(depthType);
|
||||
draw->setIs3D(is3D);
|
||||
draw->setColorMode(impl->colorMode);
|
||||
|
||||
@@ -4,10 +4,15 @@
|
||||
#include <mbgl/util/ignore.hpp>
|
||||
|
||||
#include <vector>
|
||||
#include <memory>
|
||||
|
||||
namespace mbgl {
|
||||
namespace gfx {
|
||||
|
||||
struct IndexBufferBase {
|
||||
virtual ~IndexBufferBase() = default;
|
||||
};
|
||||
|
||||
class IndexVectorBase {
|
||||
protected:
|
||||
std::vector<uint16_t> v;
|
||||
@@ -18,6 +23,35 @@ public:
|
||||
IndexVectorBase() = default;
|
||||
IndexVectorBase(std::vector<uint16_t>&& indexes)
|
||||
: v(std::move(indexes)) {}
|
||||
IndexVectorBase(const IndexVectorBase&) {} // buffer is not copied
|
||||
IndexVectorBase(IndexVectorBase&& other)
|
||||
: buffer(std::move(other.buffer)),
|
||||
dirty(other.dirty),
|
||||
released(other.released) {}
|
||||
virtual ~IndexVectorBase() = default;
|
||||
|
||||
IndexBufferBase* getBuffer() const { return buffer.get(); }
|
||||
void setBuffer(std::unique_ptr<IndexBufferBase>&& value) { buffer = std::move(value); }
|
||||
|
||||
bool getDirty() const { return dirty; }
|
||||
void setDirty(bool value = true) { dirty = value; }
|
||||
|
||||
bool isReleased() const { return released; }
|
||||
|
||||
void extend(std::size_t n, const uint16_t val) {
|
||||
v.resize(v.size() + n, val);
|
||||
dirty = true;
|
||||
}
|
||||
|
||||
uint16_t& at(std::size_t n) {
|
||||
assert(n < v.size());
|
||||
dirty = true;
|
||||
return v.at(n);
|
||||
}
|
||||
const uint16_t& at(std::size_t n) const {
|
||||
assert(n < v.size());
|
||||
return v.at(n);
|
||||
}
|
||||
|
||||
std::size_t elements() const { return v.size(); }
|
||||
|
||||
@@ -25,15 +59,31 @@ public:
|
||||
|
||||
bool empty() const { return v.empty(); }
|
||||
|
||||
void clear() { v.clear(); }
|
||||
void clear() {
|
||||
dirty = true;
|
||||
v.clear();
|
||||
}
|
||||
|
||||
void release() {
|
||||
// If we've already created a buffer, we don't need the raw data any more.
|
||||
if (buffer) {
|
||||
clear();
|
||||
}
|
||||
released = true;
|
||||
}
|
||||
|
||||
const uint16_t* data() const { return v.data(); }
|
||||
|
||||
const std::vector<uint16_t>& vector() const { return v; }
|
||||
|
||||
protected:
|
||||
std::unique_ptr<IndexBufferBase> buffer;
|
||||
bool dirty = true;
|
||||
bool released = false;
|
||||
};
|
||||
|
||||
template <class DrawMode>
|
||||
class IndexVector : public IndexVectorBase {
|
||||
class IndexVector final : public IndexVectorBase {
|
||||
public:
|
||||
static constexpr std::size_t groupSize = BufferGroupSizeOf<DrawMode>::value;
|
||||
|
||||
@@ -44,5 +94,7 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
using IndexVectorBasePtr = std::shared_ptr<IndexVectorBase>;
|
||||
|
||||
} // namespace gfx
|
||||
} // namespace mbgl
|
||||
|
||||
@@ -127,28 +127,6 @@ public:
|
||||
updateTextureResourceSub(texture.getResource(), offsetX, offsetY, image.size, image.data.get(), format, type);
|
||||
}
|
||||
|
||||
#if MLN_DRAWABLE_RENDERER
|
||||
template <typename Image>
|
||||
void updateTexture(Texture2D& texture,
|
||||
const Image& image,
|
||||
TextureChannelDataType type = TextureChannelDataType::UnsignedByte) {
|
||||
const auto format = image.channels == 4 ? TexturePixelType::RGBA : TexturePixelType::Alpha;
|
||||
updateTexture2D(texture, image.size, image.data.get(), format, type);
|
||||
}
|
||||
|
||||
template <typename Image>
|
||||
void updateTextureSub(Texture2D& texture,
|
||||
const Image& image,
|
||||
const uint16_t offsetX,
|
||||
const uint16_t offsetY,
|
||||
TextureChannelDataType type = TextureChannelDataType::UnsignedByte) {
|
||||
assert(image.size.width + offsetX <= texture.getSize().width);
|
||||
assert(image.size.height + offsetY <= texture.getSize().height);
|
||||
const auto format = image.channels == 4 ? TexturePixelType::RGBA : TexturePixelType::Alpha;
|
||||
updateTextureResourceSub(texture.getResource(), offsetX, offsetY, image.size, image.data.get(), format, type);
|
||||
}
|
||||
#endif
|
||||
|
||||
public:
|
||||
virtual std::unique_ptr<TextureResource> createTextureResource(Size,
|
||||
const void* data,
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
#include <mbgl/util/ignore.hpp>
|
||||
|
||||
#include <vector>
|
||||
#include <memory>
|
||||
|
||||
namespace mbgl {
|
||||
namespace gfx {
|
||||
|
||||
@@ -17,7 +17,6 @@ DrawableGL::DrawableGL(std::string name_)
|
||||
impl(std::make_unique<Impl>()) {}
|
||||
|
||||
DrawableGL::~DrawableGL() {
|
||||
impl->indexBuffer = {0, nullptr};
|
||||
impl->attributeBuffers.clear();
|
||||
}
|
||||
|
||||
@@ -40,8 +39,12 @@ void DrawableGL::draw(PaintParameters& parameters) const {
|
||||
return;
|
||||
}
|
||||
|
||||
context.setDepthMode(getIs3D() ? parameters.depthModeFor3D()
|
||||
: parameters.depthModeForSublayer(getSubLayerIndex(), getDepthType()));
|
||||
if (enableDepth) {
|
||||
context.setDepthMode(getIs3D() ? parameters.depthModeFor3D()
|
||||
: parameters.depthModeForSublayer(getSubLayerIndex(), getDepthType()));
|
||||
} else {
|
||||
context.setDepthMode(gfx::DepthMode::disabled());
|
||||
}
|
||||
|
||||
// force disable depth test for debugging
|
||||
// context.setDepthMode({gfx::DepthFunctionType::Always, gfx::DepthMaskType::ReadOnly, {0,1}});
|
||||
@@ -136,6 +139,14 @@ void DrawableGL::unbindUniformBuffers() const {
|
||||
}
|
||||
}
|
||||
|
||||
struct IndexBufferGL : public gfx::IndexBufferBase {
|
||||
IndexBufferGL(std::unique_ptr<gfx::IndexBuffer>&& buffer_)
|
||||
: buffer(std::move(buffer_)) {}
|
||||
~IndexBufferGL() override = default;
|
||||
|
||||
std::unique_ptr<mbgl::gfx::IndexBuffer> buffer;
|
||||
};
|
||||
|
||||
void DrawableGL::upload(gfx::UploadPass& uploadPass) {
|
||||
if (!shader) {
|
||||
return;
|
||||
@@ -151,10 +162,6 @@ void DrawableGL::upload(gfx::UploadPass& uploadPass) {
|
||||
auto& glContext = static_cast<gl::Context&>(context);
|
||||
constexpr auto usage = gfx::BufferUsageType::StaticDraw;
|
||||
|
||||
const auto indexBytes = impl->indexes->elements() * sizeof(gfx::IndexVectorBase::value_type);
|
||||
auto indexBufferResource = uploadPass.createIndexBufferResource(impl->indexes->data(), indexBytes, usage);
|
||||
auto indexBuffer = gfx::IndexBuffer{impl->indexes->elements(), std::move(indexBufferResource)};
|
||||
|
||||
// Apply drawable values to shader defaults
|
||||
const auto& defaults = shader->getVertexAttributes();
|
||||
const auto& overrides = impl->vertexAttributes;
|
||||
@@ -173,7 +180,17 @@ void DrawableGL::upload(gfx::UploadPass& uploadPass) {
|
||||
vertexBuffers);
|
||||
|
||||
impl->attributeBuffers = std::move(vertexBuffers);
|
||||
impl->indexBuffer = std::move(indexBuffer);
|
||||
|
||||
if (impl->indexes->getDirty()) {
|
||||
auto indexBufferResource{
|
||||
uploadPass.createIndexBufferResource(impl->indexes->data(), impl->indexes->bytes(), usage)};
|
||||
auto indexBuffer = std::make_unique<gfx::IndexBuffer>(impl->indexes->elements(),
|
||||
std::move(indexBufferResource));
|
||||
auto buffer = std::make_unique<IndexBufferGL>(std::move(indexBuffer));
|
||||
|
||||
impl->indexes->setBuffer(std::move(buffer));
|
||||
impl->indexes->setDirty(false);
|
||||
}
|
||||
|
||||
// Create a VAO for each group of vertexes described by a segment
|
||||
for (const auto& seg : impl->segments) {
|
||||
@@ -190,13 +207,13 @@ void DrawableGL::upload(gfx::UploadPass& uploadPass) {
|
||||
}
|
||||
}
|
||||
|
||||
auto vertexArray = glContext.createVertexArray();
|
||||
|
||||
vertexArray.bind(glContext, impl->indexBuffer, bindings);
|
||||
|
||||
assert(vertexArray.isValid());
|
||||
|
||||
glSeg.setVertexArray(std::move(vertexArray));
|
||||
if (!glSeg.getVertexArray().isValid()) {
|
||||
auto vertexArray = glContext.createVertexArray();
|
||||
IndexBufferGL& indexBuffer = *static_cast<IndexBufferGL*>(impl->indexes->getBuffer());
|
||||
vertexArray.bind(glContext, *indexBuffer.buffer, bindings);
|
||||
assert(vertexArray.isValid());
|
||||
glSeg.setVertexArray(std::move(vertexArray));
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -40,7 +40,6 @@ public:
|
||||
|
||||
VertexAttributeArrayGL vertexAttributes;
|
||||
|
||||
gfx::IndexBuffer indexBuffer = {0, nullptr};
|
||||
std::vector<gfx::UniqueVertexBufferResource> attributeBuffers;
|
||||
|
||||
UniformBufferArrayGL uniformBuffers;
|
||||
|
||||
@@ -96,6 +96,9 @@ void RendererBackend::initShaders(gfx::ShaderRegistry& shaders, const ProgramPar
|
||||
registerTypes<shaders::BuiltIn::BackgroundShader,
|
||||
shaders::BuiltIn::BackgroundPatternShader,
|
||||
shaders::BuiltIn::CircleShader,
|
||||
shaders::BuiltIn::CollisionBoxShader,
|
||||
shaders::BuiltIn::CollisionCircleShader,
|
||||
shaders::BuiltIn::DebugShader,
|
||||
shaders::BuiltIn::FillShader,
|
||||
shaders::BuiltIn::FillOutlineShader,
|
||||
shaders::BuiltIn::LineShader,
|
||||
|
||||
@@ -203,7 +203,11 @@ void Texture2D::uploadSubRegion(const void* pixelData, const Size& size_, uint16
|
||||
using namespace platform;
|
||||
|
||||
assert(textureResource);
|
||||
assert(!samplerStateDirty);
|
||||
|
||||
// update sampler configuration if needed
|
||||
if (samplerStateDirty) {
|
||||
updateSamplerConfiguration();
|
||||
}
|
||||
|
||||
// Bind to TU 0 and upload
|
||||
context.activeTextureUnit = 0;
|
||||
|
||||
@@ -153,6 +153,7 @@ const gfx::UniqueVertexBufferResource& UploadPass::getBuffer(const gfx::VertexVe
|
||||
if (rawBufSize <= resource.byteSize) {
|
||||
if (vec->getDirty()) {
|
||||
updateVertexBufferResource(resource, rawBufPtr, rawBufSize);
|
||||
vec->setDirty(false);
|
||||
}
|
||||
return rawData->resource;
|
||||
}
|
||||
@@ -162,6 +163,7 @@ const gfx::UniqueVertexBufferResource& UploadPass::getBuffer(const gfx::VertexVe
|
||||
auto buffer = std::make_unique<VertexBufferGL>();
|
||||
buffer->resource = createVertexBufferResource(rawBufPtr, rawBufSize, usage);
|
||||
vec->setBuffer(std::move(buffer));
|
||||
vec->setDirty(false);
|
||||
return static_cast<VertexBufferGL*>(vec->getBuffer())->resource;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1124,7 +1124,7 @@ void SymbolLayout::addToDebugBuffers(SymbolBucket& bucket) {
|
||||
if (collisionBuffer.segments.empty() || collisionBuffer.segments.back().vertexLength + vertexLength >
|
||||
std::numeric_limits<uint16_t>::max()) {
|
||||
collisionBuffer.segments.emplace_back(
|
||||
collisionBuffer.vertices.elements(),
|
||||
collisionBuffer.vertices().elements(),
|
||||
feature.alongLine ? (isText ? bucket.textCollisionCircle->triangles.elements()
|
||||
: bucket.iconCollisionCircle->triangles.elements())
|
||||
: (isText ? bucket.textCollisionBox->lines.elements()
|
||||
@@ -1134,23 +1134,23 @@ void SymbolLayout::addToDebugBuffers(SymbolBucket& bucket) {
|
||||
auto& segment = collisionBuffer.segments.back();
|
||||
auto index = static_cast<uint16_t>(segment.vertexLength);
|
||||
|
||||
collisionBuffer.vertices.emplace_back(
|
||||
collisionBuffer.vertices().emplace_back(
|
||||
CollisionBoxProgram::layoutVertex(anchor, symbolInstance.anchor.point, tl));
|
||||
collisionBuffer.vertices.emplace_back(
|
||||
collisionBuffer.vertices().emplace_back(
|
||||
CollisionBoxProgram::layoutVertex(anchor, symbolInstance.anchor.point, tr));
|
||||
collisionBuffer.vertices.emplace_back(
|
||||
collisionBuffer.vertices().emplace_back(
|
||||
CollisionBoxProgram::layoutVertex(anchor, symbolInstance.anchor.point, br));
|
||||
collisionBuffer.vertices.emplace_back(
|
||||
collisionBuffer.vertices().emplace_back(
|
||||
CollisionBoxProgram::layoutVertex(anchor, symbolInstance.anchor.point, bl));
|
||||
|
||||
// Dynamic vertices are initialized so that the vertex count
|
||||
// always agrees with the layout vertex buffer, but they will
|
||||
// always be updated before rendering happens
|
||||
auto dynamicVertex = CollisionBoxProgram::dynamicVertex(false, false, {});
|
||||
collisionBuffer.dynamicVertices.emplace_back(dynamicVertex);
|
||||
collisionBuffer.dynamicVertices.emplace_back(dynamicVertex);
|
||||
collisionBuffer.dynamicVertices.emplace_back(dynamicVertex);
|
||||
collisionBuffer.dynamicVertices.emplace_back(dynamicVertex);
|
||||
collisionBuffer.dynamicVertices().emplace_back(dynamicVertex);
|
||||
collisionBuffer.dynamicVertices().emplace_back(dynamicVertex);
|
||||
collisionBuffer.dynamicVertices().emplace_back(dynamicVertex);
|
||||
collisionBuffer.dynamicVertices().emplace_back(dynamicVertex);
|
||||
|
||||
if (feature.alongLine) {
|
||||
auto& collisionCircle = (isText ? bucket.textCollisionCircle : bucket.iconCollisionCircle);
|
||||
|
||||
@@ -134,15 +134,15 @@ void SymbolBucket::upload([[maybe_unused]] gfx::UploadPass& uploadPass) {
|
||||
const auto updateCollisionBox = [&](CollisionBoxBuffer& collisionBox) {
|
||||
if (!staticUploaded) {
|
||||
collisionBox.indexBuffer = uploadPass.createIndexBuffer(std::move(collisionBox.lines));
|
||||
collisionBox.vertexBuffer = uploadPass.createVertexBuffer(std::move(collisionBox.vertices));
|
||||
collisionBox.vertexBuffer = uploadPass.createVertexBuffer(std::move(collisionBox.vertices()));
|
||||
}
|
||||
if (!placementChangesUploaded) {
|
||||
if (!collisionBox.dynamicVertexBuffer) {
|
||||
collisionBox.dynamicVertexBuffer = uploadPass.createVertexBuffer(
|
||||
std::move(collisionBox.dynamicVertices), gfx::BufferUsageType::StreamDraw);
|
||||
std::move(collisionBox.dynamicVertices()), gfx::BufferUsageType::StreamDraw);
|
||||
} else {
|
||||
uploadPass.updateVertexBuffer(*collisionBox.dynamicVertexBuffer,
|
||||
std::move(collisionBox.dynamicVertices));
|
||||
std::move(collisionBox.dynamicVertices()));
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -157,15 +157,15 @@ void SymbolBucket::upload([[maybe_unused]] gfx::UploadPass& uploadPass) {
|
||||
const auto updateCollisionCircle = [&](CollisionCircleBuffer& collisionCircle) {
|
||||
if (!staticUploaded) {
|
||||
collisionCircle.indexBuffer = uploadPass.createIndexBuffer(std::move(collisionCircle.triangles));
|
||||
collisionCircle.vertexBuffer = uploadPass.createVertexBuffer(std::move(collisionCircle.vertices));
|
||||
collisionCircle.vertexBuffer = uploadPass.createVertexBuffer(std::move(collisionCircle.vertices()));
|
||||
}
|
||||
if (!placementChangesUploaded) {
|
||||
if (!collisionCircle.dynamicVertexBuffer) {
|
||||
collisionCircle.dynamicVertexBuffer = uploadPass.createVertexBuffer(
|
||||
std::move(collisionCircle.dynamicVertices), gfx::BufferUsageType::StreamDraw);
|
||||
std::move(collisionCircle.dynamicVertices()), gfx::BufferUsageType::StreamDraw);
|
||||
} else {
|
||||
uploadPass.updateVertexBuffer(*collisionCircle.dynamicVertexBuffer,
|
||||
std::move(collisionCircle.dynamicVertices));
|
||||
std::move(collisionCircle.dynamicVertices()));
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -178,18 +178,34 @@ public:
|
||||
Buffer icon;
|
||||
Buffer sdfIcon;
|
||||
|
||||
using CollisionVertexVector = gfx::VertexVector<gfx::Vertex<CollisionBoxLayoutAttributes>>;
|
||||
using CollisionDynamicVertexVector = gfx::VertexVector<gfx::Vertex<CollisionBoxDynamicAttributes>>;
|
||||
|
||||
struct CollisionBuffer {
|
||||
gfx::VertexVector<gfx::Vertex<CollisionBoxLayoutAttributes>> vertices;
|
||||
gfx::VertexVector<gfx::Vertex<CollisionBoxDynamicAttributes>> dynamicVertices;
|
||||
std::shared_ptr<CollisionVertexVector> sharedVertices = std::make_shared<CollisionVertexVector>();
|
||||
CollisionVertexVector& vertices() { return *sharedVertices; }
|
||||
const CollisionVertexVector& vertices() const { return *sharedVertices; }
|
||||
|
||||
std::shared_ptr<CollisionDynamicVertexVector> sharedDynamicVertices =
|
||||
std::make_shared<CollisionDynamicVertexVector>();
|
||||
CollisionDynamicVertexVector& dynamicVertices() { return *sharedDynamicVertices; }
|
||||
const CollisionDynamicVertexVector& dynamicVertices() const { return *sharedDynamicVertices; }
|
||||
|
||||
SegmentVector<CollisionBoxProgram::AttributeList> segments;
|
||||
|
||||
#if MLN_LEGACY_RENDERER
|
||||
std::optional<gfx::VertexBuffer<gfx::Vertex<CollisionBoxLayoutAttributes>>> vertexBuffer;
|
||||
std::optional<gfx::VertexBuffer<gfx::Vertex<CollisionBoxDynamicAttributes>>> dynamicVertexBuffer;
|
||||
#endif // MLN_LEGACY_RENDERER
|
||||
};
|
||||
|
||||
struct CollisionBoxBuffer : public CollisionBuffer {
|
||||
gfx::IndexVector<gfx::Lines> lines;
|
||||
using LineIndexVector = gfx::IndexVector<gfx::Lines>;
|
||||
const std::shared_ptr<LineIndexVector> sharedLines = std::make_shared<LineIndexVector>();
|
||||
LineIndexVector& lines = *sharedLines;
|
||||
#if MLN_LEGACY_RENDERER
|
||||
std::optional<gfx::IndexBuffer> indexBuffer;
|
||||
#endif // MLN_LEGACY_RENDERER
|
||||
};
|
||||
std::unique_ptr<CollisionBoxBuffer> iconCollisionBox;
|
||||
std::unique_ptr<CollisionBoxBuffer> textCollisionBox;
|
||||
@@ -205,8 +221,12 @@ public:
|
||||
}
|
||||
|
||||
struct CollisionCircleBuffer : public CollisionBuffer {
|
||||
gfx::IndexVector<gfx::Triangles> triangles;
|
||||
using TriangleIndexVector = gfx::IndexVector<gfx::Triangles>;
|
||||
const std::shared_ptr<TriangleIndexVector> sharedTriangles = std::make_shared<TriangleIndexVector>();
|
||||
TriangleIndexVector& triangles = *sharedTriangles;
|
||||
#if MLN_LEGACY_RENDERER
|
||||
std::optional<gfx::IndexBuffer> indexBuffer;
|
||||
#endif // MLN_LEGACY_RENDERER
|
||||
};
|
||||
std::unique_ptr<CollisionCircleBuffer> iconCollisionCircle;
|
||||
std::unique_ptr<CollisionCircleBuffer> textCollisionCircle;
|
||||
|
||||
@@ -81,7 +81,7 @@ void BackgroundLayerTweaker::execute(LayerGroupBase& layerGroup, const RenderTre
|
||||
}
|
||||
layerGroup.setEnabled(true);
|
||||
|
||||
int32_t samplerLocation = -1;
|
||||
std::optional<uint32_t> samplerLocation{};
|
||||
layerGroup.visitDrawables([&](gfx::Drawable& drawable) {
|
||||
assert(drawable.getTileID());
|
||||
|
||||
@@ -99,14 +99,16 @@ void BackgroundLayerTweaker::execute(LayerGroupBase& layerGroup, const RenderTre
|
||||
uniforms.createOrUpdate(BackgroundDrawableUBOName, &drawableUBO, context);
|
||||
|
||||
if (hasPattern) {
|
||||
if (samplerLocation < 0) {
|
||||
if (const auto index = shader->getSamplerLocation(texUniformName)) {
|
||||
samplerLocation = *index;
|
||||
if (!samplerLocation.has_value()) {
|
||||
samplerLocation = shader->getSamplerLocation(texUniformName);
|
||||
if (const auto& tex = parameters.patternAtlas.texture()) {
|
||||
tex->setSamplerConfiguration(
|
||||
{gfx::TextureFilterType::Linear, gfx::TextureWrapType::Clamp, gfx::TextureWrapType::Clamp});
|
||||
}
|
||||
}
|
||||
if (0 <= samplerLocation) {
|
||||
if (samplerLocation.has_value()) {
|
||||
if (const auto& tex = parameters.patternAtlas.texture()) {
|
||||
drawable.setTexture(tex, samplerLocation);
|
||||
drawable.setTexture(tex, samplerLocation.value());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -71,6 +71,7 @@ void CircleLayerTweaker::execute(LayerGroupBase& layerGroup,
|
||||
paintParamsUniformBuffer->update(&paintParamsUBO, sizeof(CirclePaintParamsUBO));
|
||||
}
|
||||
|
||||
const bool scaleWithMap = evaluated.get<CirclePitchScale>() == CirclePitchScaleType::Map;
|
||||
const bool pitchWithMap = evaluated.get<CirclePitchAlignment>() == AlignmentType::Map;
|
||||
|
||||
// Updated only with evaluated properties
|
||||
@@ -84,7 +85,7 @@ void CircleLayerTweaker::execute(LayerGroupBase& layerGroup,
|
||||
/* .stroke_width = */ evaluated.get<CircleStrokeWidth>().constantOr(CircleStrokeWidth::defaultValue()),
|
||||
/* .stroke_opacity = */
|
||||
evaluated.get<CircleStrokeOpacity>().constantOr(CircleStrokeOpacity::defaultValue()),
|
||||
/* .scale_with_map = */ evaluated.get<CirclePitchScale>() == CirclePitchScaleType::Map,
|
||||
/* .scale_with_map = */ scaleWithMap,
|
||||
/* .pitch_with_map = */ pitchWithMap,
|
||||
/* .padding = */ 0};
|
||||
evaluatedPropsUniformBuffer = context.createUniformBuffer(&evaluatedPropsUBO, sizeof(evaluatedPropsUBO));
|
||||
@@ -113,7 +114,7 @@ void CircleLayerTweaker::execute(LayerGroupBase& layerGroup,
|
||||
const CircleDrawableUBO drawableUBO = {
|
||||
/* .matrix = */ util::cast<float>(matrix),
|
||||
/* .extrude_scale = */
|
||||
pitchWithMap ? std::array<float, 2>{{pixelsToTileUnits}} : parameters.pixelsToGLUnits,
|
||||
pitchWithMap ? std::array<float, 2>{{pixelsToTileUnits, pixelsToTileUnits}} : parameters.pixelsToGLUnits,
|
||||
/* .padding = */ {0}};
|
||||
|
||||
uniforms.createOrUpdate(CircleDrawableUBOName, &drawableUBO, context);
|
||||
|
||||
94
src/mbgl/renderer/layers/collision_layer_tweaker.cpp
Normal file
94
src/mbgl/renderer/layers/collision_layer_tweaker.cpp
Normal file
@@ -0,0 +1,94 @@
|
||||
#include <mbgl/renderer/layers/collision_layer_tweaker.hpp>
|
||||
|
||||
#include <mbgl/gfx/context.hpp>
|
||||
#include <mbgl/gfx/drawable.hpp>
|
||||
#include <mbgl/gfx/renderable.hpp>
|
||||
#include <mbgl/gfx/renderer_backend.hpp>
|
||||
#include <mbgl/gfx/collision_drawable_data.hpp>
|
||||
#include <mbgl/renderer/layer_group.hpp>
|
||||
#include <mbgl/renderer/render_tree.hpp>
|
||||
#include <mbgl/renderer/paint_parameters.hpp>
|
||||
#include <mbgl/renderer/paint_property_binder.hpp>
|
||||
#include <mbgl/shaders/shader_program_base.hpp>
|
||||
#include <mbgl/style/layers/symbol_layer_properties.hpp>
|
||||
#include <mbgl/util/convert.hpp>
|
||||
#include <mbgl/util/std.hpp>
|
||||
#include <mbgl/util/logging.hpp>
|
||||
|
||||
namespace mbgl {
|
||||
|
||||
using namespace style;
|
||||
|
||||
namespace {
|
||||
|
||||
struct alignas(16) CollisionUBO {
|
||||
std::array<float, 4 * 4> matrix;
|
||||
std::array<float, 2> extrude_scale;
|
||||
float camera_to_center_distance;
|
||||
float overscale_factor;
|
||||
};
|
||||
static_assert(sizeof(CollisionUBO) == 20 * 4);
|
||||
|
||||
} // namespace
|
||||
|
||||
void CollisionLayerTweaker::execute(LayerGroupBase& layerGroup,
|
||||
const RenderTree& renderTree,
|
||||
const PaintParameters& parameters) {
|
||||
if (layerGroup.empty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto& context = parameters.context;
|
||||
const auto& state = parameters.state;
|
||||
|
||||
#if !defined(NDEBUG)
|
||||
const auto label = layerGroup.getName() + "-update-uniforms";
|
||||
const auto debugGroup = parameters.encoder->createDebugGroup(label.c_str());
|
||||
#endif
|
||||
|
||||
layerGroup.visitDrawables([&](gfx::Drawable& drawable) {
|
||||
if (!drawable.getTileID() || !drawable.getData()) {
|
||||
return;
|
||||
}
|
||||
|
||||
const auto tileID = drawable.getTileID()->toUnwrapped();
|
||||
const auto& data = static_cast<gfx::CollisionDrawableData&>(*drawable.getData());
|
||||
|
||||
// matrix
|
||||
const auto translate = data.translate;
|
||||
const auto anchor = data.translateAnchor;
|
||||
constexpr bool nearClipped = false;
|
||||
constexpr bool inViewportPixelUnits = false;
|
||||
const auto matrix = getTileMatrix(
|
||||
tileID, renderTree, state, translate, anchor, nearClipped, inViewportPixelUnits);
|
||||
|
||||
// extrude scale
|
||||
const auto pixelRatio = tileID.pixelsToTileUnits(1.0f, static_cast<float>(parameters.state.getZoom()));
|
||||
const auto scale = static_cast<float>(
|
||||
std::pow(2, parameters.state.getZoom() - drawable.getTileID()->overscaledZ));
|
||||
const std::array<float, 2> extrudeScale = {{parameters.pixelsToGLUnits[0] / (pixelRatio * scale),
|
||||
parameters.pixelsToGLUnits[1] / (pixelRatio * scale)}};
|
||||
|
||||
const CollisionUBO drawableUBO = {
|
||||
/*.matrix=*/util::cast<float>(matrix),
|
||||
/*.extrude_scale*/ extrudeScale,
|
||||
/*.camera_to_center_distance*/ parameters.state.getCameraToCenterDistance(),
|
||||
/*.overscale_factor*/ static_cast<float>(drawable.getTileID()->overscaleFactor())};
|
||||
|
||||
const auto shader = drawable.getShader();
|
||||
const auto& shaderUniforms = shader->getUniformBlocks();
|
||||
auto& uniforms = drawable.mutableUniformBuffers();
|
||||
|
||||
if (shaderUniforms.get(std::string(CollisionBoxUBOName))) {
|
||||
// collision box
|
||||
uniforms.createOrUpdate(CollisionBoxUBOName, &drawableUBO, context);
|
||||
} else if (shaderUniforms.get(std::string(CollisionCircleUBOName))) {
|
||||
// collision circle
|
||||
uniforms.createOrUpdate(CollisionCircleUBOName, &drawableUBO, context);
|
||||
} else {
|
||||
Log::Error(Event::General, "Collision shader uniform name unknown.");
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
} // namespace mbgl
|
||||
26
src/mbgl/renderer/layers/collision_layer_tweaker.hpp
Normal file
26
src/mbgl/renderer/layers/collision_layer_tweaker.hpp
Normal file
@@ -0,0 +1,26 @@
|
||||
#pragma once
|
||||
|
||||
#include <mbgl/renderer/layer_tweaker.hpp>
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace mbgl {
|
||||
|
||||
/**
|
||||
Collision drawables' layer tweaker
|
||||
*/
|
||||
class CollisionLayerTweaker : public LayerTweaker {
|
||||
public:
|
||||
CollisionLayerTweaker(Immutable<style::LayerProperties> properties)
|
||||
: LayerTweaker(properties){};
|
||||
|
||||
public:
|
||||
~CollisionLayerTweaker() override = default;
|
||||
|
||||
void execute(LayerGroupBase&, const RenderTree&, const PaintParameters&) override;
|
||||
|
||||
static constexpr std::string_view CollisionCircleUBOName = "CollisionCircleUBO";
|
||||
static constexpr std::string_view CollisionBoxUBOName = "CollisionBoxUBO";
|
||||
};
|
||||
|
||||
} // namespace mbgl
|
||||
@@ -34,7 +34,7 @@ static_assert(sizeof(FillExtrusionDrawableUBO) == 7 * 16);
|
||||
|
||||
/// Evaluated properties that do not depend on the tile
|
||||
struct alignas(16) FillExtrusionDrawablePropsUBO {
|
||||
/* 0 */ std::array<float, 4> color;
|
||||
/* 0 */ Color color;
|
||||
/* 16 */ std::array<float, 3> light_color;
|
||||
/* 28 */ float pad1;
|
||||
/* 32 */ std::array<float, 3> light_position;
|
||||
@@ -82,7 +82,7 @@ void FillExtrusionLayerTweaker::execute(LayerGroupBase& layerGroup,
|
||||
// UBO depends on more than just evaluated properties, so we need to update every time,
|
||||
// but the resulting buffer can be shared across all the drawables from the layer.
|
||||
const FillExtrusionDrawablePropsUBO paramsUBO = {
|
||||
/* .color = */ gfx::VertexAttribute::colorAttrRGBA(constOrDefault<FillExtrusionColor>(evaluated)),
|
||||
/* .color = */ constOrDefault<FillExtrusionColor>(evaluated),
|
||||
/* .light_color = */ FillExtrusionProgram::lightColor(parameters.evaluatedLight),
|
||||
/* .pad = */ 0,
|
||||
/* .light_position = */ FillExtrusionProgram::lightPosition(parameters.evaluatedLight, state),
|
||||
|
||||
@@ -448,7 +448,11 @@ void RenderFillExtrusionLayer::update(gfx::ShaderRegistry& shaders,
|
||||
tweaker = std::make_shared<gfx::DrawableAtlasesTweaker>(atlases,
|
||||
std::string(),
|
||||
std::string(IconTextureName),
|
||||
/*isText=*/false);
|
||||
/*isText=*/false,
|
||||
false,
|
||||
style::AlignmentType::Auto,
|
||||
false,
|
||||
false);
|
||||
if (depthBuilder) {
|
||||
depthBuilder->addTweaker(tweaker);
|
||||
}
|
||||
|
||||
@@ -339,7 +339,7 @@ void RenderFillLayer::update(gfx::ShaderRegistry& shaders,
|
||||
std::unique_ptr<gfx::DrawableBuilder> outlinePatternBuilder;
|
||||
|
||||
const auto layerPrefix = getID() + "/";
|
||||
const auto renderPass = static_cast<RenderPass>(evaluatedProperties->renderPasses);
|
||||
const auto renderPass = RenderPass::Translucent;
|
||||
|
||||
const auto finish = [&](gfx::DrawableBuilder& builder,
|
||||
const OverscaledTileID& tileID,
|
||||
@@ -462,7 +462,7 @@ void RenderFillLayer::update(gfx::ShaderRegistry& shaders,
|
||||
: gfx::DepthMaskType::ReadOnly);
|
||||
builder->setColorMode(renderPass == RenderPass::Translucent ? gfx::ColorMode::alphaBlended()
|
||||
: gfx::ColorMode::unblended());
|
||||
builder->setSubLayerIndex(0);
|
||||
builder->setSubLayerIndex(1);
|
||||
builder->setRenderPass(renderPass);
|
||||
fillBuilder = std::move(builder);
|
||||
}
|
||||
@@ -549,7 +549,11 @@ void RenderFillLayer::update(gfx::ShaderRegistry& shaders,
|
||||
auto tweaker = std::make_shared<gfx::DrawableAtlasesTweaker>(atlases,
|
||||
/*glyphName=*/std::string(),
|
||||
std::string(IconTextureName),
|
||||
/*isText=*/false);
|
||||
/*isText=*/false,
|
||||
false,
|
||||
style::AlignmentType::Auto,
|
||||
false,
|
||||
false);
|
||||
if (patternBuilder) {
|
||||
patternBuilder->addTweaker(tweaker);
|
||||
}
|
||||
|
||||
@@ -390,10 +390,10 @@ void RenderHeatmapLayer::update(gfx::ShaderRegistry& shaders,
|
||||
|
||||
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->setEnableDepth(false);
|
||||
heatmapBuilder->setColorMode(gfx::ColorMode::additive());
|
||||
heatmapBuilder->setCullFaceMode(gfx::CullFaceMode::disabled());
|
||||
heatmapBuilder->setEnableStencil(false);
|
||||
heatmapBuilder->setRenderPass(renderPass);
|
||||
heatmapBuilder->setVertexAttributes(std::move(heatmapVertexAttrs));
|
||||
heatmapBuilder->setRawVertices({}, vertexCount, gfx::AttributeDataType::Short2);
|
||||
@@ -450,10 +450,10 @@ void RenderHeatmapLayer::update(gfx::ShaderRegistry& shaders,
|
||||
|
||||
heatmapTextureBuilder = context.createDrawableBuilder("heatmapTexture");
|
||||
heatmapTextureBuilder->setShader(heatmapTextureShader);
|
||||
heatmapTextureBuilder->setDepthType((renderPass == RenderPass::Opaque) ? gfx::DepthMaskType::ReadWrite
|
||||
: gfx::DepthMaskType::ReadOnly);
|
||||
heatmapTextureBuilder->setEnableDepth(false);
|
||||
heatmapTextureBuilder->setColorMode(gfx::ColorMode::alphaBlended());
|
||||
heatmapTextureBuilder->setCullFaceMode(gfx::CullFaceMode::disabled());
|
||||
heatmapTextureBuilder->setEnableStencil(false);
|
||||
heatmapTextureBuilder->setRenderPass(renderPass);
|
||||
heatmapTextureBuilder->setVertexAttributes(std::move(textureVertexAttrs));
|
||||
heatmapTextureBuilder->setRawVertices({}, textureVertexCount, gfx::AttributeDataType::Short2);
|
||||
|
||||
@@ -387,13 +387,13 @@ void RenderHillshadeLayer::update(gfx::ShaderRegistry& shaders,
|
||||
offsetof(HillshadeLayoutVertex, a2),
|
||||
0,
|
||||
sizeof(HillshadeLayoutVertex),
|
||||
gfx::AttributeDataType::Short4);
|
||||
gfx::AttributeDataType::Short2);
|
||||
}
|
||||
|
||||
hillshadePrepareBuilder = context.createDrawableBuilder("hillshadePrepare");
|
||||
hillshadePrepareBuilder->setShader(hillshadePrepareShader);
|
||||
hillshadePrepareBuilder->setDepthType(gfx::DepthMaskType::ReadOnly);
|
||||
hillshadePrepareBuilder->setColorMode(gfx::ColorMode::alphaBlended());
|
||||
hillshadePrepareBuilder->setColorMode(gfx::ColorMode::unblended());
|
||||
hillshadePrepareBuilder->setCullFaceMode(gfx::CullFaceMode::disabled());
|
||||
|
||||
hillshadePrepareBuilder->setRenderPass(renderPass);
|
||||
@@ -448,7 +448,7 @@ void RenderHillshadeLayer::update(gfx::ShaderRegistry& shaders,
|
||||
offsetof(HillshadeLayoutVertex, a2),
|
||||
0,
|
||||
sizeof(HillshadeLayoutVertex),
|
||||
gfx::AttributeDataType::Short4);
|
||||
gfx::AttributeDataType::Short2);
|
||||
}
|
||||
|
||||
hillshadeBuilder = context.createDrawableBuilder("hillshade");
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
|
||||
#if MLN_DRAWABLE_RENDERER
|
||||
#include <mbgl/gfx/drawable_builder.hpp>
|
||||
#include <mbgl/gfx/drawable_atlases_tweaker.hpp>
|
||||
#include <mbgl/renderer/layer_group.hpp>
|
||||
#include <mbgl/renderer/layers/line_layer_tweaker.hpp>
|
||||
#include <mbgl/gfx/line_drawable_data.hpp>
|
||||
@@ -406,6 +407,8 @@ struct alignas(16) LinePatternTilePropertiesUBO {
|
||||
static_assert(sizeof(LinePatternTilePropertiesUBO) % 16 == 0);
|
||||
static constexpr std::string_view LinePatternTilePropertiesUBOName = "LinePatternTilePropertiesUBO";
|
||||
|
||||
static constexpr auto LineImageUniformName = "u_image";
|
||||
|
||||
void RenderLineLayer::update(gfx::ShaderRegistry& shaders,
|
||||
gfx::Context& context,
|
||||
const TransformState& state,
|
||||
@@ -643,24 +646,34 @@ void RenderLineLayer::update(gfx::ShaderRegistry& shaders,
|
||||
|
||||
// texture
|
||||
if (const auto& atlases = tile.getAtlasTextures(); atlases && atlases->icon) {
|
||||
if (const auto samplerLocation = builder->getShader()->getSamplerLocation("u_image")) {
|
||||
builder->setTexture(atlases->icon, samplerLocation.value());
|
||||
if (!iconTweaker) {
|
||||
iconTweaker = std::make_shared<gfx::DrawableAtlasesTweaker>(
|
||||
atlases,
|
||||
"",
|
||||
LineImageUniformName,
|
||||
/*isText*/ false,
|
||||
/*sdfIcons*/ true, // to force linear filter
|
||||
/*rotationAlignment_*/ AlignmentType::Auto,
|
||||
/*iconScaled*/ false,
|
||||
/*textSizeIsZoomConstant_*/ false);
|
||||
}
|
||||
|
||||
// segments
|
||||
setSegments(builder, bucket);
|
||||
builder->addTweaker(iconTweaker);
|
||||
|
||||
// finish
|
||||
builder->flush();
|
||||
for (auto& drawable : builder->clearDrawables()) {
|
||||
drawable->setTileID(tileID);
|
||||
drawable->mutableUniformBuffers().createOrUpdate(
|
||||
LinePatternInterpolationUBOName, &linePatternInterpolationUBO, context);
|
||||
drawable->mutableUniformBuffers().createOrUpdate(
|
||||
LinePatternTilePropertiesUBOName, &linePatternTilePropertiesUBO, context);
|
||||
// segments
|
||||
setSegments(builder, bucket);
|
||||
|
||||
tileLayerGroup->addDrawable(renderPass, tileID, std::move(drawable));
|
||||
++stats.drawablesAdded;
|
||||
}
|
||||
// finish
|
||||
builder->flush();
|
||||
for (auto& drawable : builder->clearDrawables()) {
|
||||
drawable->setTileID(tileID);
|
||||
drawable->mutableUniformBuffers().createOrUpdate(
|
||||
LinePatternInterpolationUBOName, &linePatternInterpolationUBO, context);
|
||||
drawable->mutableUniformBuffers().createOrUpdate(
|
||||
LinePatternTilePropertiesUBOName, &linePatternTilePropertiesUBO, context);
|
||||
|
||||
tileLayerGroup->addDrawable(renderPass, tileID, std::move(drawable));
|
||||
++stats.drawablesAdded;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -678,7 +691,7 @@ void RenderLineLayer::update(gfx::ShaderRegistry& shaders,
|
||||
addAttributes(*builder, bucket, std::move(vertexAttrs));
|
||||
|
||||
// texture
|
||||
if (const auto samplerLocation = builder->getShader()->getSamplerLocation("u_image")) {
|
||||
if (const auto samplerLocation = builder->getShader()->getSamplerLocation(LineImageUniformName)) {
|
||||
if (!colorRampTexture2D && colorRamp->valid()) {
|
||||
// create texture. to be reused for all the tiles of the layer
|
||||
colorRampTexture2D = context.createTexture2D();
|
||||
|
||||
@@ -88,6 +88,8 @@ private:
|
||||
gfx::ShaderGroupPtr lineGradientShaderGroup;
|
||||
gfx::ShaderGroupPtr lineSDFShaderGroup;
|
||||
gfx::ShaderGroupPtr linePatternShaderGroup;
|
||||
|
||||
gfx::DrawableTweakerPtr iconTweaker;
|
||||
#endif
|
||||
};
|
||||
|
||||
|
||||
@@ -256,11 +256,11 @@ void RenderRasterLayer::update(gfx::ShaderRegistry& shaders,
|
||||
rasterShader = context.getGenericShader(shaders, "RasterShader");
|
||||
}
|
||||
|
||||
if (!staticDataSharedVertices) {
|
||||
staticDataSharedVertices = std::make_shared<RasterVertexVector>(RenderStaticData::rasterVertices());
|
||||
if (!staticDataVertices) {
|
||||
staticDataVertices = std::make_shared<RasterVertexVector>(RenderStaticData::rasterVertices());
|
||||
}
|
||||
if (!staticDataIndices) {
|
||||
staticDataIndices = std::make_shared<RasterIndexVector>(RenderStaticData::quadTriangleIndices());
|
||||
staticDataIndices = std::make_shared<TriangleIndexVector>(RenderStaticData::quadTriangleIndices());
|
||||
}
|
||||
if (!staticDataSegments) {
|
||||
staticDataSegments = std::make_shared<RasterSegmentVector>(RenderStaticData::rasterSegments());
|
||||
@@ -306,99 +306,9 @@ void RenderRasterLayer::update(gfx::ShaderRegistry& shaders,
|
||||
}
|
||||
};
|
||||
|
||||
auto buildTileDrawables = [&setTextures](std::unique_ptr<gfx::DrawableBuilder>& builder,
|
||||
const RasterBucket& bucket) {
|
||||
auto buildRenderData = [](const TileMask& mask,
|
||||
std::vector<std::array<int16_t, 2>>& vertices,
|
||||
std::vector<std::array<int16_t, 2>>& attributes,
|
||||
std::vector<uint16_t>& indices,
|
||||
std::vector<SegmentBase>& segments) {
|
||||
constexpr const uint16_t vertexLength = 4;
|
||||
|
||||
if (vertices.empty()) {
|
||||
vertices.reserve(mask.size() * vertexLength);
|
||||
attributes.reserve(mask.size() * vertexLength);
|
||||
indices.reserve(mask.size() * 6);
|
||||
segments.reserve(mask.size());
|
||||
}
|
||||
// Create the vertex buffer for the specified tile mask.
|
||||
for (const auto& id : mask) {
|
||||
// Create a quad for every masked tile.
|
||||
const int32_t vertexExtent = util::EXTENT >> id.z;
|
||||
|
||||
const Point<int16_t> tlVertex = {static_cast<int16_t>(id.x * vertexExtent),
|
||||
static_cast<int16_t>(id.y * vertexExtent)};
|
||||
const Point<int16_t> brVertex = {static_cast<int16_t>(tlVertex.x + vertexExtent),
|
||||
static_cast<int16_t>(tlVertex.y + vertexExtent)};
|
||||
|
||||
if (segments.empty() ||
|
||||
(segments.back().vertexLength + vertexLength > std::numeric_limits<uint16_t>::max())) {
|
||||
// Move to a new segments because the old one can't hold the geometry.
|
||||
segments.emplace_back(vertices.size(), indices.size());
|
||||
}
|
||||
|
||||
vertices.emplace_back(std::array<int16_t, 2>{{tlVertex.x, tlVertex.y}});
|
||||
attributes.emplace_back(std::array<int16_t, 2>{{tlVertex.x, tlVertex.y}});
|
||||
|
||||
vertices.emplace_back(std::array<int16_t, 2>{{brVertex.x, tlVertex.y}});
|
||||
attributes.emplace_back(std::array<int16_t, 2>{{brVertex.x, tlVertex.y}});
|
||||
|
||||
vertices.emplace_back(std::array<int16_t, 2>{{tlVertex.x, brVertex.y}});
|
||||
attributes.emplace_back(std::array<int16_t, 2>{{tlVertex.x, brVertex.y}});
|
||||
|
||||
vertices.emplace_back(std::array<int16_t, 2>{{brVertex.x, brVertex.y}});
|
||||
attributes.emplace_back(std::array<int16_t, 2>{{brVertex.x, brVertex.y}});
|
||||
|
||||
auto& segment = segments.back();
|
||||
assert(segment.vertexLength <= std::numeric_limits<uint16_t>::max());
|
||||
const auto offset = static_cast<uint16_t>(segment.vertexLength);
|
||||
|
||||
// 0, 1, 2
|
||||
// 1, 2, 3
|
||||
indices.insert(indices.end(),
|
||||
{offset,
|
||||
static_cast<uint16_t>(offset + 1u),
|
||||
static_cast<uint16_t>(offset + 2u),
|
||||
static_cast<uint16_t>(offset + 1u),
|
||||
static_cast<uint16_t>(offset + 2u),
|
||||
static_cast<uint16_t>(offset + 3u)});
|
||||
|
||||
segment.vertexLength += vertexLength;
|
||||
segment.indexLength += 6;
|
||||
}
|
||||
};
|
||||
|
||||
std::vector<std::array<int16_t, 2>> vertices, attributes;
|
||||
std::vector<uint16_t> indices;
|
||||
std::vector<SegmentBase> segments;
|
||||
buildRenderData(bucket.mask, vertices, attributes, indices, segments);
|
||||
builder->addVertices(vertices, 0, vertices.size());
|
||||
builder->setSegments(gfx::Triangles(), indices, segments.data(), segments.size());
|
||||
|
||||
// attributes
|
||||
{
|
||||
gfx::VertexAttributeArray vertexAttrs;
|
||||
if (const auto& attr = vertexAttrs.getOrAdd(TexturePosAttribName)) {
|
||||
attr->reserve(attributes.size());
|
||||
std::size_t index{0};
|
||||
for (const auto& a : attributes) {
|
||||
attr->set<gfx::VertexAttribute::int2>(index++, {a[0], a[1]});
|
||||
}
|
||||
}
|
||||
builder->setVertexAttributes(std::move(vertexAttrs));
|
||||
}
|
||||
|
||||
// textures
|
||||
setTextures(builder, bucket);
|
||||
};
|
||||
|
||||
auto updateTileDrawables = [&](std::unique_ptr<gfx::DrawableBuilder>& builder,
|
||||
auto* tileLayerGroup,
|
||||
const auto& tileID,
|
||||
const RasterBucket& bucket) {
|
||||
// Set up tile drawable
|
||||
auto vertices = staticDataSharedVertices;
|
||||
auto indices = staticDataIndices;
|
||||
auto buildVertexData = [this](std::unique_ptr<gfx::DrawableBuilder>& builder, const RasterBucket& bucket) {
|
||||
RasterVertexVectorPtr vertices = staticDataVertices;
|
||||
TriangleIndexVectorPtr indices = staticDataIndices;
|
||||
const RasterSegmentVector* segments = staticDataSegments.get();
|
||||
|
||||
if (!bucket.vertices.empty() && !bucket.indices.empty() && !bucket.segments.empty()) {
|
||||
@@ -407,75 +317,52 @@ void RenderRasterLayer::update(gfx::ShaderRegistry& shaders,
|
||||
segments = &bucket.segments;
|
||||
}
|
||||
|
||||
// attributes
|
||||
gfx::VertexAttributeArray vertexAttrs;
|
||||
|
||||
if (const auto& attr = vertexAttrs.add(PosAttribName)) {
|
||||
attr->setSharedRawData(vertices,
|
||||
offsetof(RasterLayoutVertex, a1),
|
||||
0,
|
||||
sizeof(RasterLayoutVertex),
|
||||
gfx::AttributeDataType::Short2);
|
||||
}
|
||||
if (const auto& attr = vertexAttrs.getOrAdd(TexturePosAttribName)) {
|
||||
attr->setSharedRawData(vertices,
|
||||
offsetof(RasterLayoutVertex, a2),
|
||||
0,
|
||||
sizeof(RasterLayoutVertex),
|
||||
gfx::AttributeDataType::Short4);
|
||||
}
|
||||
|
||||
tileLayerGroup->visitDrawables(renderPass, tileID, [&](gfx::Drawable& drawable) {
|
||||
drawable.setVertexAttributes(std::move(vertexAttrs));
|
||||
drawable.setVertices({}, vertices->elements(), gfx::AttributeDataType::Short2);
|
||||
|
||||
std::vector<std::unique_ptr<gfx::Drawable::DrawSegment>> drawSegments;
|
||||
for (std::size_t i = 0; i < segments->size(); ++i) {
|
||||
const auto& seg = segments->data()[i];
|
||||
auto segCopy = SegmentBase{
|
||||
// no copy constructor
|
||||
seg.vertexOffset,
|
||||
seg.indexOffset,
|
||||
seg.vertexLength,
|
||||
seg.indexLength,
|
||||
seg.sortKey,
|
||||
};
|
||||
drawSegments.emplace_back(builder->createSegment(gfx::Triangles(), std::move(segCopy)));
|
||||
}
|
||||
drawable.setIndexData(indices->vector(), std::move(drawSegments));
|
||||
});
|
||||
};
|
||||
|
||||
auto buildImageDrawables = [&setTextures](std::unique_ptr<gfx::DrawableBuilder>& builder,
|
||||
const RasterBucket& bucket) {
|
||||
// attributes
|
||||
{
|
||||
gfx::VertexAttributeArray vertexAttrs;
|
||||
|
||||
if (auto& attr = vertexAttrs.add(PosAttribName)) {
|
||||
attr->setSharedRawData(bucket.sharedVertices,
|
||||
attr->setSharedRawData(vertices,
|
||||
offsetof(RasterLayoutVertex, a1),
|
||||
/*vertexOffset=*/0,
|
||||
sizeof(RasterLayoutVertex),
|
||||
gfx::AttributeDataType::Short2);
|
||||
}
|
||||
|
||||
if (auto& attr = vertexAttrs.getOrAdd(TexturePosAttribName)) {
|
||||
std::size_t index{0};
|
||||
for (auto& v : bucket.vertices.vector()) {
|
||||
attr->set<gfx::VertexAttribute::int2>(index++, {v.a2[0], v.a2[1]});
|
||||
}
|
||||
if (auto& attr = vertexAttrs.add(TexturePosAttribName)) {
|
||||
attr->setSharedRawData(vertices,
|
||||
offsetof(RasterLayoutVertex, a2),
|
||||
/*vertexOffset=*/0,
|
||||
sizeof(RasterLayoutVertex),
|
||||
gfx::AttributeDataType::Short2);
|
||||
}
|
||||
builder->setVertexAttributes(std::move(vertexAttrs));
|
||||
}
|
||||
|
||||
builder->setRawVertices({}, bucket.vertices.elements(), gfx::AttributeDataType::Short2);
|
||||
builder->setSegments(gfx::Triangles(), bucket.sharedTriangles, bucket.segments.data(), bucket.segments.size());
|
||||
builder->setRawVertices({}, vertices->elements(), gfx::AttributeDataType::Short2);
|
||||
builder->setSegments(gfx::Triangles(), indices, segments->data(), segments->size());
|
||||
};
|
||||
|
||||
// textures
|
||||
auto buildDrawables = [&setTextures, &buildVertexData](std::unique_ptr<gfx::DrawableBuilder>& builder,
|
||||
const RasterBucket& bucket) {
|
||||
buildVertexData(builder, bucket);
|
||||
setTextures(builder, bucket);
|
||||
};
|
||||
|
||||
auto updateTileDrawables = [&](std::unique_ptr<gfx::DrawableBuilder>& builder,
|
||||
auto* tileLayerGroup,
|
||||
const auto& tileID,
|
||||
const RasterBucket& bucket) {
|
||||
// TODO: check for oportunity to skip
|
||||
|
||||
buildVertexData(builder, bucket);
|
||||
tileLayerGroup->visitDrawables(renderPass, tileID, [&](gfx::Drawable& drawable) {
|
||||
for (auto& tex : drawable.getTextures()) {
|
||||
builder->setTexture(tex.second, tex.first);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
if (imageData) {
|
||||
RasterBucket& bucket = *imageData->bucket;
|
||||
if (!bucket.vertices.empty()) {
|
||||
@@ -490,7 +377,7 @@ void RenderRasterLayer::update(gfx::ShaderRegistry& shaders,
|
||||
|
||||
auto builder = createBuilder();
|
||||
for (const auto& matrix_ : imageData->matrices) {
|
||||
buildImageDrawables(builder, bucket);
|
||||
buildDrawables(builder, bucket);
|
||||
|
||||
// finish
|
||||
builder->flush();
|
||||
@@ -538,21 +425,23 @@ void RenderRasterLayer::update(gfx::ShaderRegistry& shaders,
|
||||
setRenderTileBucketID(tileID, bucket.getID());
|
||||
|
||||
if (tileLayerGroup->getDrawableCount(renderPass, tileID) > 0) {
|
||||
// re-create drawable geometry and pass texture
|
||||
updateTileDrawables(builder, tileLayerGroup, tileID, bucket);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (bucket.image) {
|
||||
buildTileDrawables(builder, bucket);
|
||||
|
||||
// finish
|
||||
builder->flush();
|
||||
for (auto& drawable : builder->clearDrawables()) {
|
||||
drawable->setTileID(tileID);
|
||||
tileLayerGroup->addDrawable(renderPass, tileID, std::move(drawable));
|
||||
++stats.drawablesAdded;
|
||||
}
|
||||
// erase current drawable
|
||||
removeTile(renderPass, tileID);
|
||||
} else if (bucket.image) {
|
||||
// build new drawable for this tile
|
||||
buildDrawables(builder, bucket);
|
||||
};
|
||||
|
||||
// finish
|
||||
builder->flush();
|
||||
for (auto& drawable : builder->clearDrawables()) {
|
||||
drawable->setTileID(tileID);
|
||||
tileLayerGroup->addDrawable(renderPass, tileID, std::move(drawable));
|
||||
++stats.drawablesAdded;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -55,12 +55,15 @@ private:
|
||||
LayerGroupPtr imageLayerGroup;
|
||||
|
||||
using RasterVertexVector = gfx::VertexVector<RasterLayoutVertex>;
|
||||
std::shared_ptr<RasterVertexVector> staticDataSharedVertices;
|
||||
using RasterVertexVectorPtr = std::shared_ptr<RasterVertexVector>;
|
||||
RasterVertexVectorPtr staticDataVertices;
|
||||
|
||||
using RasterIndexVector = gfx::IndexVector<gfx::Triangles>;
|
||||
std::shared_ptr<RasterIndexVector> staticDataIndices;
|
||||
using TriangleIndexVector = gfx::IndexVector<gfx::Triangles>;
|
||||
using TriangleIndexVectorPtr = std::shared_ptr<TriangleIndexVector>;
|
||||
TriangleIndexVectorPtr staticDataIndices;
|
||||
|
||||
using RasterSegmentVector = SegmentVector<RasterAttributes>;
|
||||
using RasterSegmentVectorPtr = std::shared_ptr<RasterSegmentVector>;
|
||||
std::shared_ptr<RasterSegmentVector> staticDataSegments;
|
||||
#endif
|
||||
};
|
||||
|
||||
@@ -26,9 +26,12 @@
|
||||
#include <mbgl/gfx/drawable_atlases_tweaker.hpp>
|
||||
#include <mbgl/gfx/drawable_builder.hpp>
|
||||
#include <mbgl/gfx/symbol_drawable_data.hpp>
|
||||
#include <mbgl/gfx/collision_drawable_data.hpp>
|
||||
#include <mbgl/renderer/layer_group.hpp>
|
||||
#include <mbgl/renderer/layers/symbol_layer_tweaker.hpp>
|
||||
#include <mbgl/shaders/shader_program_base.hpp>
|
||||
#include <mbgl/gfx/collision_drawable_data.hpp>
|
||||
#include <mbgl/renderer/layers/collision_layer_tweaker.hpp>
|
||||
#endif // MLN_DRAWABLE_RENDERER
|
||||
|
||||
#include <cmath>
|
||||
@@ -45,6 +48,8 @@ constexpr std::string_view SymbolIconShaderName = "SymbolIconShader";
|
||||
constexpr std::string_view SymbolSDFIconShaderName = "SymbolSDFTextShader";
|
||||
constexpr std::string_view SymbolSDFTextShaderName = "SymbolSDFIconShader";
|
||||
constexpr std::string_view SymbolTextAndIconShaderName = "SymbolTextAndIconShader";
|
||||
constexpr std::string_view CollisionBoxShaderName = "CollisionBoxShader";
|
||||
constexpr std::string_view CollisionCircleShaderName = "CollisionCircleShader";
|
||||
|
||||
#endif // MLN_DRAWABLE_RENDERER
|
||||
|
||||
@@ -839,8 +844,113 @@ void updateTileDrawable(gfx::Drawable& drawable,
|
||||
drawable.setVertexAttributes(std::move(attribs));
|
||||
}
|
||||
|
||||
constexpr auto CollisionPosAttribName = "a_pos";
|
||||
constexpr auto CollisionAnchorPosAttribName = "a_anchor_pos";
|
||||
constexpr auto CollisionExtrudeAttribName = "a_extrude";
|
||||
constexpr auto CollisionPlacedAttribName = "a_placed";
|
||||
constexpr auto CollisionShiftAttribName = "a_shift";
|
||||
|
||||
gfx::VertexAttributeArray getCollisionVertexAttributes(const SymbolBucket::CollisionBuffer& buffer, bool staticCopy) {
|
||||
gfx::VertexAttributeArray vertexAttrs;
|
||||
|
||||
if (staticCopy) {
|
||||
if (auto& attr = vertexAttrs.getOrAdd(CollisionPosAttribName)) {
|
||||
std::size_t index{0};
|
||||
for (auto& v : buffer.vertices().vector()) {
|
||||
attr->set<gfx::VertexAttribute::int2>(index++, {v.a1[0], v.a1[1]});
|
||||
}
|
||||
}
|
||||
if (auto& attr = vertexAttrs.getOrAdd(CollisionAnchorPosAttribName)) {
|
||||
std::size_t index{0};
|
||||
for (auto& v : buffer.vertices().vector()) {
|
||||
attr->set<gfx::VertexAttribute::int2>(index++, {v.a2[0], v.a2[1]});
|
||||
}
|
||||
}
|
||||
if (auto& attr = vertexAttrs.getOrAdd(CollisionExtrudeAttribName)) {
|
||||
std::size_t index{0};
|
||||
for (auto& v : buffer.vertices().vector()) {
|
||||
attr->set<gfx::VertexAttribute::int2>(index++, {v.a3[0], v.a3[1]});
|
||||
}
|
||||
}
|
||||
|
||||
if (auto& attr = vertexAttrs.getOrAdd(CollisionPlacedAttribName)) {
|
||||
std::size_t index{0};
|
||||
for (auto& v : buffer.dynamicVertices().vector()) {
|
||||
attr->set<gfx::VertexAttribute::int2>(index++, {v.a1[0], v.a1[1]});
|
||||
}
|
||||
}
|
||||
if (auto& attr = vertexAttrs.getOrAdd(CollisionShiftAttribName)) {
|
||||
std::size_t index{0};
|
||||
for (auto& v : buffer.dynamicVertices().vector()) {
|
||||
attr->set<gfx::VertexAttribute::float2>(index++, {v.a2[0], v.a2[1]});
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (const auto& attr = vertexAttrs.getOrAdd(CollisionPosAttribName)) {
|
||||
attr->setSharedRawData(buffer.sharedVertices,
|
||||
offsetof(CollisionBoxVertex, a1),
|
||||
/*vertexOffset=*/0,
|
||||
sizeof(CollisionBoxVertex),
|
||||
gfx::AttributeDataType::Short2);
|
||||
}
|
||||
if (const auto& attr = vertexAttrs.getOrAdd(CollisionAnchorPosAttribName)) {
|
||||
attr->setSharedRawData(buffer.sharedVertices,
|
||||
offsetof(CollisionBoxVertex, a2),
|
||||
/*vertexOffset=*/0,
|
||||
sizeof(CollisionBoxVertex),
|
||||
gfx::AttributeDataType::Short2);
|
||||
}
|
||||
if (const auto& attr = vertexAttrs.getOrAdd(CollisionExtrudeAttribName)) {
|
||||
attr->setSharedRawData(buffer.sharedVertices,
|
||||
offsetof(CollisionBoxVertex, a3),
|
||||
/*vertexOffset=*/0,
|
||||
sizeof(CollisionBoxVertex),
|
||||
gfx::AttributeDataType::Short2);
|
||||
}
|
||||
|
||||
using DynamicVertex = gfx::Vertex<CollisionBoxDynamicAttributes>;
|
||||
|
||||
if (const auto& attr = vertexAttrs.getOrAdd(CollisionPlacedAttribName)) {
|
||||
attr->setSharedRawData(buffer.sharedDynamicVertices,
|
||||
offsetof(DynamicVertex, a1),
|
||||
/*vertexOffset=*/0,
|
||||
sizeof(DynamicVertex),
|
||||
gfx::AttributeDataType::UByte2);
|
||||
}
|
||||
if (const auto& attr = vertexAttrs.getOrAdd(CollisionShiftAttribName)) {
|
||||
attr->setSharedRawData(buffer.sharedDynamicVertices,
|
||||
offsetof(DynamicVertex, a2),
|
||||
/*vertexOffset=*/0,
|
||||
sizeof(DynamicVertex),
|
||||
gfx::AttributeDataType::Float2);
|
||||
}
|
||||
}
|
||||
|
||||
return vertexAttrs;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
void RenderSymbolLayer::removeTile(RenderPass renderPass, const OverscaledTileID& tileID) {
|
||||
if (const auto tileGroup = static_cast<TileLayerGroup*>(layerGroup.get())) {
|
||||
stats.drawablesRemoved += tileGroup->removeDrawables(renderPass, tileID).size();
|
||||
}
|
||||
if (collisionTileLayerGroup) {
|
||||
stats.drawablesRemoved += collisionTileLayerGroup->removeDrawables(renderPass, tileID).size();
|
||||
}
|
||||
}
|
||||
|
||||
void RenderSymbolLayer::removeAllDrawables() {
|
||||
if (layerGroup) {
|
||||
stats.drawablesRemoved += layerGroup->getDrawableCount();
|
||||
layerGroup->clearDrawables();
|
||||
}
|
||||
if (collisionTileLayerGroup) {
|
||||
stats.drawablesRemoved += collisionTileLayerGroup->getDrawableCount();
|
||||
collisionTileLayerGroup->clearDrawables();
|
||||
}
|
||||
}
|
||||
|
||||
void RenderSymbolLayer::update(gfx::ShaderRegistry& shaders,
|
||||
gfx::Context& context,
|
||||
const TransformState& state,
|
||||
@@ -859,6 +969,14 @@ void RenderSymbolLayer::update(gfx::ShaderRegistry& shaders,
|
||||
}
|
||||
}
|
||||
|
||||
if (!collisionTileLayerGroup) {
|
||||
if ((collisionTileLayerGroup = context.createTileLayerGroup(
|
||||
layerIndex, /*initialCapacity=*/64, getID() + "-collision"))) {
|
||||
collisionTileLayerGroup->setLayerTweaker(std::make_shared<CollisionLayerTweaker>(evaluatedProperties));
|
||||
activateLayerGroup(collisionTileLayerGroup, true, changes);
|
||||
}
|
||||
}
|
||||
|
||||
if (!symbolIconGroup) {
|
||||
symbolIconGroup = shaders.getShaderGroup(std::string(SymbolIconShaderName));
|
||||
}
|
||||
@@ -871,7 +989,14 @@ void RenderSymbolLayer::update(gfx::ShaderRegistry& shaders,
|
||||
if (!symbolTextAndIconGroup) {
|
||||
symbolTextAndIconGroup = shaders.getShaderGroup(std::string(SymbolTextAndIconShaderName));
|
||||
}
|
||||
if (!collisionBoxGroup) {
|
||||
collisionBoxGroup = shaders.getShaderGroup(std::string(CollisionBoxShaderName));
|
||||
}
|
||||
if (!collisionCircleGroup) {
|
||||
collisionCircleGroup = shaders.getShaderGroup(std::string(CollisionCircleShaderName));
|
||||
}
|
||||
|
||||
// remove drawables that are dropped out of scope
|
||||
auto* tileLayerGroup = static_cast<TileLayerGroup*>(layerGroup.get());
|
||||
stats.drawablesRemoved += tileLayerGroup->removeDrawablesIf([&](gfx::Drawable& drawable) {
|
||||
// If the render pass has changed or the tile has dropped out of the cover set, remove it.
|
||||
@@ -881,6 +1006,14 @@ void RenderSymbolLayer::update(gfx::ShaderRegistry& shaders,
|
||||
}
|
||||
return false;
|
||||
});
|
||||
stats.drawablesRemoved += collisionTileLayerGroup->removeDrawablesIf([&](gfx::Drawable& drawable) {
|
||||
// If the render pass has changed or the tile has dropped out of the cover set, remove it.
|
||||
const auto& tileID = drawable.getTileID();
|
||||
if (drawable.getRenderPass() != passes || (tileID && !hasRenderTile(*tileID))) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
});
|
||||
|
||||
const bool sortFeaturesByKey = !impl_cast(baseImpl).layout.get<SymbolSortKey>().isUndefined();
|
||||
std::multiset<RenderableSegment> renderableSegments;
|
||||
@@ -888,6 +1021,16 @@ void RenderSymbolLayer::update(gfx::ShaderRegistry& shaders,
|
||||
|
||||
const auto currentZoom = static_cast<float>(state.getZoom());
|
||||
const auto layerPrefix = getID() + "/";
|
||||
const auto layerCollisionPrefix = getID() + "-collision/";
|
||||
|
||||
std::unique_ptr<gfx::DrawableBuilder> collisionBuilder = context.createDrawableBuilder(layerCollisionPrefix);
|
||||
collisionBuilder->setSubLayerIndex(0);
|
||||
collisionBuilder->setEnableStencil(false);
|
||||
collisionBuilder->setEnableDepth(false);
|
||||
collisionBuilder->setRenderPass(passes);
|
||||
collisionBuilder->setCullFaceMode(gfx::CullFaceMode::disabled());
|
||||
collisionBuilder->setColorMode(gfx::ColorMode::alphaBlended());
|
||||
collisionBuilder->setVertexAttrName(CollisionPosAttribName);
|
||||
|
||||
for (const RenderTile& tile : *renderTiles) {
|
||||
const auto& tileID = tile.getOverscaledTileID();
|
||||
@@ -911,6 +1054,77 @@ void RenderSymbolLayer::update(gfx::ShaderRegistry& shaders,
|
||||
assert(bucket.paintProperties.find(getID()) != bucket.paintProperties.end());
|
||||
const auto& bucketPaintProperties = bucket.paintProperties.at(getID());
|
||||
|
||||
auto addCollisionDrawables =
|
||||
[&collisionBuilder, this, &bucket, &renderData, &context, &layerCollisionPrefix, &tileID](
|
||||
const bool isText, const bool hasCollisionBox, const bool hasCollisionCircle) {
|
||||
if (!hasCollisionBox && !hasCollisionCircle) return;
|
||||
|
||||
const auto& layout = *bucket.layout;
|
||||
const auto& evaluated = getEvaluated<SymbolLayerProperties>(renderData.layerProperties);
|
||||
const auto values = isText ? textPropertyValues(evaluated, layout)
|
||||
: iconPropertyValues(evaluated, layout);
|
||||
const std::string suffix = isText ? "text/" : "icon/";
|
||||
|
||||
auto addVertices = [&collisionBuilder](const auto& vertices, bool staticCopy) {
|
||||
if (staticCopy) {
|
||||
std::vector<std::array<int16_t, 2>> verts(vertices.size());
|
||||
std::transform(vertices.begin(),
|
||||
vertices.end(),
|
||||
verts.begin(),
|
||||
[](const auto& v) -> std::array<int16_t, 2> { return v.a1; });
|
||||
collisionBuilder->addVertices(verts, 0, verts.size());
|
||||
} else {
|
||||
collisionBuilder->setRawVertices({}, vertices.size(), gfx::AttributeDataType::Short2);
|
||||
}
|
||||
};
|
||||
|
||||
constexpr bool staticVertexAndAttributes = true;
|
||||
|
||||
if (hasCollisionBox) {
|
||||
const auto& collisionBox = isText ? bucket.textCollisionBox : bucket.iconCollisionBox;
|
||||
if (const auto shader = std::static_pointer_cast<gfx::ShaderProgramBase>(
|
||||
collisionBoxGroup->getOrCreateShader(context, {}, CollisionPosAttribName))) {
|
||||
collisionBuilder->setDrawableName(layerCollisionPrefix + suffix + "box");
|
||||
collisionBuilder->setShader(shader);
|
||||
addVertices(collisionBox->vertices().vector(), staticVertexAndAttributes);
|
||||
collisionBuilder->setVertexAttributes(
|
||||
getCollisionVertexAttributes(*collisionBox, staticVertexAndAttributes));
|
||||
collisionBuilder->setSegments(gfx::Lines(1.0f),
|
||||
collisionBox->sharedLines,
|
||||
collisionBox->segments.data(),
|
||||
collisionBox->segments.size());
|
||||
collisionBuilder->flush();
|
||||
}
|
||||
}
|
||||
|
||||
if (hasCollisionCircle) {
|
||||
const auto& collisionCircle = isText ? bucket.textCollisionCircle : bucket.iconCollisionCircle;
|
||||
if (const auto shader = std::static_pointer_cast<gfx::ShaderProgramBase>(
|
||||
collisionCircleGroup->getOrCreateShader(context, {}, CollisionPosAttribName))) {
|
||||
collisionBuilder->setDrawableName(layerCollisionPrefix + suffix + "circle");
|
||||
collisionBuilder->setShader(shader);
|
||||
addVertices(collisionCircle->vertices().vector(), staticVertexAndAttributes);
|
||||
collisionBuilder->setVertexAttributes(
|
||||
getCollisionVertexAttributes(*collisionCircle, staticVertexAndAttributes));
|
||||
collisionBuilder->setSegments(gfx::Triangles(),
|
||||
collisionCircle->sharedTriangles,
|
||||
collisionCircle->segments.data(),
|
||||
collisionCircle->segments.size());
|
||||
collisionBuilder->flush();
|
||||
}
|
||||
}
|
||||
|
||||
// add drawables to layer group
|
||||
for (auto& drawable : collisionBuilder->clearDrawables()) {
|
||||
drawable->setTileID(tileID);
|
||||
auto drawData = std::make_unique<gfx::CollisionDrawableData>(values.translate,
|
||||
values.translateAnchor);
|
||||
drawable->setData(std::move(drawData));
|
||||
collisionTileLayerGroup->addDrawable(passes, tileID, std::move(drawable));
|
||||
++stats.drawablesAdded;
|
||||
}
|
||||
};
|
||||
|
||||
// If we already have drawables for this tile, update them.
|
||||
if (tileLayerGroup->getDrawableCount(passes, tileID) > 0) {
|
||||
// Just update the drawables we already created
|
||||
@@ -918,6 +1132,14 @@ void RenderSymbolLayer::update(gfx::ShaderRegistry& shaders,
|
||||
const auto& evaluated = getEvaluated<SymbolLayerProperties>(renderData.layerProperties);
|
||||
updateTileDrawable(drawable, context, bucket, bucketPaintProperties, evaluated, state);
|
||||
});
|
||||
|
||||
// re-create collision drawables
|
||||
collisionTileLayerGroup->removeDrawables(passes, tileID);
|
||||
addCollisionDrawables(
|
||||
false /*isText*/, bucket.hasIconCollisionBoxData(), bucket.hasIconCollisionCircleData());
|
||||
addCollisionDrawables(
|
||||
true /*isText*/, bucket.hasTextCollisionBoxData(), bucket.hasTextCollisionCircleData());
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -946,6 +1168,9 @@ void RenderSymbolLayer::update(gfx::ShaderRegistry& shaders,
|
||||
if (bucket.hasTextData() && atlases->glyph) {
|
||||
addRenderables(bucket.text, SymbolType::Text);
|
||||
}
|
||||
|
||||
addCollisionDrawables(false /*isText*/, bucket.hasIconCollisionBoxData(), bucket.hasIconCollisionCircleData());
|
||||
addCollisionDrawables(true /*isText*/, bucket.hasTextCollisionBoxData(), bucket.hasTextCollisionCircleData());
|
||||
}
|
||||
|
||||
// We'll be processing renderables across tiles, potentially out-of-order, so keep
|
||||
@@ -1008,12 +1233,27 @@ void RenderSymbolLayer::update(gfx::ShaderRegistry& shaders,
|
||||
|
||||
// We can use the same tweakers for all the segments in a tile
|
||||
if (isText && !tileInfo.textTweaker) {
|
||||
tileInfo.textTweaker = std::make_shared<gfx::DrawableAtlasesTweaker>(
|
||||
atlases, iconTexUniformName, texUniformName, isText);
|
||||
const bool textSizeIsZoomConstant =
|
||||
bucket.textSizeBinder->evaluateForZoom(static_cast<float>(state.getZoom())).isZoomConstant;
|
||||
tileInfo.textTweaker = std::make_shared<gfx::DrawableAtlasesTweaker>(atlases,
|
||||
iconTexUniformName,
|
||||
texUniformName,
|
||||
isText,
|
||||
false,
|
||||
values.rotationAlignment,
|
||||
false,
|
||||
textSizeIsZoomConstant);
|
||||
}
|
||||
if (!isText && !tileInfo.iconTweaker) {
|
||||
tileInfo.iconTweaker = std::make_shared<gfx::DrawableAtlasesTweaker>(
|
||||
atlases, iconTexUniformName, texUniformName, isText);
|
||||
const bool iconScaled = layout.get<IconSize>().constantOr(1.0) != 1.0 || bucket.iconsNeedLinear;
|
||||
tileInfo.iconTweaker = std::make_shared<gfx::DrawableAtlasesTweaker>(atlases,
|
||||
iconTexUniformName,
|
||||
texUniformName,
|
||||
isText,
|
||||
sdfIcons,
|
||||
values.rotationAlignment,
|
||||
iconScaled,
|
||||
false);
|
||||
}
|
||||
|
||||
if (!builder) {
|
||||
@@ -1043,11 +1283,6 @@ void RenderSymbolLayer::update(gfx::ShaderRegistry& shaders,
|
||||
builder->setDrawableName(layerPrefix + std::string(suffix));
|
||||
builder->setVertexAttributes(attribs);
|
||||
|
||||
// TODO: texture filtering
|
||||
// const bool linear = parameters.state.isChanging() || transformed ||
|
||||
// !partiallyEvaluatedTextSize.isZoomConstant; const auto filterType = linear ?
|
||||
// gfx::TextureFilterType::Linear : gfx::TextureFilterType::Nearest;
|
||||
|
||||
builder->setSegments(gfx::Triangles(), buffer.sharedTriangles, &renderable.segment.get(), 1);
|
||||
|
||||
builder->flush();
|
||||
|
||||
@@ -94,6 +94,15 @@ public:
|
||||
UniqueChangeRequestVec&) override;
|
||||
#endif // MLN_DRAWABLE_RENDERER
|
||||
|
||||
protected:
|
||||
#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 // MLN_DRAWABLE_RENDERER
|
||||
|
||||
private:
|
||||
void transition(const TransitionParameters&) override;
|
||||
void evaluate(const PropertyEvaluationParameters&) override;
|
||||
@@ -125,6 +134,10 @@ private:
|
||||
gfx::ShaderGroupPtr symbolSDFIconGroup;
|
||||
gfx::ShaderGroupPtr symbolSDFTextGroup;
|
||||
gfx::ShaderGroupPtr symbolTextAndIconGroup;
|
||||
|
||||
gfx::ShaderGroupPtr collisionBoxGroup;
|
||||
gfx::ShaderGroupPtr collisionCircleGroup;
|
||||
std::shared_ptr<TileLayerGroup> collisionTileLayerGroup;
|
||||
#endif // MLN_DRAWABLE_RENDERER
|
||||
};
|
||||
|
||||
|
||||
@@ -45,8 +45,8 @@ static_assert(sizeof(SymbolDrawableUBO) == 15 * 16);
|
||||
|
||||
/// Evaluated properties that do not depend on the tile
|
||||
struct alignas(16) SymbolDrawablePaintUBO {
|
||||
/* 0 */ std::array<float, 4> fill_color;
|
||||
/* 16 */ std::array<float, 4> halo_color;
|
||||
/* 0 */ Color fill_color;
|
||||
/* 16 */ Color halo_color;
|
||||
/* 32 */ float opacity;
|
||||
/* 36 */ float halo_width;
|
||||
/* 40 */ float halo_blur;
|
||||
@@ -80,11 +80,9 @@ auto constOrDefault(const IndexedTuple<TypeList<Is...>, TypeList<Ts...>>& evalua
|
||||
|
||||
SymbolDrawablePaintUBO buildPaintUBO(bool isText, const SymbolPaintProperties::PossiblyEvaluated& evaluated) {
|
||||
return {
|
||||
/*.fill_color=*/gfx::VertexAttribute::colorAttrRGBA(isText ? constOrDefault<TextColor>(evaluated)
|
||||
: constOrDefault<IconColor>(evaluated)),
|
||||
/*.fill_color=*/isText ? constOrDefault<TextColor>(evaluated) : constOrDefault<IconColor>(evaluated),
|
||||
/*.halo_color=*/
|
||||
gfx::VertexAttribute::colorAttrRGBA(isText ? constOrDefault<TextHaloColor>(evaluated)
|
||||
: constOrDefault<IconHaloColor>(evaluated)),
|
||||
isText ? constOrDefault<TextHaloColor>(evaluated) : constOrDefault<IconHaloColor>(evaluated),
|
||||
/*.opacity=*/isText ? constOrDefault<TextOpacity>(evaluated) : constOrDefault<IconOpacity>(evaluated),
|
||||
/*.halo_width=*/
|
||||
isText ? constOrDefault<TextHaloWidth>(evaluated) : constOrDefault<IconHaloWidth>(evaluated),
|
||||
|
||||
@@ -150,7 +150,7 @@ void PaintParameters::renderTileClippingMasks(TIter beg, TIter end, GetTileIDFun
|
||||
for (auto i = beg; i != end; ++i) {
|
||||
const auto& tileID = f(*i);
|
||||
|
||||
const int32_t stencilID = nextStencilID + 1;
|
||||
const int32_t stencilID = nextStencilID;
|
||||
const auto result = tileClippingMaskIDs.insert(std::make_pair(tileID, stencilID));
|
||||
if (result.second) {
|
||||
// inserted
|
||||
|
||||
@@ -107,18 +107,14 @@ void PatternAtlas::upload([[maybe_unused]] gfx::UploadPass& uploadPass) {
|
||||
dirty = false;
|
||||
}
|
||||
|
||||
#if MLN_LEGACY_RENDERER
|
||||
// @note: Deprecated
|
||||
gfx::TextureBinding PatternAtlas::textureBinding() const {
|
||||
#if MLN_DRAWABLE_RENDERER
|
||||
assert(atlasTexture2D);
|
||||
assert(!dirty);
|
||||
return {atlasTexture2D->getResource(), gfx::TextureFilterType::Linear};
|
||||
#else
|
||||
assert(atlasTexture);
|
||||
assert(!dirty);
|
||||
return {atlasTexture->getResource(), gfx::TextureFilterType::Linear};
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
#if MLN_DRAWABLE_RENDERER
|
||||
const std::shared_ptr<gfx::Texture2D>& PatternAtlas::texture() const {
|
||||
|
||||
@@ -32,9 +32,10 @@ public:
|
||||
std::optional<ImagePosition> addPattern(const style::Image::Impl&);
|
||||
void removePattern(const std::string&);
|
||||
|
||||
gfx::TextureBinding textureBinding() const; // @TODO: Migrate
|
||||
#if MLN_DRAWABLE_RENDERER
|
||||
const std::shared_ptr<gfx::Texture2D>& texture() const;
|
||||
#else
|
||||
gfx::TextureBinding textureBinding() const; // @TODO: Migrate
|
||||
#endif
|
||||
|
||||
void upload(gfx::UploadPass&);
|
||||
|
||||
@@ -58,6 +58,9 @@ private:
|
||||
void upload(gfx::UploadPass& pass) const override { layer.get().upload(pass); }
|
||||
void render(PaintParameters& parameters) const override { layer.get().render(parameters); }
|
||||
const std::string& getName() const override { return layer.get().getID(); }
|
||||
#if MLN_DRAWABLE_RENDERER
|
||||
void updateDebugDrawables(DebugLayerGroupMap&, PaintParameters&) const override{};
|
||||
#endif
|
||||
};
|
||||
|
||||
class RenderTreeImpl final : public RenderTree {
|
||||
@@ -772,6 +775,16 @@ void RenderOrchestrator::clearData() {
|
||||
if (!layerImpls->empty()) layerImpls = makeMutable<std::vector<Immutable<style::Layer::Impl>>>();
|
||||
if (!imageImpls->empty()) imageImpls = makeMutable<std::vector<Immutable<style::Image::Impl>>>();
|
||||
|
||||
#if MLN_DRAWABLE_RENDERER
|
||||
UniqueChangeRequestVec changes;
|
||||
for (const auto& entry : renderLayers) {
|
||||
entry.second->layerRemoved(changes);
|
||||
}
|
||||
addChanges(changes);
|
||||
|
||||
debugLayerGroups.clear();
|
||||
#endif
|
||||
|
||||
renderSources.clear();
|
||||
renderLayers.clear();
|
||||
|
||||
@@ -805,36 +818,42 @@ void RenderOrchestrator::updateLayerGroupOrder() {
|
||||
|
||||
bool RenderOrchestrator::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) {
|
||||
onRemoveLayerGroup(*result.first->second);
|
||||
result.first->second = std::move(layerGroup);
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
auto range = layerGroupsByLayerIndex.equal_range(index);
|
||||
bool found = false;
|
||||
for (auto it = range.first; it != range.second; ++it) {
|
||||
if (it->second == layerGroup) {
|
||||
found = true;
|
||||
if (replace) {
|
||||
onRemoveLayerGroup(*it->second);
|
||||
it->second = std::move(layerGroup);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (found)
|
||||
return replace;
|
||||
else {
|
||||
layerGroupsByLayerIndex.insert(std::make_pair(index, std::move(layerGroup)));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool RenderOrchestrator::removeLayerGroup(const int32_t layerIndex) {
|
||||
const auto hit = layerGroupsByLayerIndex.find(layerIndex);
|
||||
if (hit != layerGroupsByLayerIndex.end()) {
|
||||
LayerGroupMap::const_iterator hit;
|
||||
bool removed = false;
|
||||
while ((hit = layerGroupsByLayerIndex.find(layerIndex)) != layerGroupsByLayerIndex.end()) {
|
||||
onRemoveLayerGroup(*hit->second);
|
||||
layerGroupsByLayerIndex.erase(hit);
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
removed = true;
|
||||
}
|
||||
return removed;
|
||||
}
|
||||
|
||||
size_t RenderOrchestrator::numLayerGroups() const noexcept {
|
||||
return layerGroupsByLayerIndex.size();
|
||||
int32_t RenderOrchestrator::maxLayerIndex() const {
|
||||
if (!layerGroupsByLayerIndex.empty()) {
|
||||
return layerGroupsByLayerIndex.crbegin()->second->getLayerIndex();
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
static const LayerGroupBasePtr no_group;
|
||||
@@ -918,17 +937,40 @@ bool RenderOrchestrator::removeRenderTarget(const RenderTargetPtr& renderTarget)
|
||||
}
|
||||
}
|
||||
|
||||
void RenderOrchestrator::observeRenderTargets(std::function<void(RenderTarget&)> f) {
|
||||
void RenderOrchestrator::visitRenderTargets(std::function<void(RenderTarget&)> f) {
|
||||
for (auto& renderTarget : renderTargets) {
|
||||
f(*renderTarget);
|
||||
}
|
||||
}
|
||||
|
||||
void RenderOrchestrator::observeRenderTargets(std::function<void(const RenderTarget&)> f) const {
|
||||
void RenderOrchestrator::visitRenderTargets(std::function<void(const RenderTarget&)> f) const {
|
||||
for (const auto& renderTarget : renderTargets) {
|
||||
f(*renderTarget);
|
||||
}
|
||||
}
|
||||
|
||||
void RenderOrchestrator::updateDebugLayerGroups(const RenderTree& renderTree, PaintParameters& parameters) {
|
||||
for (const RenderItem& item : renderTree.getSourceRenderItems()) {
|
||||
item.updateDebugDrawables(debugLayerGroups, parameters);
|
||||
}
|
||||
}
|
||||
|
||||
void RenderOrchestrator::visitDebugLayerGroups(std::function<void(LayerGroupBase&)> f) {
|
||||
for (auto& pair : debugLayerGroups) {
|
||||
if (pair.second) {
|
||||
f(*pair.second);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void RenderOrchestrator::visitDebugLayerGroups(std::function<void(const LayerGroupBase&)> f) const {
|
||||
for (const auto& pair : debugLayerGroups) {
|
||||
if (pair.second) {
|
||||
f(*pair.second);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif // MLN_DRAWABLE_RENDERER
|
||||
|
||||
void RenderOrchestrator::onGlyphsError(const FontStack& fontStack,
|
||||
|
||||
@@ -100,7 +100,7 @@ public:
|
||||
#if MLN_DRAWABLE_RENDERER
|
||||
bool addLayerGroup(LayerGroupBasePtr, bool replace);
|
||||
bool removeLayerGroup(const int32_t layerIndex);
|
||||
size_t numLayerGroups() const noexcept;
|
||||
int32_t maxLayerIndex() const;
|
||||
const LayerGroupBasePtr& getLayerGroup(const int32_t layerIndex) const;
|
||||
void visitLayerGroups(std::function<void(LayerGroupBase&)>);
|
||||
void visitLayerGroups(std::function<void(const LayerGroupBase&)>) const;
|
||||
@@ -117,8 +117,12 @@ public:
|
||||
|
||||
bool addRenderTarget(RenderTargetPtr);
|
||||
bool removeRenderTarget(const RenderTargetPtr&);
|
||||
void observeRenderTargets(std::function<void(RenderTarget&)> f);
|
||||
void observeRenderTargets(std::function<void(const RenderTarget&)> f) const;
|
||||
void visitRenderTargets(std::function<void(RenderTarget&)> f);
|
||||
void visitRenderTargets(std::function<void(const RenderTarget&)> f) const;
|
||||
|
||||
void updateDebugLayerGroups(const RenderTree& renderTree, PaintParameters& parameters);
|
||||
void visitDebugLayerGroups(std::function<void(LayerGroupBase&)>);
|
||||
void visitDebugLayerGroups(std::function<void(const LayerGroupBase&)>) const;
|
||||
#endif
|
||||
|
||||
const ZoomHistory& getZoomHistory() const { return zoomHistory; }
|
||||
@@ -195,11 +199,12 @@ private:
|
||||
#if MLN_DRAWABLE_RENDERER
|
||||
std::vector<std::unique_ptr<ChangeRequest>> pendingChanges;
|
||||
|
||||
using LayerGroupMap = std::map<int32_t, LayerGroupBasePtr>;
|
||||
using LayerGroupMap = std::multimap<int32_t, LayerGroupBasePtr>;
|
||||
LayerGroupMap layerGroupsByLayerIndex;
|
||||
bool layerGroupOrderDirty = false;
|
||||
|
||||
std::vector<RenderTargetPtr> renderTargets;
|
||||
RenderItem::DebugLayerGroupMap debugLayerGroups;
|
||||
#endif
|
||||
};
|
||||
|
||||
|
||||
@@ -107,11 +107,6 @@ const gfx::Texture2DPtr& RenderTile::getGlyphAtlasTexture() const {
|
||||
return renderData ? renderData->getGlyphAtlasTexture() : noTexture;
|
||||
}
|
||||
|
||||
gfx::TextureBinding RenderTile::getGlyphAtlasTextureBinding(gfx::TextureFilterType filter) const {
|
||||
assert(renderData && renderData->getGlyphAtlasTexture());
|
||||
return {getGlyphAtlasTexture()->getResource(), filter};
|
||||
}
|
||||
|
||||
bool RenderTile::hasIconAtlasTexture() const {
|
||||
return renderData && renderData->getIconAtlasTexture();
|
||||
}
|
||||
@@ -120,11 +115,6 @@ const gfx::Texture2DPtr& RenderTile::getIconAtlasTexture() const {
|
||||
return renderData ? renderData->getIconAtlasTexture() : noTexture;
|
||||
}
|
||||
|
||||
gfx::TextureBinding RenderTile::getIconAtlasTextureBinding(gfx::TextureFilterType filter) const {
|
||||
assert(renderData && renderData->getIconAtlasTexture());
|
||||
return {getIconAtlasTexture()->getResource(), filter};
|
||||
}
|
||||
|
||||
static const std::shared_ptr<TileAtlasTextures> noAtlas;
|
||||
const std::shared_ptr<TileAtlasTextures>& RenderTile::getAtlasTextures() const {
|
||||
return renderData ? renderData->getAtlasTextures() : noAtlas;
|
||||
|
||||
@@ -65,13 +65,13 @@ public:
|
||||
#if MLN_DRAWABLE_RENDERER
|
||||
bool hasGlyphAtlasTexture() const;
|
||||
const gfx::Texture2DPtr& getGlyphAtlasTexture() const;
|
||||
gfx::TextureBinding getGlyphAtlasTextureBinding(gfx::TextureFilterType) const;
|
||||
|
||||
bool hasIconAtlasTexture() const;
|
||||
const gfx::Texture2DPtr& getIconAtlasTexture() const;
|
||||
gfx::TextureBinding getIconAtlasTextureBinding(gfx::TextureFilterType) const;
|
||||
|
||||
const std::shared_ptr<TileAtlasTextures>& getAtlasTextures() const;
|
||||
|
||||
bool getNeedsRendering() const { return needsRendering; };
|
||||
#else
|
||||
gfx::TextureBinding getGlyphAtlasTextureBinding(gfx::TextureFilterType) const;
|
||||
gfx::TextureBinding getIconAtlasTextureBinding(gfx::TextureFilterType) const;
|
||||
|
||||
@@ -17,15 +17,29 @@ class PatternAtlas;
|
||||
|
||||
namespace gfx {
|
||||
class UploadPass;
|
||||
class Context;
|
||||
} // namespace gfx
|
||||
|
||||
class LayerGroupBase;
|
||||
using LayerGroupBasePtr = std::shared_ptr<LayerGroupBase>;
|
||||
|
||||
class RenderItem {
|
||||
public:
|
||||
enum class DebugType {
|
||||
TextOutline,
|
||||
Text,
|
||||
Border
|
||||
};
|
||||
using DebugLayerGroupMap = std::map<DebugType, LayerGroupBasePtr>;
|
||||
|
||||
virtual ~RenderItem() = default;
|
||||
virtual void upload(gfx::UploadPass&) const = 0;
|
||||
virtual void render(PaintParameters&) const = 0;
|
||||
virtual bool hasRenderPass(RenderPass) const = 0;
|
||||
virtual const std::string& getName() const = 0;
|
||||
#if MLN_DRAWABLE_RENDERER
|
||||
virtual void updateDebugDrawables(DebugLayerGroupMap&, PaintParameters&) const = 0;
|
||||
#endif
|
||||
};
|
||||
|
||||
using RenderItems = std::vector<std::reference_wrapper<const RenderItem>>;
|
||||
|
||||
@@ -23,6 +23,8 @@
|
||||
#include <mbgl/renderer/layer_tweaker.hpp>
|
||||
#include <mbgl/renderer/render_target.hpp>
|
||||
#include <mbgl/shaders/gl/shader_program_gl.hpp>
|
||||
|
||||
#include <limits>
|
||||
#endif
|
||||
|
||||
#if (MLN_LEGACY_RENDERER && MLN_DRAWABLE_RENDERER)
|
||||
@@ -91,6 +93,7 @@ void Renderer::Impl::render(const RenderTree& renderTree,
|
||||
|
||||
const auto& renderTreeParameters = renderTree.getParameters();
|
||||
staticData->has3D = renderTreeParameters.has3D;
|
||||
staticData->backendSize = backend.getDefaultRenderable().getSize();
|
||||
|
||||
if (renderState == RenderState::Never) {
|
||||
observer->onWillStartRenderingMap();
|
||||
@@ -140,7 +143,7 @@ void Renderer::Impl::render(const RenderTree& renderTree,
|
||||
*staticData->shaders, context, renderTreeParameters.transformParams.state, updateParameters, renderTree);
|
||||
}
|
||||
|
||||
// Run changes
|
||||
// Process changes
|
||||
orchestrator.processChanges();
|
||||
|
||||
// Run layer tweakers to update any dynamic elements
|
||||
@@ -150,6 +153,9 @@ void Renderer::Impl::render(const RenderTree& renderTree,
|
||||
}
|
||||
});
|
||||
|
||||
// Update the debug layer groups
|
||||
orchestrator.updateDebugLayerGroups(renderTree, parameters);
|
||||
|
||||
// Give the layers a chance to do setup
|
||||
// orchestrator.visitLayerGroups([&](LayerGroup& layerGroup) { layerGroup.preRender(orchestrator, parameters);
|
||||
// });
|
||||
@@ -162,7 +168,10 @@ void Renderer::Impl::render(const RenderTree& renderTree,
|
||||
orchestrator.visitLayerGroups([&](LayerGroupBase& layerGroup) { layerGroup.upload(*uploadPass); });
|
||||
|
||||
// Give the render targets a chance to upload
|
||||
orchestrator.observeRenderTargets([&](RenderTarget& renderTarget) { renderTarget.upload(*uploadPass); });
|
||||
orchestrator.visitRenderTargets([&](RenderTarget& renderTarget) { renderTarget.upload(*uploadPass); });
|
||||
|
||||
// Upload the Debug layer group
|
||||
orchestrator.visitDebugLayerGroups([&](LayerGroupBase& layerGroup) { layerGroup.upload(*uploadPass); });
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -219,7 +228,7 @@ void Renderer::Impl::render(const RenderTree& renderTree,
|
||||
#if MLN_DRAWABLE_RENDERER
|
||||
const auto drawableTargetsPass = [&] {
|
||||
// draw render targets
|
||||
orchestrator.observeRenderTargets(
|
||||
orchestrator.visitRenderTargets(
|
||||
[&](RenderTarget& renderTarget) { renderTarget.render(orchestrator, renderTree, parameters); });
|
||||
};
|
||||
#endif
|
||||
@@ -246,31 +255,28 @@ void Renderer::Impl::render(const RenderTree& renderTree,
|
||||
// Drawables
|
||||
const auto drawableOpaquePass = [&] {
|
||||
const auto debugGroup(parameters.renderPass->createDebugGroup("drawables-opaque"));
|
||||
const auto maxLayerIndex = orchestrator.maxLayerIndex();
|
||||
parameters.pass = RenderPass::Opaque;
|
||||
parameters.currentLayer = 0;
|
||||
parameters.depthRangeSize = 1 - (orchestrator.numLayerGroups() + 2) * parameters.numSublayers *
|
||||
PaintParameters::depthEpsilon;
|
||||
parameters.depthRangeSize = 1 - (maxLayerIndex + 3) * parameters.numSublayers * PaintParameters::depthEpsilon;
|
||||
|
||||
// draw layer groups, opaque pass
|
||||
orchestrator.visitLayerGroups([&](LayerGroupBase& layerGroup) {
|
||||
parameters.currentLayer = layerGroup.getLayerIndex();
|
||||
layerGroup.render(orchestrator, parameters);
|
||||
parameters.currentLayer++;
|
||||
});
|
||||
};
|
||||
|
||||
const auto drawableTranslucentPass = [&] {
|
||||
const auto debugGroup(parameters.renderPass->createDebugGroup("drawables-translucent"));
|
||||
const auto maxLayerIndex = orchestrator.maxLayerIndex();
|
||||
parameters.pass = RenderPass::Translucent;
|
||||
parameters.currentLayer = static_cast<int32_t>(orchestrator.numLayerGroups()) - 1;
|
||||
parameters.depthRangeSize = 1 - (orchestrator.numLayerGroups() + 2) * parameters.numSublayers *
|
||||
PaintParameters::depthEpsilon;
|
||||
parameters.depthRangeSize = 1 - (maxLayerIndex + 3) * parameters.numSublayers * PaintParameters::depthEpsilon;
|
||||
|
||||
// draw layer groups, translucent pass
|
||||
orchestrator.visitLayerGroups([&](LayerGroupBase& layerGroup) {
|
||||
parameters.currentLayer = maxLayerIndex - layerGroup.getLayerIndex();
|
||||
layerGroup.render(orchestrator, parameters);
|
||||
if (parameters.currentLayer != 0) {
|
||||
parameters.currentLayer--;
|
||||
}
|
||||
});
|
||||
};
|
||||
#endif
|
||||
@@ -313,6 +319,45 @@ void Renderer::Impl::render(const RenderTree& renderTree,
|
||||
};
|
||||
#endif // MLN_LEGACY_RENDERER
|
||||
|
||||
#if MLN_DRAWABLE_RENDERER
|
||||
const auto drawableDebugOverlays = [&] {
|
||||
// Renders debug overlays.
|
||||
{
|
||||
const auto debugGroup(parameters.renderPass->createDebugGroup("debug"));
|
||||
orchestrator.visitDebugLayerGroups([&](LayerGroupBase& layerGroup) {
|
||||
layerGroup.visitDrawables([&](gfx::Drawable& drawable) { drawable.draw(parameters); });
|
||||
});
|
||||
}
|
||||
};
|
||||
#endif // MLN_DRAWABLE_RENDERER
|
||||
|
||||
#if MLN_LEGACY_RENDERER
|
||||
const auto renderDebugOverlays = [&] {
|
||||
// Renders debug overlays.
|
||||
{
|
||||
const auto debugGroup(parameters.renderPass->createDebugGroup("debug"));
|
||||
|
||||
// Finalize the rendering, e.g. by calling debug render calls per tile.
|
||||
// This guarantees that we have at least one function per tile called.
|
||||
// When only rendering layers via the stylesheet, it's possible that we
|
||||
// don't ever visit a tile during rendering.
|
||||
for (const RenderItem& renderItem : sourceRenderItems) {
|
||||
renderItem.render(parameters);
|
||||
}
|
||||
}
|
||||
|
||||
#if !defined(NDEBUG)
|
||||
if (parameters.debugOptions & MapDebugOptions::StencilClip) {
|
||||
// Render tile clip boundaries, using stencil buffer to calculate fill color.
|
||||
parameters.context.visualizeStencilBuffer();
|
||||
} else if (parameters.debugOptions & MapDebugOptions::DepthBuffer) {
|
||||
// Render the depth buffer.
|
||||
parameters.context.visualizeDepthBuffer(parameters.depthRangeSize);
|
||||
}
|
||||
#endif
|
||||
};
|
||||
#endif // MLN_LEGACY_RENDERER
|
||||
|
||||
#if (MLN_DRAWABLE_RENDERER && !MLN_LEGACY_RENDERER)
|
||||
if (parameters.staticData.has3D) {
|
||||
common3DPass();
|
||||
@@ -322,6 +367,7 @@ void Renderer::Impl::render(const RenderTree& renderTree,
|
||||
commonClearPass();
|
||||
drawableOpaquePass();
|
||||
drawableTranslucentPass();
|
||||
drawableDebugOverlays();
|
||||
#elif (MLN_LEGACY_RENDERER && !MLN_DRAWABLE_RENDERER)
|
||||
if (parameters.staticData.has3D) {
|
||||
common3DPass();
|
||||
@@ -330,6 +376,7 @@ void Renderer::Impl::render(const RenderTree& renderTree,
|
||||
commonClearPass();
|
||||
renderLayerOpaquePass();
|
||||
renderLayerTranslucentPass();
|
||||
renderDebugOverlays();
|
||||
#elif (MLN_DRAWABLE_RENDERER && MLN_LEGACY_RENDERER)
|
||||
#if MLN_RENDERER_SPLIT_VIEW
|
||||
[[maybe_unused]] const auto W = backend.getDefaultRenderable().getSize().width;
|
||||
@@ -384,6 +431,7 @@ void Renderer::Impl::render(const RenderTree& renderTree,
|
||||
parameters.clearTileClippingMasks();
|
||||
drawableOpaquePass();
|
||||
drawableTranslucentPass();
|
||||
drawableDebugOverlays();
|
||||
|
||||
// RenderLayers on the right
|
||||
platform::glScissor(halfW, 0, W, H);
|
||||
@@ -391,6 +439,7 @@ void Renderer::Impl::render(const RenderTree& renderTree,
|
||||
parameters.clearTileClippingMasks();
|
||||
renderLayerOpaquePass();
|
||||
renderLayerTranslucentPass();
|
||||
renderDebugOverlays();
|
||||
#endif // MLN_RENDERER_QUAD_SPLIT_VIEW
|
||||
// Reset viewport
|
||||
platform::glScissor(0, 0, W, H);
|
||||
@@ -409,38 +458,14 @@ void Renderer::Impl::render(const RenderTree& renderTree,
|
||||
|
||||
drawableOpaquePass();
|
||||
drawableTranslucentPass();
|
||||
|
||||
renderDebugOverlays();
|
||||
drawableDebugOverlays();
|
||||
#endif // MLN_RENDERER_SPLIT_VIEW
|
||||
#else
|
||||
static_assert(0, "Must define one of (MLN_DRAWABLE_RENDERER, MLN_LEGACY_RENDERER)");
|
||||
#endif
|
||||
|
||||
#if MLN_LEGACY_RENDERER
|
||||
// - DEBUG PASS
|
||||
// --------------------------------------------------------------------------------
|
||||
// Renders debug overlays.
|
||||
{
|
||||
const auto debugGroup(parameters.renderPass->createDebugGroup("debug"));
|
||||
|
||||
// Finalize the rendering, e.g. by calling debug render calls per tile.
|
||||
// This guarantees that we have at least one function per tile called.
|
||||
// When only rendering layers via the stylesheet, it's possible that we
|
||||
// don't ever visit a tile during rendering.
|
||||
for (const RenderItem& renderItem : sourceRenderItems) {
|
||||
renderItem.render(parameters);
|
||||
}
|
||||
}
|
||||
|
||||
#if !defined(NDEBUG)
|
||||
if (parameters.debugOptions & MapDebugOptions::StencilClip) {
|
||||
// Render tile clip boundaries, using stencil buffer to calculate fill color.
|
||||
parameters.context.visualizeStencilBuffer();
|
||||
} else if (parameters.debugOptions & MapDebugOptions::DepthBuffer) {
|
||||
// Render the depth buffer.
|
||||
parameters.context.visualizeDepthBuffer(parameters.depthRangeSize);
|
||||
}
|
||||
#endif
|
||||
#endif // MLN_LEGACY_RENDERER
|
||||
|
||||
#if MLN_DRAWABLE_RENDERER
|
||||
// Give the layers a chance to do cleanup
|
||||
orchestrator.visitLayerGroups([&](LayerGroupBase& layerGroup) { layerGroup.postRender(orchestrator, parameters); });
|
||||
|
||||
@@ -25,6 +25,9 @@ private:
|
||||
bool hasRenderPass(RenderPass) const override { return false; }
|
||||
const std::string& getName() const override { return name; }
|
||||
std::string name;
|
||||
#if MLN_DRAWABLE_RENDERER
|
||||
void updateDebugDrawables(DebugLayerGroupMap&, PaintParameters&) const override{};
|
||||
#endif
|
||||
mutable std::optional<gfx::Texture> debugTexture;
|
||||
};
|
||||
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
|
||||
#include <mbgl/renderer/buckets/debug_bucket.hpp>
|
||||
#include <mbgl/renderer/render_tile.hpp>
|
||||
#include <mbgl/renderer/render_tree.hpp>
|
||||
#include <mbgl/renderer/paint_parameters.hpp>
|
||||
#include <mbgl/renderer/tile_parameters.hpp>
|
||||
#include <mbgl/renderer/tile_render_data.hpp>
|
||||
@@ -10,26 +9,21 @@
|
||||
#include <mbgl/util/constants.hpp>
|
||||
#include <mbgl/util/math.hpp>
|
||||
|
||||
#if MLN_DRAWABLE_RENDERER
|
||||
#include <mbgl/renderer/layer_group.hpp>
|
||||
#include <mbgl/renderer/render_static_data.hpp>
|
||||
#include <mbgl/gfx/drawable.hpp>
|
||||
#include <mbgl/gfx/drawable_builder.hpp>
|
||||
#include <mbgl/shaders/shader_program_base.hpp>
|
||||
#include <mbgl/util/convert.hpp>
|
||||
|
||||
#include <unordered_set>
|
||||
#endif
|
||||
|
||||
namespace mbgl {
|
||||
|
||||
using namespace style;
|
||||
|
||||
class TileSourceRenderItem : public RenderItem {
|
||||
public:
|
||||
TileSourceRenderItem(Immutable<std::vector<RenderTile>> renderTiles_, std::string name_)
|
||||
: renderTiles(std::move(renderTiles_)),
|
||||
name(std::move(name_)) {}
|
||||
|
||||
private:
|
||||
void upload(gfx::UploadPass&) const override;
|
||||
void render(PaintParameters&) const override;
|
||||
bool hasRenderPass(RenderPass) const override { return false; }
|
||||
const std::string& getName() const override { return name; }
|
||||
|
||||
Immutable<std::vector<RenderTile>> renderTiles;
|
||||
std::string name;
|
||||
};
|
||||
|
||||
void TileSourceRenderItem::upload(gfx::UploadPass& parameters) const {
|
||||
for (auto& tile : *renderTiles) {
|
||||
tile.upload(parameters);
|
||||
@@ -42,6 +36,225 @@ void TileSourceRenderItem::render(PaintParameters& parameters) const {
|
||||
}
|
||||
}
|
||||
|
||||
#if MLN_DRAWABLE_RENDERER
|
||||
void TileSourceRenderItem::updateDebugDrawables(DebugLayerGroupMap& debugLayerGroups,
|
||||
PaintParameters& parameters) const {
|
||||
if (!(parameters.debugOptions &
|
||||
(MapDebugOptions::Timestamps | MapDebugOptions::ParseStatus | MapDebugOptions::TileBorders))) {
|
||||
debugLayerGroups.clear();
|
||||
return;
|
||||
}
|
||||
|
||||
// Debug UBO definition
|
||||
struct alignas(16) DebugUBO {
|
||||
std::array<float, 4 * 4> matrix;
|
||||
Color color;
|
||||
float overlay_scale;
|
||||
float pad1, pad2, pad3;
|
||||
};
|
||||
static_assert(sizeof(DebugUBO) % 16 == 0);
|
||||
constexpr auto DebugUBOName = "DebugUBO";
|
||||
|
||||
// initialize
|
||||
auto& context = parameters.context;
|
||||
const auto renderPass = RenderPass::None;
|
||||
auto& shaders = *parameters.staticData.shaders;
|
||||
constexpr auto DebugShaderName = "DebugShader";
|
||||
gfx::ShaderProgramBasePtr debugShader = context.getGenericShader(shaders, std::string(DebugShaderName));
|
||||
|
||||
// create a builder
|
||||
constexpr auto VertexAttribName = "a_pos";
|
||||
std::unique_ptr<gfx::DrawableBuilder> builder = context.createDrawableBuilder("debug-builder");
|
||||
builder->setShader(debugShader);
|
||||
builder->setRenderPass(renderPass);
|
||||
builder->setEnableDepth(false);
|
||||
builder->setColorMode(gfx::ColorMode::unblended());
|
||||
builder->setCullFaceMode(gfx::CullFaceMode::disabled());
|
||||
builder->setEnableStencil(false);
|
||||
builder->setVertexAttrName(VertexAttribName);
|
||||
|
||||
// add or get the layer group for a debug type
|
||||
const auto addOrGetLayerGroupForType = [&debugLayerGroups, &context](
|
||||
DebugType type,
|
||||
const std::string&& layerName) -> DebugLayerGroupMap::const_iterator {
|
||||
auto it = debugLayerGroups.find(type);
|
||||
if (it == debugLayerGroups.end()) {
|
||||
auto inserted = debugLayerGroups.insert(std::make_pair(
|
||||
type, context.createTileLayerGroup(static_cast<int32_t>(type), /*initialCapacity=*/64, layerName)));
|
||||
assert(inserted.second);
|
||||
it = inserted.first;
|
||||
}
|
||||
return it;
|
||||
};
|
||||
|
||||
// build a set of tiles to cover
|
||||
std::unordered_set<OverscaledTileID> newTiles;
|
||||
for (auto& tile : *renderTiles) {
|
||||
if (tile.getNeedsRendering()) {
|
||||
newTiles.insert(tile.getOverscaledTileID());
|
||||
}
|
||||
}
|
||||
|
||||
// create texture. to be reused for all the tiles of the debug layers
|
||||
auto texture = context.createTexture2D();
|
||||
std::optional<uint32_t> samplerLocation;
|
||||
{
|
||||
std::array<uint8_t, 4> data{{0, 0, 0, 0}};
|
||||
auto emptyImage = std::make_shared<PremultipliedImage>(Size(1, 1), data.data(), data.size());
|
||||
texture->setImage(emptyImage);
|
||||
texture->setSamplerConfiguration(
|
||||
{gfx::TextureFilterType::Linear, gfx::TextureWrapType::Clamp, gfx::TextureWrapType::Clamp});
|
||||
constexpr auto DebugOverlayUniformName = "u_overlay";
|
||||
samplerLocation = debugShader->getSamplerLocation(DebugOverlayUniformName);
|
||||
}
|
||||
assert(samplerLocation.has_value());
|
||||
if (!samplerLocation.has_value()) return;
|
||||
|
||||
// function to update existing tile drawables with UBO value. return number of updated drawables
|
||||
const auto updateDrawables =
|
||||
[&](TileLayerGroup* tileLayerGroup, const OverscaledTileID& tileID, const DebugUBO& debugUBO) -> size_t {
|
||||
auto updatedCount = tileLayerGroup->visitDrawables(renderPass, tileID, [&](gfx::Drawable& drawable) {
|
||||
// update existing drawable
|
||||
auto& uniforms = drawable.mutableUniformBuffers();
|
||||
uniforms.createOrUpdate(DebugUBOName, &debugUBO, context);
|
||||
});
|
||||
return updatedCount;
|
||||
};
|
||||
|
||||
// function to add drawable
|
||||
const auto addDrawable = [&](TileLayerGroup* tileLayerGroup,
|
||||
const OverscaledTileID& tileID,
|
||||
const DebugUBO& debugUBO,
|
||||
const gfx::DrawMode mode,
|
||||
const auto& vertices,
|
||||
const auto& indexes,
|
||||
const auto& segments) {
|
||||
// create new drawable
|
||||
std::vector<std::array<int16_t, 2>> verts(vertices.size());
|
||||
std::transform(vertices.begin(), vertices.end(), verts.begin(), [](const auto& v) -> std::array<int16_t, 2> {
|
||||
return v.a1;
|
||||
});
|
||||
|
||||
builder->addVertices(verts, 0, verts.size());
|
||||
builder->setSegments(mode, indexes, segments.data(), segments.size());
|
||||
// texture
|
||||
builder->setTexture(texture, samplerLocation.value());
|
||||
|
||||
// finish
|
||||
builder->flush();
|
||||
for (auto& drawable : builder->clearDrawables()) {
|
||||
drawable->setTileID(tileID);
|
||||
auto& uniforms = drawable->mutableUniformBuffers();
|
||||
uniforms.createOrUpdate(DebugUBOName, &debugUBO, context);
|
||||
|
||||
tileLayerGroup->addDrawable(renderPass, tileID, std::move(drawable));
|
||||
}
|
||||
};
|
||||
|
||||
// Timestamps or Parse Status
|
||||
if (parameters.debugOptions & (MapDebugOptions::Timestamps | MapDebugOptions::ParseStatus)) {
|
||||
TileLayerGroup* outlineLayerGroup = static_cast<TileLayerGroup*>(
|
||||
addOrGetLayerGroupForType(DebugType::TextOutline, "debug-text-outline")->second.get());
|
||||
TileLayerGroup* textLayerGroup = static_cast<TileLayerGroup*>(
|
||||
addOrGetLayerGroupForType(DebugType::Text, "debug-text")->second.get());
|
||||
|
||||
// erase drawables that are not in the current tile set
|
||||
for (auto& lg : {outlineLayerGroup, textLayerGroup}) {
|
||||
lg->removeDrawablesIf([&](gfx::Drawable& drawable) {
|
||||
return !(drawable.getTileID().has_value() && newTiles.count(*drawable.getTileID()) > 0);
|
||||
});
|
||||
}
|
||||
|
||||
// add new drawables and update existing ones
|
||||
for (auto& tile : *renderTiles) {
|
||||
if (tile.getNeedsRendering()) {
|
||||
const auto tileID = tile.getOverscaledTileID();
|
||||
const auto& debugBucket = tile.debugBucket;
|
||||
if (!debugBucket) continue;
|
||||
|
||||
const DebugUBO outlineUBO{/*matrix = */ util::cast<float>(tile.matrix),
|
||||
/*color = */ Color::white(),
|
||||
/*overlay_scale = */ 1.0f,
|
||||
0,
|
||||
0,
|
||||
0};
|
||||
if (0 == updateDrawables(outlineLayerGroup, tileID, outlineUBO)) {
|
||||
addDrawable(outlineLayerGroup,
|
||||
tileID,
|
||||
outlineUBO,
|
||||
gfx::Lines(4.0f * parameters.pixelRatio),
|
||||
debugBucket->vertices.vector(),
|
||||
debugBucket->indices.vector(),
|
||||
debugBucket->segments);
|
||||
}
|
||||
|
||||
const DebugUBO textUBO{/*matrix = */ util::cast<float>(tile.matrix),
|
||||
/*color = */ Color::black(),
|
||||
/*overlay_scale = */ 1.0f,
|
||||
0,
|
||||
0,
|
||||
0};
|
||||
if (0 == updateDrawables(textLayerGroup, tileID, textUBO)) {
|
||||
addDrawable(textLayerGroup,
|
||||
tileID,
|
||||
textUBO,
|
||||
gfx::Lines(2.0f * parameters.pixelRatio),
|
||||
debugBucket->vertices.vector(),
|
||||
debugBucket->indices.vector(),
|
||||
debugBucket->segments);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// tile texts are not required, erase layer groups
|
||||
debugLayerGroups.erase(DebugType::TextOutline);
|
||||
debugLayerGroups.erase(DebugType::Text);
|
||||
}
|
||||
|
||||
// Tile Borders
|
||||
if (parameters.debugOptions & (MapDebugOptions::TileBorders)) {
|
||||
TileLayerGroup* tileLayerGroup = static_cast<TileLayerGroup*>(
|
||||
addOrGetLayerGroupForType(DebugType::Border, "debug-border")->second.get());
|
||||
|
||||
// erase drawables that are not in the current tile set
|
||||
tileLayerGroup->removeDrawablesIf([&](gfx::Drawable& drawable) {
|
||||
return !(drawable.getTileID().has_value() && newTiles.count(*drawable.getTileID()) > 0);
|
||||
});
|
||||
|
||||
// add new drawables and update existing ones
|
||||
auto vertices = RenderStaticData::tileVertices().vector();
|
||||
auto indexes = RenderStaticData::tileLineStripIndices().vector();
|
||||
auto segments = RenderStaticData::tileBorderSegments();
|
||||
for (auto& tile : *renderTiles) {
|
||||
if (tile.getNeedsRendering()) {
|
||||
const auto tileID = tile.getOverscaledTileID();
|
||||
const auto& debugBucket = tile.debugBucket;
|
||||
if (!debugBucket) continue;
|
||||
|
||||
const DebugUBO debugUBO{/*matrix = */ util::cast<float>(tile.matrix),
|
||||
/*color = */ Color::red(),
|
||||
/*overlay_scale = */ 1.0f,
|
||||
0,
|
||||
0,
|
||||
0};
|
||||
if (0 == updateDrawables(tileLayerGroup, tileID, debugUBO)) {
|
||||
addDrawable(tileLayerGroup,
|
||||
tileID,
|
||||
debugUBO,
|
||||
gfx::LineStrip(4.0f * parameters.pixelRatio),
|
||||
vertices,
|
||||
indexes,
|
||||
segments);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// if tile borders are not required, erase layer group
|
||||
debugLayerGroups.erase(DebugType::Border);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
RenderTileSource::RenderTileSource(Immutable<style::Source::Impl> impl_)
|
||||
: RenderSource(std::move(impl_)),
|
||||
renderTiles(makeMutable<std::vector<RenderTile>>()) {
|
||||
|
||||
@@ -4,6 +4,11 @@
|
||||
#include <mbgl/renderer/source_state.hpp>
|
||||
#include <mbgl/renderer/tile_pyramid.hpp>
|
||||
#include <mbgl/style/sources/vector_source_impl.hpp>
|
||||
#include <mbgl/renderer/render_tree.hpp>
|
||||
|
||||
#if MLN_DRAWABLE_RENDERER
|
||||
#include <mbgl/gfx/context.hpp>
|
||||
#endif
|
||||
|
||||
namespace mbgl {
|
||||
|
||||
@@ -84,4 +89,24 @@ private:
|
||||
std::optional<Tileset> cachedTileset;
|
||||
};
|
||||
|
||||
class TileSourceRenderItem : public RenderItem {
|
||||
public:
|
||||
TileSourceRenderItem(Immutable<std::vector<RenderTile>> renderTiles_, std::string name_)
|
||||
: renderTiles(std::move(renderTiles_)),
|
||||
name(std::move(name_)) {}
|
||||
|
||||
private:
|
||||
void upload(gfx::UploadPass&) const override;
|
||||
void render(PaintParameters&) const override;
|
||||
bool hasRenderPass(RenderPass) const override { return false; }
|
||||
const std::string& getName() const override { return name; }
|
||||
|
||||
#if MLN_DRAWABLE_RENDERER
|
||||
void updateDebugDrawables(DebugLayerGroupMap&, PaintParameters&) const override;
|
||||
#endif
|
||||
|
||||
Immutable<std::vector<RenderTile>> renderTiles;
|
||||
std::string name;
|
||||
};
|
||||
|
||||
} // namespace mbgl
|
||||
|
||||
@@ -952,10 +952,10 @@ void Placement::updateBucketOpacities(SymbolBucket& bucket,
|
||||
if (bucket.hasTextData()) bucket.text.sharedOpacityVertices->clear();
|
||||
if (bucket.hasIconData()) bucket.icon.sharedOpacityVertices->clear();
|
||||
if (bucket.hasSdfIconData()) bucket.sdfIcon.sharedOpacityVertices->clear();
|
||||
if (bucket.hasIconCollisionBoxData()) bucket.iconCollisionBox->dynamicVertices.clear();
|
||||
if (bucket.hasIconCollisionCircleData()) bucket.iconCollisionCircle->dynamicVertices.clear();
|
||||
if (bucket.hasTextCollisionBoxData()) bucket.textCollisionBox->dynamicVertices.clear();
|
||||
if (bucket.hasTextCollisionCircleData()) bucket.textCollisionCircle->dynamicVertices.clear();
|
||||
if (bucket.hasIconCollisionBoxData()) bucket.iconCollisionBox->dynamicVertices().clear();
|
||||
if (bucket.hasIconCollisionCircleData()) bucket.iconCollisionCircle->dynamicVertices().clear();
|
||||
if (bucket.hasTextCollisionBoxData()) bucket.textCollisionBox->dynamicVertices().clear();
|
||||
if (bucket.hasTextCollisionCircleData()) bucket.textCollisionCircle->dynamicVertices().clear();
|
||||
|
||||
const JointOpacityState duplicateOpacityState(false, false, true);
|
||||
|
||||
@@ -1056,7 +1056,7 @@ void Placement::updateBucketOpacities(SymbolBucket& bucket,
|
||||
return;
|
||||
}
|
||||
const auto& dynamicVertex = CollisionBoxProgram::dynamicVertex(placed, false, shift);
|
||||
bucket.iconCollisionBox->dynamicVertices.extend(feature.boxes.size() * 4, dynamicVertex);
|
||||
bucket.iconCollisionBox->dynamicVertices().extend(feature.boxes.size() * 4, dynamicVertex);
|
||||
};
|
||||
|
||||
auto updateTextCollisionBox =
|
||||
@@ -1092,7 +1092,7 @@ void Placement::updateBucketOpacities(SymbolBucket& bucket,
|
||||
}
|
||||
}
|
||||
const auto& dynamicVertex = CollisionBoxProgram::dynamicVertex(placed, !used, shift);
|
||||
bucket.textCollisionBox->dynamicVertices.extend(feature.boxes.size() * 4, dynamicVertex);
|
||||
bucket.textCollisionBox->dynamicVertices().extend(feature.boxes.size() * 4, dynamicVertex);
|
||||
return shift;
|
||||
};
|
||||
|
||||
@@ -1104,15 +1104,15 @@ void Placement::updateBucketOpacities(SymbolBucket& bucket,
|
||||
if (circles != collisionCircles.end()) {
|
||||
for (const auto& circle : circles->second) {
|
||||
const auto& dynamicVertex = CollisionBoxProgram::dynamicVertex(placed, !circle.isCircle(), {});
|
||||
isText ? bucket.textCollisionCircle->dynamicVertices.extend(4, dynamicVertex)
|
||||
: bucket.iconCollisionCircle->dynamicVertices.extend(4, dynamicVertex);
|
||||
isText ? bucket.textCollisionCircle->dynamicVertices().extend(4, dynamicVertex)
|
||||
: bucket.iconCollisionCircle->dynamicVertices().extend(4, dynamicVertex);
|
||||
}
|
||||
} else {
|
||||
// This feature was not placed, because it was not loaded or
|
||||
// from a fading tile. Apply default values.
|
||||
static const auto dynamicVertex = CollisionBoxProgram::dynamicVertex(placed, false /*not used*/, {});
|
||||
isText ? bucket.textCollisionCircle->dynamicVertices.extend(4 * feature.boxes.size(), dynamicVertex)
|
||||
: bucket.iconCollisionCircle->dynamicVertices.extend(4 * feature.boxes.size(), dynamicVertex);
|
||||
isText ? bucket.textCollisionCircle->dynamicVertices().extend(4 * feature.boxes.size(), dynamicVertex)
|
||||
: bucket.iconCollisionCircle->dynamicVertices().extend(4 * feature.boxes.size(), dynamicVertex);
|
||||
}
|
||||
};
|
||||
Point<float> textShift{0.0f, 0.0f};
|
||||
|
||||
Reference in New Issue
Block a user