blob: 3819515d2062fba98184ba8ae6d1af19287e84cd [file] [log] [blame]
// Copyright 2017 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_GFX_ENGINE_ENGINE_H_
#define SRC_UI_SCENIC_LIB_GFX_ENGINE_ENGINE_H_
#include <lib/fit/function.h>
#include <lib/sys/cpp/component_context.h>
#include <memory>
#include <set>
#include <vector>
#include <fbl/ref_ptr.h>
#include "src/lib/inspect_deprecated/inspect.h"
#include "src/ui/lib/escher/escher.h"
#include "src/ui/lib/escher/flib/release_fence_signaller.h"
#include "src/ui/lib/escher/geometry/types.h"
#include "src/ui/lib/escher/renderer/batch_gpu_uploader.h"
#include "src/ui/lib/escher/resources/resource_recycler.h"
#include "src/ui/lib/escher/vk/image_factory.h"
#include "src/ui/scenic/lib/display/display_manager.h"
#include "src/ui/scenic/lib/gfx/engine/annotation_manager.h"
#include "src/ui/scenic/lib/gfx/engine/engine_renderer.h"
#include "src/ui/scenic/lib/gfx/engine/object_linker.h"
#include "src/ui/scenic/lib/gfx/engine/scene_graph.h"
#include "src/ui/scenic/lib/gfx/engine/session_context.h"
#include "src/ui/scenic/lib/gfx/engine/session_manager.h"
#include "src/ui/scenic/lib/gfx/resources/nodes/scene.h"
#include "src/ui/scenic/lib/gfx/sysmem.h"
#include "src/ui/scenic/lib/scenic/event_reporter.h"
#include "src/ui/scenic/lib/scheduling/delegating_frame_scheduler.h"
#include "src/ui/scenic/lib/scheduling/frame_scheduler.h"
#include "src/ui/scenic/lib/scheduling/id.h"
namespace scenic_impl {
namespace gfx {
class Compositor;
class Engine;
using EngineWeakPtr = fxl::WeakPtr<Engine>;
class View;
class ViewHolder;
using ViewLinker = ObjectLinker<ViewHolder*, View*>;
using PresentationInfo = fuchsia::images::PresentationInfo;
using OnPresentedCallback = fit::function<void(PresentationInfo)>;
// Manages the interactions between the scene graph, renderers, and displays,
// producing output when prompted through the scheduling::FrameRenderer
// interface.
//
// Engine synchronizes with other gfx components, including Screenshotter and
// Snapshotter, using ChainedSemaphoreGenerator.
//
// Each component waits on a semaphore it fetches from Escher's
// ChainedSemaphoreGenerator, which was generated by previous component before,
// and then signals a new semaphore ChainedSemaphoreGenerator generates for
// future components.
//
// (1) Synchronization between Engine and Screenshotter:
//
// /-------- Engine --------\ /--- Screenshotter --\ /- Engine-\
// GpuUploader Renderer Renderer + DownloadImage (*) GpuUploader
// [TX] --(i)-> [GRAPHICS] --(s)-> [GRAPHICS] --(s)-> [TX]
//
// Note: [TX] means transfer queue and [GRAPHICS] means graphics queue.
// --(i)-> means internal semaphore defined in EngineRenderer,
// --(s)-> is the semaphore we generate (and fetch later) from
// ChainedSemaphoreGenerator.
//
// The (*) semaphore ensures we won't upload HostImage until we finish taking
// the screenshot.
//
// (2) Synchronization between Engine and Snapshotter:
//
// /-------- Engine --------\ /- Snapshotter -\ /- Engine-\
// GpuUploader Renderer (*) GpuDownloader (**) GpuUploader
// [TX] --(i)-> [GRAPHICS] --(s)-> [TX] --(s)-> [TX]
//
// (*) semaphore enforces that we don't execute GpuDownloader (i.e. take
// snapshots) until we finish rendering; and (**) semaphore enforces we do not
// upload new HostImages until we finish downloading them all.
//
// (3) Synchronization between two frames:
//
// /-------- Engine --------\ /-------- Engine --------\
// GpuUploader Renderer (*) GpuUploader Renderer
// [TX] --(i)-> [GRAPHICS] --(s)-> [TX] --(i)-> [GRAPHICS]
//
// (*) semaphore ensures GpuUploader will never upload to a HostImage if it
// hasn't finished rendering.
//
class Engine : public scheduling::FrameRenderer {
public:
Engine(sys::ComponentContext* app_context,
const std::shared_ptr<scheduling::FrameScheduler>& frame_scheduler,
escher::EscherWeakPtr escher, inspect_deprecated::Node inspect_node);
// Only used for testing.
Engine(sys::ComponentContext* app_context,
const std::shared_ptr<scheduling::FrameScheduler>& frame_scheduler,
std::unique_ptr<escher::ReleaseFenceSignaller> release_fence_signaller,
escher::EscherWeakPtr escher);
~Engine() override = default;
escher::Escher* escher() const { return escher_.get(); }
escher::EscherWeakPtr GetEscherWeakPtr() const { return escher_; }
EngineWeakPtr GetWeakPtr() { return weak_factory_.GetWeakPtr(); }
vk::Device vk_device() { return escher_ ? escher_->vulkan_context().device : vk::Device(); }
EngineRenderer* renderer() { return engine_renderer_.get(); }
// TODO(SCN-1151)
// Instead of a set of Compositors, we should probably root at a set of
// Displays. Or, we might not even need to store this set, and Displays (or
// Compositors) would just be able to schedule a frame for themselves.
SceneGraphWeakPtr scene_graph() { return scene_graph_.GetWeakPtr(); }
ViewLinker* view_linker() { return &view_linker_; }
AnnotationManager* annotation_manager() { return annotation_manager_.get(); }
SessionContext session_context() {
return SessionContext{vk_device(),
escher(),
escher_resource_recycler(),
escher_image_factory(),
release_fence_signaller(),
delegating_frame_scheduler_,
scene_graph(),
&view_linker_};
}
// Invoke Escher::Cleanup(). If more work remains afterward, post a delayed
// task to try again; this is typically because cleanup couldn't finish due
// to unfinished GPU work.
void CleanupEscher();
// Dumps the contents of all scene graphs.
void DumpScenes(std::ostream& output,
std::unordered_set<GlobalId, GlobalId::Hash>* visited_resources) const;
// |scheduling::FrameRenderer|
//
// Renders a new frame. Returns true if successful, false otherwise.
scheduling::RenderFrameResult RenderFrame(fxl::WeakPtr<scheduling::FrameTimings> frame,
zx::time presentation_time) override;
private:
// Initialize annotation session and annotation manager.
void InitializeAnnotationManager();
// Initialize all inspect_deprecated::Nodes, so that the Engine state can be observed.
void InitializeInspectObjects();
// Takes care of cleanup between frames.
void EndCurrentFrame(uint64_t frame_number);
escher::ResourceRecycler* escher_resource_recycler() {
return escher_ ? escher_->resource_recycler() : nullptr;
}
escher::ImageFactory* escher_image_factory() { return image_factory_.get(); }
escher::ReleaseFenceSignaller* release_fence_signaller() {
return release_fence_signaller_.get();
}
void InitializeShaderFs();
// Returns true if layers contain content to be rendered.
bool CheckForRenderableContent(const std::vector<HardwareLayerAssignment>& hlas);
// Returns true if layers contain protected content.
bool CheckForProtectedMemoryUse(const std::vector<HardwareLayerAssignment>& hlas);
// Update and deliver metrics for all nodes which subscribe to metrics
// events.
void UpdateAndDeliverMetrics(zx::time presentation_time);
// Update reported metrics for nodes which subscribe to metrics events.
// If anything changed, append the node to |updated_nodes|.
void UpdateMetrics(Node* node, const ::fuchsia::ui::gfx::Metrics& parent_metrics,
std::vector<Node*>* updated_nodes);
const escher::EscherWeakPtr escher_;
std::unique_ptr<EngineRenderer> engine_renderer_;
ViewLinker view_linker_;
std::unique_ptr<escher::ImageFactoryAdapter> image_factory_;
std::unique_ptr<escher::ReleaseFenceSignaller> release_fence_signaller_;
// TODO(SCN-1502): This is a temporary solution until we can remove frame_scheduler from
// ResourceContext. Do not add any additional dependencies on this object/pointer.
std::shared_ptr<scheduling::DelegatingFrameScheduler> delegating_frame_scheduler_;
SceneGraph scene_graph_;
bool escher_cleanup_scheduled_ = false;
bool render_continuously_ = false;
bool first_frame_ = true;
bool last_frame_uses_protected_memory_ = false;
std::unique_ptr<AnnotationManager> annotation_manager_;
inspect_deprecated::Node inspect_node_;
inspect_deprecated::LazyStringProperty inspect_scene_dump_;
fxl::WeakPtrFactory<Engine> weak_factory_; // must be last
FXL_DISALLOW_COPY_AND_ASSIGN(Engine);
};
} // namespace gfx
} // namespace scenic_impl
#endif // SRC_UI_SCENIC_LIB_GFX_ENGINE_ENGINE_H_