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