| // Copyright 2020 The Chromium Authors |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "components/viz/service/display_embedder/output_presenter_gl.h" |
| |
| #include <memory> |
| #include <utility> |
| #include <variant> |
| #include <vector> |
| |
| #include "base/check.h" |
| #include "base/feature_list.h" |
| #include "base/task/single_thread_task_runner.h" |
| #include "build/build_config.h" |
| #include "components/viz/common/features.h" |
| #include "components/viz/service/display_embedder/skia_output_surface_dependency.h" |
| #include "gpu/command_buffer/service/shared_context_state.h" |
| #include "ui/display/types/display_snapshot.h" |
| #include "ui/gfx/buffer_format_util.h" |
| #include "ui/gfx/geometry/rect_conversions.h" |
| #include "ui/gfx/geometry/rrect_f.h" |
| #include "ui/gfx/overlay_plane_data.h" |
| #include "ui/gfx/overlay_transform.h" |
| #include "ui/gl/gl_fence.h" |
| #include "ui/gl/presenter.h" |
| |
| #if BUILDFLAG(IS_OZONE) |
| #include "ui/base/ui_base_features.h" |
| #endif |
| |
| namespace viz { |
| |
| namespace { |
| |
| #if BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_OZONE) |
| // Helper function for moving a GpuFence from a fence handle to a unique_ptr. |
| std::unique_ptr<gfx::GpuFence> TakeGpuFence(gfx::GpuFenceHandle fence) { |
| return fence.is_null() ? nullptr |
| : std::make_unique<gfx::GpuFence>(std::move(fence)); |
| } |
| #endif |
| |
| } // namespace |
| |
| OutputPresenterGL::OutputPresenterGL(scoped_refptr<gl::Presenter> presenter, |
| SkiaOutputSurfaceDependency* deps) |
| : presenter_(presenter), dependency_(deps) {} |
| |
| OutputPresenterGL::~OutputPresenterGL() = default; |
| |
| void OutputPresenterGL::InitializeCapabilities( |
| OutputSurface::Capabilities* capabilities) { |
| capabilities->android_surface_control_feature_enabled = true; |
| capabilities->supports_post_sub_buffer = true; |
| capabilities->supports_viewporter = presenter_->SupportsViewporter(); |
| |
| // Set supports_surfaceless to enable overlays. |
| capabilities->supports_surfaceless = true; |
| // We expect origin of buffers is at top left. |
| capabilities->output_surface_origin = gfx::SurfaceOrigin::kTopLeft; |
| // Set resize_based_on_root_surface to omit platform proposed size. |
| capabilities->resize_based_on_root_surface = |
| presenter_->SupportsOverridePlatformSize(); |
| #if BUILDFLAG(IS_ANDROID) |
| capabilities->supports_dynamic_frame_buffer_allocation = true; |
| #endif |
| // MakeCurrent needs to be called if the platform can not rely on kernel (GPU |
| // fences) to sync. In configurations like this, the Presenter commonly waits |
| // on CPU for GPU to finish with a (EGL) fence + a worker thread. |
| capabilities->present_requires_make_current = |
| !presenter_->SupportsPlaneGpuFences(); |
| |
| // TODO(crbug.com/40141277): only add supported formats base on |
| // platform, driver, etc. |
| capabilities->sk_color_type_map[SinglePlaneFormat::kBGR_565] = |
| kRGB_565_SkColorType; |
| capabilities->sk_color_type_map[SinglePlaneFormat::kRGBA_4444] = |
| kARGB_4444_SkColorType; |
| capabilities->sk_color_type_map[SinglePlaneFormat::kRGBX_8888] = |
| kRGB_888x_SkColorType; |
| capabilities->sk_color_type_map[SinglePlaneFormat::kRGBA_8888] = |
| kRGBA_8888_SkColorType; |
| capabilities->sk_color_type_map[SinglePlaneFormat::kBGRX_8888] = |
| kBGRA_8888_SkColorType; |
| capabilities->sk_color_type_map[SinglePlaneFormat::kBGRA_8888] = |
| kBGRA_8888_SkColorType; |
| capabilities->sk_color_type_map[SinglePlaneFormat::kBGRA_1010102] = |
| kBGRA_1010102_SkColorType; |
| capabilities->sk_color_type_map[SinglePlaneFormat::kRGBA_1010102] = |
| kRGBA_1010102_SkColorType; |
| capabilities->sk_color_type_map[SinglePlaneFormat::kRGBA_F16] = |
| kRGBA_F16_SkColorType; |
| } |
| |
| bool OutputPresenterGL::Reshape(const ReshapeParams& params) { |
| const gfx::Size size = params.GfxSize(); |
| const bool has_alpha = !params.image_info.isOpaque(); |
| return presenter_->Resize(size, params.device_scale_factor, |
| params.color_space, has_alpha); |
| } |
| |
| void OutputPresenterGL::Present(SwapCompletionCallback completion_callback, |
| BufferPresentedCallback presentation_callback, |
| gfx::FrameData data) { |
| presenter_->Present(std::move(completion_callback), |
| std::move(presentation_callback), data); |
| } |
| |
| void OutputPresenterGL::ScheduleOverlayPlane( |
| const OutputPresenter::OverlayPlaneCandidate& overlay_plane_candidate, |
| ScopedOverlayAccess* access) { |
| // Note that |overlay_plane_candidate| has different types on different |
| // platforms. On Android, Ozone, and Windows, it is an OverlayCandidate and on |
| // macOS it is a CALayeroverlay. |
| #if BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_OZONE) |
| #if BUILDFLAG(IS_OZONE) |
| // TODO(crbug.com/40239878): Add ScopedOverlayAccess::GetOverlayImage() that |
| // works on all platforms. |
| gl::OverlayImage overlay_image = access ? access->GetNativePixmap() : nullptr; |
| if (!overlay_image && !overlay_plane_candidate.is_solid_color) { |
| // Allow non-root overlays to be skipped if missing for transient causes. |
| // E.g. missing overlay_image because video decoder is destroyed during |
| // navigation. |
| // TODO(crbug.com/405022140): root_render_pass overlay_image should exist, |
| // but when there is a CopyOutputRequest, root_render_pass can be a |
| // WrappedSkImage without overlay access. Plumb such information and fail |
| // properly. |
| LOG_IF(WARNING, overlay_plane_candidate.is_root_render_pass) |
| << "root_render_pass is missing overlay_image."; |
| return; |
| } |
| #elif BUILDFLAG(IS_ANDROID) |
| gl::OverlayImage overlay_image = |
| access ? access->GetAHardwareBufferFenceSync() : nullptr; |
| if (!overlay_image) { |
| return; |
| } |
| #endif |
| #if DCHECK_IS_ON() |
| if (overlay_plane_candidate.is_solid_color) { |
| LOG_IF(FATAL, !overlay_plane_candidate.color.has_value()) |
| << "Solid color quads must have color set."; |
| } |
| #endif // DCHECK_IS_ON() |
| |
| std::unique_ptr<gfx::GpuFence> acquire_fence; |
| if (access) { |
| auto access_fence = TakeGpuFence(access->TakeAcquireFence()); |
| if (access_fence) { |
| DCHECK(!acquire_fence); |
| acquire_fence = std::move(access_fence); |
| } |
| } |
| |
| presenter_->ScheduleOverlayPlane( |
| std::move(overlay_image), std::move(acquire_fence), |
| gfx::OverlayPlaneData( |
| overlay_plane_candidate.plane_z_order, |
| overlay_plane_candidate.transform, |
| overlay_plane_candidate.display_rect, overlay_plane_candidate.uv_rect, |
| !overlay_plane_candidate.is_opaque, |
| ToEnclosingRect(overlay_plane_candidate.damage_rect), |
| overlay_plane_candidate.opacity, |
| overlay_plane_candidate.priority_hint, |
| overlay_plane_candidate.rounded_corners, |
| overlay_plane_candidate.color_space, |
| overlay_plane_candidate.hdr_metadata, overlay_plane_candidate.color, |
| overlay_plane_candidate.is_solid_color, |
| overlay_plane_candidate.is_root_render_pass, |
| overlay_plane_candidate.clip_rect, |
| overlay_plane_candidate.overlay_type)); |
| #elif BUILDFLAG(IS_APPLE) |
| gfx::ScopedIOSurface io_surface; |
| gfx::ColorSpace io_surface_color_space; |
| std::vector<gfx::MTLSharedEventFence> backpressure_fences; |
| if (access) { |
| io_surface = access->GetIOSurface(); |
| io_surface_color_space = access->representation()->color_space(); |
| backpressure_fences = access->GetBackpressureFences(); |
| } |
| presenter_->ScheduleCALayer( |
| ui::CARendererLayerParams( |
| overlay_plane_candidate.clip_rect.has_value(), |
| overlay_plane_candidate.clip_rect.value_or(gfx::Rect()), |
| overlay_plane_candidate.rounded_corners, |
| overlay_plane_candidate.sorting_context_id, |
| std::get<gfx::Transform>(overlay_plane_candidate.transform), |
| io_surface, io_surface_color_space, overlay_plane_candidate.uv_rect, |
| gfx::ToEnclosingRect(overlay_plane_candidate.display_rect), |
| overlay_plane_candidate.color.value_or(SkColors::kTransparent), |
| overlay_plane_candidate.edge_aa_mask, overlay_plane_candidate.opacity, |
| overlay_plane_candidate.nearest_neighbor_filter, |
| overlay_plane_candidate.hdr_metadata, |
| overlay_plane_candidate.protected_video_type, |
| overlay_plane_candidate.is_render_pass_draw_quad), |
| std::move(backpressure_fences)); |
| |
| #endif |
| } |
| |
| void OutputPresenterGL::SetVSyncDisplayID(int64_t display_id) { |
| presenter_->SetVSyncDisplayID(display_id); |
| } |
| |
| #if BUILDFLAG(IS_APPLE) |
| void OutputPresenterGL::SetMaxPendingSwaps(int max_pending_swaps) { |
| presenter_->SetMaxPendingSwaps(max_pending_swaps); |
| } |
| #endif |
| |
| } // namespace viz |