diff --git a/include/mbgl/gfx/vertex_attribute.hpp b/include/mbgl/gfx/vertex_attribute.hpp index cef74f616..0d1b954f8 100644 --- a/include/mbgl/gfx/vertex_attribute.hpp +++ b/include/mbgl/gfx/vertex_attribute.hpp @@ -452,14 +452,17 @@ protected: return; } - if (const auto& sharedVector = binder->getSharedVertexVector()) { - const auto rawSize = static_cast(sharedVector->getRawSize()); + if (binder->interleavedVertexBuffer) { + const auto& interleavedSharedVector = binder->interleavedVertexBuffer->sharedVertexVector; + + const auto rawSize = static_cast(binder->interleavedVertexBuffer->stride); const bool isInterpolated = binder->isInterpolated(); const auto dataType = isInterpolated ? InterpType::DataType : Type::DataType; - assert(rawSize == static_cast(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(binder->vertexOffset), 0, rawSize, dataType); } else { const auto vertexCount = binder->getVertexCount(); for (std::size_t i = 0; i < vertexCount; ++i) { diff --git a/src/mbgl/gfx/vertex_vector.hpp b/src/mbgl/gfx/vertex_vector.hpp index 14e176c99..c1debf9a3 100644 --- a/src/mbgl/gfx/vertex_vector.hpp +++ b/src/mbgl/gfx/vertex_vector.hpp @@ -33,8 +33,8 @@ public: std::chrono::duration getLastModified() const { return lastModified; } bool isModifiedAfter(std::chrono::duration t) const { return t < lastModified; } - void updateModified() { - if (dirty) { + void updateModified(bool force = false) { + if (dirty || force) { lastModified = util::MonotonicTimer::now(); dirty = false; } diff --git a/src/mbgl/renderer/paint_property_binder.hpp b/src/mbgl/renderer/paint_property_binder.hpp index 8fcb4c018..d532a1e6b 100644 --- a/src/mbgl/renderer/paint_property_binder.hpp +++ b/src/mbgl/renderer/paint_property_binder.hpp @@ -26,6 +26,41 @@ struct FeatureVertexRange { using FeatureVertexRangeMap = std::map>; +struct InterleavedVertexBuffer { + std::size_t stride = 0; + std::size_t vertexCount = 0; + + gfx::VertexVectorPtr sharedVertexVector = std::make_shared>(); + + template + 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(sharedVertexVector->data() + stride * index + offset); + memcpy(const_cast(data), &value, sizeof(value)); + } + + template + const T& get(std::size_t index, std::size_t offset) { + assert(stride * index + offset + sizeof(T) <= sharedVertexVector->bytes()); + return *reinterpret_cast(sharedVertexVector->data() + stride * index + offset); + } + + template + 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 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...> 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...> 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 + void setInterleavedBuffer(InterleavedVertexBuffer& buffer) { + interleavedVertexBuffer = &buffer; + + if (vertexOffset == 0) { + vertexOffset = interleavedVertexBuffer->extendVertexFormat(); + } + } static std::unique_ptr create(const PossiblyEvaluatedType& value, float zoom, T defaultValue); PaintPropertyStatistics statistics; + InterleavedVertexBuffer* interleavedVertexBuffer = nullptr; + std::size_t vertexOffset = 0; }; namespace detail { @@ -172,14 +219,10 @@ public: using BaseAttributeType = A; using BaseVertex = gfx::VertexType; - std::size_t getVertexCount() const override { return 0; } - std::tuple> getVertexValue(std::size_t) const override { return {ZoomInterpolatedVertexType{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...> getVertexValue(std::size_t) const override { return {ZoomInterpolatedVertexType{0}...}; } - gfx::VertexVectorBasePtr getSharedVertexVector() const override { return detail::noVector; } - private: Faded constant; std::tuple, std::array> constantPatternPositions; @@ -242,7 +281,7 @@ public: SourceFunctionPaintPropertyBinder(style::PropertyExpression expression_, T defaultValue_) : expression(std::move(expression_)), defaultValue(std::move(defaultValue_)) {} - ~SourceFunctionPaintPropertyBinder() override { sharedVertexVector->release(); } + ~SourceFunctionPaintPropertyBinder() override {} void setPatternParameters(const std::optional&, const std::optional&, @@ -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 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 interpolationFactor(float) const override { return std::tuple{0.0f}; } @@ -316,22 +355,19 @@ public: } } - std::size_t getVertexCount() const override { return vertexVector.elements(); } - std::tuple> getVertexValue(std::size_t index) const override { - const BaseVertex& value = vertexVector.at(index); + const BaseVertex& value = this->interleavedVertexBuffer->template get(index, this->vertexOffset); return {ZoomInterpolatedVertexType{concatenate(value.a1, value.a1)}}; } - gfx::VertexVectorBasePtr getSharedVertexVector() const override { return sharedVertexVector; } + using PaintPropertyBinder, A>::setInterleavedBuffer; + void setInterleavedBuffer(InterleavedVertexBuffer& buffer) override { + this->template setInterleavedBuffer(buffer); + } private: style::PropertyExpression expression; T defaultValue; - - gfx::VertexVectorPtr sharedVertexVector = std::make_shared>(); - gfx::VertexVector& 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&, const std::optional&, @@ -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 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, A>::setInterleavedBuffer; + void setInterleavedBuffer(InterleavedVertexBuffer& buffer) override { + this->template setInterleavedBuffer(buffer); + } std::tuple> getVertexValue(std::size_t index) const override { - return {vertexVector.at(index)}; + return {this->interleavedVertexBuffer->template get(index, this->vertexOffset)}; } private: style::PropertyExpression expression; T defaultValue; Range zoomRange; - - gfx::VertexVectorPtr sharedVertexVector = std::make_shared>(); - gfx::VertexVector& 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&, const std::optional&, @@ -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{{0, 0, 0, 0}}}); + const auto value = Vertex{std::array{{0, 0, 0, 0}}}; + this->interleavedVertexBuffer->set(i, this->vertexOffset, value); zoomInVertexVector.emplace_back(Vertex2{std::array{{0, 0, 0, 0}}}); zoomOutVertexVector.emplace_back(Vertex2{std::array{{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> getVertexValue( std::size_t index) const override { - const Vertex& patternValue = patternToVertexVector.at(index); + const Vertex& patternValue = this->interleavedVertexBuffer->template get(index, this->vertexOffset); const Vertex2& zoomValue = crossfade.fromScale == 2 ? zoomInVertexVector.at(index) : zoomOutVertexVector.at(index); return {ZoomInterpolatedVertexType{concatenate(patternValue.a1, patternValue.a1)}, ZoomInterpolatedVertexType{concatenate(zoomValue.a1, zoomValue.a1)}}; } - gfx::VertexVectorBasePtr getSharedVertexVector() const override { return sharedPatternToVertexVector; } + using PaintPropertyBinder, PossiblyEvaluatedPropertyValue>, A1, A2>:: + setInterleavedBuffer; + void setInterleavedBuffer(InterleavedVertexBuffer& buffer) override { + this->template setInterleavedBuffer(buffer); + } private: style::PropertyExpression expression; T defaultValue; Range zoomRange; - gfx::VertexVectorPtr sharedPatternToVertexVector = std::make_shared>(); - gfx::VertexVector& patternToVertexVector = *sharedPatternToVertexVector; - gfx::VertexVector zoomInVertexVector; gfx::VertexVector zoomOutVertexVector; @@ -655,10 +686,25 @@ public: PaintPropertyBinders(const EvaluatedProperties& properties, float z) : binders(Binder::create(properties.template get(), z, Ps::defaultValue())...) { (void)z; // Workaround for https://gcc.gnu.org/bugzilla/show_bug.cgi?id=56958 + + (([&] { + binders.template get()->setInterleavedBuffer(interleavedVertexBuffer); + }()), + ...); + } + + PaintPropertyBinders(PaintPropertyBinders&& other) noexcept { + binders = std::move(other.binders); + interleavedVertexBuffer = std::move(other.interleavedVertexBuffer); + + (([&] { + binders.template get()->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& patternDependencies, const CanonicalTileID& canonical, const style::expression::Value& formattedSection = {}) { + interleavedVertexBuffer.sharedVertexVector->extend( + (length - interleavedVertexBuffer.vertexCount) * interleavedVertexBuffer.stride, {}); + util::ignore({(binders.template get()->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()->updateVertexVectors(states, layer, imagePositions), 0)...}); + interleavedVertexBuffer.sharedVertexVector->updateModified(true); } void setPatternParameters(const std::optional& posA, const std::optional& posB, const CrossfadeParameters& crossfade) { util::ignore({(binders.template get()->setPatternParameters(posA, posB, crossfade), 0)...}); + interleavedVertexBuffer.sharedVertexVector->updateModified(true); } template @@ -721,6 +775,8 @@ public: return binders.template get

()->statistics; } + InterleavedVertexBuffer interleavedVertexBuffer; + private: Binders binders; };