From 33a1e162bc9c3d2f5bfe8aad11cd39bc7ec19baa Mon Sep 17 00:00:00 2001 From: Tim Sylvester Date: Fri, 17 May 2024 07:30:55 -0700 Subject: [PATCH] GPU Expressions (#2202) --- .github/workflows/linux-ci.yml | 6 +- CMakeLists.txt | 2 + bazel/core.bzl | 2 + include/mbgl/gfx/backend.hpp | 5 + include/mbgl/gfx/gpu_expression.hpp | 108 +++ include/mbgl/shaders/layer_ubo.hpp | 3 +- include/mbgl/shaders/line_layer_ubo.hpp | 32 +- include/mbgl/shaders/mtl/common.hpp | 191 ++++- include/mbgl/shaders/mtl/line.hpp | 233 +++--- include/mbgl/style/expression/expression.hpp | 21 +- .../mbgl/style/expression/find_zoom_curve.hpp | 13 +- include/mbgl/style/expression/interpolate.hpp | 2 + include/mbgl/style/expression/let.hpp | 3 +- include/mbgl/style/expression/step.hpp | 2 + include/mbgl/style/property_expression.hpp | 65 +- include/mbgl/style/property_value.hpp | 1 + include/mbgl/util/color.hpp | 2 + include/mbgl/util/convert.hpp | 8 + include/mbgl/util/enum.hpp | 2 + include/mbgl/util/indexed_tuple.hpp | 21 +- include/mbgl/util/suppress_copies.hpp | 10 +- include/mbgl/util/type_list.hpp | 1 + .../default/src/mbgl/gfx/headless_backend.cpp | 2 + platform/ios/BUILD.bazel | 5 +- platform/ios/benchmark/BUILD.bazel | 2 - platform/ios/benchmark/assets/BUILD.bazel | 14 + .../ios/benchmark/assets/glyphs/download.sh | 316 +++++++- .../ios/benchmark/assets/tiles/download.sh | 683 ++++++++++++++++++ render-test/render_test.cpp | 9 + src/mbgl/gfx/gpu_expression.cpp | 183 +++++ src/mbgl/gfx/rendering_stats.cpp | 51 +- src/mbgl/map/map_impl.cpp | 7 +- .../cross_faded_property_evaluator.hpp | 1 + .../data_driven_property_evaluator.hpp | 6 +- src/mbgl/renderer/image_atlas.cpp | 13 +- src/mbgl/renderer/image_manager.cpp | 4 +- .../renderer/layers/line_layer_tweaker.cpp | 152 +++- .../renderer/layers/line_layer_tweaker.hpp | 36 +- .../layers/render_background_layer.cpp | 3 +- .../renderer/layers/render_circle_layer.cpp | 6 +- .../layers/render_fill_extrusion_layer.cpp | 8 +- .../renderer/layers/render_fill_layer.cpp | 3 +- .../renderer/layers/render_heatmap_layer.cpp | 6 +- .../layers/render_hillshade_layer.cpp | 7 +- .../renderer/layers/render_line_layer.cpp | 25 +- .../renderer/layers/render_raster_layer.cpp | 7 +- .../renderer/layers/render_symbol_layer.cpp | 7 +- src/mbgl/renderer/paint_property_binder.hpp | 2 +- .../possibly_evaluated_property_value.hpp | 5 + .../property_evaluation_parameters.hpp | 4 + src/mbgl/renderer/property_evaluator.hpp | 1 + src/mbgl/renderer/render_orchestrator.cpp | 25 +- src/mbgl/renderer/renderer_impl.cpp | 5 +- .../renderer/sources/render_tile_source.cpp | 7 +- src/mbgl/shaders/mtl/line.cpp | 17 +- src/mbgl/style/expression/coercion.cpp | 5 +- .../style/expression/collator_expression.cpp | 9 +- src/mbgl/style/expression/expression.cpp | 2 +- src/mbgl/style/expression/find_zoom_curve.cpp | 59 +- src/mbgl/style/expression/parsing_context.cpp | 23 +- .../style/layers/custom_drawable_layer.cpp | 18 +- src/mbgl/style/properties.hpp | 88 ++- src/mbgl/style/property_expression.cpp | 80 +- test/style/expression/dependency.test.cpp | 15 +- 64 files changed, 2336 insertions(+), 318 deletions(-) create mode 100644 include/mbgl/gfx/gpu_expression.hpp create mode 100644 platform/ios/benchmark/assets/BUILD.bazel mode change 100644 => 100755 platform/ios/benchmark/assets/glyphs/download.sh mode change 100644 => 100755 platform/ios/benchmark/assets/tiles/download.sh create mode 100644 src/mbgl/gfx/gpu_expression.cpp diff --git a/.github/workflows/linux-ci.yml b/.github/workflows/linux-ci.yml index d5598a79b..b97bbdb28 100644 --- a/.github/workflows/linux-ci.yml +++ b/.github/workflows/linux-ci.yml @@ -154,12 +154,12 @@ jobs: run: xvfb-run -a build/mbgl-render-test-runner --manifestPath=metrics/linux-${{ matrix.renderer }}.json - name: Upload render test result - if: always() && steps.render_test.outcome == 'failure' && matrix.renderer == 'drawable' + if: always() && steps.render_test.outcome == 'failure' uses: actions/upload-artifact@v4 with: - name: render-test-result + name: render-test-result-${{ matrix.renderer }} path: | - metrics/linux-drawable.html + metrics/linux-${{ matrix.renderer }}.html # expression tests diff --git a/CMakeLists.txt b/CMakeLists.txt index db3a22bfa..d726a1065 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -149,6 +149,7 @@ if(MLN_DRAWABLE_RENDERER) ${PROJECT_SOURCE_DIR}/include/mbgl/gfx/drawable_tweaker.hpp ${PROJECT_SOURCE_DIR}/include/mbgl/gfx/drawable_atlases_tweaker.hpp ${PROJECT_SOURCE_DIR}/include/mbgl/gfx/drawable_custom_layer_host_tweaker.hpp + ${PROJECT_SOURCE_DIR}/include/mbgl/gfx/gpu_expression.hpp ${PROJECT_SOURCE_DIR}/include/mbgl/gfx/uniform_block.hpp ${PROJECT_SOURCE_DIR}/include/mbgl/gfx/uniform_buffer.hpp ${PROJECT_SOURCE_DIR}/include/mbgl/gfx/vertex_attribute.hpp @@ -177,6 +178,7 @@ if(MLN_DRAWABLE_RENDERER) ${PROJECT_SOURCE_DIR}/src/mbgl/gfx/drawable_builder_impl.cpp ${PROJECT_SOURCE_DIR}/src/mbgl/gfx/drawable_atlases_tweaker.cpp ${PROJECT_SOURCE_DIR}/src/mbgl/gfx/drawable_custom_layer_host_tweaker.cpp + ${PROJECT_SOURCE_DIR}/src/mbgl/gfx/gpu_expression.cpp ${PROJECT_SOURCE_DIR}/src/mbgl/gfx/hillshade_prepare_drawable_data.hpp ${PROJECT_SOURCE_DIR}/src/mbgl/gfx/image_drawable_data.hpp ${PROJECT_SOURCE_DIR}/src/mbgl/gfx/line_drawable_data.hpp diff --git a/bazel/core.bzl b/bazel/core.bzl index 5da7139b2..48e4fbeb8 100644 --- a/bazel/core.bzl +++ b/bazel/core.bzl @@ -922,6 +922,7 @@ MLN_DRAWABLES_SOURCE = [ "src/mbgl/gfx/drawable_builder_impl.cpp", "src/mbgl/gfx/drawable_atlases_tweaker.cpp", "src/mbgl/gfx/drawable_custom_layer_host_tweaker.cpp", + "src/mbgl/gfx/gpu_expression.cpp", "src/mbgl/gfx/hillshade_prepare_drawable_data.hpp", "src/mbgl/gfx/image_drawable_data.hpp", "src/mbgl/gfx/line_drawable_data.hpp", @@ -976,6 +977,7 @@ MLN_DRAWABLES_HEADERS = [ "include/mbgl/gfx/drawable_tweaker.hpp", "include/mbgl/gfx/drawable_atlases_tweaker.hpp", "include/mbgl/gfx/drawable_custom_layer_host_tweaker.hpp", + "include/mbgl/gfx/gpu_expression.hpp", "include/mbgl/gfx/uniform_block.hpp", "include/mbgl/gfx/uniform_buffer.hpp", "include/mbgl/gfx/vertex_attribute.hpp", diff --git a/include/mbgl/gfx/backend.hpp b/include/mbgl/gfx/backend.hpp index 859bc5f23..66bbe4a3b 100644 --- a/include/mbgl/gfx/backend.hpp +++ b/include/mbgl/gfx/backend.hpp @@ -31,6 +31,9 @@ public: static Type GetType() { return Value(DefaultType); } + static bool getEnableGPUExpressionEval() { return enableGPUExpressionEval; } + static void setEnableGPUExpressionEval(bool value) { enableGPUExpressionEval = value; } + template static std::unique_ptr Create(Args... args) { #if MLN_RENDER_BACKEND_METAL @@ -48,6 +51,8 @@ private: static const Type type = value; return type; } + + static bool enableGPUExpressionEval; }; } // namespace gfx diff --git a/include/mbgl/gfx/gpu_expression.hpp b/include/mbgl/gfx/gpu_expression.hpp new file mode 100644 index 000000000..8a80a8324 --- /dev/null +++ b/include/mbgl/gfx/gpu_expression.hpp @@ -0,0 +1,108 @@ +#pragma once + +#include +#include + +#include + +#if MLN_DRAWABLE_RENDERER + +namespace mbgl { +namespace style { +namespace expression { +class Expression; +class Interpolate; +class Step; +} // namespace expression +using ZoomCurvePtr = variant; +} // namespace style +namespace gfx { + +enum class GPUInterpType : std::uint16_t { + Step, + Linear, + Exponential, + Bezier +}; +enum class GPUOutputType : std::uint16_t { + Float, + Color, +}; +enum class GPUOptions : std::uint16_t { + None = 0, + IntegerZoom = 1 << 0, + Transitioning = 1 << 1, +}; + +class GPUExpression; +using UniqueGPUExpression = std::unique_ptr; + +class alignas(16) GPUExpression { +public: + static constexpr std::size_t maxStops = 16; + + GPUExpression() = delete; + GPUExpression(GPUOutputType type, uint16_t count) + : outputType(type), + stopCount(count) {} + GPUExpression(GPUExpression&&) = default; + GPUExpression(const GPUExpression&) = default; + GPUExpression(const GPUExpression* ptr) + : GPUExpression(ptr ? *ptr : empty) {} + GPUExpression& operator=(GPUExpression&&) = delete; + GPUExpression& operator=(const GPUExpression&) = delete; + + /* 0 */ const GPUOutputType outputType; + /* 2 */ const std::uint16_t stopCount; + /* 4 */ GPUOptions options; + /* 6 */ GPUInterpType interpolation; + + /* 8 */ union InterpOptions { + struct Exponential { + float base; + } exponential; + + struct Bezier { + float x1; + float y1; + float x2; + float y2; + } bezier; + } interpOptions; + + /* 24 */ float inputs[maxStops]; + + /* 24 + (4 * maxStops) = 88 */ union Stops { + float floats[maxStops]; + float colors[2 * maxStops]; + } stops; + + static UniqueGPUExpression create(GPUOutputType, std::uint16_t stopCount); + static UniqueGPUExpression create(const style::expression::Expression&, const style::ZoomCurvePtr&, bool intZoom); + + float evaluateFloat(const float zoom) const; + Color evaluateColor(const float zoom) const; + + template + auto evaluate(const float zoom) const; + + Color getColor(std::size_t index) const; + + static const GPUExpression empty; +}; +static_assert(sizeof(GPUExpression) == 32 + (4 + 8) * GPUExpression::maxStops); +static_assert(sizeof(GPUExpression) % 16 == 0); + +template <> +inline auto GPUExpression::evaluate(const float zoom) const { + return evaluateColor(zoom); +} +template <> +inline auto GPUExpression::evaluate(const float zoom) const { + return evaluateFloat(zoom); +} + +} // namespace gfx +} // namespace mbgl + +#endif diff --git a/include/mbgl/shaders/layer_ubo.hpp b/include/mbgl/shaders/layer_ubo.hpp index 3a07caf5d..347fb15e7 100644 --- a/include/mbgl/shaders/layer_ubo.hpp +++ b/include/mbgl/shaders/layer_ubo.hpp @@ -44,7 +44,8 @@ struct alignas(16) GlobalPaintParamsUBO { float symbol_fade_change; float aspect_ratio; float pixel_ratio; - float pad1, pad2; + float zoom; + float pad1; }; static_assert(sizeof(GlobalPaintParamsUBO) == 3 * 16); diff --git a/include/mbgl/shaders/line_layer_ubo.hpp b/include/mbgl/shaders/line_layer_ubo.hpp index f2632115c..29c09f26b 100644 --- a/include/mbgl/shaders/line_layer_ubo.hpp +++ b/include/mbgl/shaders/line_layer_ubo.hpp @@ -1,10 +1,27 @@ #pragma once #include +#include +#include + +#if MLN_DRAWABLE_RENDERER +#include +#endif // MLN_DRAWABLE_RENDERER namespace mbgl { namespace shaders { +enum class LineExpressionMask : uint32_t { + None = 0, + Color = 1 << 0, + Opacity = 1 << 1, + Blur = 1 << 2, + Width = 1 << 3, + GapWidth = 1 << 4, + FloorWidth = 1 << 5, + Offset = 1 << 6, +}; + // // Line @@ -26,6 +43,17 @@ struct alignas(16) LineInterpolationUBO { }; static_assert(sizeof(LineInterpolationUBO) % 16 == 0); +struct alignas(16) LineExpressionUBO { + gfx::GPUExpression color; + gfx::GPUExpression blur; + gfx::GPUExpression opacity; + gfx::GPUExpression gapwidth; + gfx::GPUExpression offset; + gfx::GPUExpression width; + gfx::GPUExpression floorWidth; +}; +static_assert(sizeof(LineExpressionUBO) % 16 == 0); + // // Line gradient @@ -110,7 +138,8 @@ struct alignas(16) LineEvaluatedPropsUBO { float offset; float width; float floorwidth; - float pad1, pad2; + LineExpressionMask expressionMask; + float pad1; }; static_assert(sizeof(LineEvaluatedPropsUBO) % 16 == 0); @@ -119,6 +148,7 @@ enum { idLineInterpolationUBO, idLineTilePropertiesUBO, idLineEvaluatedPropsUBO, + idLineExpressionUBO, lineUBOCount }; diff --git a/include/mbgl/shaders/mtl/common.hpp b/include/mbgl/shaders/mtl/common.hpp index eb717c614..fc093b704 100644 --- a/include/mbgl/shaders/mtl/common.hpp +++ b/include/mbgl/shaders/mtl/common.hpp @@ -54,6 +54,191 @@ float4 unpack_mix_color(const float4 packedColors, const float t) { decode_color(float2(packedColors[2], packedColors[3])), t); } + + +template +ForwardIt upper_bound(ForwardIt first, ForwardIt last, thread const T& value) +{ + size_t count = last - first; + while (count > 0) + { + ForwardIt it = first; + const size_t step = count / 2; + it += step; + if (!(value < *it)) + { + first = ++it; + count -= step + 1; + } + else { + count = step; + } + } + return first; +} + +float interpolationFactor(float base, float rangeMin, float rangeMax, float z) { + const float zoomDiff = rangeMax - rangeMin; + const float zoomProgress = z - rangeMin; + if (zoomDiff == 0) { + return 0; + } else if (base == 1.0f) { + return zoomProgress / zoomDiff; + } else { + return (pow(base, zoomProgress) - 1) / (pow(base, zoomDiff) - 1); + } +} + + +enum class GPUInterpType : uint16_t { + Step, + Linear, + Exponential, + Bezier +}; +enum class GPUOutputType : uint16_t { + Float, + Color, +}; +enum class GPUOptions : uint16_t { + None = 0, + IntegerZoom = 1 << 0, + Transitioning = 1 << 1, +}; +bool operator&(GPUOptions a, GPUOptions b) { return (uint16_t)a & (uint16_t)b; } + +constant const int maxExprStops = 16; +struct alignas(16) GPUExpression { + GPUOutputType outputType; + uint16_t stopCount; + GPUOptions options; + GPUInterpType interpolation; + + union InterpOptions { + struct Exponential { + float base; + } exponential; + + struct Bezier { + float x1; + float y1; + float x2; + float y2; + } bezier; + } interpOptions; + + float inputs[maxExprStops]; + + union Stops { + float floats[maxExprStops]; + float2 colors[maxExprStops]; + } stops; + + float eval(float zoom) device const { + const auto effectiveZoom = (options & GPUOptions::IntegerZoom) ? floor(zoom) : zoom; + const auto index = find(effectiveZoom); + if (index == 0) { + return stops.floats[0]; + } else if (index == stopCount) { + return stops.floats[stopCount - 1]; + } + switch (interpolation) { + case GPUInterpType::Step: return stops.floats[index - 1]; + default: assert(false); + [[fallthrough]]; + case GPUInterpType::Linear: assert(interpOptions.exponential.base == 1.0f); + [[fallthrough]]; + case GPUInterpType::Exponential: { + const float rangeBeg = inputs[index - 1]; + const float rangeEnd = inputs[index]; + const auto t = interpolationFactor(interpOptions.exponential.base, rangeBeg, rangeEnd, effectiveZoom); + return mix(stops.floats[index - 1], stops.floats[index], t); + } + case GPUInterpType::Bezier: + assert(false); + return stops.floats[0]; + } + } + + float4 evalColor(float zoom) device const { + const auto effectiveZoom = (options & GPUOptions::IntegerZoom) ? floor(zoom) : zoom; + const auto index = find(effectiveZoom); + if (index == 0) { + return getColor(0); + } else if (index == stopCount) { + return getColor(stopCount - 1); + } + switch (interpolation) { + case GPUInterpType::Step: + return getColor(index - 1); + default: + assert(false); + [[fallthrough]]; + case GPUInterpType::Linear: + assert(interpOptions.exponential.base == 1.0f); + [[fallthrough]]; + case GPUInterpType::Exponential: { + const float rangeBeg = inputs[index - 1]; + const float rangeEnd = inputs[index]; + const auto t = interpolationFactor(interpOptions.exponential.base, rangeBeg, rangeEnd, effectiveZoom); + return mix(getColor(index - 1), getColor(index), clamp(t, 0.0, 1.0)); + } + case GPUInterpType::Bezier: + assert(false); + return getColor(0); + } + } + + /// Get the index of the entry to use from the zoom level + size_t find(float zoom) device const { + return upper_bound(&inputs[0], &inputs[stopCount], zoom) - &inputs[0]; + } + + float4 getColor(size_t index) device const { return decode_color(stops.colors[index]); } +}; +static_assert(sizeof(GPUExpression) == 32 + (4 + 8) * maxExprStops, "wrong alignment"); +static_assert(sizeof(GPUExpression) % 16 == 0, "wrong alignment"); + + +enum { + idGlobalPaintParamsUBO, + globalUBOCount +}; + +enum { + idLineDrawableUBO = globalUBOCount, + idLineInterpolationUBO, + idLineTilePropertiesUBO, + idLineEvaluatedPropsUBO, + idLineExpressionUBO, + lineUBOCount +}; + + +enum class LineExpressionMask : uint32_t { + None = 0, + Color = 1 << 0, + Opacity = 1 << 1, + Blur = 1 << 2, + Width = 1 << 3, + GapWidth = 1 << 4, + FloorWidth = 1 << 5, + Offset = 1 << 6, +}; +bool operator&(LineExpressionMask a, LineExpressionMask b) { return (uint32_t)a & (uint32_t)b; } + +struct alignas(16) LineExpressionUBO { + GPUExpression color; + GPUExpression blur; + GPUExpression opacity; + GPUExpression gapwidth; + GPUExpression offset; + GPUExpression width; + GPUExpression floorwidth; +}; +static_assert(sizeof(LineExpressionUBO) % 16 == 0, "wrong alignment"); + + struct alignas(16) GlobalPaintParamsUBO { /* 0 */ float2 pattern_atlas_texsize; /* 8 */ float2 units_to_pixels; @@ -62,7 +247,8 @@ struct alignas(16) GlobalPaintParamsUBO { /* 28 */ float symbol_fade_change; /* 32 */ float aspect_ratio; /* 36 */ float pixel_ratio; - /* 40 */ float pad1, pad2; + /* 40 */ float zoom; + /* 44 */ float pad1; /* 48 */ }; static_assert(sizeof(GlobalPaintParamsUBO) == 3 * 16, "unexpected padding"); @@ -129,7 +315,8 @@ struct alignas(16) LineEvaluatedPropsUBO { float offset; float width; float floorwidth; - float pad1, pad2; + LineExpressionMask expressionMask; + float pad1; }; struct alignas(16) SymbolDrawableUBO { diff --git a/include/mbgl/shaders/mtl/line.hpp b/include/mbgl/shaders/mtl/line.hpp index a975c0797..eb66d8788 100644 --- a/include/mbgl/shaders/mtl/line.hpp +++ b/include/mbgl/shaders/mtl/line.hpp @@ -14,33 +14,33 @@ struct ShaderSource { static constexpr auto vertexMainFunction = "vertexMain"; static constexpr auto fragmentMainFunction = "fragmentMain"; - static const std::array uniforms; + static const std::array uniforms; static const std::array attributes; static constexpr std::array instanceAttributes{}; static const std::array textures; static constexpr auto source = R"( struct VertexStage { - short2 pos_normal [[attribute(5)]]; - uchar4 data [[attribute(6)]]; + short2 pos_normal [[attribute(lineUBOCount + 0)]]; + uchar4 data [[attribute(lineUBOCount + 1)]]; #if !defined(HAS_UNIFORM_u_color) - float4 color [[attribute(7)]]; + float4 color [[attribute(lineUBOCount + 2)]]; #endif #if !defined(HAS_UNIFORM_u_blur) - float2 blur [[attribute(8)]]; + float2 blur [[attribute(lineUBOCount + 3)]]; #endif #if !defined(HAS_UNIFORM_u_opacity) - float2 opacity [[attribute(9)]]; + float2 opacity [[attribute(lineUBOCount + 4)]]; #endif #if !defined(HAS_UNIFORM_u_gapwidth) - float2 gapwidth [[attribute(10)]]; + float2 gapwidth [[attribute(lineUBOCount + 5)]]; #endif #if !defined(HAS_UNIFORM_u_offset) - float2 offset [[attribute(11)]]; + float2 offset [[attribute(lineUBOCount + 6)]]; #endif #if !defined(HAS_UNIFORM_u_width) - float2 width [[attribute(12)]]; + float2 width [[attribute(lineUBOCount + 7)]]; #endif }; @@ -78,23 +78,29 @@ struct alignas(16) LineInterpolationUBO { }; FragmentStage vertex vertexMain(thread const VertexStage vertx [[stage_in]], - device const GlobalPaintParamsUBO& paintParams [[buffer(0)]], - device const LineDrawableUBO& drawable [[buffer(1)]], - device const LineInterpolationUBO& interp [[buffer(2)]], - device const LineEvaluatedPropsUBO& props [[buffer(4)]]) { + device const GlobalPaintParamsUBO& paintParams [[buffer(idGlobalPaintParamsUBO)]], + device const LineDrawableUBO& drawable [[buffer(idLineDrawableUBO)]], + device const LineInterpolationUBO& interp [[buffer(idLineInterpolationUBO)]], + device const LineEvaluatedPropsUBO& props [[buffer(idLineEvaluatedPropsUBO)]], + device const LineExpressionUBO& expr [[buffer(idLineExpressionUBO)]]) { #if defined(HAS_UNIFORM_u_gapwidth) - const auto gapwidth = props.gapwidth / 2; + const auto exprGapWidth = (props.expressionMask & LineExpressionMask::GapWidth); + const auto gapwidth = (exprGapWidth ? expr.gapwidth.eval(paintParams.zoom) : props.gapwidth) / 2; #else const auto gapwidth = unpack_mix_float(vertx.gapwidth, interp.gapwidth_t) / 2; #endif + #if defined(HAS_UNIFORM_u_offset) - const auto offset = props.offset * -1; + const auto exprOffset = (props.expressionMask & LineExpressionMask::Offset); + const auto offset = (exprOffset ? expr.offset.eval(paintParams.zoom) : props.offset) * -1; #else const auto offset = unpack_mix_float(vertx.offset, interp.offset_t) * -1; #endif + #if defined(HAS_UNIFORM_u_width) - const auto width = props.width; + const auto exprWidth = (props.expressionMask & LineExpressionMask::Width); + const auto width = exprWidth ? expr.width.eval(paintParams.zoom) : props.width; #else const auto width = unpack_mix_float(vertx.width, interp.width_t); #endif @@ -154,23 +160,30 @@ FragmentStage vertex vertexMain(thread const VertexStage vertx [[stage_in]], } half4 fragment fragmentMain(FragmentStage in [[stage_in]], - device const LineEvaluatedPropsUBO& props [[buffer(4)]]) { + device const GlobalPaintParamsUBO& paintParams [[buffer(idGlobalPaintParamsUBO)]], + device const LineEvaluatedPropsUBO& props [[buffer(idLineEvaluatedPropsUBO)]], + device const LineExpressionUBO& expr [[buffer(idLineExpressionUBO)]]) { #if defined(OVERDRAW_INSPECTOR) return half4(1.0); #endif #if defined(HAS_UNIFORM_u_color) - const float4 color = props.color; + const auto exprColor = (props.expressionMask & LineExpressionMask::Color); + const auto color = exprColor ? expr.color.evalColor(paintParams.zoom) : props.color; #else const float4 color = in.color; #endif + #if defined(HAS_UNIFORM_u_blur) - const float blur = props.blur; + const auto exprBlur = (props.expressionMask & LineExpressionMask::Blur); + const float blur = exprBlur ? expr.blur.eval(paintParams.zoom) : props.blur; #else const float blur = in.blur; #endif + #if defined(HAS_UNIFORM_u_opacity) - const float opacity = props.opacity; + const auto exprOpacity = (props.expressionMask & LineExpressionMask::Opacity); + const float opacity = exprOpacity ? expr.opacity.eval(paintParams.zoom) : props.opacity; #else const float opacity = in.opacity; #endif @@ -201,13 +214,23 @@ struct ShaderSource { static constexpr auto source = R"( struct VertexStage { - short2 pos_normal [[attribute(5)]]; - uchar4 data [[attribute(6)]]; - float2 blur [[attribute(7)]]; - float2 opacity [[attribute(8)]]; - float2 gapwidth [[attribute(9)]]; - float2 offset [[attribute(10)]]; - float2 width [[attribute(11)]]; + short2 pos_normal [[attribute(lineUBOCount + 0)]]; + uchar4 data [[attribute(lineUBOCount + 1)]]; +#if !defined(HAS_UNIFORM_u_blur) + float2 blur [[attribute(lineUBOCount + 2)]]; +#endif +#if !defined(HAS_UNIFORM_u_opacity) + float2 opacity [[attribute(lineUBOCount + 3)]]; +#endif +#if !defined(HAS_UNIFORM_u_gapwidth) + float2 gapwidth [[attribute(lineUBOCount + 4)]]; +#endif +#if !defined(HAS_UNIFORM_u_offset) + float2 offset [[attribute(lineUBOCount + 5)]]; +#endif +#if !defined(HAS_UNIFORM_u_width) + float2 width [[attribute(lineUBOCount + 6)]]; +#endif }; struct FragmentStage { @@ -241,10 +264,11 @@ struct alignas(16) LineGradientInterpolationUBO { }; FragmentStage vertex vertexMain(thread const VertexStage vertx [[stage_in]], - device const GlobalPaintParamsUBO& paintParams [[buffer(0)]], - device const LineGradientDrawableUBO& drawable [[buffer(1)]], - device const LineGradientInterpolationUBO& interp [[buffer(2)]], - device const LineEvaluatedPropsUBO& props [[buffer(4)]]) { + device const GlobalPaintParamsUBO& paintParams [[buffer(idGlobalPaintParamsUBO)]], + device const LineGradientDrawableUBO& drawable [[buffer(idLineDrawableUBO)]], + device const LineGradientInterpolationUBO& interp [[buffer(idLineInterpolationUBO)]], + device const LineEvaluatedPropsUBO& props [[buffer(idLineEvaluatedPropsUBO)]], + device const LineExpressionUBO& expr [[buffer(idLineExpressionUBO)]]) { #if !defined(HAS_UNIFORM_u_blur) const auto blur = unpack_mix_float(vertx.blur, interp.blur_t); @@ -253,12 +277,12 @@ FragmentStage vertex vertexMain(thread const VertexStage vertx [[stage_in]], const auto opacity = unpack_mix_float(vertx.opacity, interp.opacity_t); #endif #if defined(HAS_UNIFORM_u_gapwidth) - const auto gapwidth = props.gapwidth; + const auto gapwidth = props.gapwidth / 2; #else const auto gapwidth = unpack_mix_float(vertx.gapwidth, interp.gapwidth_t) / 2; #endif #if defined(HAS_UNIFORM_u_offset) - const auto offset = props.offset; + const auto offset = props.offset * -1; #else const auto offset = unpack_mix_float(vertx.offset, interp.offset_t) * -1; #endif @@ -322,7 +346,8 @@ FragmentStage vertex vertexMain(thread const VertexStage vertx [[stage_in]], } half4 fragment fragmentMain(FragmentStage in [[stage_in]], - device const LineEvaluatedPropsUBO& props [[buffer(4)]], + device const LineEvaluatedPropsUBO& props [[buffer(idLineEvaluatedPropsUBO)]], + device const LineExpressionUBO& expr [[buffer(idLineExpressionUBO)]], texture2d gradientTexture [[texture(0)]]) { #if defined(OVERDRAW_INSPECTOR) return half4(1.0); @@ -363,36 +388,36 @@ struct ShaderSource { static constexpr auto vertexMainFunction = "vertexMain"; static constexpr auto fragmentMainFunction = "fragmentMain"; - static const std::array uniforms; + static const std::array uniforms; static const std::array attributes; static constexpr std::array instanceAttributes{}; static const std::array textures; static constexpr auto source = R"( struct VertexStage { - short2 pos_normal [[attribute(5)]]; - uchar4 data [[attribute(6)]]; + short2 pos_normal [[attribute(lineUBOCount + 0)]]; + uchar4 data [[attribute(lineUBOCount + 1)]]; #if !defined(HAS_UNIFORM_u_blur) - float2 blur [[attribute(7)]]; + float2 blur [[attribute(lineUBOCount + 2)]]; #endif #if !defined(HAS_UNIFORM_u_opacity) - float2 opacity [[attribute(8)]]; + float2 opacity [[attribute(lineUBOCount + 3)]]; #endif #if !defined(HAS_UNIFORM_u_gapwidth) - float2 gapwidth [[attribute(9)]]; + float2 gapwidth [[attribute(lineUBOCount + 4)]]; #endif #if !defined(HAS_UNIFORM_u_offset) - float2 offset [[attribute(10)]]; + float2 offset [[attribute(lineUBOCount + 5)]]; #endif #if !defined(HAS_UNIFORM_u_width) - float2 width [[attribute(11)]]; + float2 width [[attribute(lineUBOCount + 6)]]; #endif #if !defined(HAS_UNIFORM_u_pattern_from) - ushort4 pattern_from [[attribute(12)]]; + ushort4 pattern_from [[attribute(lineUBOCount + 7)]]; #endif #if !defined(HAS_UNIFORM_u_pattern_to) - ushort4 pattern_to [[attribute(13)]]; + ushort4 pattern_to [[attribute(lineUBOCount + 8)]]; #endif }; @@ -442,26 +467,32 @@ struct alignas(16) LinePatternTilePropertiesUBO { }; FragmentStage vertex vertexMain(thread const VertexStage vertx [[stage_in]], - device const GlobalPaintParamsUBO& paintParams [[buffer(0)]], - device const LinePatternDrawableUBO& drawable [[buffer(1)]], - device const LinePatternInterpolationUBO& interp [[buffer(2)]], - device const LinePatternTilePropertiesUBO& tileProps [[buffer(3)]], - device const LineEvaluatedPropsUBO& props [[buffer(4)]]) { + device const GlobalPaintParamsUBO& paintParams [[buffer(idGlobalPaintParamsUBO)]], + device const LinePatternDrawableUBO& drawable [[buffer(idLineDrawableUBO)]], + device const LinePatternInterpolationUBO& interp [[buffer(idLineInterpolationUBO)]], + device const LinePatternTilePropertiesUBO& tileProps [[buffer(idLineTilePropertiesUBO)]], + device const LineEvaluatedPropsUBO& props [[buffer(idLineEvaluatedPropsUBO)]], + device const LineExpressionUBO& expr [[buffer(idLineExpressionUBO)]]) { #if defined(HAS_UNIFORM_u_gapwidth) - const auto gapwidth = props.gapwidth / 2; + const auto exprGapWidth = (props.expressionMask & LineExpressionMask::GapWidth); + const auto gapwidth = (exprGapWidth ? expr.gapwidth.eval(paintParams.zoom) : props.gapwidth) / 2; #else const auto gapwidth = unpack_mix_float(vertx.gapwidth, interp.gapwidth_t) / 2; #endif + #if defined(HAS_UNIFORM_u_offset) - const auto offset = props.offset * -1; + const auto exprOffset = (props.expressionMask & LineExpressionMask::Offset); + const auto offset = (exprOffset ? expr.offset.eval(paintParams.zoom) : props.offset) * -1; #else - const auto offset = unpack_mix_float(vertx.offset, interp.offset_t) * -1; + const auto offset = unpack_mix_float(vertx.offset, interp.offset_t) * -1; #endif + #if defined(HAS_UNIFORM_u_width) - const auto width = props.width; + const auto exprWidth = (props.expressionMask & LineExpressionMask::Width); + const auto width = exprWidth ? expr.width.eval(paintParams.zoom) : props.width; #else - const auto width = unpack_mix_float(vertx.width, interp.width_t); + const auto width = unpack_mix_float(vertx.width, interp.width_t); #endif // the distance over which the line edge fades out. @@ -525,9 +556,11 @@ FragmentStage vertex vertexMain(thread const VertexStage vertx [[stage_in]], } half4 fragment fragmentMain(FragmentStage in [[stage_in]], - device const LinePatternDrawableUBO& drawable [[buffer(1)]], - device const LinePatternTilePropertiesUBO& tileProps [[buffer(3)]], - device const LineEvaluatedPropsUBO& props [[buffer(4)]], + device const GlobalPaintParamsUBO& paintParams [[buffer(idGlobalPaintParamsUBO)]], + device const LinePatternDrawableUBO& drawable [[buffer(idLineDrawableUBO)]], + device const LinePatternTilePropertiesUBO& tileProps [[buffer(idLineTilePropertiesUBO)]], + device const LineEvaluatedPropsUBO& props [[buffer(idLineEvaluatedPropsUBO)]], + device const LineExpressionUBO& expr [[buffer(idLineExpressionUBO)]], texture2d image0 [[texture(0)]], sampler image0_sampler [[sampler(0)]]) { #if defined(OVERDRAW_INSPECTOR) @@ -535,20 +568,25 @@ half4 fragment fragmentMain(FragmentStage in [[stage_in]], #endif #if defined(HAS_UNIFORM_u_blur) - const half blur = props.blur; + const auto exprBlur = (props.expressionMask & LineExpressionMask::Blur); + const float blur = exprBlur ? expr.blur.eval(paintParams.zoom) : props.blur; #else - const half blur = in.blur; + const float blur = in.blur; #endif + #if defined(HAS_UNIFORM_u_opacity) - const half opacity = props.opacity; + const auto exprOpacity = (props.expressionMask & LineExpressionMask::Opacity); + const float opacity = exprOpacity ? expr.opacity.eval(paintParams.zoom) : props.opacity; #else - const half opacity = in.opacity; + const float opacity = in.opacity; #endif + #if defined(HAS_UNIFORM_u_pattern_from) const auto pattern_from = float4(tileProps.pattern_from); #else const auto pattern_from = float4(in.pattern_from); #endif + #if defined(HAS_UNIFORM_u_pattern_to) const auto pattern_to = float4(tileProps.pattern_to); #else @@ -606,36 +644,36 @@ struct ShaderSource { static constexpr auto vertexMainFunction = "vertexMain"; static constexpr auto fragmentMainFunction = "fragmentMain"; - static const std::array uniforms; + static const std::array uniforms; static const std::array attributes; static constexpr std::array instanceAttributes{}; static const std::array textures; static constexpr auto source = R"( struct VertexStage { - short2 pos_normal [[attribute(5)]]; - uchar4 data [[attribute(6)]]; + short2 pos_normal [[attribute(lineUBOCount + 0)]]; + uchar4 data [[attribute(lineUBOCount + 1)]]; #if !defined(HAS_UNIFORM_u_color) - float4 color [[attribute(7)]]; + float4 color [[attribute(lineUBOCount + 2)]]; #endif #if !defined(HAS_UNIFORM_u_blur) - float2 blur [[attribute(8)]]; + float2 blur [[attribute(lineUBOCount + 3)]]; #endif #if !defined(HAS_UNIFORM_u_opacity) - float2 opacity [[attribute(9)]]; + float2 opacity [[attribute(lineUBOCount + 4)]]; #endif #if !defined(HAS_UNIFORM_u_gapwidth) - float2 gapwidth [[attribute(10)]]; + float2 gapwidth [[attribute(lineUBOCount + 5)]]; #endif #if !defined(HAS_UNIFORM_u_offset) - float2 offset [[attribute(11)]]; + float2 offset [[attribute(lineUBOCount + 6)]]; #endif #if !defined(HAS_UNIFORM_u_width) - float2 width [[attribute(12)]]; + float2 width [[attribute(lineUBOCount + 7)]]; #endif #if !defined(HAS_UNIFORM_u_floorwidth) - float2 floorwidth [[attribute(13)]]; + float2 floorwidth [[attribute(lineUBOCount + 8)]]; #endif }; @@ -685,28 +723,36 @@ struct alignas(16) LineSDFInterpolationUBO { }; FragmentStage vertex vertexMain(thread const VertexStage vertx [[stage_in]], - device const GlobalPaintParamsUBO& paintParams [[buffer(0)]], - device const LineSDFDrawableUBO& drawable [[buffer(1)]], - device const LineSDFInterpolationUBO& interp [[buffer(2)]], - device const LineEvaluatedPropsUBO& props [[buffer(4)]]) { + device const GlobalPaintParamsUBO& paintParams [[buffer(idGlobalPaintParamsUBO)]], + device const LineSDFDrawableUBO& drawable [[buffer(idLineDrawableUBO)]], + device const LineSDFInterpolationUBO& interp [[buffer(idLineInterpolationUBO)]], + device const LineEvaluatedPropsUBO& props [[buffer(idLineEvaluatedPropsUBO)]], + device const LineExpressionUBO& expr [[buffer(idLineExpressionUBO)]]) { #if defined(HAS_UNIFORM_u_gapwidth) - const auto gapwidth = props.gapwidth / 2; + const auto exprGapWidth = (props.expressionMask & LineExpressionMask::GapWidth); + const auto gapwidth = (exprGapWidth ? expr.gapwidth.eval(paintParams.zoom) : props.gapwidth) / 2; #else - const auto gapwidth = unpack_mix_float(vertx.gapwidth, interp.gapwidth_t) / 2; + const auto gapwidth = unpack_mix_float(vertx.gapwidth, interp.gapwidth_t) / 2; #endif + #if defined(HAS_UNIFORM_u_offset) - const auto offset = props.offset * -1; + const auto exprOffset = (props.expressionMask & LineExpressionMask::Offset); + const auto offset = (exprOffset ? expr.offset.eval(paintParams.zoom) : props.offset) * -1; #else - const auto offset = unpack_mix_float(vertx.offset, interp.offset_t) * -1; + const auto offset = unpack_mix_float(vertx.offset, interp.offset_t) * -1; #endif + #if defined(HAS_UNIFORM_u_width) - const auto width = props.width; + const auto exprWidth = (props.expressionMask & LineExpressionMask::Width); + const auto width = exprWidth ? expr.width.eval(paintParams.zoom) : props.width; #else - const auto width = unpack_mix_float(vertx.width, interp.width_t); + const auto width = unpack_mix_float(vertx.width, interp.width_t); #endif + #if defined(HAS_UNIFORM_u_floorwidth) - const auto floorwidth = props.floorwidth; + const auto exprFloorWidth = (props.expressionMask & LineExpressionMask::FloorWidth); + const auto floorwidth = exprFloorWidth ? expr.floorwidth.eval(paintParams.zoom) : props.floorwidth; #else const auto floorwidth = unpack_mix_float(vertx.floorwidth, interp.floorwidth_t); #endif @@ -773,8 +819,10 @@ FragmentStage vertex vertexMain(thread const VertexStage vertx [[stage_in]], } half4 fragment fragmentMain(FragmentStage in [[stage_in]], - device const LineSDFDrawableUBO& drawable [[buffer(1)]], - device const LineEvaluatedPropsUBO& props [[buffer(4)]], + device const GlobalPaintParamsUBO& paintParams [[buffer(idGlobalPaintParamsUBO)]], + device const LineSDFDrawableUBO& drawable [[buffer(idLineDrawableUBO)]], + device const LineEvaluatedPropsUBO& props [[buffer(idLineEvaluatedPropsUBO)]], + device const LineExpressionUBO& expr [[buffer(idLineExpressionUBO)]], texture2d image0 [[texture(0)]], sampler image0_sampler [[sampler(0)]]) { #if defined(OVERDRAW_INSPECTOR) @@ -782,24 +830,31 @@ half4 fragment fragmentMain(FragmentStage in [[stage_in]], #endif #if defined(HAS_UNIFORM_u_color) - const float4 color = props.color; + const auto exprColor = (props.expressionMask & LineExpressionMask::Color); + const auto color = exprColor ? expr.color.evalColor(paintParams.zoom) : props.color; #else const float4 color = in.color; #endif + #if defined(HAS_UNIFORM_u_blur) - const float blur = props.blur; + const auto exprBlur = (props.expressionMask & LineExpressionMask::Blur); + const float blur = exprBlur ? expr.blur.eval(paintParams.zoom) : props.blur; #else const float blur = in.blur; #endif + #if defined(HAS_UNIFORM_u_opacity) - const float opacity = props.opacity; + const auto exprOpacity = (props.expressionMask & LineExpressionMask::Opacity); + const float opacity = exprOpacity ? expr.opacity.eval(paintParams.zoom) : props.opacity; #else const float opacity = in.opacity; #endif + #if defined(HAS_UNIFORM_u_floorwidth) - const float floorwidth = props.floorwidth; + const auto exprFloorWidth = (props.expressionMask & LineExpressionMask::FloorWidth); + const auto floorwidth = exprFloorWidth ? expr.floorwidth.eval(paintParams.zoom) : props.floorwidth; #else - const float floorwidth = in.floorwidth; + const auto floorwidth = in.floorwidth; #endif // Calculate the antialiasing fade factor. This is either when fading in the diff --git a/include/mbgl/style/expression/expression.hpp b/include/mbgl/style/expression/expression.hpp index b53951305..268fdb980 100644 --- a/include/mbgl/style/expression/expression.hpp +++ b/include/mbgl/style/expression/expression.hpp @@ -4,6 +4,7 @@ #include #include #include +#include #include #include #include @@ -202,17 +203,14 @@ enum class Dependency : uint32_t { Var = 1 << 5, // Use variable binding Override = 1 << 6, // Property override MaskCount = 7, + All = (1 << MaskCount) - 1, }; -inline constexpr static Dependency operator|(Dependency x, Dependency y) noexcept { - return Dependency{mbgl::underlying_type(x) | mbgl::underlying_type(y)}; -} -inline constexpr static Dependency operator&(Dependency x, Dependency y) noexcept { - return Dependency{mbgl::underlying_type(x) & mbgl::underlying_type(y)}; -} -inline static Dependency& operator|=(Dependency& target, Dependency source) noexcept { - target = target | source; - return target; -} + +class Interpolate; +class Step; + +using ZoomCurveOrError = std::optional>; +using ZoomCurvePtr = variant; class Expression { public: @@ -264,6 +262,9 @@ public: const Dependency dependencies; + /// Test the expression's dependencies for any of one or more values + bool has(Dependency dep) const { return (dependencies & dep); } + protected: template static bool childrenEqual(const T& lhs, const T& rhs) noexcept { diff --git a/include/mbgl/style/expression/find_zoom_curve.hpp b/include/mbgl/style/expression/find_zoom_curve.hpp index 83fcc3686..2507fe5b1 100644 --- a/include/mbgl/style/expression/find_zoom_curve.hpp +++ b/include/mbgl/style/expression/find_zoom_curve.hpp @@ -11,9 +11,18 @@ namespace mbgl { namespace style { namespace expression { -std::optional> findZoomCurve(const expression::Expression*); +using ZoomCurveOrError = std::optional>; +using ZoomCurvePtr = variant; -variant findZoomCurveChecked(const expression::Expression&); +/// Find a zoom curve in the expression tree. +/// @param expr Expression root +/// @return The relevant step or interpolate item, or the error if the expression represents an error +ZoomCurveOrError findZoomCurve(const expression::Expression&); + +/// Find a zoom curve in the expression tree. +/// @param expr Expression root +/// @return The relevant step or interpolate item, or null if the expression represents an error +ZoomCurvePtr findZoomCurveChecked(const expression::Expression& expr); } // namespace expression } // namespace style diff --git a/include/mbgl/style/expression/interpolate.hpp b/include/mbgl/style/expression/interpolate.hpp index 70d3aa0b4..565aa16b4 100644 --- a/include/mbgl/style/expression/interpolate.hpp +++ b/include/mbgl/style/expression/interpolate.hpp @@ -34,6 +34,8 @@ public: } } + std::size_t getStopCount() const { return stops.size(); } + void eachStop(const std::function& visit) const { for (const auto& stop : stops) { visit(stop.first, *stop.second); diff --git a/include/mbgl/style/expression/let.hpp b/include/mbgl/style/expression/let.hpp index 2855b5679..54a97c783 100644 --- a/include/mbgl/style/expression/let.hpp +++ b/include/mbgl/style/expression/let.hpp @@ -17,7 +17,8 @@ public: using Bindings = std::map>; Let(Bindings bindings_, std::unique_ptr result_) - : Expression(Kind::Let, result_->getType(), collectDependencies(bindings_) | Dependency::Bind), + : Expression( + Kind::Let, result_->getType(), collectDependencies(bindings_) | depsOf(result_) | Dependency::Bind), bindings(std::move(bindings_)), result(std::move(result_)) {} diff --git a/include/mbgl/style/expression/step.hpp b/include/mbgl/style/expression/step.hpp index ac47fcd3b..7d0ab4945 100644 --- a/include/mbgl/style/expression/step.hpp +++ b/include/mbgl/style/expression/step.hpp @@ -20,6 +20,8 @@ public: EvaluationResult evaluate(const EvaluationContext& params) const override; void eachChild(const std::function& visit) const override; + + std::size_t getStopCount() const { return stops.size(); } void eachStop(const std::function& visit) const; const std::unique_ptr& getInput() const noexcept { return input; } diff --git a/include/mbgl/style/property_expression.hpp b/include/mbgl/style/property_expression.hpp index 6730b8e8b..f645442d0 100644 --- a/include/mbgl/style/property_expression.hpp +++ b/include/mbgl/style/property_expression.hpp @@ -5,45 +5,75 @@ #include #include #include +#include #include +#if MLN_DRAWABLE_RENDERER +#include +#endif // MLN_DRAWABLE_RENDERER + #include namespace mbgl { +namespace gfx { +class GPUExpression; +using UniqueGPUExpression = std::unique_ptr; +} // namespace gfx + namespace style { class PropertyExpressionBase { public: - explicit PropertyExpressionBase(std::unique_ptr) noexcept; + using Expression = expression::Expression; + using Dependency = expression::Dependency; + using ZoomCurvePtr = expression::ZoomCurvePtr; + + PropertyExpressionBase(PropertyExpressionBase&&); + PropertyExpressionBase(const PropertyExpressionBase&); + explicit PropertyExpressionBase(std::unique_ptr); + virtual ~PropertyExpressionBase() = default; + + PropertyExpressionBase& operator=(PropertyExpressionBase&&); + PropertyExpressionBase& operator=(const PropertyExpressionBase&); bool isZoomConstant() const noexcept { return isZoomConstant_; } bool isFeatureConstant() const noexcept { return isFeatureConstant_; } bool isRuntimeConstant() const noexcept { return isRuntimeConstant_; } float interpolationFactor(const Range&, float) const noexcept; Range getCoveringStops(float, float) const noexcept; - const expression::Expression& getExpression() const noexcept; + const Expression& getExpression() const noexcept; - /// Can be used for aggregating property expressions from multiple - /// properties(layers) into single match / case expression. Method may - /// be removed if a better way of aggregation is found. - std::shared_ptr getSharedExpression() const noexcept; + bool isGPUCapable() const { return isGPUCapable_; } - bool useIntegerZoom = false; + bool getUseIntegerZoom() const { return useIntegerZoom_; } + void setUseIntegerZoom(bool value) { useIntegerZoom_ = value; } - using Dependency = expression::Dependency; - Dependency getDependencies() const noexcept { - auto v = expression ? expression->dependencies : Dependency::None; - assert(isZoomConstant_ == !(underlying_type(v) & underlying_type(Dependency::Zoom))); - assert(isFeatureConstant_ == !(underlying_type(v) & underlying_type(Dependency::Feature))); - return v; - } + /// Can be used for aggregating property expressions from multiple properties(layers) into single match / case + /// expression. May be removed if a better way of aggregation is found. + std::shared_ptr getSharedExpression() const noexcept; + +#if MLN_DRAWABLE_RENDERER + /// Build a cached GPU representation of the expression, with the same lifetime as this object. + gfx::UniqueGPUExpression getGPUExpression(bool intZoom) const; +#endif // MLN_DRAWABLE_RENDERER + + Dependency getDependencies() const noexcept { return expression ? expression->dependencies : Dependency::None; } + + const ZoomCurvePtr& getZoomCurve() const { return zoomCurve; } protected: - std::shared_ptr expression; + std::shared_ptr expression; + + ZoomCurvePtr zoomCurve; + + bool useIntegerZoom_ = false; bool isZoomConstant_; bool isFeatureConstant_; bool isRuntimeConstant_; - variant zoomCurve; + + // If the expression depends on zoom and nothing else, and produces + // a number or color, we can potentially evaluate it on the GPU + bool isGPUCapable_; }; template @@ -52,8 +82,7 @@ class PropertyExpression final : public PropertyExpressionBase { public: // Second parameter to be used only for conversions from legacy functions. - PropertyExpression(std::unique_ptr expression_, - std::optional defaultValue_ = std::nullopt) noexcept + PropertyExpression(std::unique_ptr expression_, std::optional defaultValue_ = std::nullopt) : PropertyExpressionBase(std::move(expression_)), defaultValue(std::move(defaultValue_)) {} diff --git a/include/mbgl/style/property_value.hpp b/include/mbgl/style/property_value.hpp index 3f51c5bbc..fce64f0d7 100644 --- a/include/mbgl/style/property_value.hpp +++ b/include/mbgl/style/property_value.hpp @@ -49,6 +49,7 @@ public: const T& asConstant() const noexcept { return value.template get(); } + PropertyExpression& asExpression() noexcept { return value.template get>(); } const PropertyExpression& asExpression() const noexcept { return value.template get>(); } template diff --git a/include/mbgl/util/color.hpp b/include/mbgl/util/color.hpp index a09479863..d9150568f 100644 --- a/include/mbgl/util/color.hpp +++ b/include/mbgl/util/color.hpp @@ -27,6 +27,8 @@ public: assert(a_ >= 0.0f); assert(a_ <= 1.0f); } + Color(const float rgba[4]) + : Color(rgba[0], rgba[1], rgba[2], rgba[3]) {} float r = 0.0f; float g = 0.0f; diff --git a/include/mbgl/util/convert.hpp b/include/mbgl/util/convert.hpp index 1ddf5bc99..3536cb8ec 100644 --- a/include/mbgl/util/convert.hpp +++ b/include/mbgl/util/convert.hpp @@ -5,6 +5,7 @@ #include #include #include +#include #include namespace mbgl { @@ -24,5 +25,12 @@ constexpr std::array cast(const std::array& from) { return to; } +/// Convert an `N`-tuple of all `T`s to `array` +template +inline constexpr auto to_array(std::tuple&& tuple) { + return std::apply([](auto&&... x) { return std::array{std::forward(x)...}; }, + std::forward>(tuple)); +} + } // namespace util } // namespace mbgl diff --git a/include/mbgl/util/enum.hpp b/include/mbgl/util/enum.hpp index 468ff25d3..209e07863 100644 --- a/include/mbgl/util/enum.hpp +++ b/include/mbgl/util/enum.hpp @@ -1,5 +1,7 @@ #pragma once +#include + #include #include #include diff --git a/include/mbgl/util/indexed_tuple.hpp b/include/mbgl/util/indexed_tuple.hpp index a1ac364a8..51377d2c7 100644 --- a/include/mbgl/util/indexed_tuple.hpp +++ b/include/mbgl/util/indexed_tuple.hpp @@ -30,31 +30,36 @@ public: static_assert(sizeof...(Is) == sizeof...(Ts), "IndexedTuple size mismatch"); template - auto& get() { - return std::get::value>(*this); + static constexpr std::size_t getIndex() { + return TypeIndex::value; } template - const auto& get() const { - return std::get::value>(*this); + constexpr auto& get() { + return std::get()>(*this); + } + + template + constexpr const auto& get() const { + return std::get()>(*this); } template - IndexedTuple(Us&&... other) + constexpr IndexedTuple(Us&&... other) : std::tuple(std::forward(other)...) {} template - IndexedTuple, TypeList> concat( + constexpr IndexedTuple, TypeList> concat( const IndexedTuple, TypeList>& other) const { return IndexedTuple, TypeList>{get()..., other.template get()...}; } // Help out MSVC++ - bool operator==(const IndexedTuple, TypeList>& other) const { + constexpr bool operator==(const IndexedTuple, TypeList>& other) const { return static_cast&>(*this) == static_cast&>(other); } - bool operator!=(const IndexedTuple, TypeList>& other) const noexcept { + constexpr bool operator!=(const IndexedTuple, TypeList>& other) const { return !(*this == other); } }; diff --git a/include/mbgl/util/suppress_copies.hpp b/include/mbgl/util/suppress_copies.hpp index 0eaf46806..eddb7d471 100644 --- a/include/mbgl/util/suppress_copies.hpp +++ b/include/mbgl/util/suppress_copies.hpp @@ -11,10 +11,18 @@ struct SuppressCopies { SuppressCopies(SuppressCopies const&) noexcept {} SuppressCopies(SuppressCopies&& other) : value(std::forward(other.value)) noexcept {} - SuppressCopies& operator=(SuppressCopies o) noexcept { + SuppressCopies& operator=(T&& o) { + value = std::move(o); + return *this; + } + SuppressCopies& operator=(SuppressCopies o) { std::swap(value, o.value); return *this; } + + T& operator->() noexcept { return value; } + const T& operator->() const noexcept { return value; } + operator T&() noexcept { return value; } T& get() noexcept { return value; } diff --git a/include/mbgl/util/type_list.hpp b/include/mbgl/util/type_list.hpp index 1b594bf7f..ab869bfe3 100644 --- a/include/mbgl/util/type_list.hpp +++ b/include/mbgl/util/type_list.hpp @@ -9,6 +9,7 @@ template struct TypeList { template