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/xdg_shell_surface.h"
44 #endif
45 
46 namespace exo {
47 
48 ////////////////////////////////////////////////////////////////////////////////
49 // Display, public:
50 
Display()51 Display::Display()
52 #if defined(USE_OZONE)
53     : client_native_pixmap_factory_(
54           gfx::CreateClientNativePixmapFactoryDmabuf())
55 #endif
56 {
57 }
58 
59 #if defined(OS_CHROMEOS)
Display(NotificationSurfaceManager * notification_surface_manager,InputMethodSurfaceManager * input_method_surface_manager,std::unique_ptr<FileHelper> file_helper)60 Display::Display(NotificationSurfaceManager* notification_surface_manager,
61                  InputMethodSurfaceManager* input_method_surface_manager,
62                  std::unique_ptr<FileHelper> file_helper)
63     : Display() {
64   file_helper_ = std::move(file_helper);
65   notification_surface_manager_ = notification_surface_manager;
66   input_method_surface_manager_ = input_method_surface_manager;
67 }
68 #endif  // defined(OS_CHROMEOS)
69 
~Display()70 Display::~Display() {}
71 
CreateSurface()72 std::unique_ptr<Surface> Display::CreateSurface() {
73   TRACE_EVENT0("exo", "Display::CreateSurface");
74 
75   return std::make_unique<Surface>();
76 }
77 
CreateSharedMemory(base::UnsafeSharedMemoryRegion shared_memory_region)78 std::unique_ptr<SharedMemory> Display::CreateSharedMemory(
79     base::UnsafeSharedMemoryRegion shared_memory_region) {
80   TRACE_EVENT1("exo", "Display::CreateSharedMemory", "size",
81                shared_memory_region.GetSize());
82 
83   if (!shared_memory_region.IsValid())
84     return nullptr;
85 
86   return std::make_unique<SharedMemory>(std::move(shared_memory_region));
87 }
88 
89 #if defined(USE_OZONE)
CreateLinuxDMABufBuffer(const gfx::Size & size,gfx::BufferFormat format,gfx::NativePixmapHandle handle,bool y_invert)90 std::unique_ptr<Buffer> Display::CreateLinuxDMABufBuffer(
91     const gfx::Size& size,
92     gfx::BufferFormat format,
93     gfx::NativePixmapHandle handle,
94     bool y_invert) {
95   TRACE_EVENT1("exo", "Display::CreateLinuxDMABufBuffer", "size",
96                size.ToString());
97 
98   gfx::GpuMemoryBufferHandle gmb_handle;
99   gmb_handle.type = gfx::NATIVE_PIXMAP;
100   gmb_handle.native_pixmap_handle = std::move(handle);
101   std::unique_ptr<gfx::GpuMemoryBuffer> gpu_memory_buffer =
102       gpu::GpuMemoryBufferImplNativePixmap::CreateFromHandle(
103           client_native_pixmap_factory_.get(), std::move(gmb_handle), size,
104           format, gfx::BufferUsage::GPU_READ,
105           gpu::GpuMemoryBufferImpl::DestructionCallback());
106   if (!gpu_memory_buffer) {
107     LOG(ERROR) << "Failed to create GpuMemoryBuffer from handle";
108     return nullptr;
109   }
110 
111   // Using zero-copy for optimal performance.
112   bool use_zero_copy = true;
113 
114 #if defined(ARCH_CPU_X86_FAMILY)
115   // TODO(dcastagna): Re-enable NV12 format as HW overlay once b/113362843
116   // is addressed.
117   bool is_overlay_candidate = format != gfx::BufferFormat::YUV_420_BIPLANAR;
118 #else
119   bool is_overlay_candidate = true;
120 #endif
121 
122   return std::make_unique<Buffer>(
123       std::move(gpu_memory_buffer),
124       gpu::NativeBufferNeedsPlatformSpecificTextureTarget(format)
125           ? gpu::GetPlatformSpecificTextureTarget()
126           : GL_TEXTURE_2D,
127       // COMMANDS_COMPLETED queries are required by native pixmaps.
128       GL_COMMANDS_COMPLETED_CHROMIUM, use_zero_copy, is_overlay_candidate,
129       y_invert);
130 }
131 #endif  // defined(USE_OZONE)
132 
133 #if defined(OS_CHROMEOS)
CreateShellSurface(Surface * surface)134 std::unique_ptr<ShellSurface> Display::CreateShellSurface(Surface* surface) {
135   TRACE_EVENT1("exo", "Display::CreateShellSurface", "surface",
136                surface->AsTracedValue());
137   if (surface->HasSurfaceDelegate()) {
138     DLOG(ERROR) << "Surface has already been assigned a role";
139     return nullptr;
140   }
141 
142   return std::make_unique<ShellSurface>(
143       surface, gfx::Point(), true /* activatable */, false /* can_minimize */,
144       ash::desks_util::GetActiveDeskContainerId());
145 }
146 
CreateXdgShellSurface(Surface * surface)147 std::unique_ptr<XdgShellSurface> Display::CreateXdgShellSurface(
148     Surface* surface) {
149   TRACE_EVENT1("exo", "Display::CreateXdgShellSurface", "surface",
150                surface->AsTracedValue());
151   if (surface->HasSurfaceDelegate()) {
152     DLOG(ERROR) << "Surface has already been assigned a role";
153     return nullptr;
154   }
155 
156   return std::make_unique<XdgShellSurface>(
157       surface, gfx::Point(), true /* activatable */, false /* can_minimize */,
158       ash::desks_util::GetActiveDeskContainerId());
159 }
160 
161 std::unique_ptr<ClientControlledShellSurface>
CreateClientControlledShellSurface(Surface * surface,int container,double default_device_scale_factor)162 Display::CreateClientControlledShellSurface(
163     Surface* surface,
164     int container,
165     double default_device_scale_factor) {
166   TRACE_EVENT2("exo", "Display::CreateRemoteShellSurface", "surface",
167                surface->AsTracedValue(), "container", container);
168 
169   if (surface->HasSurfaceDelegate()) {
170     DLOG(ERROR) << "Surface has already been assigned a role";
171     return nullptr;
172   }
173 
174   // Remote shell surfaces in system modal container cannot be minimized.
175   bool can_minimize = container != ash::kShellWindowId_SystemModalContainer;
176 
177   std::unique_ptr<ClientControlledShellSurface> shell_surface(
178       std::make_unique<ClientControlledShellSurface>(surface, can_minimize,
179                                                      container));
180   DCHECK_GE(default_device_scale_factor, 1.0);
181   shell_surface->SetScale(default_device_scale_factor);
182   shell_surface->CommitPendingScale();
183   return shell_surface;
184 }
185 
CreateNotificationSurface(Surface * surface,const std::string & notification_key)186 std::unique_ptr<NotificationSurface> Display::CreateNotificationSurface(
187     Surface* surface,
188     const std::string& notification_key) {
189   TRACE_EVENT2("exo", "Display::CreateNotificationSurface", "surface",
190                surface->AsTracedValue(), "notification_key", notification_key);
191 
192   if (!notification_surface_manager_ ||
193       notification_surface_manager_->GetSurface(notification_key)) {
194     DLOG(ERROR) << "Invalid notification key, key=" << notification_key;
195     return nullptr;
196   }
197 
198   return std::make_unique<NotificationSurface>(notification_surface_manager_,
199                                                surface, notification_key);
200 }
201 
CreateInputMethodSurface(Surface * surface,double default_device_scale_factor)202 std::unique_ptr<InputMethodSurface> Display::CreateInputMethodSurface(
203     Surface* surface,
204     double default_device_scale_factor) {
205   TRACE_EVENT1("exo", "Display::CreateInputMethodSurface", "surface",
206                surface->AsTracedValue());
207 
208   if (!input_method_surface_manager_) {
209     DLOG(ERROR) << "Input method surface cannot be registered";
210     return nullptr;
211   }
212 
213   if (surface->HasSurfaceDelegate()) {
214     DLOG(ERROR) << "Surface has already been assigned a role";
215     return nullptr;
216   }
217 
218   return std::make_unique<InputMethodSurface>(
219       input_method_surface_manager_, surface, default_device_scale_factor);
220 }
221 #endif  // defined(OS_CHROMEOS)
222 
CreateSubSurface(Surface * surface,Surface * parent)223 std::unique_ptr<SubSurface> Display::CreateSubSurface(Surface* surface,
224                                                       Surface* parent) {
225   TRACE_EVENT2("exo", "Display::CreateSubSurface", "surface",
226                surface->AsTracedValue(), "parent", parent->AsTracedValue());
227 
228   if (surface->window()->Contains(parent->window())) {
229     DLOG(ERROR) << "Parent is contained within surface's hierarchy";
230     return nullptr;
231   }
232 
233   if (surface->HasSurfaceDelegate()) {
234     DLOG(ERROR) << "Surface has already been assigned a role";
235     return nullptr;
236   }
237 
238   return std::make_unique<SubSurface>(surface, parent);
239 }
240 
CreateDataDevice(DataDeviceDelegate * delegate)241 std::unique_ptr<DataDevice> Display::CreateDataDevice(
242     DataDeviceDelegate* delegate) {
243   return std::make_unique<DataDevice>(delegate, &seat_, file_helper_.get());
244 }
245 
246 }  // namespace exo
247