blob: a8cb6cda1fd6c507741d410b43dd6dfa3b8c0304 [file] [log] [blame]
// Copyright 2019 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef SRC_UI_SCENIC_LIB_FLATLAND_UBER_STRUCT_SYSTEM_H_
#define SRC_UI_SCENIC_LIB_FLATLAND_UBER_STRUCT_SYSTEM_H_
#include <mutex>
#include <optional>
#include <queue>
#include <unordered_map>
#include "src/ui/scenic/lib/flatland/transform_handle.h"
#include "src/ui/scenic/lib/flatland/uber_struct.h"
#include "src/ui/scenic/lib/scheduling/frame_scheduler.h"
namespace flatland {
// TODO(fxbug.dev/45932): write a bug to find a better name for this system
//
// A system for aggregating local data from Flatland instances to be consumed by the render loop.
// All functions are thread safe. The intent is for separate worker threads to own each Flatland
// instance, compute local data (such as topology vectors) in their local thread, and then commit
// those vectors to this class in a concurrent manner.
class UberStructSystem {
public:
UberStructSystem() = default;
// Returns the next instance ID for this particular UberStructSystem. Instance IDs are guaranteed
// to be unique for each caller and should be used as keys for setting UberStructs and accessing
// UberStructs in snapshots.
TransformHandle::InstanceId GetNextInstanceId();
// An UberStruct that has not been published to the visible snapshot and the PresentId it is
// associated with.
struct PendingUberStruct {
scheduling::PresentId present_id;
std::unique_ptr<UberStruct> uber_struct;
};
// An interface for UberStructSystem clients to queue UberStructs to be published into the
// visible snapshot.
class UberStructQueue {
public:
// Queues an UberStruct for |present_id|. Each Flatland instance can queue multiple UberStructs
// in the UberStructSystem by using different PresentIds. PresentIds must be increasing between
// subsequent calls.
void Push(scheduling::PresentId present_id, std::unique_ptr<UberStruct> uber_struct);
// Pops a PendingUberStruct off of this Queue. If the queue is currently empty, returns
// std::nullopt.
std::optional<PendingUberStruct> Pop();
// Returns the number of PendingUberStructs in this queue.
size_t GetPendingSize();
private:
// TODO(fxbug.dev/57745): add a lock-free queue.
// Protects access to |pending_structs_|.
std::mutex queue_mutex_;
std::queue<PendingUberStruct> pending_structs_;
};
// Allocates an UberStructQueue for |session_id| and returns a shared reference to that
// UberStructQueue. Callers should call |RemoveSession| when the session associated with that
// |session_id| has exited to clean up the allocated resources.
std::shared_ptr<UberStructQueue> AllocateQueueForSession(scheduling::SessionId session_id);
// Removes the UberStructQueue and current UberStruct associated with |session_id|. Any
// PendingUberStructs pushed into the queue after this call will never be published to the
// InstanceMap.
void RemoveSession(scheduling::SessionId session_id);
// Commits a new UberStruct to the instance map for each key/value pair in |sessions_to_update|.
// All pending UberStructs associated with each SessionId with lower PresentIds will be
// discarded. Returns the set of SessionIds that did not have their associated PresentId in their
// queue, indicating the session failed to update.
scheduling::SessionUpdater::UpdateResults UpdateSessions(
const std::unordered_map<scheduling::SessionId, scheduling::PresentId>& sessions_to_update);
// Snapshots the current map of UberStructs and returns the copy.
UberStruct::InstanceMap Snapshot();
// For pushing all pending UberStructs in tests.
void ForceUpdateAllSessions(size_t max_updates_per_queue = 10);
// For validating cleanup logic in tests.
size_t GetSessionCount();
// For getting Flatland InstanceIds in tests.
TransformHandle::InstanceId GetLatestInstanceId() const;
private:
// The queue of UberStructs pending for each active session. Flatland instances push UberStructs
// onto these queues using |UberStructQueue::Push()|. This UberStructSystem removes entries using
// |UberStructQueue::Pop()|. Both of those operations are threadsafe, but the map itself is only
// modified from a single thread.
std::unordered_map<scheduling::SessionId, std::shared_ptr<UberStructQueue>>
pending_structs_queues_;
// The current UberStruct for each Flatland instance.
UberStruct::InstanceMap uber_struct_map_;
// The InstanceId most recently returned from GetNextInstanceId().
TransformHandle::InstanceId latest_instance_id_;
};
} // namespace flatland
#endif // SRC_UI_SCENIC_LIB_FLATLAND_UBER_STRUCT_SYSTEM_H_