core: Use interleaved buffer for paint property binders (#4124)
Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
This commit is contained in:
@@ -452,14 +452,17 @@ protected:
|
||||
return;
|
||||
}
|
||||
|
||||
if (const auto& sharedVector = binder->getSharedVertexVector()) {
|
||||
const auto rawSize = static_cast<uint32_t>(sharedVector->getRawSize());
|
||||
if (binder->interleavedVertexBuffer) {
|
||||
const auto& interleavedSharedVector = binder->interleavedVertexBuffer->sharedVertexVector;
|
||||
|
||||
const auto rawSize = static_cast<uint32_t>(binder->interleavedVertexBuffer->stride);
|
||||
const bool isInterpolated = binder->isInterpolated();
|
||||
const auto dataType = isInterpolated ? InterpType::DataType : Type::DataType;
|
||||
assert(rawSize == static_cast<uint32_t>(isInterpolated ? sizeof(typename InterpType::Value)
|
||||
: sizeof(typename Type::Value)));
|
||||
assert(sharedVector->getRawCount() == binder->getVertexCount());
|
||||
attrib->setSharedRawData(std::move(sharedVector), 0, 0, rawSize, dataType);
|
||||
|
||||
assert(interleavedSharedVector->getRawCount() / binder->interleavedVertexBuffer->stride ==
|
||||
binder->getVertexCount());
|
||||
attrib->setSharedRawData(
|
||||
std::move(interleavedSharedVector), static_cast<uint32_t>(binder->vertexOffset), 0, rawSize, dataType);
|
||||
} else {
|
||||
const auto vertexCount = binder->getVertexCount();
|
||||
for (std::size_t i = 0; i < vertexCount; ++i) {
|
||||
|
||||
@@ -33,8 +33,8 @@ public:
|
||||
std::chrono::duration<double> getLastModified() const { return lastModified; }
|
||||
bool isModifiedAfter(std::chrono::duration<double> t) const { return t < lastModified; }
|
||||
|
||||
void updateModified() {
|
||||
if (dirty) {
|
||||
void updateModified(bool force = false) {
|
||||
if (dirty || force) {
|
||||
lastModified = util::MonotonicTimer::now();
|
||||
dirty = false;
|
||||
}
|
||||
|
||||
@@ -26,6 +26,41 @@ struct FeatureVertexRange {
|
||||
|
||||
using FeatureVertexRangeMap = std::map<std::string, std::vector<FeatureVertexRange>>;
|
||||
|
||||
struct InterleavedVertexBuffer {
|
||||
std::size_t stride = 0;
|
||||
std::size_t vertexCount = 0;
|
||||
|
||||
gfx::VertexVectorPtr<uint8_t> sharedVertexVector = std::make_shared<gfx::VertexVector<uint8_t>>();
|
||||
|
||||
template <typename T>
|
||||
void set(std::size_t index, std::size_t offset, const T& value) {
|
||||
assert(stride * index + offset + sizeof(T) <= sharedVertexVector->bytes());
|
||||
const void* data = reinterpret_cast<const void*>(sharedVertexVector->data() + stride * index + offset);
|
||||
memcpy(const_cast<void*>(data), &value, sizeof(value));
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
const T& get(std::size_t index, std::size_t offset) {
|
||||
assert(stride * index + offset + sizeof(T) <= sharedVertexVector->bytes());
|
||||
return *reinterpret_cast<const T*>(sharedVertexVector->data() + stride * index + offset);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
size_t extendVertexFormat() {
|
||||
constexpr auto alignment = alignof(T);
|
||||
|
||||
size_t offset = stride & (alignment - 1);
|
||||
if (offset != 0) {
|
||||
offset = alignment - offset;
|
||||
}
|
||||
|
||||
size_t vertexOffset = stride + offset;
|
||||
stride += sizeof(T) + offset;
|
||||
|
||||
return vertexOffset;
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
ZoomInterpolatedAttribute<Attr> is a 'compound' attribute, representing two
|
||||
values of the the base attribute Attr. These two values are provided to the
|
||||
@@ -126,18 +161,30 @@ public:
|
||||
virtual std::tuple<ExpandToType<As, UniformValueType>...> uniformValue(
|
||||
const PossiblyEvaluatedType& currentValue) const = 0;
|
||||
|
||||
virtual std::size_t getVertexCount() const = 0;
|
||||
|
||||
/// Indicates that the vertex data is duplicated for interpolation
|
||||
virtual bool isInterpolated() const { return false; }
|
||||
|
||||
virtual std::tuple<ZoomInterpolatedVertexType<As>...> getVertexValue(std::size_t index) const = 0;
|
||||
|
||||
virtual gfx::VertexVectorBasePtr getSharedVertexVector() const = 0;
|
||||
virtual std::size_t getVertexCount() const {
|
||||
return interleavedVertexBuffer ? interleavedVertexBuffer->vertexCount : 0;
|
||||
}
|
||||
virtual void setInterleavedBuffer(InterleavedVertexBuffer&) {}
|
||||
|
||||
template <typename VertexFormat>
|
||||
void setInterleavedBuffer(InterleavedVertexBuffer& buffer) {
|
||||
interleavedVertexBuffer = &buffer;
|
||||
|
||||
if (vertexOffset == 0) {
|
||||
vertexOffset = interleavedVertexBuffer->extendVertexFormat<VertexFormat>();
|
||||
}
|
||||
}
|
||||
|
||||
static std::unique_ptr<PaintPropertyBinder> create(const PossiblyEvaluatedType& value, float zoom, T defaultValue);
|
||||
|
||||
PaintPropertyStatistics<T> statistics;
|
||||
InterleavedVertexBuffer* interleavedVertexBuffer = nullptr;
|
||||
std::size_t vertexOffset = 0;
|
||||
};
|
||||
|
||||
namespace detail {
|
||||
@@ -172,14 +219,10 @@ public:
|
||||
using BaseAttributeType = A;
|
||||
using BaseVertex = gfx::VertexType<BaseAttributeType>;
|
||||
|
||||
std::size_t getVertexCount() const override { return 0; }
|
||||
|
||||
std::tuple<ZoomInterpolatedVertexType<A>> getVertexValue(std::size_t) const override {
|
||||
return {ZoomInterpolatedVertexType<A>{0}};
|
||||
}
|
||||
|
||||
gfx::VertexVectorBasePtr getSharedVertexVector() const override { return detail::noVector; }
|
||||
|
||||
private:
|
||||
T constant;
|
||||
mutable BaseVertex convertedValue;
|
||||
@@ -220,14 +263,10 @@ public:
|
||||
return constantPatternPositions;
|
||||
}
|
||||
|
||||
std::size_t getVertexCount() const override { return 0; }
|
||||
|
||||
std::tuple<ZoomInterpolatedVertexType<As>...> getVertexValue(std::size_t) const override {
|
||||
return {ZoomInterpolatedVertexType<As>{0}...};
|
||||
}
|
||||
|
||||
gfx::VertexVectorBasePtr getSharedVertexVector() const override { return detail::noVector; }
|
||||
|
||||
private:
|
||||
Faded<T> constant;
|
||||
std::tuple<std::array<uint16_t, 4>, std::array<uint16_t, 4>> constantPatternPositions;
|
||||
@@ -242,7 +281,7 @@ public:
|
||||
SourceFunctionPaintPropertyBinder(style::PropertyExpression<T> expression_, T defaultValue_)
|
||||
: expression(std::move(expression_)),
|
||||
defaultValue(std::move(defaultValue_)) {}
|
||||
~SourceFunctionPaintPropertyBinder() override { sharedVertexVector->release(); }
|
||||
~SourceFunctionPaintPropertyBinder() override {}
|
||||
|
||||
void setPatternParameters(const std::optional<ImagePosition>&,
|
||||
const std::optional<ImagePosition>&,
|
||||
@@ -260,9 +299,11 @@ public:
|
||||
defaultValue);
|
||||
this->statistics.add(evaluated);
|
||||
auto value = attributeValue(evaluated);
|
||||
auto elements = vertexVector.elements();
|
||||
|
||||
const std::size_t elements = this->getVertexCount();
|
||||
|
||||
for (std::size_t i = elements; i < length; ++i) {
|
||||
vertexVector.emplace_back(BaseVertex{value});
|
||||
this->interleavedVertexBuffer->set(i, this->vertexOffset, BaseVertex{value});
|
||||
}
|
||||
std::optional<std::string> idStr = featureIDtoString(feature.getID());
|
||||
if (idStr) {
|
||||
@@ -299,10 +340,8 @@ public:
|
||||
|
||||
const auto value = BaseVertex{attributeValue(evaluated)};
|
||||
for (std::size_t i = start; i < end; ++i) {
|
||||
vertexVector.at(i) = value;
|
||||
this->interleavedVertexBuffer->set(i, this->vertexOffset, value);
|
||||
}
|
||||
|
||||
vertexVector.updateModified();
|
||||
}
|
||||
|
||||
std::tuple<float> interpolationFactor(float) const override { return std::tuple<float>{0.0f}; }
|
||||
@@ -316,22 +355,19 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
std::size_t getVertexCount() const override { return vertexVector.elements(); }
|
||||
|
||||
std::tuple<ZoomInterpolatedVertexType<A>> getVertexValue(std::size_t index) const override {
|
||||
const BaseVertex& value = vertexVector.at(index);
|
||||
const BaseVertex& value = this->interleavedVertexBuffer->template get<BaseVertex>(index, this->vertexOffset);
|
||||
return {ZoomInterpolatedVertexType<A>{concatenate(value.a1, value.a1)}};
|
||||
}
|
||||
|
||||
gfx::VertexVectorBasePtr getSharedVertexVector() const override { return sharedVertexVector; }
|
||||
using PaintPropertyBinder<T, T, PossiblyEvaluatedPropertyValue<T>, A>::setInterleavedBuffer;
|
||||
void setInterleavedBuffer(InterleavedVertexBuffer& buffer) override {
|
||||
this->template setInterleavedBuffer<BaseVertex>(buffer);
|
||||
}
|
||||
|
||||
private:
|
||||
style::PropertyExpression<T> expression;
|
||||
T defaultValue;
|
||||
|
||||
gfx::VertexVectorPtr<BaseVertex> sharedVertexVector = std::make_shared<gfx::VertexVector<BaseVertex>>();
|
||||
gfx::VertexVector<BaseVertex>& vertexVector = *sharedVertexVector;
|
||||
|
||||
FeatureVertexRangeMap featureMap;
|
||||
};
|
||||
|
||||
@@ -347,7 +383,7 @@ public:
|
||||
: expression(std::move(expression_)),
|
||||
defaultValue(std::move(defaultValue_)),
|
||||
zoomRange({zoom, zoom + 1}) {}
|
||||
~CompositeFunctionPaintPropertyBinder() override { sharedVertexVector->release(); }
|
||||
~CompositeFunctionPaintPropertyBinder() override {}
|
||||
|
||||
void setPatternParameters(const std::optional<ImagePosition>&,
|
||||
const std::optional<ImagePosition>&,
|
||||
@@ -374,12 +410,10 @@ public:
|
||||
this->statistics.add(range.max);
|
||||
const AttributeValue value = zoomInterpolatedAttributeValue(attributeValue(range.min),
|
||||
attributeValue(range.max));
|
||||
const auto elements = vertexVector.elements();
|
||||
if (vertexVector.empty()) {
|
||||
vertexVector.reserve(length);
|
||||
}
|
||||
const std::size_t elements = this->getVertexCount();
|
||||
|
||||
for (std::size_t i = elements; i < length; ++i) {
|
||||
vertexVector.emplace_back(Vertex{value});
|
||||
this->interleavedVertexBuffer->set(i, this->vertexOffset, Vertex{value});
|
||||
}
|
||||
if (auto idStr = featureIDtoString(feature.getID())) {
|
||||
featureMap[*idStr].emplace_back(FeatureVertexRange{index, elements, length});
|
||||
@@ -420,10 +454,8 @@ public:
|
||||
zoomInterpolatedAttributeValue(attributeValue(range.min), attributeValue(range.max))};
|
||||
|
||||
for (std::size_t i = start; i < end; ++i) {
|
||||
vertexVector.at(i) = value;
|
||||
this->interleavedVertexBuffer->set(i, this->vertexOffset, value);
|
||||
}
|
||||
|
||||
vertexVector.updateModified();
|
||||
}
|
||||
|
||||
std::tuple<float> interpolationFactor(float currentZoom) const override {
|
||||
@@ -442,24 +474,21 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
std::size_t getVertexCount() const override { return vertexVector.elements(); }
|
||||
|
||||
bool isInterpolated() const override { return true; }
|
||||
|
||||
gfx::VertexVectorBasePtr getSharedVertexVector() const override { return sharedVertexVector; }
|
||||
using PaintPropertyBinder<T, T, PossiblyEvaluatedPropertyValue<T>, A>::setInterleavedBuffer;
|
||||
void setInterleavedBuffer(InterleavedVertexBuffer& buffer) override {
|
||||
this->template setInterleavedBuffer<Vertex>(buffer);
|
||||
}
|
||||
|
||||
std::tuple<ZoomInterpolatedVertexType<A>> getVertexValue(std::size_t index) const override {
|
||||
return {vertexVector.at(index)};
|
||||
return {this->interleavedVertexBuffer->template get<Vertex>(index, this->vertexOffset)};
|
||||
}
|
||||
|
||||
private:
|
||||
style::PropertyExpression<T> expression;
|
||||
T defaultValue;
|
||||
Range<float> zoomRange;
|
||||
|
||||
gfx::VertexVectorPtr<Vertex> sharedVertexVector = std::make_shared<gfx::VertexVector<Vertex>>();
|
||||
gfx::VertexVector<Vertex>& vertexVector = *sharedVertexVector;
|
||||
|
||||
FeatureVertexRangeMap featureMap;
|
||||
};
|
||||
|
||||
@@ -477,7 +506,7 @@ public:
|
||||
: expression(std::move(expression_)),
|
||||
defaultValue(std::move(defaultValue_)),
|
||||
zoomRange({zoom, zoom + 1}) {}
|
||||
~CompositeCrossFadedPaintPropertyBinder() override { sharedPatternToVertexVector->release(); }
|
||||
~CompositeCrossFadedPaintPropertyBinder() override {}
|
||||
|
||||
void setPatternParameters(const std::optional<ImagePosition>&,
|
||||
const std::optional<ImagePosition>&,
|
||||
@@ -500,7 +529,8 @@ public:
|
||||
// try to draw the layer because we don't know at draw time if all
|
||||
// features were evaluated to valid pattern dependencies.
|
||||
for (std::size_t i = zoomInVertexVector.elements(); i < length; ++i) {
|
||||
patternToVertexVector.emplace_back(Vertex{std::array<uint16_t, 4>{{0, 0, 0, 0}}});
|
||||
const auto value = Vertex{std::array<uint16_t, 4>{{0, 0, 0, 0}}};
|
||||
this->interleavedVertexBuffer->set(i, this->vertexOffset, value);
|
||||
zoomInVertexVector.emplace_back(Vertex2{std::array<uint16_t, 4>{{0, 0, 0, 0}}});
|
||||
zoomOutVertexVector.emplace_back(Vertex2{std::array<uint16_t, 4>{{0, 0, 0, 0}}});
|
||||
}
|
||||
@@ -517,9 +547,11 @@ public:
|
||||
const ImagePosition imageMax = max->second;
|
||||
|
||||
for (std::size_t i = zoomInVertexVector.elements(); i < length; ++i) {
|
||||
patternToVertexVector.emplace_back(Vertex{imageMid.tlbr()});
|
||||
zoomInVertexVector.emplace_back(Vertex2{imageMin.tlbr()});
|
||||
zoomOutVertexVector.emplace_back(Vertex2{imageMax.tlbr()});
|
||||
|
||||
const auto& value = Vertex{imageMid.tlbr()};
|
||||
this->interleavedVertexBuffer->set(i, this->vertexOffset, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -534,27 +566,26 @@ public:
|
||||
return {};
|
||||
}
|
||||
|
||||
std::size_t getVertexCount() const override { return patternToVertexVector.elements(); }
|
||||
|
||||
std::tuple<ZoomInterpolatedVertexType<A1>, ZoomInterpolatedVertexType<A2>> getVertexValue(
|
||||
std::size_t index) const override {
|
||||
const Vertex& patternValue = patternToVertexVector.at(index);
|
||||
const Vertex& patternValue = this->interleavedVertexBuffer->template get<Vertex>(index, this->vertexOffset);
|
||||
const Vertex2& zoomValue = crossfade.fromScale == 2 ? zoomInVertexVector.at(index)
|
||||
: zoomOutVertexVector.at(index);
|
||||
return {ZoomInterpolatedVertexType<A1>{concatenate(patternValue.a1, patternValue.a1)},
|
||||
ZoomInterpolatedVertexType<A2>{concatenate(zoomValue.a1, zoomValue.a1)}};
|
||||
}
|
||||
|
||||
gfx::VertexVectorBasePtr getSharedVertexVector() const override { return sharedPatternToVertexVector; }
|
||||
using PaintPropertyBinder<T, std::array<uint16_t, 4>, PossiblyEvaluatedPropertyValue<Faded<T>>, A1, A2>::
|
||||
setInterleavedBuffer;
|
||||
void setInterleavedBuffer(InterleavedVertexBuffer& buffer) override {
|
||||
this->template setInterleavedBuffer<Vertex>(buffer);
|
||||
}
|
||||
|
||||
private:
|
||||
style::PropertyExpression<T> expression;
|
||||
T defaultValue;
|
||||
Range<float> zoomRange;
|
||||
|
||||
gfx::VertexVectorPtr<Vertex> sharedPatternToVertexVector = std::make_shared<gfx::VertexVector<Vertex>>();
|
||||
gfx::VertexVector<Vertex>& patternToVertexVector = *sharedPatternToVertexVector;
|
||||
|
||||
gfx::VertexVector<Vertex2> zoomInVertexVector;
|
||||
gfx::VertexVector<Vertex2> zoomOutVertexVector;
|
||||
|
||||
@@ -655,10 +686,25 @@ public:
|
||||
PaintPropertyBinders(const EvaluatedProperties& properties, float z)
|
||||
: binders(Binder<Ps>::create(properties.template get<Ps>(), z, Ps::defaultValue())...) {
|
||||
(void)z; // Workaround for https://gcc.gnu.org/bugzilla/show_bug.cgi?id=56958
|
||||
|
||||
(([&] {
|
||||
binders.template get<Ps>()->setInterleavedBuffer(interleavedVertexBuffer);
|
||||
}()),
|
||||
...);
|
||||
}
|
||||
|
||||
PaintPropertyBinders(PaintPropertyBinders&& other) noexcept {
|
||||
binders = std::move(other.binders);
|
||||
interleavedVertexBuffer = std::move(other.interleavedVertexBuffer);
|
||||
|
||||
(([&] {
|
||||
binders.template get<Ps>()->setInterleavedBuffer(interleavedVertexBuffer);
|
||||
}()),
|
||||
...);
|
||||
}
|
||||
|
||||
PaintPropertyBinders(PaintPropertyBinders&&) noexcept = default;
|
||||
PaintPropertyBinders(const PaintPropertyBinders&) = delete;
|
||||
~PaintPropertyBinders() = default;
|
||||
|
||||
void populateVertexVectors(const GeometryTileFeature& feature,
|
||||
std::size_t length,
|
||||
@@ -667,21 +713,29 @@ public:
|
||||
const std::optional<PatternDependency>& patternDependencies,
|
||||
const CanonicalTileID& canonical,
|
||||
const style::expression::Value& formattedSection = {}) {
|
||||
interleavedVertexBuffer.sharedVertexVector->extend(
|
||||
(length - interleavedVertexBuffer.vertexCount) * interleavedVertexBuffer.stride, {});
|
||||
|
||||
util::ignore({(binders.template get<Ps>()->populateVertexVector(
|
||||
feature, length, index, patternPositions, patternDependencies, canonical, formattedSection),
|
||||
0)...});
|
||||
|
||||
interleavedVertexBuffer.vertexCount += length - interleavedVertexBuffer.vertexCount;
|
||||
interleavedVertexBuffer.sharedVertexVector->updateModified(true);
|
||||
}
|
||||
|
||||
void updateVertexVectors(const FeatureStates& states,
|
||||
const GeometryTileLayer& layer,
|
||||
const ImagePositions& imagePositions) {
|
||||
util::ignore({(binders.template get<Ps>()->updateVertexVectors(states, layer, imagePositions), 0)...});
|
||||
interleavedVertexBuffer.sharedVertexVector->updateModified(true);
|
||||
}
|
||||
|
||||
void setPatternParameters(const std::optional<ImagePosition>& posA,
|
||||
const std::optional<ImagePosition>& posB,
|
||||
const CrossfadeParameters& crossfade) {
|
||||
util::ignore({(binders.template get<Ps>()->setPatternParameters(posA, posB, crossfade), 0)...});
|
||||
interleavedVertexBuffer.sharedVertexVector->updateModified(true);
|
||||
}
|
||||
|
||||
template <class P>
|
||||
@@ -721,6 +775,8 @@ public:
|
||||
return binders.template get<P>()->statistics;
|
||||
}
|
||||
|
||||
InterleavedVertexBuffer interleavedVertexBuffer;
|
||||
|
||||
private:
|
||||
Binders binders;
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user