Skip to content

Commit

Permalink
Separate properties-as-uniforms per drawable (#1856)
Browse files Browse the repository at this point in the history
  • Loading branch information
TimSylvester authored Nov 14, 2023
1 parent 9884b1e commit 37a9c08
Show file tree
Hide file tree
Showing 6 changed files with 67 additions and 41 deletions.
7 changes: 5 additions & 2 deletions include/mbgl/renderer/layer_tweaker.hpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
#pragma once

#include <mbgl/shaders/layer_ubo.hpp>
#include <mbgl/shaders/shader_source.hpp>
#include <mbgl/util/immutable.hpp>

Expand Down Expand Up @@ -53,8 +54,10 @@ class LayerTweaker {
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) {
Expand Down
18 changes: 16 additions & 2 deletions include/mbgl/util/tiny_unordered_map.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -78,11 +78,11 @@ struct TinyUnorderedMap : private std::unordered_map<Key, T, Hash, KeyEqual, All

/// 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
Expand Down Expand Up @@ -159,6 +159,20 @@ struct TinyUnorderedMap : private std::unordered_map<Key, T, Hash, KeyEqual, All
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;
Expand Down
11 changes: 9 additions & 2 deletions src/mbgl/gfx/symbol_drawable_data.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

#include <mbgl/gfx/drawable_data.hpp>
#include <mbgl/style/types.hpp>
#include <mbgl/util/tiny_unordered_map.hpp>

#include <memory>

Expand All @@ -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;
Expand All @@ -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>;
Expand Down
9 changes: 0 additions & 9 deletions src/mbgl/renderer/layer_tweaker.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down
21 changes: 16 additions & 5 deletions src/mbgl/renderer/layers/render_symbol_layer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -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,
Expand All @@ -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
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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));
Expand Down
42 changes: 21 additions & 21 deletions src/mbgl/renderer/layers/symbol_layer_tweaker.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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));
Expand Down Expand Up @@ -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
});
}
Expand Down

0 comments on commit 37a9c08

Please sign in to comment.