123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953 |
- // Copyright 2020 The Chromium Authors. All rights reserved.
- // Use of this source code is governed by a BSD-style license that can be
- // found in the LICENSE file.
- #include "android_webview/browser/gfx/overlay_processor_webview.h"
- #include "android_webview/browser/gfx/gpu_service_webview.h"
- #include "android_webview/browser/gfx/viz_compositor_thread_runner_webview.h"
- #include "base/android/android_hardware_buffer_compat.h"
- #include "base/android/scoped_hardware_buffer_fence_sync.h"
- #include "base/callback_helpers.h"
- #include "base/memory/raw_ptr.h"
- #include "base/memory/ref_counted.h"
- #include "base/task/bind_post_task.h"
- #include "base/threading/thread_checker.h"
- #include "components/viz/common/quads/texture_draw_quad.h"
- #include "components/viz/service/display/display_compositor_memory_and_task_controller.h"
- #include "components/viz/service/display/resolved_frame_data.h"
- #include "components/viz/service/frame_sinks/frame_sink_manager_impl.h"
- #include "components/viz/service/gl/gpu_service_impl.h"
- #include "components/viz/service/surfaces/surface.h"
- #include "gpu/command_buffer/service/display_compositor_memory_and_task_controller_on_gpu.h"
- #include "gpu/command_buffer/service/memory_tracking.h"
- #include "gpu/command_buffer/service/scheduler_sequence.h"
- #include "gpu/command_buffer/service/shared_image/shared_image_manager.h"
- #include "gpu/command_buffer/service/shared_image/shared_image_representation.h"
- #include "gpu/command_buffer/service/single_task_sequence.h"
- #include "ui/gfx/android/android_surface_control_compat.h"
- #include "ui/gfx/geometry/rect_conversions.h"
- namespace android_webview {
- namespace {
- constexpr gpu::CommandBufferNamespace kOverlayProcessorNamespace =
- gpu::CommandBufferNamespace::IN_PROCESS;
- constexpr int kMaxBuffersInFlight = 3;
- scoped_refptr<gpu::SyncPointClientState> CreateSyncPointClientState(
- gpu::CommandBufferId command_buffer_id,
- gpu::SequenceId sequence_id) {
- return GpuServiceWebView::GetInstance()
- ->sync_point_manager()
- ->CreateSyncPointClientState(kOverlayProcessorNamespace,
- command_buffer_id, sequence_id);
- }
- } // namespace
- // Manages ASurfaceControl life-cycle and handles ASurfaceTransactions. Created
- // on Android RenderThread, but both used on both Android RenderThread and GPU
- // Main thread, so can be destroyed on one of them.
- class OverlayProcessorWebView::Manager
- : public base::RefCountedThreadSafe<OverlayProcessorWebView::Manager> {
- private:
- class Resource {
- public:
- Resource(gpu::SharedImageManager* shared_image_manager,
- gpu::MemoryTypeTracker* memory_tracker,
- const gpu::Mailbox& mailbox,
- const gfx::RectF& uv_rect,
- base::ScopedClosureRunner return_resource)
- : return_resource(std::move(return_resource)) {
- representation_ =
- shared_image_manager->ProduceOverlay(mailbox, memory_tracker);
- if (!representation_) {
- return;
- }
- read_access_ = representation_->BeginScopedReadAccess(false);
- if (!read_access_) {
- LOG(ERROR) << "Couldn't access shared image for read.";
- return;
- }
- gfx::GpuFenceHandle acquire_fence = read_access_->TakeAcquireFence();
- if (!acquire_fence.is_null()) {
- begin_read_fence_ = std::move(acquire_fence.owned_fd);
- }
- AHardwareBuffer_Desc desc;
- base::AndroidHardwareBufferCompat::GetInstance().Describe(
- GetAHardwareBuffer(), &desc);
- gfx::RectF scaled_rect = gfx::ScaleRect(uv_rect, desc.width, desc.height);
- crop_rect_ = gfx::ToEnclosedRect(scaled_rect);
- }
- ~Resource() {
- DCHECK(!read_access_)
- << "Return() or ReturnUnused() must be called before dtor";
- DCHECK(!representation_);
- }
- Resource(Resource&&) = default;
- Resource& operator=(Resource&&) = default;
- Resource(const Resource&) = delete;
- Resource& operator=(const Resource&) = delete;
- void Return(base::ScopedFD end_read_fence) {
- // It's possible that we didn't have buffer for the first frame (see
- // `GetAHardwareBuffer()`) so there will be no read_access to set fence
- // to. On the other hand we shouldn't get a fence from flinger for this
- // surface in this case.
- if (read_access_) {
- gfx::GpuFenceHandle fence_handle;
- fence_handle.owned_fd = std::move(end_read_fence);
- read_access_->SetReleaseFence(std::move(fence_handle));
- read_access_.reset();
- } else {
- DCHECK(!end_read_fence.is_valid());
- }
- representation_.reset();
- }
- void ReturnUnused() {
- read_access_.reset();
- representation_.reset();
- begin_read_fence_.reset();
- }
- base::ScopedFD TakeBeginReadFence() { return std::move(begin_read_fence_); }
- AHardwareBuffer* GetAHardwareBuffer() {
- // Note, that it's possible that BeginScopedReadAccess() will fail if
- // media couldn't get us a frame. We don't fail creation of resource in
- // this case, because if affects Surface acks and we don't to change the
- // frame submission flow. Instead we just set empty buffer to the surface.
- // Note, that it should only happen for the first frame in very rare
- // cases.
- if (!read_access_)
- return nullptr;
- DCHECK(representation_);
- DCHECK(read_access_);
- return read_access_->GetAHardwareBuffer();
- }
- const gfx::Rect& crop_rect() { return crop_rect_; }
- private:
- gfx::Rect crop_rect_;
- base::ScopedClosureRunner return_resource;
- std::unique_ptr<gpu::OverlayImageRepresentation> representation_;
- std::unique_ptr<gpu::OverlayImageRepresentation::ScopedReadAccess>
- read_access_;
- base::ScopedFD begin_read_fence_;
- };
- public:
- Manager(gpu::CommandBufferId command_buffer_id, gpu::SequenceId sequence_id)
- : shared_image_manager_(
- GpuServiceWebView::GetInstance()->shared_image_manager()),
- memory_tracker_(std::make_unique<gpu::MemoryTypeTracker>(nullptr)),
- sync_point_client_state_(
- CreateSyncPointClientState(command_buffer_id, sequence_id)) {
- DETACH_FROM_THREAD(gpu_thread_checker_);
- }
- void SetGpuService(viz::GpuServiceImpl* gpu_service) {
- DCHECK_CALLED_ON_VALID_THREAD(render_thread_checker_);
- DCHECK_EQ(shared_image_manager_, gpu_service->shared_image_manager());
- gpu_task_runner_ = gpu_service->main_runner();
- }
- // Create SurfaceControl for |overlay_id| and set it up.
- void CreateOverlay(uint64_t overlay_id,
- const viz::OverlayCandidate& candidate,
- base::ScopedClosureRunner return_resource,
- uint64_t sync_fence_release) {
- DCHECK_CALLED_ON_VALID_THREAD(render_thread_checker_);
- TRACE_EVENT1("gpu,benchmark,android_webview",
- "OverlayProcessorWebview::Manager::CreateOverlay",
- "overlay_id", overlay_id);
- auto& transaction = GetHWUITransaction();
- std::unique_ptr<Resource> resource =
- CreateResource(candidate.mailbox, candidate.unclipped_uv_rect,
- std::move(return_resource));
- {
- base::AutoLock lock(lock_);
- bool inserted;
- base::flat_map<uint64_t, OverlaySurface>::iterator it;
- std::tie(it, inserted) =
- overlay_surfaces_.emplace(overlay_id, GetParentSurface());
- DCHECK(inserted);
- auto& overlay_surface = it->second;
- UpdateGeometryInTransaction(transaction, *overlay_surface.bounds_surface,
- candidate);
- UpdateBufferInTransaction(transaction, *overlay_surface.buffer_surface,
- resource.get());
- overlay_surface.buffer_update_pending = true;
- }
- DCHECK(!pending_resource_update_.contains(overlay_id));
- pending_resource_update_[overlay_id] = std::move(resource);
- sync_point_client_state_->ReleaseFenceSync(sync_fence_release);
- }
- // Update geometry of SurfaceControl for |overlay_id|.
- void UpdateOverlayGeometry(uint64_t overlay_id,
- const viz::OverlayCandidate& candidate) {
- DCHECK_CALLED_ON_VALID_THREAD(render_thread_checker_);
- TRACE_EVENT1("gpu,benchmark,android_webview",
- "OverlayProcessorWebview::Manager::UpdateOverlayGeometry",
- "overlay_id", overlay_id);
- auto& transaction = GetHWUITransaction();
- base::AutoLock lock(lock_);
- auto& overlay_surface = GetOverlaySurfaceLocked(overlay_id);
- UpdateGeometryInTransaction(transaction, *overlay_surface.bounds_surface,
- candidate);
- }
- // Update buffer in SurfaceControl for |overlay_id|. Called on GPU Main
- // Thread.
- void UpdateOverlayBuffer(uint64_t overlay_id,
- gpu::Mailbox mailbox,
- const gfx::RectF& uv_rect,
- base::ScopedClosureRunner return_resource) {
- DCHECK_CALLED_ON_VALID_THREAD(gpu_thread_checker_);
- TRACE_EVENT1("gpu,benchmark,android_webview",
- "OverlayProcessorWebview::Manager::UpdateOverlayBuffer",
- "overlay_id", overlay_id);
- base::AutoLock lock(lock_);
- auto& overlay_surface = GetOverlaySurfaceLocked(overlay_id);
- // If we're going to remove this overlay, there is no point in updating
- // buffer anymore. Resource will be unlocked by |return_resource| getting
- // out of scope.
- if (overlay_surface.pending_remove) {
- return;
- }
- std::unique_ptr<Resource> resource =
- CreateResource(mailbox, uv_rect, std::move(return_resource));
- // If there is already transaction with buffer update in-flight, store this
- // one. This will return any previous stored resource if any.
- if (overlay_surface.buffer_update_pending) {
- overlay_surface.SetPendingResource(std::move(resource));
- return;
- }
- SubmitTransactionWithBufferLocked(overlay_id, overlay_surface,
- std::move(resource));
- }
- // Initiate removal of SurfaceControl for |overlay_id|. Removal done in next
- // steps:
- // Unparent SurfaceControl, this happens synchronously with HWUI draw.
- // Set buffer to nullptr, to get current_buffer back with a fence.
- // Free SurfaceControl.
- void RemoveOverlay(uint64_t overlay_id) {
- DCHECK_CALLED_ON_VALID_THREAD(render_thread_checker_);
- TRACE_EVENT1("gpu,benchmark,android_webview",
- "OverlayProcessorWebview::Manager::RemoveOverlay",
- "overlay_id", overlay_id);
- auto& transaction = GetHWUITransaction();
- {
- base::AutoLock lock(lock_);
- auto& overlay_surface = GetOverlaySurfaceLocked(overlay_id);
- transaction.SetParent(*overlay_surface.bounds_surface, nullptr);
- }
- pending_removals_.insert(overlay_id);
- }
- // Initiate removal of all current surfaces and drop reference to
- // parent_surface. This can be called with empty array.
- void RemoveOverlays(std::vector<uint64_t> overlay_ids) {
- DCHECK_CALLED_ON_VALID_THREAD(render_thread_checker_);
- TRACE_EVENT0("gpu,benchmark,webview",
- "OverlayProcessorWebview::Manager::RemoveOverlays");
- parent_surface_.reset();
- if (overlay_ids.empty())
- return;
- auto& transaction = GetHWUITransaction();
- {
- base::AutoLock lock(lock_);
- for (auto overlay_id : overlay_ids) {
- auto& overlay = GetOverlaySurfaceLocked(overlay_id);
- transaction.SetParent(*overlay.bounds_surface, nullptr);
- }
- }
- pending_removals_.insert(overlay_ids.begin(), overlay_ids.end());
- }
- void OnUpdateBufferTransactionAck(
- uint64_t overlay_id,
- std::unique_ptr<Resource> resource,
- gfx::SurfaceControl::TransactionStats transaction_stats) {
- DCHECK_CALLED_ON_VALID_THREAD(gpu_thread_checker_);
- TRACE_EVENT2(
- "gpu,benchmark,android_webview",
- "OverlayProcessorWebview::Manager::OnUpdateBufferTransactionAck",
- "overlay_id", overlay_id, "has_resource", !!resource);
- base::AutoLock lock(lock_);
- auto& overlay_surface = GetOverlaySurfaceLocked(overlay_id);
- DCHECK_EQ(transaction_stats.surface_stats.size(), 1u);
- DCHECK_EQ(transaction_stats.surface_stats.front().surface,
- overlay_surface.buffer_surface->surface());
- bool empty_buffer = !resource;
- overlay_surface.SetResource(
- std::move(resource),
- std::move(transaction_stats.surface_stats.front().fence));
- if (overlay_surface.pending_resource) {
- DCHECK(!overlay_surface.pending_remove);
- SubmitTransactionWithBufferLocked(
- overlay_id, overlay_surface,
- std::move(overlay_surface.pending_resource));
- }
- if (overlay_surface.pending_remove) {
- // If there is no resource, we can free our surface.
- if (empty_buffer) {
- overlay_surface.Reset();
- overlay_surfaces_.erase(overlay_id);
- } else {
- // This means there was buffer transaction in flight when surface was
- // hidden, we need to set buffer to nullptr, to free current one before
- // we can free the surface.
- SubmitTransactionWithBufferLocked(overlay_id, overlay_surface, nullptr);
- }
- }
- }
- void OnHWUITransactionAck(
- base::flat_map<uint64_t, std::unique_ptr<Resource>> resource_updates,
- base::flat_set<uint64_t> removes,
- gfx::SurfaceControl::TransactionStats transaction_stats) {
- DCHECK_CALLED_ON_VALID_THREAD(gpu_thread_checker_);
- TRACE_EVENT0("gpu,benchmark,android_webview",
- "OverlayProcessorWebview::Manager::OnHWUITransactionAck");
- base::AutoLock lock(lock_);
- for (auto& update : resource_updates) {
- auto& overlay_surface = GetOverlaySurfaceLocked(update.first);
- base::ScopedFD fence;
- for (auto& stat : transaction_stats.surface_stats) {
- if (stat.surface == overlay_surface.buffer_surface->surface()) {
- DCHECK(!fence.is_valid());
- fence = std::move(stat.fence);
- }
- }
- overlay_surface.SetResource(std::move(update.second), std::move(fence));
- if (overlay_surface.pending_resource) {
- SubmitTransactionWithBufferLocked(
- update.first, overlay_surface,
- std::move(overlay_surface.pending_resource));
- }
- }
- for (auto& overlay_id : removes) {
- auto& overlay_surface = GetOverlaySurfaceLocked(overlay_id);
- overlay_surface.pending_remove = true;
- if (overlay_surface.pending_resource) {
- overlay_surface.pending_resource->ReturnUnused();
- overlay_surface.pending_resource.reset();
- }
- if (!overlay_surface.buffer_update_pending) {
- SubmitTransactionWithBufferLocked(overlay_id, overlay_surface, nullptr);
- }
- }
- }
- absl::optional<gfx::SurfaceControl::Transaction> TakeHWUITransaction() {
- DCHECK_CALLED_ON_VALID_THREAD(render_thread_checker_);
- absl::optional<gfx::SurfaceControl::Transaction> result;
- if (hwui_transaction_) {
- DCHECK(gpu_task_runner_);
- if (!pending_resource_update_.empty() || !pending_removals_.empty()) {
- auto cb = base::BindOnce(&Manager::OnHWUITransactionAck, this,
- std::move(pending_resource_update_),
- std::move(pending_removals_));
- hwui_transaction_->SetOnCompleteCb(std::move(cb), gpu_task_runner_);
- }
- result.swap(hwui_transaction_);
- }
- return result;
- }
- private:
- friend class OverlayProcessorWebView::ScopedSurfaceControlAvailable;
- friend class base::RefCountedThreadSafe<Manager>;
- // Class that holds SurfaceControl and associated resources.
- class OverlaySurface {
- public:
- OverlaySurface(const gfx::SurfaceControl::Surface& parent)
- : bounds_surface(base::MakeRefCounted<gfx::SurfaceControl::Surface>(
- parent,
- "webview_overlay_bounds")),
- buffer_surface(base::MakeRefCounted<gfx::SurfaceControl::Surface>(
- *bounds_surface,
- "webview_overlay_content")) {}
- OverlaySurface(OverlaySurface&& other) = default;
- OverlaySurface& operator=(OverlaySurface&& other) = default;
- ~OverlaySurface() {
- DCHECK(!bounds_surface);
- DCHECK(!buffer_surface);
- DCHECK(!current_resource);
- }
- void SetResource(std::unique_ptr<Resource> resource,
- base::ScopedFD end_read_fence) {
- if (current_resource) {
- current_resource->Return(std::move(end_read_fence));
- }
- current_resource = std::move(resource);
- DCHECK(buffer_update_pending);
- buffer_update_pending = false;
- }
- void SetPendingResource(std::unique_ptr<Resource> resource) {
- DCHECK(buffer_update_pending);
- if (pending_resource) {
- pending_resource->ReturnUnused();
- }
- pending_resource = std::move(resource);
- }
- void Reset() {
- DCHECK(!pending_resource);
- DCHECK(!current_resource);
- bounds_surface.reset();
- buffer_surface.reset();
- }
- // Set when we're in process of removing this overlay.
- bool pending_remove = false;
- // This is true when there is SurfaceControl transaction that affects buffer
- // of this overlay is in-flight.
- bool buffer_update_pending = false;
- // Resource that is currently latched by SurfaceControl
- std::unique_ptr<Resource> current_resource;
- // Resource that we want to send to SurfaceControl, but there was another
- // transaction with buffer update in-flight.
- std::unique_ptr<Resource> pending_resource;
- // SurfaceControl for this overlay.
- scoped_refptr<gfx::SurfaceControl::Surface> bounds_surface;
- scoped_refptr<gfx::SurfaceControl::Surface> buffer_surface;
- };
- ~Manager() {
- DCHECK(!hwui_transaction_);
- DCHECK(!parent_surface_);
- }
- gfx::SurfaceControl::Transaction& GetHWUITransaction() {
- DCHECK_CALLED_ON_VALID_THREAD(render_thread_checker_);
- if (!hwui_transaction_)
- hwui_transaction_.emplace();
- return hwui_transaction_.value();
- }
- const gfx::SurfaceControl::Surface& GetParentSurface() {
- DCHECK_CALLED_ON_VALID_THREAD(render_thread_checker_);
- if (!parent_surface_) {
- DCHECK(get_surface_control_);
- parent_surface_ =
- gfx::SurfaceControl::Surface::WrapUnowned(get_surface_control_());
- DCHECK(parent_surface_);
- }
- return *parent_surface_;
- }
- OverlaySurface& GetOverlaySurfaceLocked(uint64_t id) {
- lock_.AssertAcquired();
- auto surface = overlay_surfaces_.find(id);
- DCHECK(surface != overlay_surfaces_.end());
- return surface->second;
- }
- std::unique_ptr<Resource> CreateResource(
- const gpu::Mailbox& mailbox,
- const gfx::RectF uv_rect,
- base::ScopedClosureRunner return_resource) {
- if (mailbox.IsZero())
- return nullptr;
- return std::make_unique<Resource>(shared_image_manager_,
- memory_tracker_.get(), mailbox, uv_rect,
- std::move(return_resource));
- }
- // Because we update different parts of geometry on different threads we use
- // two surfaces to avoid races. The Bounds surface is setup the way it assumes
- // that its content size is kBoundsSurfaceContentSize. The Buffer surface is
- // setup to scale itself to kBoundsSurfaceContentSize. Note, that from scaling
- // perspective this number doesn't matter as scales of two surfaces will be
- // just multiplied inside SurfaceFlinger, but because positions and crop rects
- // are integers we need the content size to be large enough to avoid rounding
- // errors. To avoid floating point errors we also use power of two.
- static constexpr float kBoundsSurfaceContentSize = 8192.0f;
- static void UpdateGeometryInTransaction(
- gfx::SurfaceControl::Transaction& transaction,
- gfx::SurfaceControl::Surface& surface,
- const viz::OverlayCandidate& candidate) {
- DCHECK_EQ(candidate.transform, gfx::OVERLAY_TRANSFORM_NONE);
- gfx::Rect dst = gfx::ToEnclosingRect(candidate.unclipped_display_rect);
- transaction.SetPosition(surface, dst.origin());
- // Setup scale so the contents of size kBoundsSurfaceContentSize would fit
- // into display_rect. The buffer surface will make sure to scale its content
- // to kBoundsSurfaceContentSize.
- float scale_x = dst.width() / kBoundsSurfaceContentSize;
- float scale_y = dst.height() / kBoundsSurfaceContentSize;
- transaction.SetScale(surface, scale_x, scale_y);
- if (candidate.clip_rect) {
- // Make |crop_rect| relative to |display_rect|.
- auto crop_rect = dst;
- crop_rect.Intersect(*candidate.clip_rect);
- crop_rect.Offset(-dst.x(), -dst.y());
- // Crop rect is in content space, so we need to scale it.
- auto scaled_clip = gfx::ToEnclosingRect(gfx::ScaleRect(
- gfx::RectF(crop_rect), 1.0f / scale_x, 1.0f / scale_y));
- transaction.SetCrop(surface, scaled_clip);
- }
- }
- static void UpdateBufferInTransaction(
- gfx::SurfaceControl::Transaction& transaction,
- gfx::SurfaceControl::Surface& surface,
- Resource* resource) {
- TRACE_EVENT1("gpu,benchmark,android_webview",
- "OverlayProcessorWebview::Manager::UpdateBufferInTransaction",
- "has_resource", !!resource);
- auto* buffer = resource ? resource->GetAHardwareBuffer() : nullptr;
- if (buffer) {
- auto crop_rect = resource->crop_rect();
- // Crop rect defines the valid portion of the buffer, so we use its as a
- // surface size. This calculates scale from our size to bounds surface
- // content size, see comment at kBoundsSurfaceContentSize.
- float scale_x = kBoundsSurfaceContentSize / crop_rect.width();
- float scale_y = kBoundsSurfaceContentSize / crop_rect.height();
- // Crop rect is defined in buffer space, so we need to translate our
- // surface to make sure crop rect origin matches bounds surface (0, 0).
- // Position is defined in parent space, so we need to scale it.
- transaction.SetPosition(surface,
- gfx::Point(-ceil(crop_rect.x() * scale_x),
- -ceil(crop_rect.y() * scale_y)));
- transaction.SetScale(surface, scale_x, scale_y);
- transaction.SetCrop(surface, crop_rect);
- transaction.SetBuffer(surface, buffer, resource->TakeBeginReadFence());
- } else {
- transaction.SetBuffer(surface, nullptr, base::ScopedFD());
- }
- }
- void SubmitTransactionWithBufferLocked(uint64_t overlay_id,
- OverlaySurface& overlay_surface,
- std::unique_ptr<Resource> resource) {
- lock_.AssertAcquired();
- DCHECK(!overlay_surface.buffer_update_pending);
- DCHECK(gpu_task_runner_);
- overlay_surface.buffer_update_pending = true;
- gfx::SurfaceControl::Transaction transaction;
- UpdateBufferInTransaction(transaction, *overlay_surface.buffer_surface,
- resource.get());
- auto cb = base::BindOnce(&Manager::OnUpdateBufferTransactionAck, this,
- overlay_id, std::move(resource));
- transaction.SetOnCompleteCb(std::move(cb), gpu_task_runner_);
- transaction.Apply();
- }
- base::Lock lock_;
- // These can be accessed on any thread, but only initialized in ctor.
- const raw_ptr<gpu::SharedImageManager> shared_image_manager_;
- std::unique_ptr<gpu::MemoryTypeTracker> memory_tracker_;
- // GPU Main Thread task runner.
- scoped_refptr<base::SingleThreadTaskRunner> gpu_task_runner_;
- // SyncPointClientState for render thread sequence.
- scoped_refptr<gpu::SyncPointClientState> sync_point_client_state_;
- // Can be accessed on both threads.
- base::flat_map<uint64_t, OverlaySurface> overlay_surfaces_ GUARDED_BY(lock_);
- // Pending updates for the current hwui transaction.
- base::flat_map<uint64_t, std::unique_ptr<Resource>> pending_resource_update_;
- base::flat_set<uint64_t> pending_removals_;
- scoped_refptr<gfx::SurfaceControl::Surface> parent_surface_;
- absl::optional<gfx::SurfaceControl::Transaction> hwui_transaction_;
- GetSurfaceControlFn get_surface_control_ = nullptr;
- THREAD_CHECKER(render_thread_checker_);
- THREAD_CHECKER(gpu_thread_checker_);
- };
- OverlayProcessorWebView::OverlayProcessorWebView(
- viz::DisplayCompositorMemoryAndTaskController* display_controller,
- viz::FrameSinkManagerImpl* frame_sink_manager)
- : command_buffer_id_(gpu::DisplayCompositorMemoryAndTaskControllerOnGpu::
- NextCommandBufferId()),
- render_thread_sequence_(display_controller->gpu_task_scheduler()),
- frame_sink_manager_(frame_sink_manager) {
- base::WaitableEvent event;
- render_thread_sequence_->ScheduleGpuTask(
- base::BindOnce(&OverlayProcessorWebView::CreateManagerOnRT,
- base::Unretained(this), command_buffer_id_,
- render_thread_sequence_->GetSequenceId(), &event),
- std::vector<gpu::SyncToken>());
- event.Wait();
- }
- OverlayProcessorWebView::~OverlayProcessorWebView() {
- render_thread_sequence_->ScheduleGpuTask(
- base::BindOnce(
- [](scoped_refptr<Manager> manager) {
- // manager leaves scope.
- },
- std::move(manager_)),
- std::vector<gpu::SyncToken>());
- }
- void OverlayProcessorWebView::CreateManagerOnRT(
- gpu::CommandBufferId command_buffer_id,
- gpu::SequenceId sequence_id,
- base::WaitableEvent* event) {
- manager_ = base::MakeRefCounted<Manager>(command_buffer_id, sequence_id);
- event->Signal();
- }
- void OverlayProcessorWebView::SetOverlaysEnabledByHWUI(bool enabled) {
- overlays_enabled_by_hwui_ = enabled;
- }
- void OverlayProcessorWebView::RemoveOverlays() {
- overlays_enabled_by_hwui_ = false;
- std::vector<uint64_t> ids;
- ids.reserve(overlays_.size());
- for (auto overlay : overlays_)
- ids.push_back(overlay.second.id);
- // Note, that we send it even there are no overlays, to drop reference to the
- // parent surface.
- render_thread_sequence_->ScheduleGpuTask(
- base::BindOnce(&Manager::RemoveOverlays, base::Unretained(manager_.get()),
- std::move(ids)),
- std::vector<gpu::SyncToken>());
- overlays_.clear();
- }
- absl::optional<gfx::SurfaceControl::Transaction>
- OverlayProcessorWebView::TakeSurfaceTransactionOnRT() {
- DCHECK(manager_);
- return manager_->TakeHWUITransaction();
- }
- void OverlayProcessorWebView::CheckOverlaySupportImpl(
- const viz::OverlayProcessorInterface::OutputSurfaceOverlayPlane*
- primary_plane,
- viz::OverlayCandidateList* candidates) {
- // If HWUI doesn't want us to overlay, we shouldn't.
- if (!overlays_enabled_by_hwui_)
- return;
- // We need GpuServiceImpl (one for Gpu Main Thread, not GpuServiceWebView) to
- // use overlays. It takes time to initialize it, so we don't block
- // RenderThread for it. Instead we're just polling here if it's done.
- if (!gpu_thread_sequence_) {
- viz::GpuServiceImpl* gpu_service =
- VizCompositorThreadRunnerWebView::GetInstance()->GetGpuService();
- if (!gpu_service)
- return;
- gpu_thread_sequence_ = std::make_unique<gpu::SchedulerSequence>(
- gpu_service->GetGpuScheduler(), gpu_service->main_runner());
- render_thread_sequence_->ScheduleGpuTask(
- base::BindOnce(&OverlayProcessorWebView::Manager::SetGpuService,
- base::Unretained(manager_.get()), gpu_service),
- std::vector<gpu::SyncToken>());
- }
- // Check candidates if they can be used with surface control.
- OverlayProcessorSurfaceControl::CheckOverlaySupportImpl(primary_plane,
- candidates);
- }
- void OverlayProcessorWebView::TakeOverlayCandidates(
- viz::OverlayCandidateList* candidate_list) {
- overlay_candidates_.swap(*candidate_list);
- candidate_list->clear();
- }
- void OverlayProcessorWebView::ScheduleOverlays(
- viz::DisplayResourceProvider* resource_provider) {
- DCHECK(!resource_provider_ || resource_provider_ == resource_provider_);
- resource_provider_ = resource_provider;
- DCHECK(gpu_thread_sequence_ || overlay_candidates_.empty());
- base::flat_set<viz::FrameSinkId> seen;
- for (auto& candidate : overlay_candidates_) {
- viz::SurfaceId surface_id =
- resource_provider->GetSurfaceId(candidate.resource_id);
- viz::FrameSinkId sink_id = surface_id.frame_sink_id();
- seen.insert(sink_id);
- auto overlay = overlays_.find(sink_id);
- if (overlay != overlays_.end()) {
- // Need to update only geometry.
- render_thread_sequence_->ScheduleGpuTask(
- base::BindOnce(&Manager::UpdateOverlayGeometry,
- base::Unretained(manager_.get()), overlay->second.id,
- candidate),
- std::vector<gpu::SyncToken>());
- // If renderer embedded new surface (i.e video player size changed) we
- // need to update buffer here. For all other cases it's updated in
- // ProcessForFrameSinkId().
- if (overlay->second.surface_id != surface_id) {
- overlay->second.surface_id = surface_id;
- UpdateOverlayResource(sink_id, candidate.resource_id,
- candidate.unclipped_uv_rect);
- }
- } else {
- overlay =
- overlays_
- .insert(std::make_pair(
- sink_id, Overlay(next_overlay_id_++, candidate.resource_id,
- resource_provider_->GetChildId(
- candidate.resource_id))))
- .first;
- overlay->second.surface_id = surface_id;
- overlay->second.create_sync_token =
- gpu::SyncToken(kOverlayProcessorNamespace, command_buffer_id_,
- ++sync_fence_release_);
- auto result = LockResource(overlay->second);
- candidate.mailbox = result.mailbox;
- render_thread_sequence_->ScheduleGpuTask(
- base::BindOnce(&Manager::CreateOverlay,
- base::Unretained(manager_.get()), overlay->second.id,
- candidate, std::move(result.unlock_cb),
- overlay->second.create_sync_token.release_count()),
- {result.sync_token});
- }
- }
- for (auto it = overlays_.begin(); it != overlays_.end();) {
- if (!seen.contains(it->first)) {
- render_thread_sequence_->ScheduleGpuTask(
- base::BindOnce(&Manager::RemoveOverlay,
- base::Unretained(manager_.get()), it->second.id),
- std::vector<gpu::SyncToken>());
- it = overlays_.erase(it);
- } else {
- ++it;
- }
- }
- }
- OverlayProcessorWebView::LockResult OverlayProcessorWebView::LockResource(
- Overlay& overlay) {
- LockResult result{};
- auto resource_id = overlay.resource_id;
- resource_lock_count_[overlay.surface_id.frame_sink_id()]++;
- OverlayResourceLock lock = OverlayResourceLock(
- static_cast<viz::DisplayResourceProviderSkia*>(resource_provider_),
- resource_id);
- result.sync_token = lock.sync_token();
- result.mailbox = lock.mailbox();
- locked_resources_.insert(std::make_pair(resource_id, std::move(lock)));
- auto return_cb = base::BindOnce(&OverlayProcessorWebView::ReturnResource,
- weak_ptr_factory_.GetWeakPtr(), resource_id,
- overlay.surface_id);
- auto return_cb_on_thread = base::BindPostTask(
- base::ThreadTaskRunnerHandle::Get(), std::move(return_cb));
- result.unlock_cb = base::ScopedClosureRunner(std::move(return_cb_on_thread));
- return result;
- }
- void OverlayProcessorWebView::UpdateOverlayResource(
- viz::FrameSinkId frame_sink_id,
- viz::ResourceId new_resource_id,
- const gfx::RectF& uv_rect) {
- DCHECK(resource_provider_);
- auto overlay = overlays_.find(frame_sink_id);
- DCHECK(overlay != overlays_.end());
- DCHECK(resource_provider_->IsOverlayCandidate(new_resource_id));
- if (new_resource_id != overlay->second.resource_id) {
- overlay->second.resource_id = new_resource_id;
- auto result = LockResource(overlay->second);
- gpu_thread_sequence_->ScheduleTask(
- base::BindOnce(&Manager::UpdateOverlayBuffer,
- base::Unretained(manager_.get()), overlay->second.id,
- result.mailbox, uv_rect, std::move(result.unlock_cb)),
- {result.sync_token, overlay->second.create_sync_token});
- }
- }
- void OverlayProcessorWebView::ReturnResource(viz::ResourceId resource_id,
- viz::SurfaceId surface_id) {
- DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
- // |locked_resources_| is multimap and can contain multiple locks of the same
- // resource_id. There is no difference between locks at this point, they all
- // just keeping resource locked so it's safe to remove any of them when
- // OverlayManager return resources. When we delete last lock resource will be
- // return to the client.
- auto it = locked_resources_.find(resource_id);
- DCHECK(it != locked_resources_.end());
- locked_resources_.erase(it);
- DCHECK(resource_lock_count_.contains(surface_id.frame_sink_id()));
- auto& count = resource_lock_count_[surface_id.frame_sink_id()];
- DCHECK_GT(count, 0);
- // When the lock count reaches kMaxBuffersInFlight, we don't send acks to the
- // client in the ProcessForFrameSinkId. In this case we send ack here when the
- // lock count drops below the threshold. Note, that because we still lock
- // resource and schedule buffer update, the lock count can be larger than
- // kMaxBuffersInFlight in certain cases, like quick overlay demotion and
- // promotion again.
- if (count == kMaxBuffersInFlight) {
- auto* surface =
- frame_sink_manager_->surface_manager()->GetSurfaceForId(surface_id);
- if (surface) {
- surface->SendAckToClient();
- }
- }
- if (!--count)
- resource_lock_count_.erase(surface_id.frame_sink_id());
- }
- void OverlayProcessorWebView::ProcessForFrameSinkId(
- const viz::FrameSinkId& frame_sink_id,
- const viz::ResolvedFrameData* frame_data) {
- auto it = overlays_.find(frame_sink_id);
- DCHECK(it != overlays_.end());
- auto& overlay = it->second;
- auto& pass = frame_data->GetRootRenderPassData();
- if (!pass.draw_quads().empty()) {
- DCHECK_EQ(pass.draw_quads().size(), 1u);
- auto* surface = frame_sink_manager_->surface_manager()->GetSurfaceForId(
- overlay.surface_id);
- // TODO(vasilyt): We should get this from surface aggregator after
- // aggregator refactoring will be finished.
- const auto& frame = surface->GetActiveFrame();
- auto* quad = viz::TextureDrawQuad::MaterialCast(
- frame.render_pass_list.back()->quad_list.front());
- DCHECK(quad->is_stream_video);
- auto uv_rect = gfx::BoundingRect(quad->uv_top_left, quad->uv_bottom_right);
- UpdateOverlayResource(frame_sink_id,
- pass.draw_quads().front().remapped_resources.ids[0],
- uv_rect);
- // If resource lock count reached kMaxBuffersInFlight it means we can't
- // schedule any more frames right away, in this case we delay sending ack to
- // the client and will send it in ReturnResources after OverlayManager will
- // process previous update.
- if (resource_lock_count_[frame_sink_id] < kMaxBuffersInFlight) {
- surface->SendAckToClient();
- }
- }
- }
- viz::SurfaceId OverlayProcessorWebView::GetOverlaySurfaceId(
- const viz::FrameSinkId& frame_sink_id) {
- auto it = overlays_.find(frame_sink_id);
- if (it != overlays_.end()) {
- return it->second.surface_id;
- }
- return viz::SurfaceId();
- }
- bool OverlayProcessorWebView::IsFrameSinkOverlayed(
- viz::FrameSinkId frame_sink_id) {
- return overlays_.contains(frame_sink_id);
- }
- OverlayProcessorWebView::ScopedSurfaceControlAvailable::
- ScopedSurfaceControlAvailable(OverlayProcessorWebView* processor,
- GetSurfaceControlFn surface_getter)
- : processor_(processor) {
- DCHECK(processor_);
- DCHECK(processor_->manager_);
- processor_->manager_->get_surface_control_ = surface_getter;
- }
- OverlayProcessorWebView::ScopedSurfaceControlAvailable::
- ~ScopedSurfaceControlAvailable() {
- processor_->manager_->get_surface_control_ = nullptr;
- }
- OverlayProcessorWebView::Overlay::Overlay(uint64_t id,
- viz::ResourceId resource_id,
- int child_id)
- : id(id), resource_id(resource_id), child_id(child_id) {}
- OverlayProcessorWebView::Overlay::Overlay(const Overlay&) = default;
- OverlayProcessorWebView::Overlay::~Overlay() = default;
- } // namespace android_webview
|