1 // Copyright 2015 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "components/exo/display.h"
6 
7 #include <iterator>
8 #include <memory>
9 #include <utility>
10 
11 #include "base/command_line.h"
12 #include "base/trace_event/trace_event.h"
13 #include "base/trace_event/traced_value.h"
14 #include "build/build_config.h"
15 #include "components/exo/data_device.h"
16 #include "components/exo/file_helper.h"
17 #include "components/exo/input_method_surface_manager.h"
18 #include "components/exo/notification_surface.h"
19 #include "components/exo/notification_surface_manager.h"
20 #include "components/exo/shared_memory.h"
21 #include "components/exo/sub_surface.h"
22 #include "components/exo/surface.h"
23 #include "ui/gfx/linux/client_native_pixmap_factory_dmabuf.h"
24 #include "ui/views/widget/widget.h"
25 #include "ui/wm/core/coordinate_conversion.h"
26 
27 #if defined(USE_OZONE)
28 #include <GLES2/gl2extchromium.h>
29 #include "components/exo/buffer.h"
30 #include "gpu/command_buffer/common/gpu_memory_buffer_support.h"
31 #include "gpu/ipc/common/gpu_memory_buffer_impl_native_pixmap.h"
32 #include "third_party/khronos/GLES2/gl2.h"
33 #include "third_party/khronos/GLES2/gl2ext.h"
34 #include "ui/ozone/public/ozone_switches.h"
35 #endif
36 
37 #if defined(OS_CHROMEOS)
38 #include "ash/public/cpp/shell_window_ids.h"
39 #include "ash/wm/desks/desks_util.h"
40 #include "components/exo/client_controlled_shell_surface.h"
41 #include "components/exo/input_method_surface.h"
42 #include "components/exo/shell_surface.h"
43 #include "components/exo/toast_surface.h"
44 #include "components/exo/toast_surface_manager.h"
45 #include "components/exo/xdg_shell_surface.h"
46 #endif
47 
48 namespace exo {
49 
50 ////////////////////////////////////////////////////////////////////////////////
51 // Display, public:
52 
Display()53 Display::Display()
54 #if defined(USE_OZONE)
55     : client_native_pixmap_factory_(
56           gfx::CreateClientNativePixmapFactoryDmabuf())
57 #endif
58 {
59 }
60 
61 #if defined(OS_CHROMEOS)
Display(std::unique_ptr<NotificationSurfaceManager> notification_surface_manager,std::unique_ptr<InputMethodSurfaceManager> input_method_surface_manager,std::unique_ptr<ToastSurfaceManager> toast_surface_manager,std::unique_ptr<FileHelper> file_helper)62 Display::Display(
63     std::unique_ptr<NotificationSurfaceManager> notification_surface_manager,
64     std::unique_ptr<InputMethodSurfaceManager> input_method_surface_manager,
65     std::unique_ptr<ToastSurfaceManager> toast_surface_manager,
66     std::unique_ptr<FileHelper> file_helper)
67     : notification_surface_manager_(std::move(notification_surface_manager)),
68       input_method_surface_manager_(std::move(input_method_surface_manager)),
69       toast_surface_manager_(std::move(toast_surface_manager)),
70       file_helper_(std::move(file_helper)),
71       client_native_pixmap_factory_(
72           gfx::CreateClientNativePixmapFactoryDmabuf()) {}
73 #endif  // defined(OS_CHROMEOS)
74 
~Display()75 Display::~Display() {
76   Shutdown();
77 }
78 
Shutdown()79 void Display::Shutdown() {
80   if (shutdown_)
81     return;
82   shutdown_ = true;
83   seat_.Shutdown();
84 }
85 
CreateSurface()86 std::unique_ptr<Surface> Display::CreateSurface() {
87   TRACE_EVENT0("exo", "Display::CreateSurface");
88 
89   return std::make_unique<Surface>();
90 }
91 
CreateSharedMemory(base::UnsafeSharedMemoryRegion shared_memory_region)92 std::unique_ptr<SharedMemory> Display::CreateSharedMemory(
93     base::UnsafeSharedMemoryRegion shared_memory_region) {
94   TRACE_EVENT1("exo", "Display::CreateSharedMemory", "size",
95                shared_memory_region.GetSize());
96 
97   if (!shared_memory_region.IsValid())
98     return nullptr;
99 
100   return std::make_unique<SharedMemory>(std::move(shared_memory_region));
101 }
102 
103 #if defined(USE_OZONE)
CreateLinuxDMABufBuffer(const gfx::Size & size,gfx::BufferFormat format,gfx::NativePixmapHandle handle,bool y_invert)104 std::unique_ptr<Buffer> Display::CreateLinuxDMABufBuffer(
105     const gfx::Size& size,
106     gfx::BufferFormat format,
107     gfx::NativePixmapHandle handle,
108     bool y_invert) {
109   TRACE_EVENT1("exo", "Display::CreateLinuxDMABufBuffer", "size",
110                size.ToString());
111 
112   gfx::GpuMemoryBufferHandle gmb_handle;
113   gmb_handle.type = gfx::NATIVE_PIXMAP;
114   gmb_handle.native_pixmap_handle = std::move(handle);
115   std::unique_ptr<gfx::GpuMemoryBuffer> gpu_memory_buffer =
116       gpu::GpuMemoryBufferImplNativePixmap::CreateFromHandle(
117           client_native_pixmap_factory_.get(), std::move(gmb_handle), size,
118           format, gfx::BufferUsage::GPU_READ,
119           gpu::GpuMemoryBufferImpl::DestructionCallback());
120   if (!gpu_memory_buffer) {
121     LOG(ERROR) << "Failed to create GpuMemoryBuffer from handle";
122     return nullptr;
123   }
124 
125   // Using zero-copy for optimal performance.
126   bool use_zero_copy = true;
127 
128   return std::make_unique<Buffer>(
129       std::move(gpu_memory_buffer),
130       gpu::NativeBufferNeedsPlatformSpecificTextureTarget(format)
131           ? gpu::GetPlatformSpecificTextureTarget()
132           : GL_TEXTURE_2D,
133       // COMMANDS_COMPLETED queries are required by native pixmaps.
134       GL_COMMANDS_COMPLETED_CHROMIUM, use_zero_copy,
135       /*is_overlay_candidate=*/true, y_invert);
136 }
137 #endif  // defined(USE_OZONE)
138 
139 #if defined(OS_CHROMEOS)
CreateShellSurface(Surface * surface)140 std::unique_ptr<ShellSurface> Display::CreateShellSurface(Surface* surface) {
141   TRACE_EVENT1("exo", "Display::CreateShellSurface", "surface",
142                surface->AsTracedValue());
143   if (surface->HasSurfaceDelegate()) {
144     DLOG(ERROR) << "Surface has already been assigned a role";
145     return nullptr;
146   }
147 
148   return std::make_unique<ShellSurface>(
149       surface, gfx::Point(), true /* activatable */, false /* can_minimize */,
150       ash::desks_util::GetActiveDeskContainerId());
151 }
152 
CreateXdgShellSurface(Surface * surface)153 std::unique_ptr<XdgShellSurface> Display::CreateXdgShellSurface(
154     Surface* surface) {
155   TRACE_EVENT1("exo", "Display::CreateXdgShellSurface", "surface",
156                surface->AsTracedValue());
157   if (surface->HasSurfaceDelegate()) {
158     DLOG(ERROR) << "Surface has already been assigned a role";
159     return nullptr;
160   }
161 
162   return std::make_unique<XdgShellSurface>(
163       surface, gfx::Point(), true /* activatable */, false /* can_minimize */,
164       ash::desks_util::GetActiveDeskContainerId());
165 }
166 
167 std::unique_ptr<ClientControlledShellSurface>
CreateClientControlledShellSurface(Surface * surface,int container,double default_device_scale_factor,bool default_scale_cancellation)168 Display::CreateClientControlledShellSurface(Surface* surface,
169                                             int container,
170                                             double default_device_scale_factor,
171                                             bool default_scale_cancellation) {
172   TRACE_EVENT2("exo", "Display::CreateRemoteShellSurface", "surface",
173                surface->AsTracedValue(), "container", container);
174 
175   if (surface->HasSurfaceDelegate()) {
176     DLOG(ERROR) << "Surface has already been assigned a role";
177     return nullptr;
178   }
179 
180   // Remote shell surfaces in system modal container cannot be minimized.
181   bool can_minimize = container != ash::kShellWindowId_SystemModalContainer;
182 
183   std::unique_ptr<ClientControlledShellSurface> shell_surface(
184       std::make_unique<ClientControlledShellSurface>(
185           surface, can_minimize, container, default_scale_cancellation));
186   if (default_scale_cancellation) {
187     shell_surface->SetScale(default_device_scale_factor);
188     shell_surface->CommitPendingScale();
189   }
190   return shell_surface;
191 }
192 
CreateNotificationSurface(Surface * surface,const std::string & notification_key)193 std::unique_ptr<NotificationSurface> Display::CreateNotificationSurface(
194     Surface* surface,
195     const std::string& notification_key) {
196   TRACE_EVENT2("exo", "Display::CreateNotificationSurface", "surface",
197                surface->AsTracedValue(), "notification_key", notification_key);
198 
199   if (!notification_surface_manager_ ||
200       notification_surface_manager_->GetSurface(notification_key)) {
201     DLOG(ERROR) << "Invalid notification key, key=" << notification_key;
202     return nullptr;
203   }
204 
205   return std::make_unique<NotificationSurface>(
206       notification_surface_manager_.get(), surface, notification_key);
207 }
208 
CreateInputMethodSurface(Surface * surface,double default_device_scale_factor,bool default_scale_cancellation)209 std::unique_ptr<InputMethodSurface> Display::CreateInputMethodSurface(
210     Surface* surface,
211     double default_device_scale_factor,
212     bool default_scale_cancellation) {
213   TRACE_EVENT1("exo", "Display::CreateInputMethodSurface", "surface",
214                surface->AsTracedValue());
215 
216   if (!input_method_surface_manager_) {
217     DLOG(ERROR) << "Input method surface cannot be registered";
218     return nullptr;
219   }
220 
221   if (surface->HasSurfaceDelegate()) {
222     DLOG(ERROR) << "Surface has already been assigned a role";
223     return nullptr;
224   }
225 
226   std::unique_ptr<InputMethodSurface> input_method_surface(
227       std::make_unique<InputMethodSurface>(input_method_surface_manager_.get(),
228                                            surface,
229                                            default_scale_cancellation));
230   if (default_scale_cancellation) {
231     input_method_surface->SetScale(default_device_scale_factor);
232     input_method_surface->CommitPendingScale();
233   }
234   return input_method_surface;
235 }
236 
CreateToastSurface(Surface * surface,double default_device_scale_factor,bool default_scale_cancellation)237 std::unique_ptr<ToastSurface> Display::CreateToastSurface(
238     Surface* surface,
239     double default_device_scale_factor,
240     bool default_scale_cancellation) {
241   TRACE_EVENT1("exo", "Display::CreateToastSurface", "surface",
242                surface->AsTracedValue());
243 
244   if (!toast_surface_manager_) {
245     DLOG(ERROR) << "Toast surface cannot be registered";
246     return nullptr;
247   }
248 
249   if (surface->HasSurfaceDelegate()) {
250     DLOG(ERROR) << "Surface has already been assigned a role";
251     return nullptr;
252   }
253 
254   std::unique_ptr<ToastSurface> toast_surface(std::make_unique<ToastSurface>(
255       toast_surface_manager_.get(), surface, default_scale_cancellation));
256   if (default_scale_cancellation) {
257     toast_surface->SetScale(default_device_scale_factor);
258     toast_surface->CommitPendingScale();
259   }
260   return toast_surface;
261 }
262 #endif  // defined(OS_CHROMEOS)
263 
CreateSubSurface(Surface * surface,Surface * parent)264 std::unique_ptr<SubSurface> Display::CreateSubSurface(Surface* surface,
265                                                       Surface* parent) {
266   TRACE_EVENT2("exo", "Display::CreateSubSurface", "surface",
267                surface->AsTracedValue(), "parent", parent->AsTracedValue());
268 
269   if (surface->window()->Contains(parent->window())) {
270     DLOG(ERROR) << "Parent is contained within surface's hierarchy";
271     return nullptr;
272   }
273 
274   if (surface->HasSurfaceDelegate()) {
275     DLOG(ERROR) << "Surface has already been assigned a role";
276     return nullptr;
277   }
278 
279   return std::make_unique<SubSurface>(surface, parent);
280 }
281 
CreateDataDevice(DataDeviceDelegate * delegate)282 std::unique_ptr<DataDevice> Display::CreateDataDevice(
283     DataDeviceDelegate* delegate) {
284   return std::make_unique<DataDevice>(delegate, seat(), file_helper_.get());
285 }
286 
287 }  // namespace exo
288