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:
mwilsnd
2023-08-25 13:33:01 -05:00
committed by Bart Louwers
parent 7afd821720
commit 642903fdb4
76 changed files with 1680 additions and 445 deletions

View File

@@ -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

View File

@@ -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",

View File

@@ -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;

View File

@@ -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

View File

@@ -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;

View File

@@ -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;

View File

@@ -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) {

View File

@@ -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:

View File

@@ -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() {

View 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

View 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

View 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

View File

@@ -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>

View File

@@ -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,

View File

@@ -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"],

View File

@@ -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

View File

@@ -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",
],

View 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",
])

View File

@@ -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
View 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
View File

@@ -35,7 +35,7 @@ while [[ $# -gt 0 ]]; do
;;
--apikey)
shift
token="$1"
args+=("--token" "$1")
shift
;;
-*|--*)

View File

@@ -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);

View File

@@ -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() {

View File

@@ -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() {

View 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;
}
}

View 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;
}

View 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;
}

View 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;
}

View 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);
}

View 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);
}

View File

@@ -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",

View File

@@ -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;

View File

@@ -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.

View 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

View File

@@ -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

View File

@@ -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);

View File

@@ -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

View File

@@ -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,

View File

@@ -3,6 +3,7 @@
#include <mbgl/util/ignore.hpp>
#include <vector>
#include <memory>
namespace mbgl {
namespace gfx {

View File

@@ -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));
}
};
}

View File

@@ -40,7 +40,6 @@ public:
VertexAttributeArrayGL vertexAttributes;
gfx::IndexBuffer indexBuffer = {0, nullptr};
std::vector<gfx::UniqueVertexBufferResource> attributeBuffers;
UniformBufferArrayGL uniformBuffers;

View File

@@ -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,

View File

@@ -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;

View File

@@ -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;
}
}

View File

@@ -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);

View File

@@ -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()));
}
}
};

View File

@@ -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;

View File

@@ -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());
}
}

View File

@@ -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);

View 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

View 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

View File

@@ -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),

View File

@@ -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);
}

View File

@@ -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);
}

View File

@@ -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);

View File

@@ -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");

View File

@@ -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();

View File

@@ -88,6 +88,8 @@ private:
gfx::ShaderGroupPtr lineGradientShaderGroup;
gfx::ShaderGroupPtr lineSDFShaderGroup;
gfx::ShaderGroupPtr linePatternShaderGroup;
gfx::DrawableTweakerPtr iconTweaker;
#endif
};

View File

@@ -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;
}
}
}
}

View File

@@ -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
};

View File

@@ -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();

View File

@@ -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
};

View File

@@ -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),

View File

@@ -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

View File

@@ -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 {

View File

@@ -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&);

View File

@@ -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,

View File

@@ -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
};

View File

@@ -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;

View File

@@ -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;

View File

@@ -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>>;

View File

@@ -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); });

View File

@@ -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;
};

View File

@@ -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>>()) {

View File

@@ -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

View File

@@ -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};