GPU Expressions (#2202)
This commit is contained in:
183
src/mbgl/gfx/gpu_expression.cpp
Normal file
183
src/mbgl/gfx/gpu_expression.cpp
Normal file
@@ -0,0 +1,183 @@
|
||||
#include <mbgl/gfx/gpu_expression.hpp>
|
||||
|
||||
#include <mbgl/renderer/paint_property_binder.hpp>
|
||||
#include <mbgl/style/expression/expression.hpp>
|
||||
#include <mbgl/style/expression/interpolate.hpp>
|
||||
#include <mbgl/style/expression/step.hpp>
|
||||
#include <mbgl/style/expression/value.hpp>
|
||||
|
||||
namespace mbgl {
|
||||
namespace gfx {
|
||||
|
||||
using namespace style::expression;
|
||||
|
||||
namespace {
|
||||
|
||||
inline GPUOutputType getOutputType(const Expression& expression) {
|
||||
if (expression.getType().is<type::NumberType>()) {
|
||||
return GPUOutputType::Float;
|
||||
} else {
|
||||
return GPUOutputType::Color;
|
||||
}
|
||||
}
|
||||
|
||||
inline GPUInterpType getInterpType(const Interpolator& interp) {
|
||||
return interp.match(
|
||||
[&](const ExponentialInterpolator& exp) {
|
||||
return (exp.base == 1.0f) ? GPUInterpType::Linear : GPUInterpType::Exponential;
|
||||
},
|
||||
[&](const CubicBezierInterpolator&) { return GPUInterpType::Bezier; });
|
||||
}
|
||||
|
||||
inline float getInterpBase(const Interpolator& interp) {
|
||||
return interp.match([&](const ExponentialInterpolator& exp) { return static_cast<float>(exp.base); },
|
||||
[&](const CubicBezierInterpolator&) { return 0.0f; });
|
||||
}
|
||||
|
||||
// Produce a function for `eachStop` that extracts a single stop into the target expression
|
||||
auto addStop(UniqueGPUExpression& expr, GPUOutputType outType, std::size_t& index) {
|
||||
return [&, outType](double input, const Expression& output) {
|
||||
if (expr) {
|
||||
if (const auto result = output.evaluate(EvaluationContext{/*zoom=*/0.0f})) {
|
||||
const style::expression::Value& value = *result;
|
||||
expr->inputs[index] = static_cast<float>(input);
|
||||
if (outType == GPUOutputType::Float) {
|
||||
assert(value.is<double>());
|
||||
if (value.is<double>()) {
|
||||
expr->stops.floats[index++] = static_cast<float>(value.get<double>());
|
||||
} else {
|
||||
// Evaluation error, cancel
|
||||
expr.reset();
|
||||
}
|
||||
} else if (outType == GPUOutputType::Color) {
|
||||
assert(value.is<Color>());
|
||||
if (value.is<Color>()) {
|
||||
const auto& color = attributeValue(value.get<Color>());
|
||||
std::copy(color.begin(), color.end(), &expr->stops.colors[2 * index++]);
|
||||
} else {
|
||||
// Evaluation error, cancel
|
||||
expr.reset();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
const GPUExpression GPUExpression::empty = {GPUOutputType::Float, 0};
|
||||
|
||||
UniqueGPUExpression GPUExpression::create(GPUOutputType type, std::uint16_t count) {
|
||||
if (1 < count && count <= maxStops) {
|
||||
return std::make_unique<GPUExpression>(type, count);
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
UniqueGPUExpression GPUExpression::create(const Expression& expression, const ZoomCurvePtr& zoomCurve, bool intZoom) {
|
||||
std::size_t index = 0;
|
||||
const auto outType = getOutputType(expression);
|
||||
const auto options = (intZoom ? GPUOptions::IntegerZoom : GPUOptions::None);
|
||||
return zoomCurve.match(
|
||||
[&](const Step* step) {
|
||||
if (step->getStopCount() > maxStops) {
|
||||
return UniqueGPUExpression{};
|
||||
}
|
||||
auto expr = GPUExpression::create(outType, step->getStopCount());
|
||||
expr->options = options;
|
||||
expr->interpolation = GPUInterpType::Step;
|
||||
step->eachStop(addStop(expr, outType, index));
|
||||
return expr;
|
||||
},
|
||||
[&](const Interpolate* interp) {
|
||||
if (interp->getStopCount() > maxStops) {
|
||||
return UniqueGPUExpression{};
|
||||
}
|
||||
auto expr = GPUExpression::create(outType, interp->getStopCount());
|
||||
expr->options = options;
|
||||
expr->interpolation = getInterpType(interp->getInterpolator());
|
||||
expr->interpOptions.exponential.base = getInterpBase(interp->getInterpolator());
|
||||
interp->eachStop(addStop(expr, outType, index));
|
||||
return expr;
|
||||
},
|
||||
[](std::nullptr_t) { return UniqueGPUExpression{}; });
|
||||
}
|
||||
|
||||
float GPUExpression::evaluateFloat(const float zoom) const {
|
||||
const auto index = std::distance(&inputs[0], std::upper_bound(&inputs[0], &inputs[stopCount], zoom));
|
||||
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 Range<double> range{inputs[index - 1], inputs[index]};
|
||||
const ExponentialInterpolator interpolator{interpOptions.exponential.base};
|
||||
const auto t = interpolator.interpolationFactor(range, zoom);
|
||||
return util::Interpolator<float>()(stops.floats[index - 1], stops.floats[index], t);
|
||||
}
|
||||
case GPUInterpType::Bezier:
|
||||
assert(false);
|
||||
return stops.floats[0];
|
||||
}
|
||||
}
|
||||
|
||||
namespace {
|
||||
std::tuple<float, float> unpack_float(const float packedValue) {
|
||||
const int packedIntValue = int(packedValue);
|
||||
const int v0 = packedIntValue / 256;
|
||||
return {static_cast<float>(v0) / 255, static_cast<float>(packedIntValue - v0 * 256) / 255};
|
||||
}
|
||||
std::tuple<float, float, float, float> decode_color(const float encoded[2]) {
|
||||
return std::tuple_cat(unpack_float(encoded[0]), unpack_float(encoded[1]));
|
||||
}
|
||||
Color toColor(std::tuple<float, float, float, float> rgba) {
|
||||
return {std::get<0>(rgba), std::get<1>(rgba), std::get<2>(rgba), std::get<3>(rgba)};
|
||||
}
|
||||
} // namespace
|
||||
|
||||
Color GPUExpression::getColor(std::size_t index) const {
|
||||
return toColor(decode_color(&stops.colors[2 * index]));
|
||||
}
|
||||
|
||||
Color GPUExpression::evaluateColor(const float zoom) const {
|
||||
const auto index = std::distance(&inputs[0], std::upper_bound(&inputs[0], &inputs[stopCount], zoom));
|
||||
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 Range<double> range{inputs[index - 1], inputs[index]};
|
||||
const ExponentialInterpolator interpolator{interpOptions.exponential.base};
|
||||
const auto t = interpolator.interpolationFactor(range, zoom);
|
||||
return util::Interpolator<Color>()(getColor(index - 1), getColor(index), t);
|
||||
break;
|
||||
}
|
||||
case GPUInterpType::Bezier:
|
||||
assert(false);
|
||||
return getColor(0);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace gfx
|
||||
} // namespace mbgl
|
||||
@@ -57,23 +57,44 @@ RenderingStats& RenderingStats::operator+=(const RenderingStats& r) {
|
||||
}
|
||||
|
||||
#if !defined(NDEBUG)
|
||||
template <typename T>
|
||||
std::ostream& optionalStatLine(std::ostream& stream, T value, std::string_view label, std::string_view sep) {
|
||||
if (value) {
|
||||
stream << label << " = " << value << sep;
|
||||
}
|
||||
return stream;
|
||||
}
|
||||
std::string RenderingStats::toString(std::string_view sep) const {
|
||||
std::stringstream ss;
|
||||
ss << "numFrames = " << numFrames << sep << "numDrawCalls = " << numDrawCalls << sep
|
||||
<< "totalDrawCalls = " << totalDrawCalls << sep << "numCreatedTextures = " << numCreatedTextures << sep
|
||||
<< "numActiveTextures = " << numActiveTextures << sep << "numTextureBindings = " << numTextureBindings << sep
|
||||
<< "numTextureUpdates = " << numTextureUpdates << sep << "textureUpdateBytes = " << textureUpdateBytes << sep
|
||||
<< "totalBuffers = " << totalBuffers << sep << "totalBufferObjs = " << totalBufferObjs << sep
|
||||
<< "bufferUpdates = " << bufferUpdates << sep << "bufferObjUpdates = " << bufferObjUpdates << sep
|
||||
<< "bufferUpdateBytes = " << bufferUpdateBytes << sep << "numBuffers = " << numBuffers << sep
|
||||
<< "numFrameBuffers = " << numFrameBuffers << sep << "numIndexBuffers = " << numIndexBuffers << sep
|
||||
<< "indexUpdateBytes = " << indexUpdateBytes << sep << "numVertexBuffers = " << numVertexBuffers << sep
|
||||
<< "vertexUpdateBytes = " << vertexUpdateBytes << sep << "numUniformBuffers = " << numUniformBuffers << sep
|
||||
<< "numUniformUpdates = " << numUniformUpdates << sep << "uniformUpdateBytes = " << uniformUpdateBytes << sep
|
||||
<< "memTextures = " << memTextures << sep << "memBuffers = " << memBuffers << sep
|
||||
<< "memIndexBuffers = " << memIndexBuffers << sep << "memVertexBuffers = " << memVertexBuffers << sep
|
||||
<< "memUniformBuffers = " << memUniformBuffers << sep << "stencilClears = " << stencilClears << sep
|
||||
<< "stencilUpdates = " << stencilUpdates << sep;
|
||||
optionalStatLine(ss, numFrames, "numFrames", sep);
|
||||
optionalStatLine(ss, numDrawCalls, "numDrawCalls", sep);
|
||||
optionalStatLine(ss, totalDrawCalls, "totalDrawCalls", sep);
|
||||
optionalStatLine(ss, numCreatedTextures, "numCreatedTextures", sep);
|
||||
optionalStatLine(ss, numActiveTextures, "numActiveTextures", sep);
|
||||
optionalStatLine(ss, numTextureBindings, "numTextureBindings", sep);
|
||||
optionalStatLine(ss, numTextureUpdates, "numTextureUpdates", sep);
|
||||
optionalStatLine(ss, textureUpdateBytes, "textureUpdateBytes", sep);
|
||||
optionalStatLine(ss, totalBuffers, "totalBuffers", sep);
|
||||
optionalStatLine(ss, totalBufferObjs, "totalBufferObjs", sep);
|
||||
optionalStatLine(ss, bufferUpdates, "bufferUpdates", sep);
|
||||
optionalStatLine(ss, bufferObjUpdates, "bufferObjUpdates", sep);
|
||||
optionalStatLine(ss, bufferUpdateBytes, "bufferUpdateBytes", sep);
|
||||
optionalStatLine(ss, numBuffers, "numBuffers", sep);
|
||||
optionalStatLine(ss, numFrameBuffers, "numFrameBuffers", sep);
|
||||
optionalStatLine(ss, numIndexBuffers, "numIndexBuffers", sep);
|
||||
optionalStatLine(ss, indexUpdateBytes, "indexUpdateBytes", sep);
|
||||
optionalStatLine(ss, numVertexBuffers, "numVertexBuffers", sep);
|
||||
optionalStatLine(ss, vertexUpdateBytes, "vertexUpdateBytes", sep);
|
||||
optionalStatLine(ss, numUniformBuffers, "numUniformBuffers", sep);
|
||||
optionalStatLine(ss, numUniformUpdates, "numUniformUpdates", sep);
|
||||
optionalStatLine(ss, uniformUpdateBytes, "uniformUpdateBytes", sep);
|
||||
optionalStatLine(ss, memTextures, "memTextures", sep);
|
||||
optionalStatLine(ss, memBuffers, "memBuffers", sep);
|
||||
optionalStatLine(ss, memIndexBuffers, "memIndexBuffers", sep);
|
||||
optionalStatLine(ss, memVertexBuffers, "memVertexBuffers", sep);
|
||||
optionalStatLine(ss, memUniformBuffers, "memUniformBuffers", sep);
|
||||
optionalStatLine(ss, stencilClears, "stencilClears", sep);
|
||||
optionalStatLine(ss, stencilUpdates, "stencilUpdates", sep);
|
||||
return ss.str();
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -22,8 +22,7 @@ void logStyleDependencies(EventSeverity severity, Event event, const style::Styl
|
||||
counts[0]++;
|
||||
} else {
|
||||
for (size_t i = 0; i < maskCount; ++i) {
|
||||
const auto mask = Dependency{1u << i};
|
||||
if ((deps & mask) == mask) {
|
||||
if (deps & Dependency{1u << i}) {
|
||||
counts[i + 1]++;
|
||||
}
|
||||
}
|
||||
@@ -33,7 +32,9 @@ void logStyleDependencies(EventSeverity severity, Event event, const style::Styl
|
||||
ss << "Style '" << style.getName() << "' has " << layers.size() << " layers:\n";
|
||||
ss << " " << Dependency::None << ": " << counts[0] << "\n";
|
||||
for (size_t i = 0; i < maskCount; ++i) {
|
||||
ss << " " << Dependency{1u << i} << ": " << counts[i + 1] << "\n";
|
||||
if (counts[i + 1]) {
|
||||
ss << " " << Dependency{1u << i} << ": " << counts[i + 1] << "\n";
|
||||
}
|
||||
}
|
||||
Log::Record(severity, event, ss.str());
|
||||
}
|
||||
|
||||
@@ -17,6 +17,7 @@ template <typename T>
|
||||
class CrossFadedPropertyEvaluator {
|
||||
public:
|
||||
using ResultType = Faded<T>;
|
||||
static constexpr bool useIntegerZoom = false;
|
||||
|
||||
CrossFadedPropertyEvaluator(const PropertyEvaluationParameters& parameters_, T defaultValue_)
|
||||
: parameters(parameters_),
|
||||
|
||||
@@ -9,10 +9,11 @@
|
||||
|
||||
namespace mbgl {
|
||||
|
||||
template <typename T, bool useIntegerZoom = false>
|
||||
template <typename T, bool useIntegerZoom_ = false>
|
||||
class DataDrivenPropertyEvaluator {
|
||||
public:
|
||||
using ResultType = PossiblyEvaluatedPropertyValue<T>;
|
||||
static constexpr bool useIntegerZoom = useIntegerZoom_;
|
||||
|
||||
DataDrivenPropertyEvaluator(const PropertyEvaluationParameters& parameters_, T defaultValue_)
|
||||
: parameters(parameters_),
|
||||
@@ -26,7 +27,7 @@ public:
|
||||
if constexpr (useIntegerZoom) { // Compiler will optimize out the unused branch.
|
||||
if (!expression.isFeatureConstant() || !expression.isRuntimeConstant()) {
|
||||
auto returnExpression = expression;
|
||||
returnExpression.useIntegerZoom = true;
|
||||
returnExpression.setUseIntegerZoom(true);
|
||||
return ResultType(returnExpression);
|
||||
}
|
||||
return ResultType(expression.evaluate(std::floor(parameters.z)));
|
||||
@@ -47,6 +48,7 @@ template <typename T>
|
||||
class DataDrivenPropertyEvaluator<Faded<T>> {
|
||||
public:
|
||||
using ResultType = PossiblyEvaluatedPropertyValue<Faded<T>>;
|
||||
static constexpr bool useIntegerZoom = false;
|
||||
|
||||
DataDrivenPropertyEvaluator(const PropertyEvaluationParameters& parameters_, T defaultValue_)
|
||||
: parameters(parameters_),
|
||||
|
||||
@@ -15,6 +15,8 @@ ImagePosition::ImagePosition(const mapbox::Bin& bin, const style::Image::Impl& i
|
||||
stretchY(image.stretchY),
|
||||
content(image.content) {}
|
||||
|
||||
namespace {
|
||||
|
||||
const mapbox::Bin& _packImage(mapbox::ShelfPack& pack,
|
||||
const style::Image::Impl& image,
|
||||
ImageAtlas& resultImage,
|
||||
@@ -26,12 +28,13 @@ const mapbox::Bin& _packImage(mapbox::ShelfPack& pack,
|
||||
|
||||
PremultipliedImage::copy(
|
||||
image.image, resultImage.image, {0, 0}, {bin.x + padding, bin.y + padding}, image.image.size);
|
||||
uint32_t x = bin.x + padding;
|
||||
uint32_t y = bin.y + padding;
|
||||
uint32_t w = image.image.size.width;
|
||||
uint32_t h = image.image.size.height;
|
||||
|
||||
if (imageType == ImageType::Pattern) {
|
||||
const uint32_t x = bin.x + padding;
|
||||
const uint32_t y = bin.y + padding;
|
||||
const uint32_t w = image.image.size.width;
|
||||
const uint32_t h = image.image.size.height;
|
||||
|
||||
// Add 1 pixel wrapped padding on each side of the image.
|
||||
PremultipliedImage::copy(image.image, resultImage.image, {0, h - 1}, {x, y - 1}, {w, 1}); // T
|
||||
PremultipliedImage::copy(image.image, resultImage.image, {0, 0}, {x, y + h}, {w, 1}); // B
|
||||
@@ -41,8 +44,6 @@ const mapbox::Bin& _packImage(mapbox::ShelfPack& pack,
|
||||
return bin;
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
void populateImagePatches(ImagePositions& imagePositions,
|
||||
const ImageManager& imageManager,
|
||||
std::vector<ImagePatch>& /*out*/ patches) {
|
||||
|
||||
@@ -10,7 +10,9 @@
|
||||
|
||||
namespace mbgl {
|
||||
|
||||
static ImageManagerObserver nullObserver;
|
||||
namespace {
|
||||
ImageManagerObserver nullObserver;
|
||||
} // namespace
|
||||
|
||||
ImageManager::ImageManager() = default;
|
||||
|
||||
|
||||
@@ -23,30 +23,135 @@ namespace mbgl {
|
||||
using namespace style;
|
||||
using namespace shaders;
|
||||
|
||||
#if MLN_RENDER_BACKEND_METAL && !defined(NDEBUG)
|
||||
constexpr bool diff(float actual, float expected, float e = 1.0e-6) {
|
||||
return actual != expected && (expected == 0 || std::fabs((actual - expected) / expected) > e);
|
||||
}
|
||||
constexpr bool diff(Color actual, Color expected, float e = 1.0e-6) {
|
||||
return diff(actual.r, expected.r, e) || diff(actual.g, expected.g, e) || diff(actual.b, expected.b, e) ||
|
||||
diff(actual.a, expected.a, e);
|
||||
}
|
||||
#endif // MLN_RENDER_BACKEND_METAL
|
||||
|
||||
#if MLN_RENDER_BACKEND_METAL && !defined(NDEBUG)
|
||||
template <typename Result>
|
||||
std::optional<Result> LineLayerTweaker::gpuEvaluate(const LinePaintProperties::PossiblyEvaluated& evaluated,
|
||||
const PaintParameters& parameters,
|
||||
const std::size_t index) const {
|
||||
if (const auto& gpu = gpuExpressions[index]) {
|
||||
const float effectiveZoom = (gpu->options & gfx::GPUOptions::IntegerZoom)
|
||||
? parameters.state.getIntegerZoom()
|
||||
: static_cast<float>(parameters.state.getZoom());
|
||||
return gpu->template evaluate<Result>(effectiveZoom);
|
||||
}
|
||||
return {};
|
||||
}
|
||||
#endif // MLN_RENDER_BACKEND_METAL
|
||||
|
||||
template <typename Property>
|
||||
auto LineLayerTweaker::evaluate([[maybe_unused]] const PaintParameters& parameters) const {
|
||||
const auto& evaluated = static_cast<const LineLayerProperties&>(*evaluatedProperties).evaluated;
|
||||
|
||||
#if MLN_RENDER_BACKEND_METAL && !defined(NDEBUG)
|
||||
constexpr auto index = propertyIndex<Property>();
|
||||
if (auto gpuValue = gpuEvaluate<typename Property::Type>(evaluated, parameters, index)) {
|
||||
assert(!diff(*gpuValue, evaluated.get<Property>().constantOr(Property::defaultValue())));
|
||||
return *gpuValue;
|
||||
}
|
||||
#endif // MLN_RENDER_BACKEND_METAL
|
||||
|
||||
return evaluated.get<Property>().constantOr(Property::defaultValue());
|
||||
}
|
||||
|
||||
void LineLayerTweaker::execute(LayerGroupBase& layerGroup, const PaintParameters& parameters) {
|
||||
auto& context = parameters.context;
|
||||
const auto zoom = parameters.state.getZoom();
|
||||
const auto& evaluated = static_cast<const LineLayerProperties&>(*evaluatedProperties).evaluated;
|
||||
const auto& crossfade = static_cast<const LineLayerProperties&>(*evaluatedProperties).crossfade;
|
||||
|
||||
// Each property UBO is updated at most once if new evaluated properties were set
|
||||
const auto zoom = static_cast<float>(parameters.state.getZoom());
|
||||
const auto intZoom = parameters.state.getIntegerZoom();
|
||||
|
||||
#if MLN_RENDER_BACKEND_METAL
|
||||
const auto getExpressionBuffer = [&]() {
|
||||
const bool enableEval = gfx::Backend::getEnableGPUExpressionEval();
|
||||
if (!expressionUniformBuffer || (gpuExpressionsUpdated && enableEval)) {
|
||||
LineExpressionUBO exprUBO = {
|
||||
/* color = */ enableEval ? gpuExpressions[propertyIndex<LineColor>()].get() : nullptr,
|
||||
/* blur = */ enableEval ? gpuExpressions[propertyIndex<LineBlur>()].get() : nullptr,
|
||||
/* opacity = */ enableEval ? gpuExpressions[propertyIndex<LineOpacity>()].get() : nullptr,
|
||||
/* gapwidth = */ enableEval ? gpuExpressions[propertyIndex<LineGapWidth>()].get() : nullptr,
|
||||
/* offset = */ enableEval ? gpuExpressions[propertyIndex<LineOffset>()].get() : nullptr,
|
||||
/* width = */ enableEval ? gpuExpressions[propertyIndex<LineWidth>()].get() : nullptr,
|
||||
/* floorWidth = */ enableEval ? gpuExpressions[propertyIndex<LineFloorWidth>()].get() : nullptr,
|
||||
};
|
||||
context.emplaceOrUpdateUniformBuffer(expressionUniformBuffer, &exprUBO);
|
||||
gpuExpressionsUpdated = false;
|
||||
}
|
||||
return expressionUniformBuffer;
|
||||
};
|
||||
#endif // MLN_RENDER_BACKEND_METAL
|
||||
|
||||
if (!evaluatedPropsUniformBuffer || propertiesUpdated) {
|
||||
const LineEvaluatedPropsUBO propsUBO = {
|
||||
/*color =*/evaluated.get<LineColor>().constantOr(LineColor::defaultValue()),
|
||||
/*blur =*/evaluated.get<LineBlur>().constantOr(LineBlur::defaultValue()),
|
||||
/*opacity =*/evaluated.get<LineOpacity>().constantOr(LineOpacity::defaultValue()),
|
||||
/*gapwidth =*/evaluated.get<LineGapWidth>().constantOr(LineGapWidth::defaultValue()),
|
||||
/*offset =*/evaluated.get<LineOffset>().constantOr(LineOffset::defaultValue()),
|
||||
/*width =*/evaluated.get<LineWidth>().constantOr(LineWidth::defaultValue()),
|
||||
/*floorwidth =*/evaluated.get<LineFloorWidth>().constantOr(LineFloorWidth::defaultValue()),
|
||||
0,
|
||||
#if MLN_RENDER_BACKEND_METAL
|
||||
expressionMask =
|
||||
!gfx::Backend::getEnableGPUExpressionEval()
|
||||
? LineExpressionMask::None
|
||||
: ((gpuExpressions[propertyIndex<LineColor>()] ? LineExpressionMask::Color : LineExpressionMask::None) |
|
||||
(gpuExpressions[propertyIndex<LineBlur>()] ? LineExpressionMask::Blur : LineExpressionMask::None) |
|
||||
(gpuExpressions[propertyIndex<LineOpacity>()] ? LineExpressionMask::Opacity
|
||||
: LineExpressionMask::None) |
|
||||
(gpuExpressions[propertyIndex<LineGapWidth>()] ? LineExpressionMask::GapWidth
|
||||
: LineExpressionMask::None) |
|
||||
(gpuExpressions[propertyIndex<LineOffset>()] ? LineExpressionMask::Offset
|
||||
: LineExpressionMask::None) |
|
||||
(gpuExpressions[propertyIndex<LineWidth>()] ? LineExpressionMask::Width : LineExpressionMask::None) |
|
||||
(gpuExpressions[propertyIndex<LineFloorWidth>()] ? LineExpressionMask::FloorWidth
|
||||
: LineExpressionMask::None));
|
||||
const LineEvaluatedPropsUBO propsUBO{
|
||||
/*color =*/(expressionMask & LineExpressionMask::Color) ? LineColor::defaultValue()
|
||||
: evaluate<LineColor>(parameters),
|
||||
/*blur =*/
|
||||
(expressionMask & LineExpressionMask::Blur) ? LineBlur::defaultValue() : evaluate<LineBlur>(parameters),
|
||||
/*opacity =*/
|
||||
(expressionMask & LineExpressionMask::Opacity) ? LineOpacity::defaultValue()
|
||||
: evaluate<LineOpacity>(parameters),
|
||||
/*gapwidth =*/
|
||||
(expressionMask & LineExpressionMask::GapWidth) ? LineGapWidth::defaultValue()
|
||||
: evaluate<LineGapWidth>(parameters),
|
||||
/*offset =*/
|
||||
(expressionMask & LineExpressionMask::Offset) ? LineOffset::defaultValue()
|
||||
: evaluate<LineOffset>(parameters),
|
||||
/*width =*/
|
||||
(expressionMask & LineExpressionMask::Width) ? LineWidth::defaultValue() : evaluate<LineWidth>(parameters),
|
||||
/*floorwidth =*/
|
||||
(expressionMask & LineExpressionMask::FloorWidth) ? LineFloorWidth::defaultValue()
|
||||
: evaluate<LineFloorWidth>(parameters),
|
||||
expressionMask,
|
||||
0};
|
||||
#else
|
||||
const LineEvaluatedPropsUBO propsUBO{/*color =*/evaluate<LineColor>(parameters),
|
||||
/*blur =*/evaluate<LineBlur>(parameters),
|
||||
/*opacity =*/evaluate<LineOpacity>(parameters),
|
||||
/*gapwidth =*/evaluate<LineGapWidth>(parameters),
|
||||
/*offset =*/evaluate<LineOffset>(parameters),
|
||||
/*width =*/evaluate<LineWidth>(parameters),
|
||||
/*floorwidth =*/evaluate<LineFloorWidth>(parameters),
|
||||
LineExpressionMask::None,
|
||||
0};
|
||||
#endif // MLN_RENDER_BACKEND_METAL
|
||||
|
||||
context.emplaceOrUpdateUniformBuffer(evaluatedPropsUniformBuffer, &propsUBO);
|
||||
propertiesUpdated = false;
|
||||
}
|
||||
auto& layerUniforms = layerGroup.mutableUniformBuffers();
|
||||
|
||||
layerUniforms.set(idLineEvaluatedPropsUBO, evaluatedPropsUniformBuffer);
|
||||
|
||||
#if MLN_RENDER_BACKEND_METAL
|
||||
// GPU Expressions
|
||||
layerUniforms.set(idLineExpressionUBO, getExpressionBuffer());
|
||||
#endif // MLN_RENDER_BACKEND_METAL
|
||||
|
||||
visitLayerGroupDrawables(layerGroup, [&](gfx::Drawable& drawable) {
|
||||
const auto shader = drawable.getShader();
|
||||
if (!drawable.getTileID() || !shader || !checkTweakDrawable(drawable)) {
|
||||
@@ -83,7 +188,6 @@ void LineLayerTweaker::execute(LayerGroupBase& layerGroup, const PaintParameters
|
||||
0,
|
||||
0};
|
||||
drawableUniforms.createOrUpdate(idLineDrawableUBO, &drawableUBO, context);
|
||||
;
|
||||
} break;
|
||||
|
||||
case LineType::Pattern: {
|
||||
@@ -95,7 +199,7 @@ void LineLayerTweaker::execute(LayerGroupBase& layerGroup, const PaintParameters
|
||||
/*matrix =*/util::cast<float>(matrix),
|
||||
/*scale =*/
|
||||
{parameters.pixelRatio,
|
||||
1 / tileID.pixelsToTileUnits(1, parameters.state.getIntegerZoom()),
|
||||
1 / tileID.pixelsToTileUnits(1, intZoom),
|
||||
crossfade.fromScale,
|
||||
crossfade.toScale},
|
||||
/*texsize =*/{static_cast<float>(textureSize.width), static_cast<float>(textureSize.height)},
|
||||
@@ -128,12 +232,10 @@ void LineLayerTweaker::execute(LayerGroupBase& layerGroup, const PaintParameters
|
||||
const LineSDFDrawableUBO drawableUBO{
|
||||
/* matrix = */ util::cast<float>(matrix),
|
||||
/* patternscale_a = */
|
||||
{1.0f / tileID.pixelsToTileUnits(widthA, parameters.state.getIntegerZoom()),
|
||||
-posA.height / 2.0f},
|
||||
{1.0f / tileID.pixelsToTileUnits(widthA, intZoom), -posA.height / 2.0f},
|
||||
/* patternscale_b = */
|
||||
{1.0f / tileID.pixelsToTileUnits(widthB, parameters.state.getIntegerZoom()),
|
||||
-posB.height / 2.0f},
|
||||
/* ratio = */ 1.0f / tileID.pixelsToTileUnits(1.0f, static_cast<float>(zoom)),
|
||||
{1.0f / tileID.pixelsToTileUnits(widthB, intZoom), -posB.height / 2.0f},
|
||||
/* ratio = */ 1.0f / tileID.pixelsToTileUnits(1.0f, zoom),
|
||||
/* tex_y_a = */ posA.y,
|
||||
/* tex_y_b = */ posB.y,
|
||||
/* sdfgamma = */ static_cast<float>(dashPatternTexture.getSize().width) /
|
||||
@@ -155,4 +257,18 @@ void LineLayerTweaker::execute(LayerGroupBase& layerGroup, const PaintParameters
|
||||
});
|
||||
}
|
||||
|
||||
#if MLN_RENDER_BACKEND_METAL
|
||||
void LineLayerTweaker::updateGPUExpressions(const Unevaluated& unevaluated, TimePoint now) {
|
||||
if (gfx::Backend::getEnableGPUExpressionEval()) {
|
||||
if (unevaluated.updateGPUExpressions(gpuExpressions, now)) {
|
||||
gpuExpressionsUpdated = true;
|
||||
|
||||
// Masks also need to be updated
|
||||
propertiesUpdated = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif // MLN_RENDER_BACKEND_METAL
|
||||
|
||||
} // namespace mbgl
|
||||
|
||||
@@ -1,8 +1,13 @@
|
||||
#pragma once
|
||||
|
||||
#include <mbgl/renderer/layer_tweaker.hpp>
|
||||
#include <mbgl/style/layers/line_layer_properties.hpp>
|
||||
|
||||
#include <string_view>
|
||||
#if MLN_RENDER_BACKEND_METAL
|
||||
#include <mbgl/shaders/line_layer_ubo.hpp>
|
||||
#endif // MLN_RENDER_BACKEND_METAL
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace mbgl {
|
||||
|
||||
@@ -30,8 +35,37 @@ public:
|
||||
|
||||
void execute(LayerGroupBase&, const PaintParameters&) override;
|
||||
|
||||
#if MLN_RENDER_BACKEND_METAL
|
||||
using LinePaintProperties = style::LinePaintProperties;
|
||||
using Unevaluated = LinePaintProperties::Unevaluated;
|
||||
void updateGPUExpressions(const Unevaluated&, TimePoint now);
|
||||
|
||||
template <typename T>
|
||||
static constexpr std::size_t propertyIndex() {
|
||||
return LinePaintProperties::Tuple<LinePaintProperties::PropertyTypes>::getIndex<T>();
|
||||
}
|
||||
#endif // MLN_RENDER_BACKEND_METAL
|
||||
|
||||
private:
|
||||
template <typename Property>
|
||||
auto evaluate(const PaintParameters& parameters) const;
|
||||
|
||||
#if MLN_RENDER_BACKEND_METAL
|
||||
template <typename Result>
|
||||
std::optional<Result> gpuEvaluate(const LinePaintProperties::PossiblyEvaluated&,
|
||||
const PaintParameters&,
|
||||
const std::size_t index) const;
|
||||
#endif // MLN_RENDER_BACKEND_METAL
|
||||
|
||||
protected:
|
||||
gfx::UniformBufferPtr evaluatedPropsUniformBuffer;
|
||||
|
||||
#if MLN_RENDER_BACKEND_METAL
|
||||
gfx::UniformBufferPtr expressionUniformBuffer;
|
||||
Unevaluated::GPUExpressions gpuExpressions;
|
||||
shaders::LineExpressionMask expressionMask = shaders::LineExpressionMask::None;
|
||||
bool gpuExpressionsUpdated = true;
|
||||
#endif // MLN_RENDER_BACKEND_METAL
|
||||
};
|
||||
|
||||
} // namespace mbgl
|
||||
|
||||
@@ -53,7 +53,8 @@ void RenderBackgroundLayer::transition(const TransitionParameters& parameters) {
|
||||
}
|
||||
|
||||
void RenderBackgroundLayer::evaluate(const PropertyEvaluationParameters& parameters) {
|
||||
auto evaluated = unevaluated.evaluate(parameters);
|
||||
const auto previousProperties = staticImmutableCast<BackgroundLayerProperties>(evaluatedProperties);
|
||||
auto evaluated = unevaluated.evaluate(parameters, previousProperties->evaluated);
|
||||
auto properties = makeMutable<BackgroundLayerProperties>(
|
||||
staticImmutableCast<BackgroundLayer::Impl>(baseImpl), parameters.getCrossfadeParameters(), evaluated);
|
||||
|
||||
|
||||
@@ -71,8 +71,10 @@ void RenderCircleLayer::transition(const TransitionParameters& parameters) {
|
||||
}
|
||||
|
||||
void RenderCircleLayer::evaluate(const PropertyEvaluationParameters& parameters) {
|
||||
auto properties = makeMutable<CircleLayerProperties>(staticImmutableCast<CircleLayer::Impl>(baseImpl),
|
||||
unevaluated.evaluate(parameters));
|
||||
const auto previousProperties = staticImmutableCast<CircleLayerProperties>(evaluatedProperties);
|
||||
auto properties = makeMutable<CircleLayerProperties>(
|
||||
staticImmutableCast<CircleLayer::Impl>(baseImpl),
|
||||
unevaluated.evaluate(parameters, previousProperties->evaluated));
|
||||
const auto& evaluated = properties->evaluated;
|
||||
|
||||
passes = ((evaluated.get<style::CircleRadius>().constantOr(1) > 0 ||
|
||||
|
||||
@@ -58,9 +58,11 @@ void RenderFillExtrusionLayer::transition(const TransitionParameters& parameters
|
||||
}
|
||||
|
||||
void RenderFillExtrusionLayer::evaluate(const PropertyEvaluationParameters& parameters) {
|
||||
auto properties = makeMutable<FillExtrusionLayerProperties>(staticImmutableCast<FillExtrusionLayer::Impl>(baseImpl),
|
||||
parameters.getCrossfadeParameters(),
|
||||
unevaluated.evaluate(parameters));
|
||||
const auto previousProperties = staticImmutableCast<FillExtrusionLayerProperties>(evaluatedProperties);
|
||||
auto properties = makeMutable<FillExtrusionLayerProperties>(
|
||||
staticImmutableCast<FillExtrusionLayer::Impl>(baseImpl),
|
||||
parameters.getCrossfadeParameters(),
|
||||
unevaluated.evaluate(parameters, previousProperties->evaluated));
|
||||
|
||||
passes = (properties->evaluated.get<style::FillExtrusionOpacity>() > 0)
|
||||
? (RenderPass::Translucent | RenderPass::Pass3D)
|
||||
|
||||
@@ -69,9 +69,10 @@ void RenderFillLayer::transition(const TransitionParameters& parameters) {
|
||||
}
|
||||
|
||||
void RenderFillLayer::evaluate(const PropertyEvaluationParameters& parameters) {
|
||||
const auto previousProperties = staticImmutableCast<FillLayerProperties>(evaluatedProperties);
|
||||
auto properties = makeMutable<FillLayerProperties>(staticImmutableCast<FillLayer::Impl>(baseImpl),
|
||||
parameters.getCrossfadeParameters(),
|
||||
unevaluated.evaluate(parameters));
|
||||
unevaluated.evaluate(parameters, previousProperties->evaluated));
|
||||
auto& evaluated = properties->evaluated;
|
||||
|
||||
if (unevaluated.get<style::FillOutlineColor>().isUndefined()) {
|
||||
|
||||
@@ -63,8 +63,10 @@ void RenderHeatmapLayer::layerChanged(const TransitionParameters& parameters,
|
||||
#endif
|
||||
|
||||
void RenderHeatmapLayer::evaluate(const PropertyEvaluationParameters& parameters) {
|
||||
auto properties = makeMutable<HeatmapLayerProperties>(staticImmutableCast<HeatmapLayer::Impl>(baseImpl),
|
||||
unevaluated.evaluate(parameters));
|
||||
const auto previousProperties = staticImmutableCast<HeatmapLayerProperties>(evaluatedProperties);
|
||||
auto properties = makeMutable<HeatmapLayerProperties>(
|
||||
staticImmutableCast<HeatmapLayer::Impl>(baseImpl),
|
||||
unevaluated.evaluate(parameters, previousProperties->evaluated));
|
||||
|
||||
passes = (properties->evaluated.get<style::HeatmapOpacity>() > 0) ? (RenderPass::Translucent | RenderPass::Pass3D)
|
||||
: RenderPass::None;
|
||||
|
||||
@@ -77,8 +77,11 @@ void RenderHillshadeLayer::layerChanged(const TransitionParameters& parameters,
|
||||
#endif
|
||||
|
||||
void RenderHillshadeLayer::evaluate(const PropertyEvaluationParameters& parameters) {
|
||||
auto properties = makeMutable<HillshadeLayerProperties>(staticImmutableCast<HillshadeLayer::Impl>(baseImpl),
|
||||
unevaluated.evaluate(parameters));
|
||||
const auto previousProperties = staticImmutableCast<HillshadeLayerProperties>(evaluatedProperties);
|
||||
auto properties = makeMutable<HillshadeLayerProperties>(
|
||||
staticImmutableCast<HillshadeLayer::Impl>(baseImpl),
|
||||
unevaluated.evaluate(parameters, previousProperties->evaluated));
|
||||
|
||||
passes = (properties->evaluated.get<style::HillshadeExaggeration>() > 0)
|
||||
? (RenderPass::Translucent | RenderPass::Pass3D)
|
||||
: RenderPass::None;
|
||||
|
||||
@@ -64,12 +64,19 @@ RenderLineLayer::~RenderLineLayer() = default;
|
||||
void RenderLineLayer::transition(const TransitionParameters& parameters) {
|
||||
unevaluated = impl_cast(baseImpl).paint.transitioned(parameters, std::move(unevaluated));
|
||||
updateColorRamp();
|
||||
|
||||
#if MLN_RENDER_BACKEND_METAL
|
||||
if (auto* tweaker = static_cast<LineLayerTweaker*>(layerTweaker.get())) {
|
||||
tweaker->updateGPUExpressions(unevaluated, parameters.now);
|
||||
}
|
||||
#endif // MLN_RENDER_BACKEND_METAL
|
||||
}
|
||||
|
||||
void RenderLineLayer::evaluate(const PropertyEvaluationParameters& parameters) {
|
||||
const auto previousProperties = staticImmutableCast<LineLayerProperties>(evaluatedProperties);
|
||||
auto properties = makeMutable<LineLayerProperties>(staticImmutableCast<LineLayer::Impl>(baseImpl),
|
||||
parameters.getCrossfadeParameters(),
|
||||
unevaluated.evaluate(parameters));
|
||||
unevaluated.evaluate(parameters, previousProperties->evaluated));
|
||||
auto& evaluated = properties->evaluated;
|
||||
|
||||
passes = (evaluated.get<style::LineOpacity>().constantOr(1.0) > 0 &&
|
||||
@@ -81,8 +88,11 @@ void RenderLineLayer::evaluate(const PropertyEvaluationParameters& parameters) {
|
||||
evaluatedProperties = std::move(properties);
|
||||
|
||||
#if MLN_DRAWABLE_RENDERER
|
||||
if (layerTweaker) {
|
||||
layerTweaker->updateProperties(evaluatedProperties);
|
||||
if (auto* tweaker = static_cast<LineLayerTweaker*>(layerTweaker.get())) {
|
||||
tweaker->updateProperties(evaluatedProperties);
|
||||
#if MLN_RENDER_BACKEND_METAL
|
||||
tweaker->updateGPUExpressions(unevaluated, parameters.now);
|
||||
#endif // MLN_RENDER_BACKEND_METAL
|
||||
}
|
||||
#endif
|
||||
}
|
||||
@@ -348,7 +358,7 @@ float RenderLineLayer::getLineWidth(const GeometryTileFeature& feature,
|
||||
void RenderLineLayer::update(gfx::ShaderRegistry& shaders,
|
||||
gfx::Context& context,
|
||||
const TransformState& state,
|
||||
const std::shared_ptr<UpdateParameters>&,
|
||||
[[maybe_unused]] const std::shared_ptr<UpdateParameters>& parameters,
|
||||
[[maybe_unused]] const RenderTree& renderTree,
|
||||
[[maybe_unused]] UniqueChangeRequestVec& changes) {
|
||||
if (!renderTiles || renderTiles->empty()) {
|
||||
@@ -367,7 +377,12 @@ void RenderLineLayer::update(gfx::ShaderRegistry& shaders,
|
||||
auto* tileLayerGroup = static_cast<TileLayerGroup*>(layerGroup.get());
|
||||
|
||||
if (!layerTweaker) {
|
||||
layerTweaker = std::make_shared<LineLayerTweaker>(getID(), evaluatedProperties);
|
||||
auto tweaker = std::make_shared<LineLayerTweaker>(getID(), evaluatedProperties);
|
||||
#if MLN_RENDER_BACKEND_METAL
|
||||
tweaker->updateGPUExpressions(unevaluated, parameters->timePoint);
|
||||
#endif // MLN_RENDER_BACKEND_METAL
|
||||
|
||||
layerTweaker = std::move(tweaker);
|
||||
layerGroup->addLayerTweaker(layerTweaker);
|
||||
}
|
||||
|
||||
|
||||
@@ -50,8 +50,11 @@ void RenderRasterLayer::transition(const TransitionParameters& parameters) {
|
||||
}
|
||||
|
||||
void RenderRasterLayer::evaluate(const PropertyEvaluationParameters& parameters) {
|
||||
auto properties = makeMutable<RasterLayerProperties>(staticImmutableCast<RasterLayer::Impl>(baseImpl),
|
||||
unevaluated.evaluate(parameters));
|
||||
const auto previousProperties = staticImmutableCast<RasterLayerProperties>(evaluatedProperties);
|
||||
auto properties = makeMutable<RasterLayerProperties>(
|
||||
staticImmutableCast<RasterLayer::Impl>(baseImpl),
|
||||
unevaluated.evaluate(parameters, previousProperties->evaluated));
|
||||
|
||||
passes = properties->evaluated.get<style::RasterOpacity>() > 0 ? RenderPass::Translucent : RenderPass::None;
|
||||
properties->renderPasses = mbgl::underlying_type(passes);
|
||||
evaluatedProperties = std::move(properties);
|
||||
|
||||
@@ -371,8 +371,11 @@ void RenderSymbolLayer::transition(const TransitionParameters& parameters) {
|
||||
}
|
||||
|
||||
void RenderSymbolLayer::evaluate(const PropertyEvaluationParameters& parameters) {
|
||||
auto properties = makeMutable<SymbolLayerProperties>(staticImmutableCast<SymbolLayer::Impl>(baseImpl),
|
||||
unevaluated.evaluate(parameters));
|
||||
const auto previousProperties = staticImmutableCast<SymbolLayerProperties>(evaluatedProperties);
|
||||
auto properties = makeMutable<SymbolLayerProperties>(
|
||||
staticImmutableCast<SymbolLayer::Impl>(baseImpl),
|
||||
unevaluated.evaluate(parameters, previousProperties->evaluated));
|
||||
|
||||
auto& evaluated = properties->evaluated;
|
||||
const auto& layout = impl_cast(baseImpl).layout;
|
||||
|
||||
|
||||
@@ -476,7 +476,7 @@ public:
|
||||
#endif // MLN_LEGACY_RENDERER
|
||||
|
||||
std::tuple<float> interpolationFactor(float currentZoom) const override {
|
||||
const float possiblyRoundedZoom = expression.useIntegerZoom ? std::floor(currentZoom) : currentZoom;
|
||||
const float possiblyRoundedZoom = expression.getUseIntegerZoom() ? std::floor(currentZoom) : currentZoom;
|
||||
|
||||
return std::tuple<float>{
|
||||
std::fmax(0.0f, std::fmin(1.0f, expression.interpolationFactor(zoomRange, possiblyRoundedZoom)))};
|
||||
|
||||
@@ -34,6 +34,11 @@ public:
|
||||
return value.match(std::forward<Ts>(ts)...);
|
||||
}
|
||||
|
||||
T evaluate(float zoom) const {
|
||||
return this->match([&](const T& constant_) { return constant_; },
|
||||
[&](const style::PropertyExpression<T>& expression) { return expression.evaluate(zoom); });
|
||||
}
|
||||
|
||||
template <class Feature>
|
||||
T evaluate(const Feature& feature, float zoom, T defaultValue) const {
|
||||
return this->match([&](const T& constant_) { return constant_; },
|
||||
|
||||
@@ -41,6 +41,10 @@ public:
|
||||
TimePoint now;
|
||||
ZoomHistory zoomHistory;
|
||||
Duration defaultFadeDuration;
|
||||
|
||||
bool zoomChanged = true;
|
||||
bool layerChanged = false;
|
||||
bool hasCrossfade = true;
|
||||
};
|
||||
|
||||
} // namespace mbgl
|
||||
|
||||
@@ -9,6 +9,7 @@ template <typename T>
|
||||
class PropertyEvaluator {
|
||||
public:
|
||||
using ResultType = T;
|
||||
static constexpr bool useIntegerZoom = false;
|
||||
|
||||
PropertyEvaluator(const PropertyEvaluationParameters& parameters_, T defaultValue_)
|
||||
: parameters(parameters_),
|
||||
|
||||
@@ -175,12 +175,11 @@ std::unique_ptr<RenderTree> RenderOrchestrator::createRenderTree(
|
||||
: TransitionOptions();
|
||||
|
||||
const TransitionParameters transitionParameters{updateParameters->timePoint, transitionOptions};
|
||||
const auto transitionDuration = transitionOptions.duration.value_or(
|
||||
isMapModeContinuous ? util::DEFAULT_TRANSITION_DURATION : Duration::zero());
|
||||
|
||||
const PropertyEvaluationParameters evaluationParameters{
|
||||
zoomHistory,
|
||||
updateParameters->timePoint,
|
||||
transitionOptions.duration.value_or(isMapModeContinuous ? util::DEFAULT_TRANSITION_DURATION
|
||||
: Duration::zero())};
|
||||
PropertyEvaluationParameters evaluationParameters{zoomHistory, updateParameters->timePoint, transitionDuration};
|
||||
evaluationParameters.zoomChanged = zoomChanged;
|
||||
|
||||
const TileParameters tileParameters{updateParameters->pixelRatio,
|
||||
updateParameters->debugOptions,
|
||||
@@ -300,13 +299,9 @@ std::unique_ptr<RenderTree> RenderOrchestrator::createRenderTree(
|
||||
for (RenderLayer& layer : orderedLayers) {
|
||||
const std::string& id = layer.getID();
|
||||
const bool layerAddedOrChanged = layerDiff.added.count(id) || layerDiff.changed.count(id);
|
||||
|
||||
// Only re-evaluate on change of zoom if the style has some reference to it
|
||||
using Dependency = expression::Dependency;
|
||||
const bool zoomChangedAndMatters = zoomChanged && !layerAddedOrChanged &&
|
||||
(layer.getStyleDependencies() & Dependency::Zoom) != Dependency::None;
|
||||
|
||||
if (layerAddedOrChanged || zoomChangedAndMatters || layer.hasTransition() || layer.hasCrossfade()) {
|
||||
evaluationParameters.layerChanged = layerAddedOrChanged;
|
||||
evaluationParameters.hasCrossfade = layer.hasCrossfade();
|
||||
if (layerAddedOrChanged || zoomChanged || evaluationParameters.hasCrossfade || layer.hasTransition()) {
|
||||
const auto previousMask = layer.evaluatedProperties->constantsMask();
|
||||
layer.evaluate(evaluationParameters);
|
||||
if (previousMask != layer.evaluatedProperties->constantsMask()) {
|
||||
@@ -907,8 +902,12 @@ void RenderOrchestrator::updateLayers(gfx::ShaderRegistry& shaders,
|
||||
transitionOptions.duration.value_or(defDuration),
|
||||
};
|
||||
|
||||
const auto& items = renderTree.getLayerRenderItemMap();
|
||||
|
||||
std::vector<std::unique_ptr<ChangeRequest>> changes;
|
||||
for (const auto& item : renderTree.getLayerRenderItemMap()) {
|
||||
changes.reserve(items.size() * 3);
|
||||
|
||||
for (const auto& item : items) {
|
||||
auto& renderLayer = item.layer.get();
|
||||
renderLayer.update(shaders, context, state, updateParameters, renderTree, changes);
|
||||
}
|
||||
|
||||
@@ -258,8 +258,9 @@ void Renderer::Impl::render(const RenderTree& renderTree,
|
||||
/* .symbol_fade_change = */ parameters.symbolFadeChange,
|
||||
/* .aspect_ratio = */ parameters.state.getSize().aspectRatio(),
|
||||
/* .pixel_ratio = */ parameters.pixelRatio,
|
||||
/* .pad1/2 = */ 0,
|
||||
0};
|
||||
/* .zoom = */ static_cast<float>(parameters.state.getZoom()),
|
||||
/* .pad1 = */ 0,
|
||||
};
|
||||
auto& globalUniforms = context.mutableGlobalUniformBuffers();
|
||||
globalUniforms.createOrUpdate(shaders::idGlobalPaintParamsUBO, &globalPaintParamsUBO, context);
|
||||
#endif
|
||||
|
||||
@@ -188,7 +188,7 @@ void TileSourceRenderItem::updateDebugDrawables(DebugLayerGroupMap& debugLayerGr
|
||||
: linePropertiesUBO(properties) {}
|
||||
~PolylineDrawableTweaker() override = default;
|
||||
|
||||
void init(gfx::Drawable&) override {};
|
||||
void init(gfx::Drawable&) override {}
|
||||
|
||||
void execute(gfx::Drawable& drawable, const PaintParameters& parameters) override {
|
||||
if (!drawable.getTileID().has_value()) {
|
||||
@@ -220,6 +220,9 @@ void TileSourceRenderItem::updateDebugDrawables(DebugLayerGroupMap& debugLayerGr
|
||||
drawableUniforms.createOrUpdate(idLineDrawableUBO, &drawableUBO, parameters.context);
|
||||
drawableUniforms.createOrUpdate(idLineInterpolationUBO, &lineInterpolationUBO, parameters.context);
|
||||
drawableUniforms.createOrUpdate(idLineEvaluatedPropsUBO, &linePropertiesUBO, parameters.context);
|
||||
|
||||
// We would need to set up `idLineExpressionUBO` if the expression mask isn't empty
|
||||
assert(linePropertiesUBO.expressionMask == LineExpressionMask::None);
|
||||
};
|
||||
|
||||
private:
|
||||
@@ -244,7 +247,7 @@ void TileSourceRenderItem::updateDebugDrawables(DebugLayerGroupMap& debugLayerGr
|
||||
/*offset*/ 0.f,
|
||||
/*width*/ 4.f,
|
||||
/*floorwidth*/ 0,
|
||||
0,
|
||||
LineExpressionMask::None,
|
||||
0};
|
||||
auto tweaker = std::make_shared<PolylineDrawableTweaker>(linePropertiesUBO);
|
||||
|
||||
|
||||
@@ -3,11 +3,12 @@
|
||||
namespace mbgl {
|
||||
namespace shaders {
|
||||
|
||||
const std::array<UniformBlockInfo, 4> ShaderSource<BuiltIn::LineShader, gfx::Backend::Type::Metal>::uniforms = {
|
||||
UniformBlockInfo{true, false, sizeof(GlobalPaintParamsUBO), idGlobalPaintParamsUBO},
|
||||
const std::array<UniformBlockInfo, 5> ShaderSource<BuiltIn::LineShader, gfx::Backend::Type::Metal>::uniforms = {
|
||||
UniformBlockInfo{true, true, sizeof(GlobalPaintParamsUBO), idGlobalPaintParamsUBO},
|
||||
UniformBlockInfo{true, false, sizeof(idLineDrawableUBO), idLineDrawableUBO},
|
||||
UniformBlockInfo{true, false, sizeof(LineInterpolationUBO), idLineInterpolationUBO},
|
||||
UniformBlockInfo{true, true, sizeof(LineEvaluatedPropsUBO), idLineEvaluatedPropsUBO},
|
||||
UniformBlockInfo{true, true, sizeof(LineExpressionUBO), idLineExpressionUBO},
|
||||
};
|
||||
const std::array<AttributeInfo, 8> ShaderSource<BuiltIn::LineShader, gfx::Backend::Type::Metal>::attributes = {
|
||||
AttributeInfo{lineUBOCount + 0, gfx::AttributeDataType::Short2, idLinePosNormalVertexAttribute},
|
||||
@@ -22,7 +23,7 @@ const std::array<AttributeInfo, 8> ShaderSource<BuiltIn::LineShader, gfx::Backen
|
||||
const std::array<TextureInfo, 0> ShaderSource<BuiltIn::LineShader, gfx::Backend::Type::Metal>::textures = {};
|
||||
|
||||
const std::array<UniformBlockInfo, 4> ShaderSource<BuiltIn::LineGradientShader, gfx::Backend::Type::Metal>::uniforms = {
|
||||
UniformBlockInfo{true, false, sizeof(GlobalPaintParamsUBO), idGlobalPaintParamsUBO},
|
||||
UniformBlockInfo{true, true, sizeof(GlobalPaintParamsUBO), idGlobalPaintParamsUBO},
|
||||
UniformBlockInfo{true, false, sizeof(LineGradientDrawableUBO), idLineDrawableUBO},
|
||||
UniformBlockInfo{true, false, sizeof(LineGradientInterpolationUBO), idLineInterpolationUBO},
|
||||
UniformBlockInfo{true, true, sizeof(LineEvaluatedPropsUBO), idLineEvaluatedPropsUBO},
|
||||
@@ -40,12 +41,13 @@ const std::array<TextureInfo, 1> ShaderSource<BuiltIn::LineGradientShader, gfx::
|
||||
TextureInfo{0, idLineImageTexture},
|
||||
};
|
||||
|
||||
const std::array<UniformBlockInfo, 5> ShaderSource<BuiltIn::LinePatternShader, gfx::Backend::Type::Metal>::uniforms = {
|
||||
UniformBlockInfo{true, false, sizeof(GlobalPaintParamsUBO), idGlobalPaintParamsUBO},
|
||||
const std::array<UniformBlockInfo, 6> ShaderSource<BuiltIn::LinePatternShader, gfx::Backend::Type::Metal>::uniforms = {
|
||||
UniformBlockInfo{true, true, sizeof(GlobalPaintParamsUBO), idGlobalPaintParamsUBO},
|
||||
UniformBlockInfo{true, true, sizeof(LinePatternDrawableUBO), idLineDrawableUBO},
|
||||
UniformBlockInfo{true, false, sizeof(LinePatternInterpolationUBO), idLineInterpolationUBO},
|
||||
UniformBlockInfo{true, true, sizeof(LinePatternTilePropertiesUBO), idLineTilePropertiesUBO},
|
||||
UniformBlockInfo{true, true, sizeof(LineEvaluatedPropsUBO), idLineEvaluatedPropsUBO},
|
||||
UniformBlockInfo{true, true, sizeof(LineExpressionUBO), idLineExpressionUBO},
|
||||
};
|
||||
const std::array<AttributeInfo, 9> ShaderSource<BuiltIn::LinePatternShader, gfx::Backend::Type::Metal>::attributes = {
|
||||
AttributeInfo{lineUBOCount + 0, gfx::AttributeDataType::Short2, idLinePosNormalVertexAttribute},
|
||||
@@ -62,11 +64,12 @@ const std::array<TextureInfo, 1> ShaderSource<BuiltIn::LinePatternShader, gfx::B
|
||||
TextureInfo{0, idLineImageTexture},
|
||||
};
|
||||
|
||||
const std::array<UniformBlockInfo, 4> ShaderSource<BuiltIn::LineSDFShader, gfx::Backend::Type::Metal>::uniforms = {
|
||||
UniformBlockInfo{true, false, sizeof(GlobalPaintParamsUBO), idGlobalPaintParamsUBO},
|
||||
const std::array<UniformBlockInfo, 5> ShaderSource<BuiltIn::LineSDFShader, gfx::Backend::Type::Metal>::uniforms = {
|
||||
UniformBlockInfo{true, true, sizeof(GlobalPaintParamsUBO), idGlobalPaintParamsUBO},
|
||||
UniformBlockInfo{true, true, sizeof(LineSDFDrawableUBO), idLineDrawableUBO},
|
||||
UniformBlockInfo{true, false, sizeof(LineSDFInterpolationUBO), idLineInterpolationUBO},
|
||||
UniformBlockInfo{true, true, sizeof(LineEvaluatedPropsUBO), idLineEvaluatedPropsUBO},
|
||||
UniformBlockInfo{true, true, sizeof(LineExpressionUBO), idLineExpressionUBO},
|
||||
};
|
||||
const std::array<AttributeInfo, 9> ShaderSource<BuiltIn::LineSDFShader, gfx::Backend::Type::Metal>::attributes = {
|
||||
AttributeInfo{lineUBOCount + 0, gfx::AttributeDataType::Short2, idLinePosNormalVertexAttribute},
|
||||
|
||||
@@ -102,8 +102,9 @@ CoerceFunction getCoerceFunction(const type::Type& t) {
|
||||
return toStringValue;
|
||||
}
|
||||
|
||||
Dependency extraDependency(const type::Type& t) {
|
||||
return t.is<type::ImageType>() ? Dependency::Image : Dependency::None;
|
||||
/// `isRuntimeConstant` does not consider values coerced to `Type` image to be of `Kind` image, so we don't either.
|
||||
constexpr Dependency extraDependency(const type::Type& /*t*/) {
|
||||
return /*t.is<type::ImageType>() ? Dependency::Image :*/ Dependency::None;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
@@ -8,14 +8,17 @@ namespace mbgl {
|
||||
namespace style {
|
||||
namespace expression {
|
||||
|
||||
namespace {
|
||||
/// Collators are considered feature-dependent, see `isFeatureConstant`
|
||||
constexpr auto extraDependency = Dependency::Feature;
|
||||
} // namespace
|
||||
|
||||
CollatorExpression::CollatorExpression(std::unique_ptr<Expression> caseSensitive_,
|
||||
std::unique_ptr<Expression> diacriticSensitive_,
|
||||
std::optional<std::unique_ptr<Expression>> locale_)
|
||||
: Expression(Kind::CollatorExpression,
|
||||
type::Collator,
|
||||
depsOf(caseSensitive_) | depsOf(diacriticSensitive_) | depsOf(locale_) |
|
||||
// Collations are treated as feature-dependent. See `style::expression::isFeatureConstant`
|
||||
Dependency::Feature),
|
||||
depsOf(caseSensitive_) | depsOf(diacriticSensitive_) | depsOf(locale_) | extraDependency),
|
||||
caseSensitive(std::move(caseSensitive_)),
|
||||
diacriticSensitive(std::move(diacriticSensitive_)),
|
||||
locale(std::move(locale_)) {}
|
||||
|
||||
@@ -17,7 +17,7 @@ std::ostream& operator<<(std::ostream& os, const Dependency deps) {
|
||||
|
||||
bool any = false;
|
||||
const auto add = [&](Dependency dep, std::string_view name) {
|
||||
if ((deps & dep) != Dependency::None) {
|
||||
if (deps & dep) {
|
||||
os << (any ? "|" : std::string_view{}) << name;
|
||||
any = true;
|
||||
}
|
||||
|
||||
@@ -12,42 +12,46 @@ namespace mbgl {
|
||||
namespace style {
|
||||
namespace expression {
|
||||
|
||||
std::optional<variant<const Interpolate*, const Step*, ParsingError>> findZoomCurve(const expression::Expression* e) {
|
||||
std::optional<variant<const Interpolate*, const Step*, ParsingError>> result;
|
||||
ZoomCurveOrError findZoomCurve(const expression::Expression& e) {
|
||||
ZoomCurveOrError result;
|
||||
|
||||
switch (e->getKind()) {
|
||||
switch (e.getKind()) {
|
||||
case Kind::Let: {
|
||||
auto let = static_cast<const Let*>(e);
|
||||
result = findZoomCurve(let->getResult());
|
||||
const auto& let = static_cast<const Let&>(e);
|
||||
if (const auto& child = let.getResult()) {
|
||||
result = findZoomCurve(*child);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case Kind::Coalesce: {
|
||||
auto coalesce = static_cast<const Coalesce*>(e);
|
||||
std::size_t length = coalesce->getLength();
|
||||
const auto& coalesce = static_cast<const Coalesce&>(e);
|
||||
const std::size_t length = coalesce.getLength();
|
||||
for (std::size_t i = 0; i < length; i++) {
|
||||
result = findZoomCurve(coalesce->getChild(i));
|
||||
if (result) {
|
||||
break;
|
||||
if (const auto* child = coalesce.getChild(i)) {
|
||||
result = findZoomCurve(*child);
|
||||
if (result) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case Kind::Interpolate: {
|
||||
auto curve = static_cast<const Interpolate*>(e);
|
||||
if (curve->getInput()->getKind() == Kind::CompoundExpression) {
|
||||
auto z = static_cast<CompoundExpression*>(curve->getInput().get());
|
||||
const auto& curve = static_cast<const Interpolate&>(e);
|
||||
if (curve.getInput()->getKind() == Kind::CompoundExpression) {
|
||||
const auto* z = static_cast<CompoundExpression*>(curve.getInput().get());
|
||||
if (z && z->getOperator() == "zoom") {
|
||||
result = {curve};
|
||||
result = {&curve};
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case Kind::Step: {
|
||||
auto step = static_cast<const Step*>(e);
|
||||
if (step->getInput()->getKind() == Kind::CompoundExpression) {
|
||||
auto z = static_cast<CompoundExpression*>(step->getInput().get());
|
||||
const auto& step = static_cast<const Step&>(e);
|
||||
if (step.getInput()->getKind() == Kind::CompoundExpression) {
|
||||
const auto* z = static_cast<CompoundExpression*>(step.getInput().get());
|
||||
if (z && z->getOperator() == "zoom") {
|
||||
result = {step};
|
||||
result = {&step};
|
||||
}
|
||||
}
|
||||
break;
|
||||
@@ -60,9 +64,8 @@ std::optional<variant<const Interpolate*, const Step*, ParsingError>> findZoomCu
|
||||
return result;
|
||||
}
|
||||
|
||||
e->eachChild([&](const Expression& child) {
|
||||
std::optional<variant<const Interpolate*, const Step*, ParsingError>> childResult(findZoomCurve(&child));
|
||||
if (childResult) {
|
||||
e.eachChild([&](const Expression& child) {
|
||||
if (const ZoomCurveOrError childResult = findZoomCurve(child)) {
|
||||
if (childResult->is<ParsingError>()) {
|
||||
result = childResult;
|
||||
} else if (!result && childResult) {
|
||||
@@ -79,16 +82,16 @@ std::optional<variant<const Interpolate*, const Step*, ParsingError>> findZoomCu
|
||||
return result;
|
||||
}
|
||||
|
||||
using ZoomCurveOrNull = variant<std::nullptr_t, const Interpolate*, const Step*>;
|
||||
|
||||
ZoomCurveOrNull findZoomCurveChecked(const expression::Expression& e) {
|
||||
assert(!expression::isZoomConstant(e));
|
||||
return findZoomCurve(&e)->match(
|
||||
[](const ParsingError& err) -> ZoomCurveOrNull {
|
||||
ZoomCurvePtr findZoomCurveChecked(const expression::Expression& e) {
|
||||
if (!e.has(Dependency::Zoom)) {
|
||||
return nullptr;
|
||||
}
|
||||
return findZoomCurve(e)->match(
|
||||
[](const ParsingError& err) -> ZoomCurvePtr {
|
||||
Log::Error(Event::Style, "Invalid Expression: " + err.message);
|
||||
return nullptr;
|
||||
},
|
||||
[](auto zoomCurve) -> ZoomCurveOrNull { return zoomCurve; });
|
||||
[](auto zoomCurve) -> ZoomCurvePtr { return zoomCurve; });
|
||||
}
|
||||
|
||||
} // namespace expression
|
||||
|
||||
@@ -248,19 +248,22 @@ ParseResult ParsingContext::parseExpression(const Convertible& value,
|
||||
}
|
||||
|
||||
ParseResult ParsingContext::parseLayerPropertyExpression(const Convertible& value) {
|
||||
std::optional<TypeAnnotationOption> typeAnnotationOption;
|
||||
if (expected && *expected == type::String) {
|
||||
typeAnnotationOption = TypeAnnotationOption::coerce;
|
||||
}
|
||||
const auto typeAnnotationOption = (expected && *expected == type::String)
|
||||
? std::make_optional(TypeAnnotationOption::coerce)
|
||||
: std::nullopt;
|
||||
ParseResult parsed = parse(value, typeAnnotationOption);
|
||||
if (parsed && !isZoomConstant(**parsed)) {
|
||||
std::optional<variant<const Interpolate*, const Step*, ParsingError>> zoomCurve = findZoomCurve(parsed->get());
|
||||
if (!zoomCurve) {
|
||||
|
||||
// If the expression is zoom-dependent, validate that we can resolve a zoom curve or treat it as an error
|
||||
assert(!parsed || !*parsed || !((*parsed)->dependencies & Dependency::Zoom) == isZoomConstant(**parsed));
|
||||
if (parsed && (*parsed)->has(Dependency::Zoom)) {
|
||||
if (const auto zoomCurve = findZoomCurve(**parsed)) {
|
||||
if (zoomCurve->is<ParsingError>()) {
|
||||
error(zoomCurve->get<ParsingError>().message);
|
||||
return ParseResult();
|
||||
}
|
||||
} else {
|
||||
error(R"("zoom" expression may only be used as input to a top-level "step" or "interpolate" expression.)");
|
||||
return ParseResult();
|
||||
} else if (zoomCurve->is<ParsingError>()) {
|
||||
error(zoomCurve->get<ParsingError>().message);
|
||||
return ParseResult();
|
||||
}
|
||||
}
|
||||
return parsed;
|
||||
|
||||
@@ -91,8 +91,9 @@ class LineDrawableTweaker : public gfx::DrawableTweaker {
|
||||
public:
|
||||
LineDrawableTweaker(const shaders::LineEvaluatedPropsUBO& properties)
|
||||
: linePropertiesUBO(properties) {}
|
||||
~LineDrawableTweaker() override = default;
|
||||
|
||||
void init(gfx::Drawable&) override {};
|
||||
void init(gfx::Drawable&) override {}
|
||||
|
||||
void execute(gfx::Drawable& drawable, const PaintParameters& parameters) override {
|
||||
if (!drawable.getTileID().has_value()) {
|
||||
@@ -124,6 +125,9 @@ public:
|
||||
drawableUniforms.createOrUpdate(idLineDrawableUBO, &drawableUBO, parameters.context);
|
||||
drawableUniforms.createOrUpdate(idLineInterpolationUBO, &lineInterpolationUBO, parameters.context);
|
||||
drawableUniforms.createOrUpdate(idLineEvaluatedPropsUBO, &linePropertiesUBO, parameters.context);
|
||||
|
||||
// We would need to set up `idLineExpressionUBO` if the expression mask isn't empty
|
||||
assert(linePropertiesUBO.expressionMask == LineExpressionMask::None);
|
||||
};
|
||||
|
||||
private:
|
||||
@@ -135,7 +139,7 @@ public:
|
||||
WideVectorDrawableTweaker(const CustomDrawableLayerHost::Interface::LineOptions& options_)
|
||||
: options(options_) {}
|
||||
|
||||
void init(gfx::Drawable&) override {};
|
||||
void init(gfx::Drawable&) override {}
|
||||
|
||||
void execute(gfx::Drawable& drawable, const PaintParameters& parameters) override {
|
||||
if (!drawable.getTileID().has_value()) {
|
||||
@@ -198,8 +202,9 @@ public:
|
||||
FillDrawableTweaker(const Color& color_, float opacity_)
|
||||
: color(color_),
|
||||
opacity(opacity_) {}
|
||||
~FillDrawableTweaker() override = default;
|
||||
|
||||
void init(gfx::Drawable&) override {};
|
||||
void init(gfx::Drawable&) override {}
|
||||
|
||||
void execute(gfx::Drawable& drawable, const PaintParameters& parameters) override {
|
||||
if (!drawable.getTileID().has_value()) {
|
||||
@@ -244,8 +249,9 @@ class SymbolDrawableTweaker : public gfx::DrawableTweaker {
|
||||
public:
|
||||
SymbolDrawableTweaker(const CustomDrawableLayerHost::Interface::SymbolOptions& options_)
|
||||
: options(options_) {}
|
||||
~SymbolDrawableTweaker() override = default;
|
||||
|
||||
void init(gfx::Drawable&) override {};
|
||||
void init(gfx::Drawable&) override {}
|
||||
|
||||
void execute(gfx::Drawable& drawable, const PaintParameters& parameters) override {
|
||||
if (!drawable.getTileID().has_value()) {
|
||||
@@ -536,8 +542,8 @@ void CustomDrawableLayerHost::Interface::finish() {
|
||||
lineOptions.gapWidth,
|
||||
lineOptions.offset,
|
||||
lineOptions.width,
|
||||
0,
|
||||
0,
|
||||
/*floorwidth=*/0,
|
||||
LineExpressionMask::None,
|
||||
0};
|
||||
auto tweaker = std::make_shared<LineDrawableTweaker>(linePropertiesUBO);
|
||||
|
||||
|
||||
@@ -6,10 +6,13 @@
|
||||
#include <mbgl/style/color_ramp_property_value.hpp>
|
||||
#include <mbgl/style/conversion/stringify.hpp>
|
||||
#include <mbgl/style/transition_options.hpp>
|
||||
#include <mbgl/util/convert.hpp>
|
||||
#include <mbgl/util/indexed_tuple.hpp>
|
||||
#include <mbgl/util/ignore.hpp>
|
||||
#include <mbgl/util/logging.hpp>
|
||||
|
||||
#include <bitset>
|
||||
#include <tuple>
|
||||
|
||||
namespace mbgl {
|
||||
|
||||
@@ -65,8 +68,13 @@ public:
|
||||
|
||||
bool hasTransition() const noexcept { return bool(prior); }
|
||||
|
||||
bool isTransitioning(TimePoint now) const {
|
||||
return hasTransition() && (begin <= now) && (now < end) && !value.isDataDriven();
|
||||
}
|
||||
|
||||
bool isUndefined() const noexcept { return value.isUndefined(); }
|
||||
|
||||
Value& getValue() noexcept { return value; }
|
||||
const Value& getValue() const noexcept { return value; }
|
||||
|
||||
private:
|
||||
@@ -296,6 +304,24 @@ public:
|
||||
return PossiblyEvaluated{evaluate<Ps>(parameters)...};
|
||||
}
|
||||
|
||||
/// Evaluate the property if necessary, or produce a copy of the previous value if appropriate
|
||||
template <class P>
|
||||
auto maybeEvaluate(const PropertyEvaluationParameters& parameters,
|
||||
const typename P::EvaluatorType::ResultType& oldResult) const {
|
||||
using Evaluator = typename P::EvaluatorType;
|
||||
const auto& property = this->template get<P>();
|
||||
const bool needEvaluate = parameters.layerChanged || parameters.hasCrossfade || property.hasTransition() ||
|
||||
(parameters.zoomChanged && (getDependencies(property) & Dependency::Zoom));
|
||||
return needEvaluate ? property.evaluate(Evaluator(parameters, P::defaultValue()), parameters.now)
|
||||
: oldResult;
|
||||
}
|
||||
|
||||
/// Optionally evaluate each property or produce a copy of the previous value, if appropriate.
|
||||
PossiblyEvaluated evaluate(const PropertyEvaluationParameters& parameters,
|
||||
const PossiblyEvaluated& previous) const {
|
||||
return PossiblyEvaluated{maybeEvaluate<Ps>(parameters, previous.template get<Ps>())...};
|
||||
}
|
||||
|
||||
template <class Writer>
|
||||
void stringify(Writer& writer) const {
|
||||
writer.StartObject();
|
||||
@@ -303,6 +329,8 @@ public:
|
||||
writer.EndObject();
|
||||
}
|
||||
|
||||
unsigned long constantsMask() const { return ConstantsMask<DataDrivenProperties>::getMask(*this); }
|
||||
|
||||
/// Get the combined dependencies of any contained expressions
|
||||
constexpr Dependency getDependencies() const noexcept {
|
||||
Dependency result = Dependency::None;
|
||||
@@ -310,9 +338,20 @@ public:
|
||||
return result;
|
||||
}
|
||||
|
||||
unsigned long constantsMask() const { return ConstantsMask<DataDrivenProperties>::getMask(*this); }
|
||||
#if MLN_DRAWABLE_RENDERER
|
||||
using GPUExpressions = std::array<gfx::UniqueGPUExpression, UnevaluatedTypes::TypeCount>;
|
||||
|
||||
/// Update the GPU expressions, if applicable, for each item in the tuple.
|
||||
/// @return true if any are updated (including being cleared)
|
||||
bool updateGPUExpressions(Unevaluated::GPUExpressions& exprs, TimePoint now) const {
|
||||
const auto results = util::to_array(std::make_tuple(updateGPUExpression<Ps>(exprs, now)...));
|
||||
return std::any_of(results.begin(), results.end(), [](bool x) { return x; });
|
||||
}
|
||||
#endif // MLN_DRAWABLE_RENDERER
|
||||
|
||||
protected:
|
||||
// gather dependencies for each type that can appear in this tuple
|
||||
|
||||
template <class P>
|
||||
Dependency getDependencies(const PropertyValue<P>& v) const noexcept {
|
||||
return v.getDependencies();
|
||||
@@ -322,6 +361,53 @@ public:
|
||||
Dependency getDependencies(const Transitioning<P>& v) const noexcept {
|
||||
return v.getValue().getDependencies();
|
||||
}
|
||||
|
||||
#if MLN_DRAWABLE_RENDERER
|
||||
template <typename P>
|
||||
bool updateGPUExpression(Unevaluated::GPUExpressions& exprs, TimePoint now) const {
|
||||
constexpr auto index = TypeIndex<P, Ps...>::value;
|
||||
constexpr bool forceIntZoom = P::EvaluatorType::useIntegerZoom;
|
||||
return updateGPUExpression(exprs[index], this->template get<P>(), now, forceIntZoom);
|
||||
}
|
||||
|
||||
template <class P>
|
||||
static bool updateGPUExpression(gfx::UniqueGPUExpression& expr,
|
||||
const PropertyValue<P>& val,
|
||||
TimePoint /*now*/,
|
||||
bool intZoom) {
|
||||
if (val.isExpression() && val.asExpression().isGPUCapable()) {
|
||||
if (!expr) {
|
||||
expr = val.asExpression().getGPUExpression(intZoom);
|
||||
return true;
|
||||
}
|
||||
} else if (expr) {
|
||||
// Previously set and shouldn't be
|
||||
expr.reset();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
template <class P>
|
||||
static bool updateGPUExpression(gfx::UniqueGPUExpression& expr,
|
||||
const Transitioning<P>& val,
|
||||
TimePoint now,
|
||||
bool intZoom) {
|
||||
if (val.isTransitioning(now)) {
|
||||
if (expr) {
|
||||
expr.reset();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
return updateGPUExpression(expr, val.getValue(), now, intZoom);
|
||||
}
|
||||
static bool updateGPUExpression(gfx::UniqueGPUExpression&,
|
||||
const style::ColorRampPropertyValue&,
|
||||
TimePoint,
|
||||
bool) {
|
||||
return false;
|
||||
}
|
||||
#endif // MLN_DRAWABLE_RENDERER
|
||||
};
|
||||
|
||||
class Transitionable : public Tuple<TransitionableTypes> {
|
||||
|
||||
@@ -1,14 +1,84 @@
|
||||
#include <mbgl/style/property_expression.hpp>
|
||||
|
||||
#include <mbgl/renderer/paint_property_binder.hpp>
|
||||
#include <mbgl/util/convert.hpp>
|
||||
|
||||
#if MLN_DRAWABLE_RENDERER
|
||||
#include <mbgl/gfx/gpu_expression.hpp>
|
||||
#endif // MLN_DRAWABLE_RENDERER
|
||||
|
||||
namespace mbgl {
|
||||
namespace style {
|
||||
|
||||
PropertyExpressionBase::PropertyExpressionBase(std::unique_ptr<expression::Expression> expression_) noexcept
|
||||
namespace {
|
||||
|
||||
using namespace expression;
|
||||
bool checkGPUCapable(const Expression& expression, const ZoomCurvePtr& zoomCurve) {
|
||||
return (expression.dependencies == Dependency::Zoom) && !zoomCurve.is<std::nullptr_t>() &&
|
||||
(expression.getType().is<type::NumberType>() || expression.getType().is<type::ColorType>());
|
||||
}
|
||||
} // namespace
|
||||
|
||||
PropertyExpressionBase::PropertyExpressionBase(std::unique_ptr<expression::Expression> expression_)
|
||||
: expression(std::move(expression_)),
|
||||
isZoomConstant_(expression::isZoomConstant(*expression)),
|
||||
isFeatureConstant_(expression::isFeatureConstant(*expression)),
|
||||
isRuntimeConstant_(expression::isRuntimeConstant(*expression)),
|
||||
zoomCurve(isZoomConstant_ ? nullptr : expression::findZoomCurveChecked(*expression)) {}
|
||||
zoomCurve(expression->has(Dependency::Zoom) ? expression::findZoomCurveChecked(*expression) : nullptr),
|
||||
useIntegerZoom_(false),
|
||||
isZoomConstant_(!expression->has(Dependency::Zoom)),
|
||||
isFeatureConstant_(!expression->has(Dependency::Feature)),
|
||||
isRuntimeConstant_(!expression->has(Dependency::Image)),
|
||||
isGPUCapable_(checkGPUCapable(*expression, zoomCurve)) {
|
||||
assert(isZoomConstant_ == expression::isZoomConstant(*expression));
|
||||
assert(isFeatureConstant_ == expression::isFeatureConstant(*expression));
|
||||
assert(isRuntimeConstant_ == expression::isRuntimeConstant(*expression));
|
||||
}
|
||||
|
||||
PropertyExpressionBase::PropertyExpressionBase(PropertyExpressionBase&& other)
|
||||
: expression(std::move(other.expression)),
|
||||
zoomCurve(std::move(other.zoomCurve)),
|
||||
useIntegerZoom_(other.useIntegerZoom_),
|
||||
isZoomConstant_(other.isZoomConstant_),
|
||||
isFeatureConstant_(other.isFeatureConstant_),
|
||||
isRuntimeConstant_(other.isRuntimeConstant_),
|
||||
isGPUCapable_(other.isGPUCapable_) {}
|
||||
|
||||
PropertyExpressionBase::PropertyExpressionBase(const PropertyExpressionBase& other)
|
||||
: expression(other.expression),
|
||||
zoomCurve(other.zoomCurve),
|
||||
useIntegerZoom_(other.useIntegerZoom_),
|
||||
isZoomConstant_(other.isZoomConstant_),
|
||||
isFeatureConstant_(other.isFeatureConstant_),
|
||||
isRuntimeConstant_(other.isRuntimeConstant_),
|
||||
isGPUCapable_(other.isGPUCapable_) {}
|
||||
|
||||
PropertyExpressionBase& PropertyExpressionBase::operator=(PropertyExpressionBase&& other) {
|
||||
expression = std::move(other.expression);
|
||||
zoomCurve = other.zoomCurve;
|
||||
useIntegerZoom_ = other.useIntegerZoom_;
|
||||
isZoomConstant_ = other.isZoomConstant_;
|
||||
isFeatureConstant_ = other.isFeatureConstant_;
|
||||
isRuntimeConstant_ = other.isRuntimeConstant_;
|
||||
isGPUCapable_ = other.isGPUCapable_;
|
||||
return *this;
|
||||
}
|
||||
|
||||
PropertyExpressionBase& PropertyExpressionBase::operator=(const PropertyExpressionBase& other) {
|
||||
expression = other.expression;
|
||||
zoomCurve = other.zoomCurve;
|
||||
useIntegerZoom_ = other.useIntegerZoom_;
|
||||
isZoomConstant_ = other.isZoomConstant_;
|
||||
isFeatureConstant_ = other.isFeatureConstant_;
|
||||
isRuntimeConstant_ = other.isRuntimeConstant_;
|
||||
isGPUCapable_ = other.isGPUCapable_;
|
||||
return *this;
|
||||
}
|
||||
|
||||
#if MLN_DRAWABLE_RENDERER
|
||||
gfx::UniqueGPUExpression PropertyExpressionBase::getGPUExpression(bool intZoom) const {
|
||||
return isGPUCapable_ ? gfx::GPUExpression::create(*expression, zoomCurve, useIntegerZoom_ || intZoom)
|
||||
: gfx::UniqueGPUExpression{};
|
||||
}
|
||||
#endif // MLN_DRAWABLE_RENDERER
|
||||
|
||||
float PropertyExpressionBase::interpolationFactor(const Range<float>& inputLevels,
|
||||
const float inputValue) const noexcept {
|
||||
return zoomCurve.match(
|
||||
|
||||
Reference in New Issue
Block a user