#include "components/viz/service/display/overlay_processor_android.h"
#include <memory>
#include <utility>
#include <vector>
#include "base/synchronization/waitable_event.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/overlay_processor_on_gpu.h"
#include "components/viz/service/display/overlay_strategy_underlay.h"
#include "components/viz/service/display/skia_output_surface.h"
#include "gpu/command_buffer/service/scheduler_sequence.h"
#include "ui/gfx/geometry/rect_conversions.h"
namespace viz {
OverlayProcessorAndroid::OverlayProcessorAndroid(
DisplayCompositorMemoryAndTaskController* display_controller)
: OverlayProcessorUsingStrategy(),
gpu_task_scheduler_(display_controller->gpu_task_scheduler()) {
prioritization_config_.changing_threshold = false;
prioritization_config_.damage_rate_threshold = false;
if (gpu_task_scheduler_) {
gpu::ScopedAllowScheduleGpuTask allow_schedule_gpu_task;
base::WaitableEvent event(base::WaitableEvent::ResetPolicy::MANUAL,
base::WaitableEvent::InitialState::NOT_SIGNALED);
auto callback = base::BindOnce(
&OverlayProcessorAndroid::InitializeOverlayProcessorOnGpu,
base::Unretained(this), display_controller->controller_on_gpu(),
&event);
gpu_task_scheduler_->ScheduleGpuTask(std::move(callback), {});
event.Wait();
}
strategies_.push_back(std::make_unique<OverlayStrategyUnderlay>(
this, OverlayStrategyUnderlay::OpaqueMode::AllowTransparentCandidates));
overlay_candidates_.clear();
}
OverlayProcessorAndroid::~OverlayProcessorAndroid() {
if (processor_on_gpu_) {
gpu::ScopedAllowScheduleGpuTask allow_schedule_gpu_task;
base::WaitableEvent event(base::WaitableEvent::ResetPolicy::MANUAL,
base::WaitableEvent::InitialState::NOT_SIGNALED);
auto callback =
base::BindOnce(&OverlayProcessorAndroid::DestroyOverlayProcessorOnGpu,
base::Unretained(this), &event);
gpu_task_scheduler_->ScheduleGpuTask(std::move(callback), {});
event.Wait();
}
}
void OverlayProcessorAndroid::InitializeOverlayProcessorOnGpu(
gpu::DisplayCompositorMemoryAndTaskControllerOnGpu*
display_controller_on_gpu,
base::WaitableEvent* event) {
processor_on_gpu_ =
std::make_unique<OverlayProcessorOnGpu>(display_controller_on_gpu);
DCHECK(event);
event->Signal();
}
void OverlayProcessorAndroid::DestroyOverlayProcessorOnGpu(
base::WaitableEvent* event) {
processor_on_gpu_ = nullptr;
DCHECK(event);
event->Signal();
}
bool OverlayProcessorAndroid::IsOverlaySupported() const {
return true;
}
bool OverlayProcessorAndroid::NeedsSurfaceDamageRectList() const {
return false;
}
void OverlayProcessorAndroid::ScheduleOverlays(
DisplayResourceProvider* resource_provider) {
if (!processor_on_gpu_)
return;
pending_overlay_locks_.emplace_back();
if (overlay_candidates_.empty())
return;
auto& locks = pending_overlay_locks_.back();
std::vector<gpu::SyncToken> locks_sync_tokens;
for (auto& candidate : overlay_candidates_) {
locks.emplace_back(resource_provider, candidate.resource_id);
locks_sync_tokens.push_back(locks.back().sync_token());
}
auto task = base::BindOnce(&OverlayProcessorOnGpu::ScheduleOverlays,
base::Unretained(processor_on_gpu_.get()),
std::move(overlay_candidates_));
gpu_task_scheduler_->ScheduleGpuTask(std::move(task), locks_sync_tokens);
overlay_candidates_.clear();
}
void OverlayProcessorAndroid::OverlayPresentationComplete() {
if (!processor_on_gpu_)
return;
committed_overlay_locks_.clear();
std::swap(committed_overlay_locks_, pending_overlay_locks_.front());
pending_overlay_locks_.pop_front();
}
void OverlayProcessorAndroid::CheckOverlaySupportImpl(
const OverlayProcessorInterface::OutputSurfaceOverlayPlane* primary_plane,
OverlayCandidateList* candidates) {
DCHECK(!primary_plane);
DCHECK_LE(candidates->size(), 1u);
if (!candidates->empty()) {
OverlayCandidate& candidate = candidates->front();
promotion_hint_info_map_[candidate.resource_id] = candidate.display_rect;
if (candidate.is_backed_by_surface_texture) {
return;
}
candidate.display_rect =
gfx::RectF(gfx::ToEnclosingRect(candidate.display_rect));
candidate.overlay_handled = true;
candidate.plane_z_order = -1;
promotion_hint_info_map_.clear();
promotion_hint_info_map_[candidate.resource_id] = candidate.display_rect;
}
}
gfx::Rect OverlayProcessorAndroid::GetOverlayDamageRectForOutputSurface(
const OverlayCandidate& overlay) const {
return ToEnclosedRect(overlay.display_rect);
}
void OverlayProcessorAndroid::TakeOverlayCandidates(
OverlayCandidateList* candidate_list) {
overlay_candidates_.swap(*candidate_list);
candidate_list->clear();
}
void OverlayProcessorAndroid::NotifyOverlayPromotion(
DisplayResourceProvider* resource_provider,
const CandidateList& candidates,
const QuadList& quad_list) {
if (!processor_on_gpu_) {
promotion_hint_info_map_.clear();
return;
}
ResourceIdSet promotion_hint_requestor_set;
for (auto* quad : quad_list) {
if (quad->material != DrawQuad::Material::kTextureContent)
continue;
const TextureDrawQuad* texture_quad = TextureDrawQuad::MaterialCast(quad);
if (!texture_quad->is_stream_video)
continue;
ResourceId id = texture_quad->resource_id();
if (!resource_provider->DoesResourceWantPromotionHint(id))
continue;
promotion_hint_requestor_set.insert(id);
}
if (promotion_hint_requestor_set.empty()) {
promotion_hint_info_map_.clear();
return;
}
base::flat_set<gpu::Mailbox> promotion_denied;
base::flat_map<gpu::Mailbox, gfx::Rect> possible_promotions;
DCHECK(candidates.empty() || candidates.size() == 1u);
std::vector<
std::unique_ptr<DisplayResourceProvider::ScopedReadLockSharedImage>>
locks;
for (auto& request : promotion_hint_requestor_set) {
if (!candidates.empty() && candidates.front().resource_id == request)
continue;
locks.emplace_back(
std::make_unique<DisplayResourceProvider::ScopedReadLockSharedImage>(
resource_provider, request));
auto iter = promotion_hint_info_map_.find(request);
if (iter != promotion_hint_info_map_.end()) {
possible_promotions.emplace(locks.back()->mailbox(),
gfx::ToEnclosedRect(iter->second));
} else {
promotion_denied.insert(locks.back()->mailbox());
}
}
std::vector<gpu::SyncToken> locks_sync_tokens;
for (auto& read_lock : locks)
locks_sync_tokens.push_back(read_lock->sync_token());
if (gpu_task_scheduler_) {
auto task = base::BindOnce(&OverlayProcessorOnGpu::NotifyOverlayPromotions,
base::Unretained(processor_on_gpu_.get()),
std::move(promotion_denied),
std::move(possible_promotions));
gpu_task_scheduler_->ScheduleGpuTask(std::move(task), locks_sync_tokens);
}
promotion_hint_info_map_.clear();
}
}