blob: e61bb91cc98e948db2ecf5148dc8f0eae4ce83d1 [file] [log] [blame]
// Copyright 2023 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_CAMERA_BIN_CAMERA_GYM_BUFFER_COLLAGE_FLATLAND_H_
#define SRC_CAMERA_BIN_CAMERA_GYM_BUFFER_COLLAGE_FLATLAND_H_
#include <fuchsia/element/cpp/fidl.h>
#include <fuchsia/math/cpp/fidl.h>
#include <fuchsia/sysmem/cpp/fidl.h>
#include <fuchsia/ui/composition/cpp/fidl.h>
#include <lib/async-loop/cpp/loop.h>
#include <lib/async/cpp/wait.h>
#include <lib/fidl/cpp/binding.h>
#include <lib/fidl/cpp/interface_request.h>
#include <lib/fpromise/promise.h>
#include <lib/fpromise/result.h>
#include <lib/syslog/cpp/macros.h>
#include <cstdint>
#include <map>
#include "fuchsia/camera/gym/cpp/fidl.h"
#include "src/lib/ui/flatland-frame-scheduling/src/simple_present.h"
#include "src/ui/scenic/lib/allocation/buffer_collection_import_export_tokens.h"
namespace camera_flatland {
using fuchsia::ui::composition::ContentId;
using fuchsia::ui::composition::LayoutInfo;
using fuchsia::ui::composition::TransformId;
// Returns an event such that when the event is signaled and the dispatcher executed, the provided
// eventpair is closed. This can be used to bridge event- and eventpair-based fence semantics. If
// this function returns an error, |eventpair| is closed immediately.
inline fpromise::result<zx::event, zx_status_t> MakeEventBridge(async_dispatcher_t* dispatcher,
zx::eventpair* eventpair) {
zx::event caller_event;
zx::event waiter_event;
zx_status_t status = zx::event::create(0, &caller_event);
if (status != ZX_OK) {
FX_PLOGS(ERROR, status);
return fpromise::error(status);
}
status = caller_event.duplicate(ZX_RIGHT_SAME_RIGHTS, &waiter_event);
if (status != ZX_OK) {
FX_PLOGS(ERROR, status);
return fpromise::error(status);
}
// A shared_ptr is necessary in order to begin the wait after setting the wait handler.
auto wait = std::make_shared<async::Wait>(waiter_event.get(), ZX_EVENT_SIGNALED);
wait->set_handler([wait, waiter_event = std::move(waiter_event)](
async_dispatcher_t* /*unused*/, async::Wait* /*unused*/,
zx_status_t /*unused*/, const zx_packet_signal_t* /*unused*/) mutable {
// Close the waiter along with its captures.
wait = nullptr;
});
status = wait->Begin(dispatcher);
if (status != ZX_OK) {
FX_PLOGS(ERROR, status);
return fpromise::error(status);
}
return fpromise::ok(std::move(caller_event));
}
// Defines a view used to render a single camera stream.
struct CollectionView {
fuchsia::sysmem::ImageFormat_2 image_format;
fuchsia::sysmem::BufferCollectionPtr buffer_collection;
std::map<uint32_t, ContentId> buffer_id_to_content_id;
uint32_t buffer_count;
bool muted = false;
bool view_created = false;
TransformId transform_id{0}; // transform_id stays constant throughout view lifecycle.
allocation::BufferCollectionImportExportTokens ref_pair;
};
// This class takes ownership of the display and presents the contents of buffer collections in a
// grid pattern. Unless otherwise noted, public methods are thread-safe and private methods must
// only be called from the loop's thread.
class BufferCollageFlatland {
public:
using CommandStatusHandler =
fit::function<void(fuchsia::camera::gym::Controller_SendCommand_Result)>;
~BufferCollageFlatland();
// Creates a new BufferCollage instance using the provided interface handles. After returning, if
// the instance stops running, either due to an error or explicit action, |stop_callback| is
// invoked exactly once if non-null.
static fpromise::result<std::unique_ptr<BufferCollageFlatland>, zx_status_t> Create(
std::unique_ptr<simple_present::FlatlandConnection> flatland_connection,
fuchsia::ui::composition::AllocatorHandle flatland_allocator,
fuchsia::element::GraphicalPresenterHandle graphical_presenter,
fuchsia::sysmem::AllocatorHandle sysmem_allocator, fit::closure stop_callback = nullptr);
// Registers a new buffer collection and adds it to the views, updating the layout of existing
// collections to fit. Returns an id representing the collection. Collections are initially
// hidden and must be made visible using PostSetCollectionVisibility.
fpromise::promise<uint32_t> AddCollection(fuchsia::sysmem::BufferCollectionTokenHandle token,
fuchsia::sysmem::ImageFormat_2 image_format,
std::string description);
// Removes the collection with the given |collection_id| from the view and updates the layout to
// fill the vacated space. If |id| is not a valid collection, the instance stops.
void RemoveCollection(uint32_t collection_id);
// Updates the view to show the given |buffer_index| in for the given |collection_id|'s node.
// Holds |release_fence| until the buffer is no longer needed, then closes the handle. If
// non-null, |subregion| specifies what sub-region of the buffer to highlight.
void PostShowBuffer(uint32_t collection_id, uint32_t buffer_index, zx::eventpair* release_fence,
std::optional<fuchsia::math::RectF> subregion);
// Present view to graphical presenter.
void PresentView();
private:
BufferCollageFlatland();
// Disconnects all channels, quits the loop, and calls the stop callback.
void Stop();
// Registers the provided interface's error handler to invoke Stop.
template <typename T>
void SetStopOnError(fidl::InterfacePtr<T>& p, std::string name = T::Name_);
// Registers the provided interface's error handler to invoke normal tear down upon any error.
// Primarily designed to handle respond to any BufferCollection errors by removing CollectionView.
template <typename T>
void SetRemoveCollectionViewOnError(fidl::InterfacePtr<T>& p, uint32_t view_id, std::string name);
// Presents buffer content on screen. See PostShowBuffer.
void ShowBuffer(uint32_t collection_id, uint32_t buffer_index, zx::eventpair* release_fence,
std::optional<fuchsia::math::RectF> subregion);
// Repositions scenic nodes to fit all collections on the screen.
void UpdateLayout();
// Initialize flatland root view.
void SetupBaseView();
// Thread used for processing camera stream buffers and calling Flatland API.
async::Loop loop_;
fuchsia::sysmem::AllocatorPtr sysmem_allocator_;
fuchsia::element::GraphicalPresenterPtr graphical_presenter_;
fit::closure stop_callback_;
std::unique_ptr<simple_present::FlatlandConnection> flatland_connection_;
fuchsia::ui::composition::Flatland* flatland_;
fuchsia::ui::composition::ParentViewportWatcherPtr parent_watcher_;
fuchsia::ui::composition::AllocatorPtr flatland_allocator_;
std::map<uint32_t, CollectionView> collection_views_;
uint32_t width_ = 0;
uint32_t height_ = 0;
const TransformId kRootTransformId{.value = 1};
int32_t next_collection_id_ = 1;
unsigned int next_transform_id = 3;
unsigned int next_content_id = 2;
zx::time start_time_;
};
} // namespace camera_flatland
#endif // SRC_CAMERA_BIN_CAMERA_GYM_BUFFER_COLLAGE_FLATLAND_H_