// Copyright 2018 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef CONTENT_BROWSER_ANDROID_SYNCHRONOUS_COMPOSITOR_SYNC_CALL_BRIDGE_H_
#define CONTENT_BROWSER_ANDROID_SYNCHRONOUS_COMPOSITOR_SYNC_CALL_BRIDGE_H_
#include <optional>
#include "base/containers/circular_deque.h"
#include "base/memory/raw_ptr.h"
#include "base/memory/ref_counted.h"
#include "base/synchronization/condition_variable.h"
#include "base/thread_annotations.h"
#include "components/viz/common/quads/compositor_frame.h"
#include "content/public/browser/android/synchronous_compositor.h"
#include "mojo/public/cpp/bindings/self_owned_receiver.h"
#include "third_party/blink/public/mojom/input/synchronous_compositor.mojom.h"
namespace content {
class SynchronousCompositorHost;
// For the synchronous compositor feature of webview it is necessary
// that the UI thread to block until the renderer process has processed
// certain messages entirely. (beginframe and resulting compositor frames).
// This object is used to manage the waiting and signaling behavior on the UI
// thread. The UI thread will wait on a WaitableEvent (via FrameFuture class)
// or condition variable which is then signal by handlers in this class.
// This object is a cross thread object accessed both on the UI and IO threads.
//
// Examples of call graphs are:
// Browser UI Thread Browser IO Thread Renderer
//
// ->VSync Java
// ----------------------------------------------->BeginFrame
// CV Wait
// BeginFrameRes<----------
// CVSignal
// WakeUp
//
//
// ->DrawHwAsync
// RegisterFrameFuture
// ----------------------------------------------->DrawHwAsync
// Do some stuff
// FrameFuture::GetFrame()
// WaitableEvent::Wait()
// ReceiveFrame<---------------
// WaitableEvent::Signal()
// WakeUp
//
// This may seem simple but it gets a little more complicated when
// multiple views are involved. Each view will have it's own SyncCallBridge.
//
// Once example is:
//
// Browser UI Thread Browser IO Thread Renderer1 Renderer2
//
// ->VSync Java
// ----------------------------------------------->BeginFrame
// BeginFrameRes<----------
// CVSignal
// ------------------------------------------------------------>BeginFrame
// CV Wait
// BeginFrameRes<----------------------------
// CVSignal
// WakeUp
//
// Notice that it is possible that before we wait on a CV variable a renderer
// may have already responded to the BeginFrame request.
//
class SynchronousCompositorSyncCallBridge
: public base::RefCountedThreadSafe<SynchronousCompositorSyncCallBridge> {
public:
explicit SynchronousCompositorSyncCallBridge(SynchronousCompositorHost* host);
SynchronousCompositorSyncCallBridge(
const SynchronousCompositorSyncCallBridge&) = delete;
SynchronousCompositorSyncCallBridge& operator=(
const SynchronousCompositorSyncCallBridge&) = delete;
// Indicatation that the remote is now ready to process requests. Called
// on either UI or IO thread.
void RemoteReady();
// Remote channel is closed signal all waiters.
void RemoteClosedOnIOThread();
// Receive a frame. Return false if the corresponding frame wasn't found.
bool ReceiveFrameOnIOThread(
int frame_sink_id,
uint32_t metadata_version,
std::optional<viz::LocalSurfaceId> local_surface_id,
std::optional<viz::CompositorFrame>,
std::optional<viz::HitTestRegionList> hit_test_region_list);
// Receive a BeginFrameResponse. Returns true if handling the response was
// successful or not.
bool BeginFrameResponseOnIOThread(
blink::mojom::SyncCompositorCommonRendererParamsPtr render_params);
// Schedule a callback for when vsync finishes and wait for the
// BeginFrameResponse callback.
bool WaitAfterVSyncOnUIThread();
// Store a FrameFuture for a later ReceiveFrame callback. Return if the
// future was stored for further handling.
bool SetFrameFutureOnUIThread(
scoped_refptr<SynchronousCompositor::FrameFuture> frame_future);
// Indicate the host is destroyed.
void HostDestroyedOnUIThread();
// Return whether the remote side is ready.
bool IsRemoteReadyOnUIThread();
// Set a weak reference to host control receiver then we can close the host
// control when the host was destroyed.
void SetHostControlReceiverOnIOThread(
mojo::SelfOwnedReceiverRef<blink::mojom::SynchronousCompositorControlHost>
host_control_receiver);
private:
friend class base::RefCountedThreadSafe<SynchronousCompositorSyncCallBridge>;
~SynchronousCompositorSyncCallBridge();
// Callback passed to WindowAndroid, runs when the current begin frame is
// completed.
void BeginFrameCompleteOnUIThread();
// Process metadata.
void ProcessFrameMetadataOnUIThread(
uint32_t metadata_version,
viz::CompositorFrameMetadata metadata,
const viz::LocalSurfaceId& local_surface_id);
// Signal all waiters for closure. Callee must host a lock to |lock_|.
void SignalRemoteClosedToAllWaitersOnIOThread()
EXCLUSIVE_LOCKS_REQUIRED(lock_);
// Close the host control on io thread.
void CloseHostControlOnIOThread();
using FrameFutureQueue =
base::circular_deque<scoped_refptr<SynchronousCompositor::FrameFuture>>;
enum class RemoteState { INIT, READY, CLOSED };
// UI thread only.
raw_ptr<SynchronousCompositorHost> host_;
// This handles the host control receiver in browser side.
mojo::SelfOwnedReceiverRef<blink::mojom::SynchronousCompositorControlHost>
host_control_receiver_;
// Shared variables between the IO thread and UI thread.
base::Lock lock_;
FrameFutureQueue frame_futures_ GUARDED_BY(lock_);
bool begin_frame_response_valid_ GUARDED_BY(lock_) = false;
blink::mojom::SyncCompositorCommonRendererParams last_render_params_
GUARDED_BY(lock_);
base::ConditionVariable begin_frame_condition_ GUARDED_BY(lock_);
RemoteState remote_state_ GUARDED_BY(lock_) = RemoteState::INIT;
};
} // namespace content
#endif // CONTENT_BROWSER_ANDROID_SYNCHRONOUS_COMPOSITOR_SYNC_CALL_BRIDGE_H_