|  | // 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 "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/abseil-cpp/absl/types/optional.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, | 
|  | absl::optional<viz::LocalSurfaceId> local_surface_id, | 
|  | absl::optional<viz::CompositorFrame>, | 
|  | absl::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_ |