blob: ee8254c48d041b504de394400b08bc7982bf33b0 [file] [log] [blame]
// Copyright 2020 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_ENGINE_ENGINE_H_
#define SRC_UI_SCENIC_LIB_FLATLAND_ENGINE_ENGINE_H_
#include "src/ui/scenic/lib/display/util.h"
#include "src/ui/scenic/lib/flatland/buffers/buffer_collection_importer.h"
#include "src/ui/scenic/lib/flatland/engine/engine_types.h"
namespace flatland {
// The engine is responsible for compositing Flatland render data onto the display(s).
// It accomplishes this either by direct hardware compositing via the display controller
// interface, or rendering on the GPU via a custom renderer API. It also handles the
// registration of sysmem buffer collections and importation of images to both the
// display controller and the renderer via the BufferCollectionImporter interface. The
// BufferCollectionImporter interface is how Flatland instances communicate with the
// Engine, providing it with the necessary data to render without exposing to Flatland
// the DisplayController or other dependencies.
class Engine final : public BufferCollectionImporter {
public:
// TODO(fxbug.dev/66807): The engine has multiple parts of its code where usage of the display
// controller is protected by locks, because of the multithreaded environment of flatland.
// Ideally, we'd want the engine to have sole ownership of the display controller - meaning that
// it would require a unique_ptr instead of a shared_ptr. But since access to the real
// display controller is provided to clients via a shared_ptr, we take in a shared_ptr as
// a parameter here. However, this could cause problems with our locking mechanisms, as
// other display-controller clients could be accessing the same functions and/or state at
// the same time as the engine without making use of locks.
Engine(std::shared_ptr<fuchsia::hardware::display::ControllerSyncPtr> display_controller,
const std::shared_ptr<Renderer>& renderer, RenderDataFunc render_data_func);
~Engine() override;
// |BufferCollectionImporter|
bool ImportBufferCollection(
sysmem_util::GlobalBufferCollectionId collection_id,
fuchsia::sysmem::Allocator_Sync* sysmem_allocator,
fidl::InterfaceHandle<fuchsia::sysmem::BufferCollectionToken> token) override;
// |BufferCollectionImporter|
void ReleaseBufferCollection(sysmem_util::GlobalBufferCollectionId collection_id) override;
// |BufferCollectionImporter|
bool ImportBufferImage(const ImageMetadata& metadata) override;
// |BufferCollectionImporter|
void ReleaseBufferImage(sysmem_util::GlobalImageId image_id) override;
// TODO(fxbug.dev/59646): Add in parameters for scheduling, etc. Right now we're just making sure
// the data is processed correctly.
void RenderFrame();
// Register a new display to the engine, which also generates the render targets to be presented
// on the display when compositing on the GPU. If num_vmos is 0, this function will not create
// any render targets for GPU composition for that display. Returns the ID for the buffer
// collection of the render targets. The buffer collection info is also returned back to the
// caller via an output parameter.
// TODO(fxbug.dev/59646): We need to figure out exactly how we want the display to anchor
// to the Flatland hierarchy.
sysmem_util::GlobalBufferCollectionId AddDisplay(
uint64_t display_id, DisplayInfo info, fuchsia::sysmem::Allocator_Sync* sysmem_allocator,
uint32_t num_vmos, fuchsia::sysmem::BufferCollectionInfo_2* collection_info = nullptr);
private:
struct DisplayConfigResponse {
// Whether or not the config can be successfully applied or not.
fuchsia::hardware::display::ConfigResult result;
// If the config is invalid, this vector will list all the operations
// that need to be performed to make the config valid again.
std::vector<fuchsia::hardware::display::ClientCompositionOp> ops;
};
struct FrameEventData {
scenic_impl::DisplayEventId wait_id;
scenic_impl::DisplayEventId signal_id;
zx::event wait_event;
zx::event signal_event;
};
struct DisplayEngineData {
// The hardware layers we've created to use on this display.
std::vector<uint64_t> layers;
// The number of vmos we are using in the case of software composition
// (1 for each render target).
uint32_t vmo_count = 0;
// The current target that is being rendererd to by the software renderer.
uint32_t curr_vmo = 0;
// The information used to create images for each render target from the vmo data.
std::vector<ImageMetadata> targets;
// Used to synchronize buffer rendering with setting the buffer on the display.
std::vector<FrameEventData> frame_event_datas;
};
// Generates a new FrameEventData struct to be used with a render target on a display.
FrameEventData NewFrameEventData();
// Generates a hardware layer for direct compositing on the display. Returns the ID used
// to reference that layer in the display controller API.
uint64_t CreateDisplayLayer();
// Does all the setup for applying the render data, which includes images and rectangles,
// onto the display via the display controller interface. Returns false if this cannot
// be completed.
bool SetRenderDataOnDisplay(const RenderData& data);
// Sets the provided layers onto the display referenced by the given display_id.
void SetDisplayLayers(uint64_t display_id, const std::vector<uint64_t>& layers);
// Takes an image and directly composites it to a hardware layer on the display.
void ApplyLayerImage(uint32_t layer_id, escher::Rectangle2D rectangle, ImageMetadata image,
scenic_impl::DisplayEventId wait_id, scenic_impl::DisplayEventId signal_id);
// Checks if the display controller is capable of applying the configuration settings that
// have been set up until that point
DisplayConfigResponse CheckConfig();
// Erases the configuration that has been set on the display controller.
void DiscardConfig();
// Applies the config to the display controller. This should only be called after CheckConfig
// has verified that the config is okay, since ApplyConfig does not return any errors.
void ApplyConfig();
// Returns the image id used by the display controller.
uint64_t InternalImageId(sysmem_util::GlobalImageId image_id) const;
// This mutex protects access to |display_controller_| and |image_id_map_|.
//
// TODO(fxbug.dev/44335): Convert this to a lock-free structure. This is a unique
// case since we are talking to a FIDL interface (display_controller_) through a lock.
// We either need lock-free threadsafe FIDL bindings, multiple channels to the display
// controller, or something else.
mutable std::mutex lock_;
// Handle to the display controller interface.
std::shared_ptr<fuchsia::hardware::display::ControllerSyncPtr> display_controller_;
// Maps the flatland global image id to the image id used by the display controller.
std::unordered_map<sysmem_util::GlobalImageId, uint64_t> image_id_map_;
// Software renderer used when render data cannot be directly composited to the display.
std::shared_ptr<Renderer> renderer_;
// Function used to get render data.
RenderDataFunc render_data_func_;
// Maps a display ID to the the DisplayInfo struct. This is kept separate from the
// display_engine_data_map_ since this only this data is needed for the render_data_func_.
std::unordered_map<uint64_t, DisplayInfo> display_info_map_;
// Maps a display ID to a struct of all the information needed to properly render to
// that display in both the hardware and software composition paths.
std::unordered_map<uint64_t, DisplayEngineData> display_engine_data_map_;
};
} // namespace flatland
#endif // SRC_UI_SCENIC_LIB_FLATLAND_ENGINE_ENGINE_H_