Separate properties-as-uniforms per drawable (#1856)
This commit is contained in:
@@ -1,5 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
#include <mbgl/shaders/layer_ubo.hpp>
|
||||
#include <mbgl/shaders/shader_source.hpp>
|
||||
#include <mbgl/util/immutable.hpp>
|
||||
|
||||
@@ -53,8 +54,10 @@ public:
|
||||
static shaders::ExpressionInputsUBO buildExpressionUBO(double zoom, uint64_t frameCount);
|
||||
|
||||
/// @brief Check whether a property name exists within the previously set collection.
|
||||
bool hasPropertyAsUniform(StringIdentity) const;
|
||||
shaders::AttributeSource getAttributeSource(StringIdentity) const;
|
||||
shaders::AttributeSource getAttributeSource(const StringIdentity id) {
|
||||
return propertiesAsUniforms.count(id) ? shaders::AttributeSource::Constant
|
||||
: shaders::AttributeSource::PerVertex;
|
||||
}
|
||||
|
||||
template <shaders::BuiltIn ShaderType>
|
||||
shaders::AttributeSource getAttributeSource(size_t index) {
|
||||
|
||||
@@ -78,11 +78,11 @@ public:
|
||||
|
||||
/// Move constructor
|
||||
TinyUnorderedMap(TinyUnorderedMap&& rhs)
|
||||
: Super(std::move(rhs)),
|
||||
linearSize(rhs.linearSize),
|
||||
: linearSize(rhs.linearSize),
|
||||
keys(std::move(rhs.keys)),
|
||||
values(std::move(rhs.values)) {
|
||||
rhs.linearSize = 0;
|
||||
Super::operator=(std::move(rhs));
|
||||
}
|
||||
|
||||
/// Copy constructor
|
||||
@@ -159,6 +159,20 @@ public:
|
||||
this->Super::clear();
|
||||
}
|
||||
|
||||
bool operator==(const TinyUnorderedMap& other) const {
|
||||
if (size() != other.size()) return false;
|
||||
assert(linearSize == other.linearSize);
|
||||
if (linearSize) {
|
||||
return std::equal(
|
||||
keys.begin(), keys.begin() + linearSize, other.keys.begin(), other.keys.begin() + linearSize) &&
|
||||
std::equal(values.begin(),
|
||||
values.begin() + linearSize,
|
||||
other.values.begin(),
|
||||
other.values.begin() + linearSize);
|
||||
}
|
||||
return std::operator==(*this, other);
|
||||
}
|
||||
|
||||
private:
|
||||
std::size_t linearSize = 0;
|
||||
std::array<std::optional<Key>, LinearThreshold> keys;
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
#include <mbgl/gfx/drawable_data.hpp>
|
||||
#include <mbgl/style/types.hpp>
|
||||
#include <mbgl/util/tiny_unordered_map.hpp>
|
||||
|
||||
#include <memory>
|
||||
|
||||
@@ -12,20 +13,25 @@ enum class SymbolType : uint8_t;
|
||||
namespace gfx {
|
||||
|
||||
struct SymbolDrawableData : public DrawableData {
|
||||
constexpr static std::size_t LinearThreshold = 10;
|
||||
using PropertyMapType = util::TinyUnorderedMap<StringIdentity, bool, LinearThreshold>;
|
||||
|
||||
SymbolDrawableData(const bool isHalo_,
|
||||
const bool bucketVariablePlacement_,
|
||||
const style::SymbolType symbolType_,
|
||||
const style::AlignmentType pitchAlignment_,
|
||||
const style::AlignmentType rotationAlignment_,
|
||||
const style::SymbolPlacementType placement_,
|
||||
const style::IconTextFitType textFit_)
|
||||
const style::IconTextFitType textFit_,
|
||||
PropertyMapType&& propertiesAsUniforms_)
|
||||
: isHalo(isHalo_),
|
||||
bucketVariablePlacement(bucketVariablePlacement_),
|
||||
symbolType(symbolType_),
|
||||
pitchAlignment(pitchAlignment_),
|
||||
rotationAlignment(rotationAlignment_),
|
||||
placement(placement_),
|
||||
textFit(textFit_) {}
|
||||
textFit(textFit_),
|
||||
propertiesAsUniforms(std::move(propertiesAsUniforms_)) {}
|
||||
~SymbolDrawableData() override = default;
|
||||
|
||||
const bool isHalo;
|
||||
@@ -35,6 +41,7 @@ struct SymbolDrawableData : public DrawableData {
|
||||
const style::AlignmentType rotationAlignment;
|
||||
const style::SymbolPlacementType placement;
|
||||
const style::IconTextFitType textFit;
|
||||
const PropertyMapType propertiesAsUniforms;
|
||||
};
|
||||
|
||||
using UniqueSymbolDrawableData = std::unique_ptr<SymbolDrawableData>;
|
||||
|
||||
@@ -64,15 +64,6 @@ shaders::ExpressionInputsUBO LayerTweaker::buildExpressionUBO(double zoom, uint6
|
||||
/* .pad = */ 0,
|
||||
0};
|
||||
}
|
||||
|
||||
bool LayerTweaker::hasPropertyAsUniform(const StringIdentity attrNameID) const {
|
||||
return propertiesAsUniforms.find(attrNameID) != propertiesAsUniforms.end();
|
||||
}
|
||||
|
||||
using namespace shaders;
|
||||
AttributeSource LayerTweaker::getAttributeSource(const StringIdentity attribNameID) const {
|
||||
return hasPropertyAsUniform(attribNameID) ? AttributeSource::Constant : AttributeSource::PerVertex;
|
||||
}
|
||||
#endif // MLN_RENDER_BACKEND_METAL
|
||||
|
||||
void LayerTweaker::setPropertiesAsUniforms([[maybe_unused]] const std::unordered_set<StringIdentity>& props) {
|
||||
|
||||
@@ -748,6 +748,13 @@ SymbolDrawableTilePropsUBO buildTileUBO(const SymbolBucket& bucket,
|
||||
};
|
||||
}
|
||||
|
||||
// Convert a properties-as-uniforms set to the type expected by `SymbolDrawableData`
|
||||
gfx::SymbolDrawableData::PropertyMapType toMap(const std::unordered_set<StringIdentity>& set) {
|
||||
// can we do this without allocating?
|
||||
auto values = std::vector<bool>(set.size());
|
||||
return gfx::SymbolDrawableData::PropertyMapType(set.begin(), set.end(), values.begin(), values.end());
|
||||
}
|
||||
|
||||
const auto idDataAttibName = stringIndexer().get("a_data");
|
||||
const auto posOffsetAttribName = "a_pos_offset";
|
||||
const auto idPosOffsetAttribName = stringIndexer().get(posOffsetAttribName);
|
||||
@@ -1198,8 +1205,9 @@ void RenderSymbolLayer::update(gfx::ShaderRegistry& shaders,
|
||||
return;
|
||||
}
|
||||
|
||||
const auto& evaluated = getEvaluated<SymbolLayerProperties>(renderData.layerProperties);
|
||||
propertiesAsUniforms.clear();
|
||||
|
||||
const auto& evaluated = getEvaluated<SymbolLayerProperties>(renderData.layerProperties);
|
||||
updateTileDrawable(drawable,
|
||||
context,
|
||||
bucket,
|
||||
@@ -1209,6 +1217,11 @@ void RenderSymbolLayer::update(gfx::ShaderRegistry& shaders,
|
||||
textInterpUBO,
|
||||
iconInterpUBO,
|
||||
propertiesAsUniforms);
|
||||
|
||||
// We assume that the properties-as-uniforms doesn't change without the style changing.
|
||||
// That would require updating the shader as well.
|
||||
[[maybe_unused]] const auto& drawData = static_cast<gfx::SymbolDrawableData&>(*drawable.getData());
|
||||
assert(drawData.propertiesAsUniforms == toMap(propertiesAsUniforms));
|
||||
});
|
||||
|
||||
// re-create collision drawables
|
||||
@@ -1295,9 +1308,6 @@ void RenderSymbolLayer::update(gfx::ShaderRegistry& shaders,
|
||||
propertiesAsUniforms.clear();
|
||||
gfx::VertexAttributeArray attribs;
|
||||
updateTileAttributes(buffer, isText, bucketPaintProperties, evaluated, attribs, propertiesAsUniforms);
|
||||
if (layerTweaker) {
|
||||
layerTweaker->setPropertiesAsUniforms(propertiesAsUniforms);
|
||||
}
|
||||
|
||||
const auto textHalo = evaluated.get<style::TextHaloColor>().constantOr(Color::black()).a > 0.0f &&
|
||||
evaluated.get<style::TextHaloWidth>().constantOr(1);
|
||||
@@ -1394,7 +1404,8 @@ void RenderSymbolLayer::update(gfx::ShaderRegistry& shaders,
|
||||
/*.pitchAlignment=*/values.pitchAlignment,
|
||||
/*.rotationAlignment=*/values.rotationAlignment,
|
||||
/*.placement=*/layout.get<SymbolPlacement>(),
|
||||
/*.textFit=*/layout.get<IconTextFit>());
|
||||
/*.textFit=*/layout.get<IconTextFit>(),
|
||||
/*propertiesAsUniforms=*/toMap(propertiesAsUniforms));
|
||||
|
||||
const auto tileUBO = buildTileUBO(bucket, *drawData, currentZoom);
|
||||
drawable->setData(std::move(drawData));
|
||||
|
||||
@@ -89,26 +89,6 @@ void SymbolLayerTweaker::execute(LayerGroupBase& layerGroup, const PaintParamete
|
||||
const auto zoom = parameters.state.getZoom();
|
||||
|
||||
#if MLN_RENDER_BACKEND_METAL
|
||||
if (permutationUpdated) {
|
||||
const SymbolPermutationUBO permutationUBO = {
|
||||
/* .fill_color = */ {/*.source=*/getAttributeSource<BuiltIn::SymbolSDFIconShader>(5), /*.expression=*/{}},
|
||||
/* .halo_color = */ {/*.source=*/getAttributeSource<BuiltIn::SymbolSDFIconShader>(6), /*.expression=*/{}},
|
||||
/* .opacity = */ {/*.source=*/getAttributeSource<BuiltIn::SymbolSDFIconShader>(7), /*.expression=*/{}},
|
||||
/* .halo_width = */ {/*.source=*/getAttributeSource<BuiltIn::SymbolSDFIconShader>(8), /*.expression=*/{}},
|
||||
/* .halo_blur = */ {/*.source=*/getAttributeSource<BuiltIn::SymbolSDFIconShader>(9), /*.expression=*/{}},
|
||||
/* .overdrawInspector = */ overdrawInspector,
|
||||
/* .pad = */ 0,
|
||||
0,
|
||||
0};
|
||||
|
||||
if (permutationUniformBuffer) {
|
||||
permutationUniformBuffer->update(&permutationUBO, sizeof(permutationUBO));
|
||||
} else {
|
||||
permutationUniformBuffer = context.createUniformBuffer(&permutationUBO, sizeof(permutationUBO));
|
||||
}
|
||||
|
||||
permutationUpdated = false;
|
||||
}
|
||||
if (!expressionUniformBuffer) {
|
||||
const auto expressionUBO = buildExpressionUBO(zoom, parameters.frameCount);
|
||||
expressionUniformBuffer = context.createUniformBuffer(&expressionUBO, sizeof(expressionUBO));
|
||||
@@ -201,8 +181,28 @@ void SymbolLayerTweaker::execute(LayerGroupBase& layerGroup, const PaintParamete
|
||||
uniforms.addOrReplace(idSymbolDrawablePaintUBOName, isText ? textPaintBuffer : iconPaintBuffer);
|
||||
|
||||
#if MLN_RENDER_BACKEND_METAL
|
||||
assert(propertiesAsUniforms.empty());
|
||||
|
||||
using namespace shaders;
|
||||
using ShaderClass = ShaderSource<BuiltIn::SymbolSDFIconShader, gfx::Backend::Type::Metal>;
|
||||
const auto source = [&](int index) {
|
||||
const auto nameID = ShaderClass::attributes[index].nameID;
|
||||
const bool uniform = symbolData.propertiesAsUniforms.count(nameID);
|
||||
return uniform ? AttributeSource::Constant : AttributeSource::PerVertex;
|
||||
};
|
||||
|
||||
const SymbolPermutationUBO permutationUBO = {/* .fill_color = */ {/*.source=*/source(5), /*.expression=*/{}},
|
||||
/* .halo_color = */ {/*.source=*/source(6), /*.expression=*/{}},
|
||||
/* .opacity = */ {/*.source=*/source(7), /*.expression=*/{}},
|
||||
/* .halo_width = */ {/*.source=*/source(8), /*.expression=*/{}},
|
||||
/* .halo_blur = */ {/*.source=*/source(9), /*.expression=*/{}},
|
||||
/* .overdrawInspector = */ overdrawInspector,
|
||||
/* .pad = */ 0,
|
||||
0,
|
||||
0};
|
||||
uniforms.createOrUpdate(idSymbolPermutationUBOName, &permutationUBO, context);
|
||||
|
||||
uniforms.addOrReplace(idExpressionInputsUBOName, expressionUniformBuffer);
|
||||
uniforms.addOrReplace(idSymbolPermutationUBOName, permutationUniformBuffer);
|
||||
#endif // MLN_RENDER_BACKEND_METAL
|
||||
});
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user