// Copyright 2015 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 "components/exo/display.h" #include #include #include #include #include "base/command_line.h" #include "base/trace_event/trace_event.h" #include "base/trace_event/traced_value.h" #include "build/build_config.h" #include "build/chromeos_buildflags.h" #include "components/exo/buffer.h" #include "components/exo/data_device.h" #include "components/exo/data_exchange_delegate.h" #include "components/exo/input_method_surface_manager.h" #include "components/exo/notification_surface.h" #include "components/exo/notification_surface_manager.h" #include "components/exo/shared_memory.h" #include "components/exo/shell_surface_util.h" #include "components/exo/sub_surface.h" #include "components/exo/surface.h" #include "gpu/command_buffer/common/gpu_memory_buffer_support.h" #include "gpu/ipc/common/gpu_memory_buffer_impl_native_pixmap.h" #include "third_party/khronos/GLES2/gl2.h" #include "third_party/khronos/GLES2/gl2ext.h" #include "ui/gfx/linux/client_native_pixmap_factory_dmabuf.h" #include "ui/ozone/public/ozone_switches.h" #include "ui/views/widget/widget.h" #include "ui/wm/core/coordinate_conversion.h" #if BUILDFLAG(IS_CHROMEOS_ASH) #include "ash/public/cpp/shell_window_ids.h" #include "ash/wm/desks/desks_util.h" #include "components/exo/client_controlled_shell_surface.h" #include "components/exo/input_method_surface.h" #include "components/exo/shell_surface.h" #include "components/exo/toast_surface.h" #include "components/exo/toast_surface_manager.h" #include "components/exo/xdg_shell_surface.h" #endif namespace exo { //////////////////////////////////////////////////////////////////////////////// // Display, public: Display::Display() : seat_(nullptr), client_native_pixmap_factory_( gfx::CreateClientNativePixmapFactoryDmabuf()) {} #if BUILDFLAG(IS_CHROMEOS_ASH) Display::Display( std::unique_ptr notification_surface_manager, std::unique_ptr input_method_surface_manager, std::unique_ptr toast_surface_manager, std::unique_ptr data_exchange_delegate) : notification_surface_manager_(std::move(notification_surface_manager)), input_method_surface_manager_(std::move(input_method_surface_manager)), toast_surface_manager_(std::move(toast_surface_manager)), seat_(std::move(data_exchange_delegate)), client_native_pixmap_factory_( gfx::CreateClientNativePixmapFactoryDmabuf()) {} #endif // BUILDFLAG(IS_CHROMEOS_ASH) Display::~Display() { Shutdown(); } void Display::Shutdown() { if (shutdown_) return; shutdown_ = true; seat_.Shutdown(); } std::unique_ptr Display::CreateSurface() { TRACE_EVENT0("exo", "Display::CreateSurface"); return std::make_unique(); } std::unique_ptr Display::CreateSharedMemory( base::UnsafeSharedMemoryRegion shared_memory_region) { TRACE_EVENT1("exo", "Display::CreateSharedMemory", "size", shared_memory_region.GetSize()); if (!shared_memory_region.IsValid()) return nullptr; return std::make_unique(std::move(shared_memory_region)); } std::unique_ptr Display::CreateLinuxDMABufBuffer( const gfx::Size& size, gfx::BufferFormat format, gfx::NativePixmapHandle handle, bool y_invert) { TRACE_EVENT1("exo", "Display::CreateLinuxDMABufBuffer", "size", size.ToString()); gfx::GpuMemoryBufferHandle gmb_handle; gmb_handle.type = gfx::NATIVE_PIXMAP; gmb_handle.native_pixmap_handle = std::move(handle); std::unique_ptr gpu_memory_buffer = gpu::GpuMemoryBufferImplNativePixmap::CreateFromHandle( client_native_pixmap_factory_.get(), std::move(gmb_handle), size, format, gfx::BufferUsage::GPU_READ, gpu::GpuMemoryBufferImpl::DestructionCallback()); if (!gpu_memory_buffer) { LOG(ERROR) << "Failed to create GpuMemoryBuffer from handle"; return nullptr; } // Using zero-copy for optimal performance. bool use_zero_copy = true; return std::make_unique( std::move(gpu_memory_buffer), gpu::NativeBufferNeedsPlatformSpecificTextureTarget(format) ? gpu::GetPlatformSpecificTextureTarget() : GL_TEXTURE_2D, // COMMANDS_COMPLETED queries are required by native pixmaps. GL_COMMANDS_COMPLETED_CHROMIUM, use_zero_copy, /*is_overlay_candidate=*/true, y_invert); } #if BUILDFLAG(IS_CHROMEOS_ASH) std::unique_ptr Display::CreateShellSurface(Surface* surface) { TRACE_EVENT1("exo", "Display::CreateShellSurface", "surface", surface->AsTracedValue()); if (surface->HasSurfaceDelegate()) { DLOG(ERROR) << "Surface has already been assigned a role"; return nullptr; } return std::make_unique( surface, gfx::Point(), /*can_minimize=*/false, ash::desks_util::GetActiveDeskContainerId()); } std::unique_ptr Display::CreateXdgShellSurface( Surface* surface) { TRACE_EVENT1("exo", "Display::CreateXdgShellSurface", "surface", surface->AsTracedValue()); if (surface->HasSurfaceDelegate()) { DLOG(ERROR) << "Surface has already been assigned a role"; return nullptr; } return std::make_unique( surface, gfx::Point(), /*can_minimize=*/false, ash::desks_util::GetActiveDeskContainerId()); } std::unique_ptr Display::CreateOrGetClientControlledShellSurface( Surface* surface, int container, double default_device_scale_factor, bool default_scale_cancellation) { TRACE_EVENT2("exo", "Display::CreateRemoteShellSurface", "surface", surface->AsTracedValue(), "container", container); if (surface->HasSurfaceDelegate()) { DLOG(ERROR) << "Surface has already been assigned a role"; return nullptr; } // Remote shell surfaces in system modal container cannot be minimized. bool can_minimize = container != ash::kShellWindowId_SystemModalContainer; std::unique_ptr shell_surface; int window_session_id = surface->GetWindowSessionId(); if (window_session_id > 0) { // Root surface has window session id, try get shell surface from external // source first. ui::PropertyHandler handler; WMHelper::AppPropertyResolver::Params params; params.window_session_id = window_session_id; WMHelper::GetInstance()->PopulateAppProperties(params, handler); shell_surface = base::WrapUnique(GetShellClientControlledShellSurface(&handler)); } if (shell_surface) { shell_surface->RebindRootSurface(surface, can_minimize, container, default_scale_cancellation); } else { shell_surface = std::make_unique( surface, can_minimize, container, default_scale_cancellation); } if (default_scale_cancellation) { shell_surface->SetScale(default_device_scale_factor); shell_surface->CommitPendingScale(); } return shell_surface; } std::unique_ptr Display::CreateNotificationSurface( Surface* surface, const std::string& notification_key) { TRACE_EVENT2("exo", "Display::CreateNotificationSurface", "surface", surface->AsTracedValue(), "notification_key", notification_key); if (!notification_surface_manager_ || notification_surface_manager_->GetSurface(notification_key)) { DLOG(ERROR) << "Invalid notification key, key=" << notification_key; return nullptr; } return std::make_unique( notification_surface_manager_.get(), surface, notification_key); } std::unique_ptr Display::CreateInputMethodSurface( Surface* surface, double default_device_scale_factor, bool default_scale_cancellation) { TRACE_EVENT1("exo", "Display::CreateInputMethodSurface", "surface", surface->AsTracedValue()); if (!input_method_surface_manager_) { DLOG(ERROR) << "Input method surface cannot be registered"; return nullptr; } if (surface->HasSurfaceDelegate()) { DLOG(ERROR) << "Surface has already been assigned a role"; return nullptr; } std::unique_ptr input_method_surface( std::make_unique(input_method_surface_manager_.get(), surface, default_scale_cancellation)); if (default_scale_cancellation) { input_method_surface->SetScale(default_device_scale_factor); input_method_surface->CommitPendingScale(); } return input_method_surface; } std::unique_ptr Display::CreateToastSurface( Surface* surface, double default_device_scale_factor, bool default_scale_cancellation) { TRACE_EVENT1("exo", "Display::CreateToastSurface", "surface", surface->AsTracedValue()); if (!toast_surface_manager_) { DLOG(ERROR) << "Toast surface cannot be registered"; return nullptr; } if (surface->HasSurfaceDelegate()) { DLOG(ERROR) << "Surface has already been assigned a role"; return nullptr; } std::unique_ptr toast_surface(std::make_unique( toast_surface_manager_.get(), surface, default_scale_cancellation)); if (default_scale_cancellation) { toast_surface->SetScale(default_device_scale_factor); toast_surface->CommitPendingScale(); } return toast_surface; } #endif // BUILDFLAG(IS_CHROMEOS_ASH) std::unique_ptr Display::CreateSubSurface(Surface* surface, Surface* parent) { TRACE_EVENT2("exo", "Display::CreateSubSurface", "surface", surface->AsTracedValue(), "parent", parent->AsTracedValue()); if (surface->window()->Contains(parent->window())) { DLOG(ERROR) << "Parent is contained within surface's hierarchy"; return nullptr; } if (surface->HasSurfaceDelegate()) { DLOG(ERROR) << "Surface has already been assigned a role"; return nullptr; } return std::make_unique(surface, parent); } std::unique_ptr Display::CreateDataDevice( DataDeviceDelegate* delegate) { return std::make_unique(delegate, seat()); } } // namespace exo