#pragma once #include #include #include #include #include #include #include #include namespace mbgl { class AsyncRequest; namespace style { // A Source-owned, preloaded validation candidate. Production runtimes can use // updateRuntimeFieldWindow() directly with an already decoded snapshot instead. struct RasterArrayRuntimeFieldDescriptor { std::string fixtureID; std::string metadataURL; std::string fieldURL; // Validation-only logical time in milliseconds. A production adapter owns // its own timeline metadata; this keeps fixtures deterministic. uint64_t timestamp = 0; }; enum class RasterArrayPlaybackState : uint8_t { Ready, Playing, Paused, Waiting, Ended }; struct RasterArrayTimelineFrame { std::shared_ptr t0; std::shared_ptr t1; float mix = 0.0f; size_t t0Index = 0; size_t t1Index = 0; uint64_t windowRevision = 0; RasterArrayPlaybackState state = RasterArrayPlaybackState::Ready; }; // Source-owned playback state. Android only sends low-frequency commands; // render frames obtain an immutable T0/T1 pair and scalar mix from Core. class RasterArrayTimelineRuntime { public: struct Entry { std::shared_ptr field; uint64_t timestamp = 0; }; explicit RasterArrayTimelineRuntime(std::vector); RasterArrayTimelineFrame tick(); bool play(); bool pause(); bool setSpeed(float); bool seek(size_t); bool step(int); bool injectGap(); bool injectInvalid(); bool recover(); RasterArrayTimelineFrame frame() const; size_t cacheCapacity() const { return cacheCapacity_; } private: RasterArrayTimelineFrame frameLocked() const; bool moveToLocked(size_t); mutable std::mutex mutex; std::vector entries; size_t t0 = 0; float mix = 0.0f; float speed = 1.0f; RasterArrayPlaybackState state = RasterArrayPlaybackState::Ready; bool gap = false; bool invalid = false; RasterArrayPlaybackState stateBeforeWait = RasterArrayPlaybackState::Paused; uint64_t windowRevision = 1; std::chrono::steady_clock::time_point lastTick{}; const size_t cacheCapacity_ = 8; }; enum class RasterArrayRuntimeFieldUpdateResult : uint8_t { Applied, Noop, RejectedNotLoaded, RejectedInvalidSnapshot, RejectedIncompatibleSnapshot, RejectedNonMonotonicGeneration, RejectedCandidateNotReady, RejectedNoCandidate, }; class RasterArraySource final : public Source { public: RasterArraySource(std::string id, std::string fixtureID, std::string metadataURL, std::string fieldURL, std::string nextFixtureID = {}, std::string nextMetadataURL = {}, std::string nextFieldURL = {}, std::vector runtimeFields = {}); ~RasterArraySource() override; class Impl; const Impl& impl() const; void loadDescription(FileSource&) override; // Advances the authoritative Source time window from T0/T1 to T1/newT1. // The caller transfers an immutable, already decoded Field snapshot; the // renderer observes the resulting Source change and owns GPU reuse/upload. RasterArrayRuntimeFieldUpdateResult updateRuntimeFieldWindow(particle::ParticleFieldSnapshot newT1); // Validation convenience: advance using the next Source-owned preloaded // candidate. Android supplies no T0/T1 state and no GPU resource here. RasterArrayRuntimeFieldUpdateResult advanceRuntimeFieldWindow(); // Validation convenience: resubmit the current T1 through the formal // update API. This must return Noop without changing the Source window. RasterArrayRuntimeFieldUpdateResult repeatRuntimeFieldWindow(); // Low-frequency JNI commands for the Source-owned validation timeline. bool controlRuntimeTimeline(int command, float value = 0.0f); bool supportsLayerType(const LayerTypeInfo*) const override; mapbox::base::WeakPtr makeWeakPtr() override { return weakFactory.makeWeakPtr(); } protected: Mutable createMutable() const noexcept override; private: struct RuntimeFieldCandidate { RasterArrayRuntimeFieldDescriptor descriptor; std::unique_ptr metadataRequest; std::unique_ptr fieldRequest; std::optional metadata; std::optional> fieldBytes; std::optional snapshot; }; void tryLoad(); void tryLoadRuntimeField(size_t); void tryInitializeTimeline(); RasterArrayRuntimeFieldUpdateResult rejectRuntimeFieldUpdate(RasterArrayRuntimeFieldUpdateResult, const std::string& reason) const; std::unique_ptr metadataRequest; std::unique_ptr fieldRequest; std::unique_ptr nextMetadataRequest; std::unique_ptr nextFieldRequest; std::optional metadata; std::optional> fieldBytes; std::optional nextMetadata; std::optional> nextFieldBytes; std::vector runtimeFields; size_t nextRuntimeField = 0; uint64_t runtimeUpdateSequence = 0; std::shared_ptr timeline; mapbox::base::WeakPtrFactory weakFactory{this}; }; template <> inline bool Source::is() const { return getType() == SourceType::RasterArray; } } // namespace style } // namespace mbgl