summaryrefslogtreecommitdiff
path: root/chromium/ui/ozone
diff options
context:
space:
mode:
authorAllan Sandfeld Jensen <allan.jensen@qt.io>2020-11-18 16:35:47 +0100
committerAllan Sandfeld Jensen <allan.jensen@qt.io>2020-11-18 15:45:54 +0000
commit32f5a1c56531e4210bc4cf8d8c7825d66e081888 (patch)
treeeeeec6822f4d738d8454525233fd0e2e3a659e6d /chromium/ui/ozone
parent99677208ff3b216fdfec551fbe548da5520cd6fb (diff)
downloadqtwebengine-chromium-32f5a1c56531e4210bc4cf8d8c7825d66e081888.tar.gz
BASELINE: Update Chromium to 87.0.4280.67
Change-Id: Ib157360be8c2ffb2c73125751a89f60e049c1d54 Reviewed-by: Allan Sandfeld Jensen <allan.jensen@qt.io>
Diffstat (limited to 'chromium/ui/ozone')
-rw-r--r--chromium/ui/ozone/BUILD.gn28
-rw-r--r--chromium/ui/ozone/ozone.gni36
-rw-r--r--chromium/ui/ozone/platform/drm/BUILD.gn23
-rw-r--r--chromium/ui/ozone/platform/drm/client_native_pixmap_factory_drm.cc (renamed from chromium/ui/ozone/platform/drm/client_native_pixmap_factory_gbm.cc)4
-rw-r--r--chromium/ui/ozone/platform/drm/client_native_pixmap_factory_drm.h (renamed from chromium/ui/ozone/platform/drm/client_native_pixmap_factory_gbm.h)8
-rw-r--r--chromium/ui/ozone/platform/drm/gpu/crtc_commit_request.cc56
-rw-r--r--chromium/ui/ozone/platform/drm/gpu/crtc_commit_request.h67
-rw-r--r--chromium/ui/ozone/platform/drm/gpu/crtc_controller.cc72
-rw-r--r--chromium/ui/ozone/platform/drm/gpu/crtc_controller.h29
-rw-r--r--chromium/ui/ozone/platform/drm/gpu/drm_display.cc145
-rw-r--r--chromium/ui/ozone/platform/drm/gpu/drm_display.h16
-rw-r--r--chromium/ui/ozone/platform/drm/gpu/drm_display_unittest.cc14
-rw-r--r--chromium/ui/ozone/platform/drm/gpu/drm_gpu_display_manager.cc153
-rw-r--r--chromium/ui/ozone/platform/drm/gpu/drm_gpu_display_manager.h24
-rw-r--r--chromium/ui/ozone/platform/drm/gpu/drm_overlay_manager.cc9
-rw-r--r--chromium/ui/ozone/platform/drm/gpu/drm_overlay_plane.cc2
-rw-r--r--chromium/ui/ozone/platform/drm/gpu/drm_overlay_validator_unittest.cc51
-rw-r--r--chromium/ui/ozone/platform/drm/gpu/drm_thread.cc32
-rw-r--r--chromium/ui/ozone/platform/drm/gpu/drm_thread.h6
-rw-r--r--chromium/ui/ozone/platform/drm/gpu/drm_window_unittest.cc137
-rw-r--r--chromium/ui/ozone/platform/drm/gpu/gbm_surface_factory.cc13
-rw-r--r--chromium/ui/ozone/platform/drm/gpu/gbm_surfaceless.cc2
-rw-r--r--chromium/ui/ozone/platform/drm/gpu/hardware_display_controller.cc101
-rw-r--r--chromium/ui/ozone/platform/drm/gpu/hardware_display_controller.h33
-rw-r--r--chromium/ui/ozone/platform/drm/gpu/hardware_display_controller_unittest.cc340
-rw-r--r--chromium/ui/ozone/platform/drm/gpu/hardware_display_plane.cc28
-rw-r--r--chromium/ui/ozone/platform/drm/gpu/hardware_display_plane.h7
-rw-r--r--chromium/ui/ozone/platform/drm/gpu/hardware_display_plane_atomic.cc106
-rw-r--r--chromium/ui/ozone/platform/drm/gpu/hardware_display_plane_atomic.h23
-rw-r--r--chromium/ui/ozone/platform/drm/gpu/hardware_display_plane_dummy.cc26
-rw-r--r--chromium/ui/ozone/platform/drm/gpu/hardware_display_plane_dummy.h27
-rw-r--r--chromium/ui/ozone/platform/drm/gpu/hardware_display_plane_manager.cc145
-rw-r--r--chromium/ui/ozone/platform/drm/gpu/hardware_display_plane_manager.h115
-rw-r--r--chromium/ui/ozone/platform/drm/gpu/hardware_display_plane_manager_atomic.cc249
-rw-r--r--chromium/ui/ozone/platform/drm/gpu/hardware_display_plane_manager_atomic.h24
-rw-r--r--chromium/ui/ozone/platform/drm/gpu/hardware_display_plane_manager_legacy.cc73
-rw-r--r--chromium/ui/ozone/platform/drm/gpu/hardware_display_plane_manager_legacy.h9
-rw-r--r--chromium/ui/ozone/platform/drm/gpu/hardware_display_plane_manager_unittest.cc348
-rw-r--r--chromium/ui/ozone/platform/drm/gpu/mock_drm_device.cc14
-rw-r--r--chromium/ui/ozone/platform/drm/gpu/screen_manager.cc314
-rw-r--r--chromium/ui/ozone/platform/drm/gpu/screen_manager.h113
-rw-r--r--chromium/ui/ozone/platform/drm/gpu/screen_manager_unittest.cc865
-rw-r--r--chromium/ui/ozone/platform/drm/gpu/vulkan_implementation_gbm.cc6
-rw-r--r--chromium/ui/ozone/platform/drm/host/drm_display_host.cc25
-rw-r--r--chromium/ui/ozone/platform/drm/host/drm_display_host.h5
-rw-r--r--chromium/ui/ozone/platform/drm/host/drm_display_host_manager.cc10
-rw-r--r--chromium/ui/ozone/platform/drm/host/drm_display_host_manager.h3
-rw-r--r--chromium/ui/ozone/platform/drm/host/drm_native_display_delegate.cc3
-rw-r--r--chromium/ui/ozone/platform/drm/host/drm_native_display_delegate.h1
-rw-r--r--chromium/ui/ozone/platform/drm/host/gpu_thread_adapter.h6
-rw-r--r--chromium/ui/ozone/platform/drm/host/host_drm_device.cc20
-rw-r--r--chromium/ui/ozone/platform/drm/host/host_drm_device.h13
-rw-r--r--chromium/ui/ozone/platform/drm/ozone_platform_drm.cc (renamed from chromium/ui/ozone/platform/drm/ozone_platform_gbm.cc)26
-rw-r--r--chromium/ui/ozone/platform/drm/ozone_platform_drm.h (renamed from chromium/ui/ozone/platform/drm/ozone_platform_gbm.h)8
-rw-r--r--chromium/ui/ozone/platform/scenic/BUILD.gn2
-rw-r--r--chromium/ui/ozone/platform/scenic/ozone_platform_scenic.cc21
-rw-r--r--chromium/ui/ozone/platform/scenic/scenic_overlay_view.cc77
-rw-r--r--chromium/ui/ozone/platform/scenic/scenic_overlay_view.h43
-rw-r--r--chromium/ui/ozone/platform/scenic/scenic_surface_factory.cc1
-rw-r--r--chromium/ui/ozone/platform/scenic/scenic_surface_factory.h2
-rw-r--r--chromium/ui/ozone/platform/scenic/sysmem_buffer_collection.cc23
-rw-r--r--chromium/ui/ozone/platform/scenic/sysmem_buffer_collection.h18
-rw-r--r--chromium/ui/ozone/platform/scenic/sysmem_buffer_manager.cc22
-rw-r--r--chromium/ui/ozone/platform/scenic/sysmem_buffer_manager.h8
-rw-r--r--chromium/ui/ozone/platform/scenic/vulkan_implementation_scenic.cc6
-rw-r--r--chromium/ui/ozone/platform/scenic/vulkan_implementation_scenic.h3
-rw-r--r--chromium/ui/ozone/platform/wayland/BUILD.gn45
-rw-r--r--chromium/ui/ozone/platform/wayland/DEPS1
-rw-r--r--chromium/ui/ozone/platform/wayland/common/wayland.cc24
-rw-r--r--chromium/ui/ozone/platform/wayland/common/wayland.h31
-rw-r--r--chromium/ui/ozone/platform/wayland/common/wayland_object.cc63
-rw-r--r--chromium/ui/ozone/platform/wayland/common/wayland_object.h68
-rw-r--r--chromium/ui/ozone/platform/wayland/common/wayland_util.cc92
-rw-r--r--chromium/ui/ozone/platform/wayland/common/wayland_util.h18
-rw-r--r--chromium/ui/ozone/platform/wayland/gpu/gbm_surfaceless_wayland.cc120
-rw-r--r--chromium/ui/ozone/platform/wayland/gpu/gbm_surfaceless_wayland.h35
-rw-r--r--chromium/ui/ozone/platform/wayland/gpu/wayland_buffer_manager_gpu.cc5
-rw-r--r--chromium/ui/ozone/platform/wayland/gpu/wayland_surface_factory_unittest.cc499
-rw-r--r--chromium/ui/ozone/platform/wayland/host/DEPS4
-rw-r--r--chromium/ui/ozone/platform/wayland/host/gtk_ui_delegate_wayland.cc41
-rw-r--r--chromium/ui/ozone/platform/wayland/host/gtk_ui_delegate_wayland.h9
-rw-r--r--chromium/ui/ozone/platform/wayland/host/wayland_auxiliary_window.cc11
-rw-r--r--chromium/ui/ozone/platform/wayland/host/wayland_buffer_manager_host.cc114
-rw-r--r--chromium/ui/ozone/platform/wayland/host/wayland_buffer_manager_host.h27
-rw-r--r--chromium/ui/ozone/platform/wayland/host/wayland_clipboard.cc3
-rw-r--r--chromium/ui/ozone/platform/wayland/host/wayland_connection.cc55
-rw-r--r--chromium/ui/ozone/platform/wayland/host/wayland_connection.h36
-rw-r--r--chromium/ui/ozone/platform/wayland/host/wayland_cursor.h2
-rw-r--r--chromium/ui/ozone/platform/wayland/host/wayland_data_device.cc12
-rw-r--r--chromium/ui/ozone/platform/wayland/host/wayland_data_device.h2
-rw-r--r--chromium/ui/ozone/platform/wayland/host/wayland_data_device_manager.cc2
-rw-r--r--chromium/ui/ozone/platform/wayland/host/wayland_data_drag_controller.cc2
-rw-r--r--chromium/ui/ozone/platform/wayland/host/wayland_data_offer.cc7
-rw-r--r--chromium/ui/ozone/platform/wayland/host/wayland_data_offer.h2
-rw-r--r--chromium/ui/ozone/platform/wayland/host/wayland_data_source.cc3
-rw-r--r--chromium/ui/ozone/platform/wayland/host/wayland_event_source.cc87
-rw-r--r--chromium/ui/ozone/platform/wayland/host/wayland_event_source.h32
-rw-r--r--chromium/ui/ozone/platform/wayland/host/wayland_event_source_unittest.cc2
-rw-r--r--chromium/ui/ozone/platform/wayland/host/wayland_event_watcher.cc26
-rw-r--r--chromium/ui/ozone/platform/wayland/host/wayland_event_watcher.h11
-rw-r--r--chromium/ui/ozone/platform/wayland/host/wayland_input_method_context.cc19
-rw-r--r--chromium/ui/ozone/platform/wayland/host/wayland_keyboard.cc7
-rw-r--r--chromium/ui/ozone/platform/wayland/host/wayland_keyboard.h3
-rw-r--r--chromium/ui/ozone/platform/wayland/host/wayland_output.cc2
-rw-r--r--chromium/ui/ozone/platform/wayland/host/wayland_pointer.cc51
-rw-r--r--chromium/ui/ozone/platform/wayland/host/wayland_pointer.h13
-rw-r--r--chromium/ui/ozone/platform/wayland/host/wayland_pointer_unittest.cc241
-rw-r--r--chromium/ui/ozone/platform/wayland/host/wayland_popup.cc14
-rw-r--r--chromium/ui/ozone/platform/wayland/host/wayland_screen.cc91
-rw-r--r--chromium/ui/ozone/platform/wayland/host/wayland_screen.h5
-rw-r--r--chromium/ui/ozone/platform/wayland/host/wayland_shm_buffer.h2
-rw-r--r--chromium/ui/ozone/platform/wayland/host/wayland_subsurface.cc22
-rw-r--r--chromium/ui/ozone/platform/wayland/host/wayland_subsurface.h16
-rw-r--r--chromium/ui/ozone/platform/wayland/host/wayland_surface.cc147
-rw-r--r--chromium/ui/ozone/platform/wayland/host/wayland_surface.h57
-rw-r--r--chromium/ui/ozone/platform/wayland/host/wayland_toplevel_window.cc28
-rw-r--r--chromium/ui/ozone/platform/wayland/host/wayland_toplevel_window.h8
-rw-r--r--chromium/ui/ozone/platform/wayland/host/wayland_touch.cc7
-rw-r--r--chromium/ui/ozone/platform/wayland/host/wayland_window.cc69
-rw-r--r--chromium/ui/ozone/platform/wayland/host/wayland_window.h8
-rw-r--r--chromium/ui/ozone/platform/wayland/host/wayland_window_drag_controller.cc15
-rw-r--r--chromium/ui/ozone/platform/wayland/host/wayland_window_drag_controller.h3
-rw-r--r--chromium/ui/ozone/platform/wayland/host/wayland_window_drag_controller_unittest.cc10
-rw-r--r--chromium/ui/ozone/platform/wayland/host/wayland_window_factory.cc33
-rw-r--r--chromium/ui/ozone/platform/wayland/host/wayland_window_manager.cc31
-rw-r--r--chromium/ui/ozone/platform/wayland/host/wayland_window_manager.h8
-rw-r--r--chromium/ui/ozone/platform/wayland/host/wayland_window_unittest.cc140
-rw-r--r--chromium/ui/ozone/platform/wayland/host/wayland_zwp_linux_dmabuf.cc10
-rw-r--r--chromium/ui/ozone/platform/wayland/host/xdg_foreign_wrapper.cc128
-rw-r--r--chromium/ui/ozone/platform/wayland/host/xdg_foreign_wrapper.h63
-rw-r--r--chromium/ui/ozone/platform/wayland/host/xdg_popup_wrapper_impl.cc48
-rw-r--r--chromium/ui/ozone/platform/wayland/host/xdg_surface_wrapper_impl.cc48
-rw-r--r--chromium/ui/ozone/platform/wayland/host/xdg_surface_wrapper_impl.h26
-rw-r--r--chromium/ui/ozone/platform/wayland/ozone_platform_wayland.cc48
-rw-r--r--chromium/ui/ozone/platform/wayland/test/mock_surface.cc4
-rw-r--r--chromium/ui/ozone/platform/wayland/test/mock_surface.h5
-rw-r--r--chromium/ui/ozone/platform/wayland/test/test_viewport.cc49
-rw-r--r--chromium/ui/ozone/platform/wayland/test/test_viewport.h32
-rw-r--r--chromium/ui/ozone/platform/wayland/test/test_viewporter.cc53
-rw-r--r--chromium/ui/ozone/platform/wayland/test/test_viewporter.h23
-rw-r--r--chromium/ui/ozone/platform/wayland/test/test_wayland_server_thread.cc2
-rw-r--r--chromium/ui/ozone/platform/wayland/test/test_wayland_server_thread.h2
-rw-r--r--chromium/ui/ozone/platform/wayland/test/wayland_test.cc12
-rw-r--r--chromium/ui/ozone/platform/wayland/test/wayland_test.h2
-rw-r--r--chromium/ui/ozone/platform/x11/ozone_platform_x11.cc47
-rw-r--r--chromium/ui/ozone/platform/x11/x11_canvas_surface.cc3
-rw-r--r--chromium/ui/ozone/platform/x11/x11_clipboard_ozone.cc5
-rw-r--r--chromium/ui/ozone/platform/x11/x11_screen_ozone.cc35
-rw-r--r--chromium/ui/ozone/platform/x11/x11_screen_ozone.h3
-rw-r--r--chromium/ui/ozone/platform_selection.cc3
-rw-r--r--chromium/ui/ozone/public/input_controller.cc1
-rw-r--r--chromium/ui/ozone/public/input_controller.h1
-rw-r--r--chromium/ui/ozone/public/mojom/drm_device.mojom11
-rw-r--r--chromium/ui/ozone/public/ozone_platform.cc3
-rw-r--r--chromium/ui/ozone/public/ozone_platform.h9
-rw-r--r--chromium/ui/ozone/public/platform_screen.cc4
-rw-r--r--chromium/ui/ozone/public/platform_screen.h3
157 files changed, 5815 insertions, 1648 deletions
diff --git a/chromium/ui/ozone/BUILD.gn b/chromium/ui/ozone/BUILD.gn
index 296c06ab333..60cd6f56a80 100644
--- a/chromium/ui/ozone/BUILD.gn
+++ b/chromium/ui/ozone/BUILD.gn
@@ -31,8 +31,8 @@ if (ozone_platform_headless) {
ozone_platform_deps += [ "platform/headless" ]
}
-if (ozone_platform_gbm) {
- ozone_platforms += [ "gbm" ]
+if (ozone_platform_drm) {
+ ozone_platforms += [ "drm" ]
ozone_platform_deps += [ "platform/drm:gbm" ]
ozone_platform_test_deps += [ "platform/drm:gbm_unittests" ]
}
@@ -129,11 +129,11 @@ component("ozone_base") {
# Everyone should depend on //ui/ozone instead except a handful of
# things that would otherwise create a cycle.
"//chromeos/system:system",
+ "//ui/base/ime/chromeos/*",
"//ui/events/ozone/*",
"//ui/ozone/common/*",
- "//ui/ozone/public/mojom",
"//ui/ozone/platform/*",
- "//ui/base/ime/chromeos/*",
+ "//ui/ozone/public/mojom",
]
configs += [ "//third_party/khronos:khronos_headers" ]
@@ -300,6 +300,8 @@ test("ozone_unittests") {
# backend.
if (ozone_platform_x11) {
test("ozone_x11_unittests") {
+ use_xvfb = true
+
deps = [ ":test_support" ]
deps += [ "platform/x11:x11_unittests" ]
@@ -314,3 +316,21 @@ buildflag_header("buildflags") {
header = "buildflags.h"
flags = [ "OZONE_PLATFORM_X11=$ozone_platform_x11" ]
}
+
+group("unittests") {
+ testonly = true
+
+ visibility += [ "*" ]
+
+ deps = [
+ ":ozone_unittests",
+ "//ui/ozone/gl:ozone_gl_unittests",
+ ]
+
+ if (ozone_platform_x11) {
+ deps += [
+ "//ui/ozone:ozone_x11_unittests",
+ "//ui/platform_window/x11:x11_unittests",
+ ]
+ }
+}
diff --git a/chromium/ui/ozone/ozone.gni b/chromium/ui/ozone/ozone.gni
index 951a5b8f425..7a4976c9c05 100644
--- a/chromium/ui/ozone/ozone.gni
+++ b/chromium/ui/ozone/ozone.gni
@@ -4,7 +4,6 @@
import("//build/config/chromecast_build.gni")
import("//build/config/ui.gni")
-import("//build/toolchain/kythe.gni")
import("//build/toolchain/toolchain.gni")
declare_args() {
@@ -14,6 +13,10 @@ declare_args() {
# Select platforms automatically. Turn this off for manual control.
ozone_auto_platforms = use_ozone
+
+ # TODO(petermcneeley): Backwards compatiblity support for VM images.
+ # Remove when deprecated. (https://crbug.com/1122009)
+ ozone_platform_gbm = -1
}
declare_args() {
@@ -24,8 +27,8 @@ declare_args() {
# Compile the 'cast' platform.
ozone_platform_cast = false
- # Compile the 'gbm' platform.
- ozone_platform_gbm = false
+ # Compile the 'drm' platform.
+ ozone_platform_drm = false
# Compile the 'headless' platform.
ozone_platform_headless = false
@@ -64,14 +67,8 @@ declare_args() {
}
} else if (is_chromeos) {
ozone_platform = "x11"
- ozone_platform_gbm = true
+ ozone_platform_drm = true
ozone_platform_x11 = true
-
- # Enable the Ozone Wayland platform for ChromiumOS codesearch-gen bots
- # so we get cross-references in codesearch. We can remove this once
- # we can compile both x11 and Ozone on desktop Linux Chrome.
- # TODO(crbug.com/1085700): Remove enable_kythe_annotations here.
- ozone_platform_wayland = enable_kythe_annotations
} else if (is_desktop_linux) {
ozone_platform = "x11"
ozone_platform_wayland = true
@@ -84,6 +81,12 @@ declare_args() {
ozone_platform_scenic = true
}
}
+
+ # TODO(petermcneeley): Backwards compatiblity support for VM images.
+ # Remove when deprecated. (https://crbug.com/1122009)
+ if (ozone_platform_gbm != -1) {
+ ozone_platform_drm = ozone_platform_gbm
+ }
}
import(ozone_extra_path)
@@ -94,9 +97,20 @@ _ozone_extra_directory = get_path_info(ozone_extra_path, "dir")
ozone_external_platform_visibility = [ "$_ozone_extra_directory/*" ]
if (is_a_target_toolchain) {
- assert(use_ozone || !(ozone_platform_cast || ozone_platform_gbm ||
+ assert(use_ozone || !(ozone_platform_cast || ozone_platform_drm ||
ozone_platform_headless || ozone_platform_x11 ||
ozone_platform_wayland || ozone_platform_windows ||
ozone_platform_scenic),
"Must set use_ozone to select ozone platforms")
}
+
+# TODO(petermcneeley): Backwards compatiblity support for VM images.
+# Remove when deprecated. (https://crbug.com/1122009)
+
+assert(ozone_platform_gbm == -1 || ozone_platform_drm == ozone_platform_gbm)
+
+ozone_platform_gbm = ozone_platform_drm
+
+if (ozone_platform == "gbm") {
+ ozone_platform = "drm"
+}
diff --git a/chromium/ui/ozone/platform/drm/BUILD.gn b/chromium/ui/ozone/platform/drm/BUILD.gn
index 01ed60608fd..11f2f10ce12 100644
--- a/chromium/ui/ozone/platform/drm/BUILD.gn
+++ b/chromium/ui/ozone/platform/drm/BUILD.gn
@@ -2,6 +2,7 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
+import("//build/config/chromecast_build.gni")
import("//build/config/linux/pkg_config.gni")
import("//gpu/vulkan/features.gni")
import("//ui/ozone/ozone.gni")
@@ -17,13 +18,15 @@ declare_args() {
source_set("gbm") {
sources = [
- "client_native_pixmap_factory_gbm.cc",
- "client_native_pixmap_factory_gbm.h",
+ "client_native_pixmap_factory_drm.cc",
+ "client_native_pixmap_factory_drm.h",
"common/display_types.h",
"common/drm_util.cc",
"common/drm_util.h",
"common/scoped_drm_types.cc",
"common/scoped_drm_types.h",
+ "gpu/crtc_commit_request.cc",
+ "gpu/crtc_commit_request.h",
"gpu/crtc_controller.cc",
"gpu/crtc_controller.h",
"gpu/drm_device.cc",
@@ -74,8 +77,6 @@ source_set("gbm") {
"gpu/hardware_display_plane.h",
"gpu/hardware_display_plane_atomic.cc",
"gpu/hardware_display_plane_atomic.h",
- "gpu/hardware_display_plane_dummy.cc",
- "gpu/hardware_display_plane_dummy.h",
"gpu/hardware_display_plane_manager.cc",
"gpu/hardware_display_plane_manager.h",
"gpu/hardware_display_plane_manager_atomic.cc",
@@ -112,8 +113,8 @@ source_set("gbm") {
"host/host_cursor_proxy.h",
"host/host_drm_device.cc",
"host/host_drm_device.h",
- "ozone_platform_gbm.cc",
- "ozone_platform_gbm.h",
+ "ozone_platform_drm.cc",
+ "ozone_platform_drm.h",
]
deps = [
@@ -150,10 +151,12 @@ source_set("gbm") {
"//ui/platform_window",
]
- data_deps = [
- "//third_party/angle:libEGL",
- "//third_party/angle:libGLESv2",
- ]
+ if (!is_chromecast) {
+ data_deps = [
+ "//third_party/angle:libEGL",
+ "//third_party/angle:libGLESv2",
+ ]
+ }
if (is_chromeos) {
deps += [ "//ui/base/ime/chromeos" ]
diff --git a/chromium/ui/ozone/platform/drm/client_native_pixmap_factory_gbm.cc b/chromium/ui/ozone/platform/drm/client_native_pixmap_factory_drm.cc
index 8e363e69280..67b821625ad 100644
--- a/chromium/ui/ozone/platform/drm/client_native_pixmap_factory_gbm.cc
+++ b/chromium/ui/ozone/platform/drm/client_native_pixmap_factory_drm.cc
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "ui/ozone/platform/drm/client_native_pixmap_factory_gbm.h"
+#include "ui/ozone/platform/drm/client_native_pixmap_factory_drm.h"
#include <utility>
@@ -12,7 +12,7 @@
namespace ui {
-gfx::ClientNativePixmapFactory* CreateClientNativePixmapFactoryGbm() {
+gfx::ClientNativePixmapFactory* CreateClientNativePixmapFactoryDrm() {
return gfx::CreateClientNativePixmapFactoryDmabuf();
}
diff --git a/chromium/ui/ozone/platform/drm/client_native_pixmap_factory_gbm.h b/chromium/ui/ozone/platform/drm/client_native_pixmap_factory_drm.h
index 05506d6db43..e0b4f9ee316 100644
--- a/chromium/ui/ozone/platform/drm/client_native_pixmap_factory_gbm.h
+++ b/chromium/ui/ozone/platform/drm/client_native_pixmap_factory_drm.h
@@ -2,8 +2,8 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#ifndef UI_OZONE_PLATFORM_DRM_CLIENT_NATIVE_PIXMAP_FACTORY_GBM_H_
-#define UI_OZONE_PLATFORM_DRM_CLIENT_NATIVE_PIXMAP_FACTORY_GBM_H_
+#ifndef UI_OZONE_PLATFORM_DRM_CLIENT_NATIVE_PIXMAP_FACTORY_DRM_H_
+#define UI_OZONE_PLATFORM_DRM_CLIENT_NATIVE_PIXMAP_FACTORY_DRM_H_
namespace gfx {
class ClientNativePixmapFactory;
@@ -12,8 +12,8 @@ class ClientNativePixmapFactory;
namespace ui {
// Constructor hook for use in constructor_list.cc
-gfx::ClientNativePixmapFactory* CreateClientNativePixmapFactoryGbm();
+gfx::ClientNativePixmapFactory* CreateClientNativePixmapFactoryDrm();
} // namespace ui
-#endif // UI_OZONE_PLATFORM_DRM_CLIENT_NATIVE_PIXMAP_FACTORY_GBM_H_
+#endif // UI_OZONE_PLATFORM_DRM_CLIENT_NATIVE_PIXMAP_FACTORY_DRM_H_
diff --git a/chromium/ui/ozone/platform/drm/gpu/crtc_commit_request.cc b/chromium/ui/ozone/platform/drm/gpu/crtc_commit_request.cc
new file mode 100644
index 00000000000..8127e1633f2
--- /dev/null
+++ b/chromium/ui/ozone/platform/drm/gpu/crtc_commit_request.cc
@@ -0,0 +1,56 @@
+// Copyright 2020 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 "ui/ozone/platform/drm/gpu/crtc_commit_request.h"
+
+namespace ui {
+
+CrtcCommitRequest::CrtcCommitRequest(uint32_t crtc_id,
+ uint32_t connector_id,
+ drmModeModeInfo mode,
+ HardwareDisplayPlaneList* plane_list,
+ DrmOverlayPlaneList overlays,
+ bool should_enable)
+ : should_enable_(should_enable),
+ crtc_id_(crtc_id),
+ connector_id_(connector_id),
+ mode_(mode),
+ plane_list_(plane_list),
+ overlays_(std::move(overlays)) {
+ DCHECK(!should_enable || DrmOverlayPlane::GetPrimaryPlane(overlays_));
+}
+
+CrtcCommitRequest::~CrtcCommitRequest() = default;
+
+CrtcCommitRequest::CrtcCommitRequest(const CrtcCommitRequest& other)
+ : should_enable_(other.should_enable_),
+ crtc_id_(other.crtc_id_),
+ connector_id_(other.connector_id_),
+ mode_(other.mode_),
+ plane_list_(other.plane_list_),
+ overlays_(DrmOverlayPlane::Clone(other.overlays_)) {}
+
+// static
+CrtcCommitRequest CrtcCommitRequest::EnableCrtcRequest(
+ uint32_t crtc_id,
+ uint32_t connector_id,
+ drmModeModeInfo mode,
+ HardwareDisplayPlaneList* plane_list,
+ DrmOverlayPlaneList overlays) {
+ DCHECK(plane_list && !overlays.empty());
+
+ return CrtcCommitRequest(crtc_id, connector_id, mode, plane_list,
+ std::move(overlays), /*should_enable=*/true);
+}
+
+// static
+CrtcCommitRequest CrtcCommitRequest::DisableCrtcRequest(
+ uint32_t crtc_id,
+ uint32_t connector_id,
+ HardwareDisplayPlaneList* plane_list) {
+ return CrtcCommitRequest(crtc_id, connector_id, {}, plane_list,
+ DrmOverlayPlaneList(), /*should_enable=*/false);
+}
+
+} // namespace ui
diff --git a/chromium/ui/ozone/platform/drm/gpu/crtc_commit_request.h b/chromium/ui/ozone/platform/drm/gpu/crtc_commit_request.h
new file mode 100644
index 00000000000..ad8eab84e7f
--- /dev/null
+++ b/chromium/ui/ozone/platform/drm/gpu/crtc_commit_request.h
@@ -0,0 +1,67 @@
+// Copyright 2020 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.
+
+#ifndef UI_OZONE_PLATFORM_DRM_GPU_CRTC_COMMIT_REQUEST_H_
+#define UI_OZONE_PLATFORM_DRM_GPU_CRTC_COMMIT_REQUEST_H_
+
+#include <stddef.h>
+#include <stdint.h>
+#include <xf86drmMode.h>
+
+#include "ui/ozone/platform/drm/gpu/drm_device.h"
+#include "ui/ozone/platform/drm/gpu/drm_overlay_plane.h"
+
+namespace ui {
+
+struct HardwareDisplayPlaneList;
+
+class CrtcCommitRequest;
+using CommitRequest = std::vector<CrtcCommitRequest>;
+
+// Container holding information for a single CRTC that need to be modeset.
+// TODO(markyacoub): PAGE_FLIP could re-use the same CrtcCommitRequest. The
+// difference between MODESET and PAGE_FLIP are minimal.
+class CrtcCommitRequest {
+ public:
+ CrtcCommitRequest(const CrtcCommitRequest& other);
+ ~CrtcCommitRequest();
+
+ static CrtcCommitRequest EnableCrtcRequest(
+ uint32_t crtc_id,
+ uint32_t connector_id,
+ drmModeModeInfo mode,
+ HardwareDisplayPlaneList* plane_list,
+ DrmOverlayPlaneList overlays);
+
+ static CrtcCommitRequest DisableCrtcRequest(
+ uint32_t crtc_id,
+ uint32_t connector_id,
+ HardwareDisplayPlaneList* plane_list = nullptr);
+
+ bool should_enable() const { return should_enable_; }
+ uint32_t crtc_id() const { return crtc_id_; }
+ uint32_t connector_id() const { return connector_id_; }
+ const drmModeModeInfo& mode() const { return mode_; }
+ HardwareDisplayPlaneList* plane_list() const { return plane_list_; }
+ const DrmOverlayPlaneList& overlays() const { return overlays_; }
+
+ private:
+ CrtcCommitRequest(uint32_t crtc_id,
+ uint32_t connector_id,
+ drmModeModeInfo mode,
+ HardwareDisplayPlaneList* plane_list,
+ DrmOverlayPlaneList overlays,
+ bool should_enable);
+
+ const bool should_enable_ = false;
+ const uint32_t crtc_id_ = 0;
+ const uint32_t connector_id_ = 0;
+ const drmModeModeInfo mode_ = {};
+ HardwareDisplayPlaneList* plane_list_ = nullptr;
+ const DrmOverlayPlaneList overlays_;
+};
+
+} // namespace ui
+
+#endif // UI_OZONE_PLATFORM_DRM_GPU_CRTC_COMMIT_REQUEST_H_
diff --git a/chromium/ui/ozone/platform/drm/gpu/crtc_controller.cc b/chromium/ui/ozone/platform/drm/gpu/crtc_controller.cc
index a7b0de83828..4aaa7b272ac 100644
--- a/chromium/ui/ozone/platform/drm/gpu/crtc_controller.cc
+++ b/chromium/ui/ozone/platform/drm/gpu/crtc_controller.cc
@@ -9,6 +9,7 @@
#include "base/logging.h"
#include "base/time/time.h"
#include "ui/gfx/presentation_feedback.h"
+#include "ui/ozone/platform/drm/common/drm_util.h"
#include "ui/ozone/platform/drm/gpu/drm_device.h"
#include "ui/ozone/platform/drm/gpu/drm_dumb_buffer.h"
#include "ui/ozone/platform/drm/gpu/drm_framebuffer.h"
@@ -22,10 +23,11 @@ CrtcController::CrtcController(const scoped_refptr<DrmDevice>& drm,
uint32_t connector)
: drm_(drm),
crtc_(crtc),
- connector_(connector) {}
+ connector_(connector),
+ state_(drm->plane_manager()->GetCrtcStateForCrtcId(crtc)) {}
CrtcController::~CrtcController() {
- if (!is_disabled_) {
+ if (!is_disabled()) {
const std::vector<std::unique_ptr<HardwareDisplayPlane>>& all_planes =
drm_->plane_manager()->planes();
for (const auto& plane : all_planes) {
@@ -34,55 +36,21 @@ CrtcController::~CrtcController() {
plane->set_in_use(false);
}
}
-
- DisableCursor();
- drm_->plane_manager()->DisableModeset(crtc_, connector_);
- }
-}
-
-bool CrtcController::Modeset(const DrmOverlayPlane& plane,
- const drmModeModeInfo& mode,
- const ui::HardwareDisplayPlaneList& plane_list) {
- if (!drm_->plane_manager()->Modeset(crtc_,
- plane.buffer->opaque_framebuffer_id(),
- connector_, mode, plane_list)) {
- PLOG(ERROR) << "Failed to modeset: crtc=" << crtc_
- << " connector=" << connector_
- << " framebuffer_id=" << plane.buffer->opaque_framebuffer_id()
- << " mode=" << mode.hdisplay << "x" << mode.vdisplay << "@"
- << mode.vrefresh;
- return false;
}
-
- mode_ = mode;
- is_disabled_ = false;
-
- // Hold modeset buffer until page flip. This fixes a crash on entering
- // hardware mirror mode in some circumstances (bug 888553).
- // TODO(spang): Fix this better by changing how mirrors are set up (bug
- // 899352).
- modeset_framebuffer_ = plane.buffer;
-
- return true;
-}
-
-bool CrtcController::Disable() {
- if (is_disabled_)
- return true;
-
- is_disabled_ = true;
- DisableCursor();
- return drm_->plane_manager()->DisableModeset(crtc_, connector_);
}
bool CrtcController::AssignOverlayPlanes(HardwareDisplayPlaneList* plane_list,
- const DrmOverlayPlaneList& overlays) {
- DCHECK(!is_disabled_);
+ const DrmOverlayPlaneList& overlays,
+ bool is_modesetting) {
+ // If we're in the process of modesetting, the CRTC is still disabled.
+ // Once the modeset is done, we expect it to be enabled.
+ DCHECK(is_modesetting || !is_disabled());
const DrmOverlayPlane* primary = DrmOverlayPlane::GetPrimaryPlane(overlays);
- if (primary && !drm_->plane_manager()->ValidatePrimarySize(*primary, mode_)) {
+ if (primary &&
+ !drm_->plane_manager()->ValidatePrimarySize(*primary, state_.mode)) {
VLOG(2) << "Trying to pageflip a buffer with the wrong size. Expected "
- << mode_.hdisplay << "x" << mode_.vdisplay << " got "
+ << ModeSize(state_.mode).ToString() << " got "
<< primary->buffer->size().ToString() << " for"
<< " crtc=" << crtc_ << " connector=" << connector_;
return true;
@@ -90,7 +58,6 @@ bool CrtcController::AssignOverlayPlanes(HardwareDisplayPlaneList* plane_list,
if (!drm_->plane_manager()->AssignOverlayPlanes(plane_list, overlays,
crtc_)) {
- PLOG(ERROR) << "Failed to assign overlay planes for crtc " << crtc_;
return false;
}
@@ -102,7 +69,7 @@ std::vector<uint64_t> CrtcController::GetFormatModifiers(uint32_t format) {
}
void CrtcController::SetCursor(uint32_t handle, const gfx::Size& size) {
- if (is_disabled_)
+ if (is_disabled())
return;
if (!drm_->SetCursor(crtc_, handle, size)) {
PLOG(ERROR) << "drmModeSetCursor: device " << drm_->device_path().value()
@@ -112,20 +79,9 @@ void CrtcController::SetCursor(uint32_t handle, const gfx::Size& size) {
}
void CrtcController::MoveCursor(const gfx::Point& location) {
- if (is_disabled_)
+ if (is_disabled())
return;
drm_->MoveCursor(crtc_, location);
}
-void CrtcController::OnPageFlipComplete() {
- modeset_framebuffer_ = nullptr;
-}
-
-void CrtcController::DisableCursor() {
- if (!drm_->SetCursor(crtc_, 0, gfx::Size())) {
- PLOG(ERROR) << "drmModeSetCursor: device " << drm_->device_path().value()
- << " crtc " << crtc_ << " disable";
- }
-}
-
} // namespace ui
diff --git a/chromium/ui/ozone/platform/drm/gpu/crtc_controller.h b/chromium/ui/ozone/platform/drm/gpu/crtc_controller.h
index 52dbd6c9458..0ecb830e19b 100644
--- a/chromium/ui/ozone/platform/drm/gpu/crtc_controller.h
+++ b/chromium/ui/ozone/platform/drm/gpu/crtc_controller.h
@@ -34,24 +34,15 @@ class CrtcController {
uint32_t connector);
~CrtcController();
- drmModeModeInfo mode() const { return mode_; }
+ drmModeModeInfo mode() const { return state_.mode; }
uint32_t crtc() const { return crtc_; }
uint32_t connector() const { return connector_; }
const scoped_refptr<DrmDevice>& drm() const { return drm_; }
- bool is_disabled() const { return is_disabled_; }
-
- // Calls the appropriate Plane Manager to perform the initial modesetting
- // operation using |plane| as the buffer for the primary plane. The CRTC
- // configuration is specified by |mode|.
- bool Modeset(const DrmOverlayPlane& plane,
- const drmModeModeInfo& mode,
- const ui::HardwareDisplayPlaneList& plane_list);
-
- // Disables the controller.
- bool Disable();
+ bool is_disabled() const { return !state_.properties.active.value; }
bool AssignOverlayPlanes(HardwareDisplayPlaneList* plane_list,
- const DrmOverlayPlaneList& planes);
+ const DrmOverlayPlaneList& planes,
+ bool is_modesetting);
// Returns a vector of format modifiers for the given fourcc format
// on this CRTCs primary plane. A format modifier describes the
@@ -66,11 +57,7 @@ class CrtcController {
void SetCursor(uint32_t handle, const gfx::Size& size);
void MoveCursor(const gfx::Point& location);
- void OnPageFlipComplete();
-
private:
- void DisableCursor();
-
const scoped_refptr<DrmDevice> drm_;
const uint32_t crtc_;
@@ -78,13 +65,7 @@ class CrtcController {
// TODO(dnicoara) Add support for hardware mirroring (multiple connectors).
const uint32_t connector_;
- drmModeModeInfo mode_ = {};
-
- scoped_refptr<DrmFramebuffer> modeset_framebuffer_;
-
- // Keeps track of the CRTC state. If a surface has been bound, then the value
- // is set to false. Otherwise it is true.
- bool is_disabled_ = true;
+ const HardwareDisplayPlaneManager::CrtcState& state_;
DISALLOW_COPY_AND_ASSIGN(CrtcController);
};
diff --git a/chromium/ui/ozone/platform/drm/gpu/drm_display.cc b/chromium/ui/ozone/platform/drm/gpu/drm_display.cc
index 8530924e44a..4f84ef488cf 100644
--- a/chromium/ui/ozone/platform/drm/gpu/drm_display.cc
+++ b/chromium/ui/ozone/platform/drm/gpu/drm_display.cc
@@ -23,6 +23,7 @@ namespace ui {
namespace {
const char kContentProtection[] = "Content Protection";
+const char kHdcpContentType[] = "HDCP Content Type";
const char kPrivacyScreen[] = "privacy-screen";
@@ -31,11 +32,20 @@ struct ContentProtectionMapping {
display::HDCPState state;
};
+struct HdcpContentTypeMapping {
+ const char* name;
+ display::ContentProtectionMethod content_type;
+};
+
const ContentProtectionMapping kContentProtectionStates[] = {
{"Undesired", display::HDCP_STATE_UNDESIRED},
{"Desired", display::HDCP_STATE_DESIRED},
{"Enabled", display::HDCP_STATE_ENABLED}};
+const HdcpContentTypeMapping kHdcpContentTypeStates[] = {
+ {"HDCP Type0", display::CONTENT_PROTECTION_METHOD_HDCP_TYPE_0},
+ {"HDCP Type1", display::CONTENT_PROTECTION_METHOD_HDCP_TYPE_1}};
+
// Converts |state| to the DRM value associated with the it.
uint32_t GetContentProtectionValue(drmModePropertyRes* property,
display::HDCPState state) {
@@ -47,9 +57,31 @@ uint32_t GetContentProtectionValue(drmModePropertyRes* property,
}
}
- for (int i = 0; i < property->count_enums; ++i)
+ for (int i = 0; i < property->count_enums; ++i) {
if (name == property->enums[i].name)
return i;
+ }
+
+ NOTREACHED();
+ return 0;
+}
+
+// Converts |content_type| to the DRM value associated with the it.
+uint32_t GetHdcpContentTypeValue(
+ drmModePropertyRes* property,
+ display::ContentProtectionMethod content_type) {
+ std::string name;
+ for (size_t i = 0; i < base::size(kHdcpContentTypeStates); ++i) {
+ if (kHdcpContentTypeStates[i].content_type == content_type) {
+ name = kHdcpContentTypeStates[i].name;
+ break;
+ }
+ }
+
+ for (int i = 0; i < property->count_enums; ++i) {
+ if (name == property->enums[i].name)
+ return i;
+ }
NOTREACHED();
return 0;
@@ -73,10 +105,6 @@ std::string GetEnumNameForProperty(drmModeObjectProperties* property_values,
return std::string();
}
-gfx::Size GetDrmModeSize(const drmModeModeInfo& mode) {
- return gfx::Size(mode.hdisplay, mode.vdisplay);
-}
-
std::vector<drmModeModeInfo> GetDrmModeVector(drmModeConnector* connector) {
std::vector<drmModeModeInfo> modes;
for (int i = 0; i < connector->count_modes; ++i)
@@ -99,11 +127,8 @@ void FillPowerFunctionValues(std::vector<display::GammaRampRGBEntry>* table,
} // namespace
-DrmDisplay::DrmDisplay(ScreenManager* screen_manager,
- const scoped_refptr<DrmDevice>& drm)
- : screen_manager_(screen_manager),
- drm_(drm),
- current_color_space_(gfx::ColorSpace::CreateSRGB()) {}
+DrmDisplay::DrmDisplay(const scoped_refptr<DrmDevice>& drm)
+ : drm_(drm), current_color_space_(gfx::ColorSpace::CreateSRGB()) {}
DrmDisplay::~DrmDisplay() = default;
@@ -140,34 +165,9 @@ std::unique_ptr<display::DisplaySnapshot> DrmDisplay::Update(
return params;
}
-bool DrmDisplay::Configure(const drmModeModeInfo* mode,
- const gfx::Point& origin) {
- VLOG(1) << "DRM configuring: device=" << drm_->device_path().value()
- << " crtc=" << crtc_ << " connector=" << connector_->connector_id
- << " origin=" << origin.ToString()
- << " size=" << (mode ? GetDrmModeSize(*mode).ToString() : "0x0")
- << " refresh_rate=" << (mode ? mode->vrefresh : 0) << "Hz";
-
- if (mode) {
- if (!screen_manager_->ConfigureDisplayController(
- drm_, crtc_, connector_->connector_id, origin, *mode)) {
- VLOG(1) << "Failed to configure: device=" << drm_->device_path().value()
- << " crtc=" << crtc_ << " connector=" << connector_->connector_id;
- return false;
- }
- } else {
- if (!screen_manager_->DisableDisplayController(drm_, crtc_)) {
- VLOG(1) << "Failed to disable device=" << drm_->device_path().value()
- << " crtc=" << crtc_;
- return false;
- }
- }
-
- origin_ = origin;
- return true;
-}
-
-bool DrmDisplay::GetHDCPState(display::HDCPState* state) {
+bool DrmDisplay::GetHDCPState(
+ display::HDCPState* state,
+ display::ContentProtectionMethod* protection_method) {
if (!connector_)
return false;
@@ -184,26 +184,83 @@ bool DrmDisplay::GetHDCPState(display::HDCPState* state) {
connector_->connector_id, DRM_MODE_OBJECT_CONNECTOR));
std::string name =
GetEnumNameForProperty(property_values.get(), hdcp_property.get());
- for (size_t i = 0; i < base::size(kContentProtectionStates); ++i) {
+ size_t i;
+ for (i = 0; i < base::size(kContentProtectionStates); ++i) {
if (name == kContentProtectionStates[i].name) {
*state = kContentProtectionStates[i].state;
VLOG(3) << "HDCP state: " << *state << " (" << name << ")";
- return true;
+ break;
+ }
+ }
+
+ if (i == base::size(kContentProtectionStates)) {
+ LOG(ERROR) << "Unknown content protection value '" << name << "'";
+ return false;
+ }
+
+ if (*state == display::HDCP_STATE_UNDESIRED) {
+ // ProtectionMethod doesn't matter if we don't have it desired/enabled.
+ *protection_method = display::CONTENT_PROTECTION_METHOD_NONE;
+ return true;
+ }
+
+ ScopedDrmPropertyPtr content_type_property(
+ drm_->GetProperty(connector_.get(), kHdcpContentType));
+ if (!content_type_property) {
+ // This won't exist if the driver doesn't support HDCP 2.2, so default it in
+ // that case.
+ VLOG(3) << "HDCP Content Type not supported, default to Type 0";
+ *protection_method = display::CONTENT_PROTECTION_METHOD_HDCP_TYPE_0;
+ return true;
+ }
+ name = GetEnumNameForProperty(property_values.get(),
+ content_type_property.get());
+ for (i = 0; i < base::size(kHdcpContentTypeStates); ++i) {
+ if (name == kHdcpContentTypeStates[i].name) {
+ *protection_method = kHdcpContentTypeStates[i].content_type;
+ VLOG(3) << "Content Protection Method: " << *protection_method << " ("
+ << name << ")";
+ break;
}
}
- LOG(ERROR) << "Unknown content protection value '" << name << "'";
- return false;
+ if (i == base::size(kHdcpContentTypeStates)) {
+ LOG(ERROR) << "Unknown HDCP content type value '" << name << "'";
+ return false;
+ }
+ return true;
}
-bool DrmDisplay::SetHDCPState(display::HDCPState state) {
+bool DrmDisplay::SetHDCPState(
+ display::HDCPState state,
+ display::ContentProtectionMethod protection_method) {
if (!connector_) {
return false;
}
+ if (protection_method != display::CONTENT_PROTECTION_METHOD_NONE) {
+ ScopedDrmPropertyPtr content_type_property(
+ drm_->GetProperty(connector_.get(), kHdcpContentType));
+ if (!content_type_property) {
+ // If the driver doesn't support HDCP 2.2, this won't exist.
+ if (protection_method & display::CONTENT_PROTECTION_METHOD_HDCP_TYPE_1) {
+ // We can't do this, since we can't specify the content type.
+ VLOG(3)
+ << "Cannot set HDCP Content Type 1 since driver doesn't support it";
+ return false;
+ }
+ VLOG(3) << "HDCP Content Type not supported, default to Type 0";
+ } else if (!drm_->SetProperty(
+ connector_->connector_id, content_type_property->prop_id,
+ GetHdcpContentTypeValue(content_type_property.get(),
+ protection_method))) {
+ // Failed setting HDCP Content Type.
+ return false;
+ }
+ }
+
ScopedDrmPropertyPtr hdcp_property(
drm_->GetProperty(connector_.get(), kContentProtection));
-
if (!hdcp_property) {
PLOG(INFO) << "'" << kContentProtection << "' property doesn't exist.";
return false;
diff --git a/chromium/ui/ozone/platform/drm/gpu/drm_display.h b/chromium/ui/ozone/platform/drm/gpu/drm_display.h
index a658477fc2d..bac3ebce50d 100644
--- a/chromium/ui/ozone/platform/drm/gpu/drm_display.h
+++ b/chromium/ui/ozone/platform/drm/gpu/drm_display.h
@@ -22,17 +22,15 @@ typedef struct _drmModeModeInfo drmModeModeInfo;
namespace display {
class DisplaySnapshot;
struct GammaRampRGBEntry;
-}
+} // namespace display
namespace ui {
class DrmDevice;
class HardwareDisplayControllerInfo;
-class ScreenManager;
class DrmDisplay {
public:
- DrmDisplay(ScreenManager* screen_manager,
- const scoped_refptr<DrmDevice>& drm);
+ explicit DrmDisplay(const scoped_refptr<DrmDevice>& drm);
~DrmDisplay();
int64_t display_id() const { return display_id_; }
@@ -45,9 +43,11 @@ class DrmDisplay {
HardwareDisplayControllerInfo* info,
size_t device_index);
- bool Configure(const drmModeModeInfo* mode, const gfx::Point& origin);
- bool GetHDCPState(display::HDCPState* state);
- bool SetHDCPState(display::HDCPState state);
+ void SetOrigin(const gfx::Point origin) { origin_ = origin; }
+ bool GetHDCPState(display::HDCPState* state,
+ display::ContentProtectionMethod* protection_method);
+ bool SetHDCPState(display::HDCPState state,
+ display::ContentProtectionMethod protection_method);
void SetColorMatrix(const std::vector<float>& color_matrix);
void SetBackgroundColor(const uint64_t background_color);
void SetGammaCorrection(
@@ -63,8 +63,6 @@ class DrmDisplay {
const std::vector<display::GammaRampRGBEntry>& degamma_lut,
const std::vector<display::GammaRampRGBEntry>& gamma_lut);
- ScreenManager* screen_manager_; // Not owned.
-
int64_t display_id_ = -1;
const scoped_refptr<DrmDevice> drm_;
uint32_t crtc_ = 0;
diff --git a/chromium/ui/ozone/platform/drm/gpu/drm_display_unittest.cc b/chromium/ui/ozone/platform/drm/gpu/drm_display_unittest.cc
index c5aadaf7b11..b8af25613ab 100644
--- a/chromium/ui/ozone/platform/drm/gpu/drm_display_unittest.cc
+++ b/chromium/ui/ozone/platform/drm/gpu/drm_display_unittest.cc
@@ -14,7 +14,6 @@
#include "ui/ozone/platform/drm/gpu/hardware_display_plane.h"
#include "ui/ozone/platform/drm/gpu/hardware_display_plane_manager.h"
#include "ui/ozone/platform/drm/gpu/mock_drm_device.h"
-#include "ui/ozone/platform/drm/gpu/screen_manager.h"
using ::testing::_;
using ::testing::SizeIs;
@@ -53,17 +52,11 @@ class MockHardwareDisplayPlaneManager : public HardwareDisplayPlaneManager {
const std::vector<display::GammaRampRGBEntry>& degamma_lut,
const std::vector<display::GammaRampRGBEntry>& gamma_lut));
- bool Modeset(uint32_t crtc_id,
- uint32_t framebuffer_id,
- uint32_t connector_id,
- const drmModeModeInfo& mode,
- const HardwareDisplayPlaneList& plane_list) override {
- return false;
- }
- bool DisableModeset(uint32_t crtc_id, uint32_t connector) override {
+ bool Commit(CommitRequest commit_request, uint32_t flags) override {
return false;
}
bool Commit(HardwareDisplayPlaneList* plane_list,
+ bool should_modeset,
scoped_refptr<PageFlipRequest> page_flip_request,
std::unique_ptr<gfx::GpuFence>* out_fence) override {
return false;
@@ -117,7 +110,7 @@ class DrmDisplayTest : public testing::Test {
DrmDisplayTest()
: mock_drm_device_(base::MakeRefCounted<MockDrmDevice>(
std::make_unique<MockGbmDevice>())),
- drm_display_(&screen_manager_, mock_drm_device_) {}
+ drm_display_(mock_drm_device_) {}
MockHardwareDisplayPlaneManager* AddMockHardwareDisplayPlaneManager() {
auto mock_hardware_display_plane_manager =
@@ -132,7 +125,6 @@ class DrmDisplayTest : public testing::Test {
base::test::TaskEnvironment env_;
scoped_refptr<DrmDevice> mock_drm_device_;
- ScreenManager screen_manager_;
DrmDisplay drm_display_;
};
diff --git a/chromium/ui/ozone/platform/drm/gpu/drm_gpu_display_manager.cc b/chromium/ui/ozone/platform/drm/gpu/drm_gpu_display_manager.cc
index 544df3618e8..61c721807f7 100644
--- a/chromium/ui/ozone/platform/drm/gpu/drm_gpu_display_manager.cc
+++ b/chromium/ui/ozone/platform/drm/gpu/drm_gpu_display_manager.cc
@@ -65,6 +65,33 @@ bool FindMatchingMode(const std::vector<drmModeModeInfo> modes,
return false;
}
+bool FindModeForDisplay(
+ drmModeModeInfo* mode_ptr,
+ const display::DisplayMode& display_mode,
+ const std::vector<drmModeModeInfo>& modes,
+ const std::vector<std::unique_ptr<DrmDisplay>>& all_displays) {
+ bool mode_found = FindMatchingMode(modes, display_mode, mode_ptr);
+ if (!mode_found) {
+ // If the display doesn't have the mode natively, then lookup the mode
+ // from other displays and try using it on the current display (some
+ // displays support panel fitting and they can use different modes even
+ // if the mode isn't explicitly declared).
+ for (const auto& other_display : all_displays) {
+ mode_found =
+ FindMatchingMode(other_display->modes(), display_mode, mode_ptr);
+ if (mode_found)
+ break;
+ }
+ if (!mode_found) {
+ LOG(ERROR) << "Failed to find mode: size="
+ << display_mode.size().ToString()
+ << " is_interlaced=" << display_mode.is_interlaced()
+ << " refresh_rate=" << display_mode.refresh_rate();
+ }
+ }
+ return mode_found;
+}
+
} // namespace
DrmGpuDisplayManager::DrmGpuDisplayManager(ScreenManager* screen_manager,
@@ -100,7 +127,7 @@ MovableDisplaySnapshots DrmGpuDisplayManager::GetDisplays() {
displays_.push_back(std::move(*it));
old_displays.erase(it);
} else {
- displays_.push_back(std::make_unique<DrmDisplay>(screen_manager_, drm));
+ displays_.push_back(std::make_unique<DrmDisplay>(drm));
}
auto display_snapshot =
@@ -139,77 +166,106 @@ void DrmGpuDisplayManager::RelinquishDisplayControl() {
drm->DropMaster();
}
-bool DrmGpuDisplayManager::ConfigureDisplay(
- int64_t display_id,
- const display::DisplayMode& display_mode,
- const gfx::Point& origin) {
- DrmDisplay* display = FindDisplay(display_id);
- if (!display) {
- LOG(ERROR) << "There is no display with ID " << display_id;
- return false;
- }
+base::flat_map<int64_t, bool> DrmGpuDisplayManager::ConfigureDisplays(
+ const std::vector<display::DisplayConfigurationParams>& config_requests) {
+ base::flat_map<int64_t, bool> statuses;
+ std::vector<ScreenManager::ControllerConfigParams> controllers_to_configure;
+
+ for (const auto& config : config_requests) {
+ int64_t display_id = config.id;
+ DrmDisplay* display = FindDisplay(display_id);
+ if (!display) {
+ LOG(ERROR) << "There is no display with ID " << display_id;
+ statuses.insert(std::make_pair(display_id, false));
+ continue;
+ }
- drmModeModeInfo mode;
- bool mode_found = FindMatchingMode(display->modes(), display_mode, &mode);
- if (!mode_found) {
- // If the display doesn't have the mode natively, then lookup the mode from
- // other displays and try using it on the current display (some displays
- // support panel fitting and they can use different modes even if the mode
- // isn't explicitly declared).
- for (const auto& other_display : displays_) {
- mode_found =
- FindMatchingMode(other_display->modes(), display_mode, &mode);
- if (mode_found)
- break;
+ std::unique_ptr<drmModeModeInfo> mode_ptr =
+ config.mode ? std::make_unique<drmModeModeInfo>() : nullptr;
+ if (config.mode) {
+ if (!FindModeForDisplay(mode_ptr.get(), *config.mode.value(),
+ display->modes(), displays_)) {
+ statuses.insert(std::make_pair(display_id, false));
+ continue;
+ }
}
- }
- if (!mode_found) {
- LOG(ERROR) << "Failed to find mode: size=" << display_mode.size().ToString()
- << " is_interlaced=" << display_mode.is_interlaced()
- << " refresh_rate=" << display_mode.refresh_rate();
- return false;
+ scoped_refptr<DrmDevice> drm = display->drm();
+
+ VLOG(1) << "DRM configuring: device=" << drm->device_path().value()
+ << " crtc=" << display->crtc()
+ << " connector=" << display->connector()
+ << " origin=" << config.origin.ToString() << " size="
+ << (mode_ptr ? ModeSize(*(mode_ptr.get())).ToString() : "0x0")
+ << " refresh_rate=" << (mode_ptr ? mode_ptr->vrefresh : 0) << "Hz";
+
+ ScreenManager::ControllerConfigParams params(
+ display->display_id(), drm, display->crtc(), display->connector(),
+ config.origin, std::move(mode_ptr));
+ controllers_to_configure.push_back(std::move(params));
}
+ if (controllers_to_configure.empty())
+ return statuses;
+
if (clear_overlay_cache_callback_)
clear_overlay_cache_callback_.Run();
- return display->Configure(&mode, origin);
-}
+ auto config_statuses =
+ screen_manager_->ConfigureDisplayControllers(controllers_to_configure);
+ for (const auto& status : config_statuses) {
+ int64_t display_id = status.first;
+ bool success = status.second;
+ DrmDisplay* display = FindDisplay(display_id);
+ auto config = std::find_if(
+ config_requests.begin(), config_requests.end(),
+ [display_id](const auto& request) { return request.id == display_id; });
+
+ if (success) {
+ display->SetOrigin(config->origin);
+ } else {
+ if (config->mode) {
+ VLOG(1) << "Failed to enable device="
+ << display->drm()->device_path().value()
+ << " crtc=" << display->crtc()
+ << " connector=" << display->connector();
+ } else {
+ VLOG(1) << "Failed to disable device="
+ << display->drm()->device_path().value()
+ << " crtc=" << display->crtc();
+ }
+ }
-bool DrmGpuDisplayManager::DisableDisplay(int64_t display_id) {
- DrmDisplay* display = FindDisplay(display_id);
- if (!display) {
- LOG(ERROR) << "There is no display with ID " << display_id;
- return false;
+ statuses.insert(std::make_pair(display_id, success));
}
- if (clear_overlay_cache_callback_)
- clear_overlay_cache_callback_.Run();
-
- return display->Configure(nullptr, gfx::Point());
+ return statuses;
}
-bool DrmGpuDisplayManager::GetHDCPState(int64_t display_id,
- display::HDCPState* state) {
+bool DrmGpuDisplayManager::GetHDCPState(
+ int64_t display_id,
+ display::HDCPState* state,
+ display::ContentProtectionMethod* protection_method) {
DrmDisplay* display = FindDisplay(display_id);
if (!display) {
LOG(ERROR) << "There is no display with ID " << display_id;
return false;
}
- return display->GetHDCPState(state);
+ return display->GetHDCPState(state, protection_method);
}
-bool DrmGpuDisplayManager::SetHDCPState(int64_t display_id,
- display::HDCPState state) {
+bool DrmGpuDisplayManager::SetHDCPState(
+ int64_t display_id,
+ display::HDCPState state,
+ display::ContentProtectionMethod protection_method) {
DrmDisplay* display = FindDisplay(display_id);
if (!display) {
LOG(ERROR) << "There is no display with ID " << display_id;
return false;
}
- return display->SetHDCPState(state);
+ return display->SetHDCPState(state, protection_method);
}
void DrmGpuDisplayManager::SetColorMatrix(
@@ -280,15 +336,18 @@ DrmDisplay* DrmGpuDisplayManager::FindDisplay(int64_t display_id) {
void DrmGpuDisplayManager::NotifyScreenManager(
const std::vector<std::unique_ptr<DrmDisplay>>& new_displays,
const std::vector<std::unique_ptr<DrmDisplay>>& old_displays) const {
+ ScreenManager::CrtcsWithDrmList controllers_to_remove;
for (const auto& old_display : old_displays) {
auto it = std::find_if(new_displays.begin(), new_displays.end(),
DisplayComparator(old_display.get()));
if (it == new_displays.end()) {
- screen_manager_->RemoveDisplayController(old_display->drm(),
- old_display->crtc());
+ controllers_to_remove.emplace_back(old_display->crtc(),
+ old_display->drm());
}
}
+ if (!controllers_to_remove.empty())
+ screen_manager_->RemoveDisplayControllers(controllers_to_remove);
for (const auto& new_display : new_displays) {
auto it = std::find_if(old_displays.begin(), old_displays.end(),
diff --git a/chromium/ui/ozone/platform/drm/gpu/drm_gpu_display_manager.h b/chromium/ui/ozone/platform/drm/gpu/drm_gpu_display_manager.h
index 6bc0d2472ea..2dbe2ba68a4 100644
--- a/chromium/ui/ozone/platform/drm/gpu/drm_gpu_display_manager.h
+++ b/chromium/ui/ozone/platform/drm/gpu/drm_gpu_display_manager.h
@@ -10,16 +10,19 @@
#include <vector>
#include "base/callback.h"
+#include "base/containers/flat_map.h"
#include "base/macros.h"
+#include "ui/display/types/display_configuration_params.h"
#include "ui/display/types/display_constants.h"
#include "ui/gfx/geometry/point.h"
#include "ui/gfx/native_widget_types.h"
#include "ui/ozone/platform/drm/common/display_types.h"
+using drmModeModeInfo = struct _drmModeModeInfo;
+
namespace display {
-class DisplayMode;
struct GammaRampRGBEntry;
-}
+} // namespace display
namespace gfx {
class ColorSpace;
@@ -49,16 +52,17 @@ class DrmGpuDisplayManager {
bool TakeDisplayControl();
void RelinquishDisplayControl();
- bool ConfigureDisplay(int64_t id,
- const display::DisplayMode& display_mode,
- const gfx::Point& origin);
- bool DisableDisplay(int64_t id);
- bool GetHDCPState(int64_t display_id, display::HDCPState* state);
- bool SetHDCPState(int64_t display_id, display::HDCPState state);
+ base::flat_map<int64_t, bool> ConfigureDisplays(
+ const std::vector<display::DisplayConfigurationParams>& config_requests);
+ bool GetHDCPState(int64_t display_id,
+ display::HDCPState* state,
+ display::ContentProtectionMethod* protection_method);
+ bool SetHDCPState(int64_t display_id,
+ display::HDCPState state,
+ display::ContentProtectionMethod protection_method);
void SetColorMatrix(int64_t display_id,
const std::vector<float>& color_matrix);
- void SetBackgroundColor(int64_t display_id,
- const uint64_t background_color);
+ void SetBackgroundColor(int64_t display_id, const uint64_t background_color);
void SetGammaCorrection(
int64_t display_id,
const std::vector<display::GammaRampRGBEntry>& degamma_lut,
diff --git a/chromium/ui/ozone/platform/drm/gpu/drm_overlay_manager.cc b/chromium/ui/ozone/platform/drm/gpu/drm_overlay_manager.cc
index 686e6633801..231d1728494 100644
--- a/chromium/ui/ozone/platform/drm/gpu/drm_overlay_manager.cc
+++ b/chromium/ui/ozone/platform/drm/gpu/drm_overlay_manager.cc
@@ -149,6 +149,15 @@ bool DrmOverlayManager::CanHandleCandidate(
if (!gfx::IsNearestRectWithinDistance(candidate.display_rect, 0.01f))
return false;
+ // DRM supposedly supports subpixel source crop. However, according to
+ // drm_plane_funcs.update_plane, devices which don't support that are
+ // free to ignore the fractional part, and every device seems to do that as
+ // of 5.4. So reject candidates that require subpixel source crop.
+ gfx::RectF crop(candidate.crop_rect);
+ crop.Scale(candidate.buffer_size.width(), candidate.buffer_size.height());
+ if (!gfx::IsNearestRectWithinDistance(crop, 0.01f))
+ return false;
+
if (candidate.is_clipped && !candidate.clip_rect.Contains(
gfx::ToNearestRect(candidate.display_rect))) {
return false;
diff --git a/chromium/ui/ozone/platform/drm/gpu/drm_overlay_plane.cc b/chromium/ui/ozone/platform/drm/gpu/drm_overlay_plane.cc
index 72a00b7dc1a..b88db11a91c 100644
--- a/chromium/ui/ozone/platform/drm/gpu/drm_overlay_plane.cc
+++ b/chromium/ui/ozone/platform/drm/gpu/drm_overlay_plane.cc
@@ -20,7 +20,7 @@ std::unique_ptr<gfx::GpuFence> CloneGpuFence(
if (!gpu_fence)
return nullptr;
return std::make_unique<gfx::GpuFence>(
- gfx::CloneHandleForIPC(gpu_fence->GetGpuFenceHandle()));
+ gpu_fence->GetGpuFenceHandle().Clone());
}
} // namespace
diff --git a/chromium/ui/ozone/platform/drm/gpu/drm_overlay_validator_unittest.cc b/chromium/ui/ozone/platform/drm/gpu/drm_overlay_validator_unittest.cc
index 3877bce8b68..6f20ce1f430 100644
--- a/chromium/ui/ozone/platform/drm/gpu/drm_overlay_validator_unittest.cc
+++ b/chromium/ui/ozone/platform/drm/gpu/drm_overlay_validator_unittest.cc
@@ -5,6 +5,7 @@
#include "ui/ozone/platform/drm/gpu/drm_overlay_validator.h"
#include <drm_fourcc.h>
+#include <xf86drm.h>
#include <memory>
#include <utility>
@@ -29,9 +30,9 @@
namespace {
-// Mode of size 6x4.
-const drmModeModeInfo kDefaultMode = {0, 6, 0, 0, 0, 0, 4, 0,
- 0, 0, 0, 0, 0, 0, {'\0'}};
+// Mode of size 12x8.
+const drmModeModeInfo kDefaultMode = {0, 12, 0, 0, 0, 0, 8, 0,
+ 0, 0, 0, 0, 0, 0, {'\0'}};
const gfx::AcceleratedWidget kDefaultWidgetHandle = 1;
constexpr uint32_t kCrtcIdBase = 1;
@@ -77,6 +78,22 @@ class DrmOverlayValidatorTest : public testing::Test {
return ui::DrmFramebuffer::AddFramebuffer(drm_, gbm_buffer.get(), size);
}
+ bool ModesetController(ui::HardwareDisplayController* controller) {
+ ui::CommitRequest commit_request;
+
+ ui::DrmOverlayPlane plane(CreateBuffer(), nullptr);
+
+ controller->GetModesetProps(&commit_request, plane, kDefaultMode);
+ ui::CommitRequest request_for_update = commit_request;
+ bool status = drm_->plane_manager()->Commit(std::move(commit_request),
+ DRM_MODE_ATOMIC_ALLOW_MODESET);
+ controller->UpdateState(
+ /*enabled=*/true,
+ ui::DrmOverlayPlane::GetPrimaryPlane(request_for_update[0].overlays()));
+
+ return status;
+ }
+
protected:
struct PlaneState {
std::vector<uint32_t> formats;
@@ -213,8 +230,11 @@ void DrmOverlayValidatorTest::InitDrmStatesAndControllers(
void DrmOverlayValidatorTest::SetupControllers() {
screen_manager_ = std::make_unique<ui::ScreenManager>();
screen_manager_->AddDisplayController(drm_, kCrtcIdBase, kConnectorIdBase);
- screen_manager_->ConfigureDisplayController(
- drm_, kCrtcIdBase, kConnectorIdBase, gfx::Point(), kDefaultMode);
+ std::vector<ui::ScreenManager::ControllerConfigParams> controllers_to_enable;
+ controllers_to_enable.emplace_back(
+ 1 /*display_id*/, drm_, kCrtcIdBase, kConnectorIdBase, gfx::Point(),
+ std::make_unique<drmModeModeInfo>(kDefaultMode));
+ screen_manager_->ConfigureDisplayControllers(controllers_to_enable);
drm_device_manager_ = std::make_unique<ui::DrmDeviceManager>(nullptr);
@@ -418,9 +438,7 @@ TEST_F(DrmOverlayValidatorTest,
ui::HardwareDisplayController* controller = window_->GetController();
controller->AddCrtc(std::make_unique<ui::CrtcController>(
drm_.get(), kCrtcIdBase + 1, kConnectorIdBase + 1));
- ui::DrmOverlayPlane plane1(CreateBuffer(), nullptr);
-
- EXPECT_TRUE(controller->Modeset(plane1, kDefaultMode));
+ EXPECT_TRUE(ModesetController(controller));
gfx::RectF crop_rect = gfx::RectF(0, 0, 0.5, 0.5);
overlay_params_.back().buffer_size = overlay_rect_.size();
@@ -463,9 +481,7 @@ TEST_F(DrmOverlayValidatorTest,
ui::HardwareDisplayController* controller = window_->GetController();
controller->AddCrtc(std::make_unique<ui::CrtcController>(
drm_.get(), kCrtcIdBase + 1, kConnectorIdBase + 1));
- ui::DrmOverlayPlane plane1(CreateBuffer(), nullptr);
-
- EXPECT_TRUE(controller->Modeset(plane1, kDefaultMode));
+ EXPECT_TRUE(ModesetController(controller));
gfx::RectF crop_rect = gfx::RectF(0, 0, 0.5, 0.5);
overlay_params_.back().buffer_size = overlay_rect_.size();
@@ -505,9 +521,7 @@ TEST_F(DrmOverlayValidatorTest,
ui::HardwareDisplayController* controller = window_->GetController();
controller->AddCrtc(std::make_unique<ui::CrtcController>(
drm_.get(), kCrtcIdBase + 1, kConnectorIdBase + 1));
- ui::DrmOverlayPlane plane1(CreateBuffer(), nullptr);
-
- EXPECT_TRUE(controller->Modeset(plane1, kDefaultMode));
+ EXPECT_TRUE(ModesetController(controller));
gfx::RectF crop_rect = gfx::RectF(0, 0, 0.5, 0.5);
overlay_params_.back().buffer_size = overlay_rect_.size();
@@ -547,8 +561,7 @@ TEST_F(DrmOverlayValidatorTest, OptimalFormatXRGB_MirroredControllers) {
ui::HardwareDisplayController* controller = window_->GetController();
controller->AddCrtc(std::make_unique<ui::CrtcController>(
drm_.get(), kCrtcIdBase + 1, kConnectorIdBase + 1));
- ui::DrmOverlayPlane plane1(CreateBuffer(), nullptr);
- EXPECT_TRUE(controller->Modeset(plane1, kDefaultMode));
+ EXPECT_TRUE(ModesetController(controller));
overlay_params_.back().buffer_size = overlay_rect_.size();
overlay_params_.back().display_rect = gfx::RectF(overlay_rect_);
@@ -583,8 +596,7 @@ TEST_F(DrmOverlayValidatorTest,
ui::HardwareDisplayController* controller = window_->GetController();
controller->AddCrtc(std::make_unique<ui::CrtcController>(
drm_.get(), kCrtcIdBase + 1, kConnectorIdBase + 1));
- ui::DrmOverlayPlane plane1(CreateBuffer(), nullptr);
- EXPECT_TRUE(controller->Modeset(plane1, kDefaultMode));
+ EXPECT_TRUE(ModesetController(controller));
overlay_params_.back().buffer_size = overlay_rect_.size();
overlay_params_.back().display_rect = gfx::RectF(overlay_rect_);
@@ -618,8 +630,7 @@ TEST_F(DrmOverlayValidatorTest,
ui::HardwareDisplayController* controller = window_->GetController();
controller->AddCrtc(std::make_unique<ui::CrtcController>(
drm_.get(), kCrtcIdBase + 1, kConnectorIdBase + 1));
- ui::DrmOverlayPlane plane1(CreateBuffer(), nullptr);
- EXPECT_TRUE(controller->Modeset(plane1, kDefaultMode));
+ EXPECT_TRUE(ModesetController(controller));
overlay_params_.back().buffer_size = overlay_rect_.size();
overlay_params_.back().display_rect = gfx::RectF(overlay_rect_);
diff --git a/chromium/ui/ozone/platform/drm/gpu/drm_thread.cc b/chromium/ui/ozone/platform/drm/gpu/drm_thread.cc
index 789edc91f68..52c31a7fa8f 100644
--- a/chromium/ui/ozone/platform/drm/gpu/drm_thread.cc
+++ b/chromium/ui/ozone/platform/drm/gpu/drm_thread.cc
@@ -330,17 +330,9 @@ void DrmThread::ConfigureNativeDisplays(
base::OnceCallback<void(const base::flat_map<int64_t, bool>&)> callback) {
TRACE_EVENT0("drm", "DrmThread::ConfigureNativeDisplays");
- base::flat_map<int64_t, bool> statuses;
- for (const auto& config : config_requests) {
- bool status = false;
- if (config.mode) {
- status = display_manager_->ConfigureDisplay(
- config.id, *config.mode.value(), config.origin);
- } else {
- status = display_manager_->DisableDisplay(config.id);
- }
- statuses.insert(std::make_pair(config.id, status));
- }
+ base::flat_map<int64_t, bool> statuses =
+ display_manager_->ConfigureDisplays(config_requests);
+
std::move(callback).Run(statuses);
}
@@ -371,19 +363,27 @@ void DrmThread::RemoveGraphicsDevice(const base::FilePath& path) {
void DrmThread::GetHDCPState(
int64_t display_id,
- base::OnceCallback<void(int64_t, bool, display::HDCPState)> callback) {
+ base::OnceCallback<void(int64_t,
+ bool,
+ display::HDCPState,
+ display::ContentProtectionMethod)> callback) {
TRACE_EVENT0("drm", "DrmThread::GetHDCPState");
display::HDCPState state = display::HDCP_STATE_UNDESIRED;
- bool success = display_manager_->GetHDCPState(display_id, &state);
- std::move(callback).Run(display_id, success, state);
+ display::ContentProtectionMethod protection_method =
+ display::CONTENT_PROTECTION_METHOD_NONE;
+ bool success =
+ display_manager_->GetHDCPState(display_id, &state, &protection_method);
+ std::move(callback).Run(display_id, success, state, protection_method);
}
void DrmThread::SetHDCPState(int64_t display_id,
display::HDCPState state,
+ display::ContentProtectionMethod protection_method,
base::OnceCallback<void(int64_t, bool)> callback) {
TRACE_EVENT0("drm", "DrmThread::SetHDCPState");
- std::move(callback).Run(display_id,
- display_manager_->SetHDCPState(display_id, state));
+ std::move(callback).Run(
+ display_id,
+ display_manager_->SetHDCPState(display_id, state, protection_method));
}
void DrmThread::SetColorMatrix(int64_t display_id,
diff --git a/chromium/ui/ozone/platform/drm/gpu/drm_thread.h b/chromium/ui/ozone/platform/drm/gpu/drm_thread.h
index a744f482bd1..a58d41063e5 100644
--- a/chromium/ui/ozone/platform/drm/gpu/drm_thread.h
+++ b/chromium/ui/ozone/platform/drm/gpu/drm_thread.h
@@ -151,10 +151,14 @@ class DrmThread : public base::Thread,
const std::vector<display::DisplayConfigurationParams>& config_requests,
ConfigureNativeDisplaysCallback callback) override;
void GetHDCPState(int64_t display_id,
- base::OnceCallback<void(int64_t, bool, display::HDCPState)>
+ base::OnceCallback<void(int64_t,
+ bool,
+ display::HDCPState,
+ display::ContentProtectionMethod)>
callback) override;
void SetHDCPState(int64_t display_id,
display::HDCPState state,
+ display::ContentProtectionMethod protection_method,
base::OnceCallback<void(int64_t, bool)> callback) override;
void SetColorMatrix(int64_t display_id,
const std::vector<float>& color_matrix) override;
diff --git a/chromium/ui/ozone/platform/drm/gpu/drm_window_unittest.cc b/chromium/ui/ozone/platform/drm/gpu/drm_window_unittest.cc
index ffb8ffb9359..1edd0cb27c0 100644
--- a/chromium/ui/ozone/platform/drm/gpu/drm_window_unittest.cc
+++ b/chromium/ui/ozone/platform/drm/gpu/drm_window_unittest.cc
@@ -6,6 +6,7 @@
#include <drm_fourcc.h>
#include <stdint.h>
+#include <xf86drm.h>
#include <memory>
#include <utility>
#include <vector>
@@ -84,6 +85,8 @@ class DrmWindowTest : public testing::Test {
}
protected:
+ void InitializeDrmState(ui::MockDrmDevice* drm, bool is_atomic = true);
+
base::test::SingleThreadTaskEnvironment task_environment_{
base::test::SingleThreadTaskEnvironment::MainThreadType::UI};
scoped_refptr<ui::MockDrmDevice> drm_;
@@ -95,6 +98,14 @@ class DrmWindowTest : public testing::Test {
gfx::PresentationFeedback last_presentation_feedback_;
private:
+ struct PlaneState {
+ std::vector<uint32_t> formats;
+ };
+
+ struct CrtcState {
+ std::vector<PlaneState> planes;
+ };
+
DISALLOW_COPY_AND_ASSIGN(DrmWindowTest);
};
@@ -105,9 +116,15 @@ void DrmWindowTest::SetUp() {
auto gbm_device = std::make_unique<ui::MockGbmDevice>();
drm_ = new ui::MockDrmDevice(std::move(gbm_device));
screen_manager_ = std::make_unique<ui::ScreenManager>();
+
+ InitializeDrmState(drm_.get());
+
screen_manager_->AddDisplayController(drm_, kDefaultCrtc, kDefaultConnector);
- screen_manager_->ConfigureDisplayController(
- drm_, kDefaultCrtc, kDefaultConnector, gfx::Point(), kDefaultMode);
+ std::vector<ui::ScreenManager::ControllerConfigParams> controllers_to_enable;
+ controllers_to_enable.emplace_back(
+ 1 /*display_id*/, drm_, kDefaultCrtc, kDefaultConnector, gfx::Point(),
+ std::make_unique<drmModeModeInfo>(kDefaultMode));
+ screen_manager_->ConfigureDisplayControllers(controllers_to_enable);
drm_device_manager_ = std::make_unique<ui::DrmDeviceManager>(nullptr);
@@ -125,6 +142,110 @@ void DrmWindowTest::TearDown() {
window->Shutdown();
}
+void DrmWindowTest::InitializeDrmState(ui::MockDrmDevice* drm, bool is_atomic) {
+ // A Sample of CRTC states.
+ std::vector<CrtcState> crtc_states = {
+ {
+ /* .planes = */
+ {{/* .formats = */ {DRM_FORMAT_XRGB8888}}},
+ },
+ {
+ /* .planes = */
+ {{/* .formats = */ {DRM_FORMAT_XRGB8888}}},
+ },
+ };
+
+ constexpr uint32_t kPlaneIdBase = 300;
+ constexpr uint32_t kInFormatsBlobPropIdBase = 400;
+
+ std::vector<ui::MockDrmDevice::CrtcProperties> crtc_properties(
+ crtc_states.size());
+ std::map<uint32_t, std::string> crtc_property_names = {
+ {1000, "ACTIVE"},
+ {1001, "MODE_ID"},
+ };
+
+ std::vector<ui::MockDrmDevice::ConnectorProperties> connector_properties(3);
+ std::map<uint32_t, std::string> connector_property_names = {
+ {2000, "CRTC_ID"},
+ };
+ for (size_t i = 0; i < connector_properties.size(); ++i) {
+ connector_properties[i].id = kDefaultConnector + i;
+ for (const auto& pair : connector_property_names) {
+ connector_properties[i].properties.push_back(
+ {/* .id = */ pair.first, /* .value = */ 0});
+ }
+ }
+
+ std::vector<ui::MockDrmDevice::PlaneProperties> plane_properties;
+ std::map<uint32_t, std::string> plane_property_names = {
+ // Add all required properties.
+ {3000, "CRTC_ID"},
+ {3001, "CRTC_X"},
+ {3002, "CRTC_Y"},
+ {3003, "CRTC_W"},
+ {3004, "CRTC_H"},
+ {3005, "FB_ID"},
+ {3006, "SRC_X"},
+ {3007, "SRC_Y"},
+ {3008, "SRC_W"},
+ {3009, "SRC_H"},
+ // Defines some optional properties we use for convenience.
+ {3010, "type"},
+ {3011, "IN_FORMATS"},
+ };
+
+ uint32_t plane_id = kPlaneIdBase;
+ uint32_t property_id = kInFormatsBlobPropIdBase;
+
+ for (size_t crtc_idx = 0; crtc_idx < crtc_states.size(); ++crtc_idx) {
+ crtc_properties[crtc_idx].id = kDefaultCrtc + crtc_idx;
+ for (const auto& pair : crtc_property_names) {
+ crtc_properties[crtc_idx].properties.push_back(
+ {/* .id = */ pair.first, /* .value = */ 0});
+ }
+
+ std::vector<ui::MockDrmDevice::PlaneProperties> crtc_plane_properties(
+ crtc_states[crtc_idx].planes.size());
+ for (size_t plane_idx = 0; plane_idx < crtc_states[crtc_idx].planes.size();
+ ++plane_idx) {
+ crtc_plane_properties[plane_idx].id = plane_id++;
+ crtc_plane_properties[plane_idx].crtc_mask = 1 << crtc_idx;
+
+ for (const auto& pair : plane_property_names) {
+ uint64_t value = 0;
+ if (pair.first == 3010) {
+ value =
+ plane_idx == 0 ? DRM_PLANE_TYPE_PRIMARY : DRM_PLANE_TYPE_OVERLAY;
+ } else if (pair.first == 3011) {
+ value = property_id++;
+ drm->SetPropertyBlob(ui::MockDrmDevice::AllocateInFormatsBlob(
+ value, crtc_states[crtc_idx].planes[plane_idx].formats,
+ std::vector<drm_format_modifier>()));
+ } else if (pair.first >= 3001 && pair.first <= 3009) {
+ value = 27;
+ }
+
+ crtc_plane_properties[plane_idx].properties.push_back(
+ {/* .id = */ pair.first, /* .value = */ value});
+ }
+ }
+
+ plane_properties.insert(plane_properties.end(),
+ crtc_plane_properties.begin(),
+ crtc_plane_properties.end());
+ }
+
+ std::map<uint32_t, std::string> property_names;
+ property_names.insert(crtc_property_names.begin(), crtc_property_names.end());
+ property_names.insert(connector_property_names.begin(),
+ connector_property_names.end());
+ property_names.insert(plane_property_names.begin(),
+ plane_property_names.end());
+ drm->InitializeState(crtc_properties, connector_properties, plane_properties,
+ property_names, /*is_atomic=*/false);
+}
+
TEST_F(DrmWindowTest, SetCursorImage) {
const gfx::Size cursor_size(6, 4);
screen_manager_->GetWindow(kDefaultWidgetHandle)
@@ -161,10 +282,16 @@ TEST_F(DrmWindowTest, CheckCursorSurfaceAfterChangingDevice) {
auto gbm_device = std::make_unique<ui::MockGbmDevice>();
scoped_refptr<ui::MockDrmDevice> drm =
new ui::MockDrmDevice(std::move(gbm_device));
+ InitializeDrmState(drm.get());
+
screen_manager_->AddDisplayController(drm, kDefaultCrtc, kDefaultConnector);
- screen_manager_->ConfigureDisplayController(
- drm, kDefaultCrtc, kDefaultConnector,
- gfx::Point(0, kDefaultMode.vdisplay), kDefaultMode);
+
+ std::vector<ui::ScreenManager::ControllerConfigParams> controllers_to_enable;
+ controllers_to_enable.emplace_back(
+ 2 /*display_id*/, drm, kDefaultCrtc, kDefaultConnector,
+ gfx::Point(0, kDefaultMode.vdisplay),
+ std::make_unique<drmModeModeInfo>(kDefaultMode));
+ screen_manager_->ConfigureDisplayControllers(controllers_to_enable);
// Move window to the display on the new device.
screen_manager_->GetWindow(kDefaultWidgetHandle)
diff --git a/chromium/ui/ozone/platform/drm/gpu/gbm_surface_factory.cc b/chromium/ui/ozone/platform/drm/gpu/gbm_surface_factory.cc
index 9a220c3ecdf..163a89f699c 100644
--- a/chromium/ui/ozone/platform/drm/gpu/gbm_surface_factory.cc
+++ b/chromium/ui/ozone/platform/drm/gpu/gbm_surface_factory.cc
@@ -24,6 +24,7 @@
#include "ui/ozone/common/egl_util.h"
#include "ui/ozone/common/gl_ozone_egl.h"
#include "ui/ozone/platform/drm/common/drm_util.h"
+#include "ui/ozone/platform/drm/common/scoped_drm_types.h"
#include "ui/ozone/platform/drm/gpu/drm_gpu_util.h"
#include "ui/ozone/platform/drm/gpu/drm_thread_proxy.h"
#include "ui/ozone/platform/drm/gpu/drm_window_proxy.h"
@@ -185,18 +186,18 @@ std::vector<gfx::BufferFormat> EnumerateSupportedBufferFormatsForTexturing() {
if (!dev_path_file.IsValid())
break;
+ // Skip the virtual graphics memory manager device.
+ ScopedDrmVersionPtr version(drmGetVersion(dev_path_file.GetPlatformFile()));
+ if (!version || base::LowerCaseEqualsASCII(version->name, "vgem")) {
+ continue;
+ }
+
ScopedGbmDevice device(gbm_create_device(dev_path_file.GetPlatformFile()));
if (!device) {
LOG(ERROR) << "Couldn't create Gbm Device at " << dev_path.MaybeAsASCII();
return supported_buffer_formats;
}
- // Skip the virtual graphics memory manager device.
- if (base::LowerCaseEqualsASCII(gbm_device_get_backend_name(device.get()),
- "vgem")) {
- continue;
- }
-
for (int i = 0; i <= static_cast<int>(gfx::BufferFormat::LAST); ++i) {
const gfx::BufferFormat buffer_format = static_cast<gfx::BufferFormat>(i);
if (base::Contains(supported_buffer_formats, buffer_format))
diff --git a/chromium/ui/ozone/platform/drm/gpu/gbm_surfaceless.cc b/chromium/ui/ozone/platform/drm/gpu/gbm_surfaceless.cc
index a868bb5175b..90d7a20d0cd 100644
--- a/chromium/ui/ozone/platform/drm/gpu/gbm_surfaceless.cc
+++ b/chromium/ui/ozone/platform/drm/gpu/gbm_surfaceless.cc
@@ -244,7 +244,7 @@ void GbmSurfaceless::SubmitFrame() {
for (auto& overlay : unsubmitted_frames_.front()->overlays) {
if (overlay.z_order() == 0 && overlay.gpu_fence()) {
submitted_frame_gpu_fence_ = std::make_unique<gfx::GpuFence>(
- gfx::CloneHandleForIPC(overlay.gpu_fence()->GetGpuFenceHandle()));
+ overlay.gpu_fence()->GetGpuFenceHandle().Clone());
break;
}
}
diff --git a/chromium/ui/ozone/platform/drm/gpu/hardware_display_controller.cc b/chromium/ui/ozone/platform/drm/gpu/hardware_display_controller.cc
index 7cc196aa293..b4736423e74 100644
--- a/chromium/ui/ozone/platform/drm/gpu/hardware_display_controller.cc
+++ b/chromium/ui/ozone/platform/drm/gpu/hardware_display_controller.cc
@@ -73,49 +73,70 @@ HardwareDisplayController::HardwareDisplayController(
HardwareDisplayController::~HardwareDisplayController() = default;
-bool HardwareDisplayController::Modeset(const DrmOverlayPlane& primary,
- const drmModeModeInfo& mode) {
- TRACE_EVENT0("drm", "HDC::Modeset");
- return ModesetCrtc(primary, /*use_current_crtc_mode=*/false, mode);
+void HardwareDisplayController::GetModesetProps(CommitRequest* commit_request,
+ const DrmOverlayPlane& primary,
+ const drmModeModeInfo& mode) {
+ TRACE_EVENT0("drm", "HDC::GetModesetProps");
+ GetModesetPropsForCrtcs(commit_request, primary,
+ /*use_current_crtc_mode=*/false, mode);
}
-bool HardwareDisplayController::Enable(const DrmOverlayPlane& primary) {
- TRACE_EVENT0("drm", "HDC::Enable");
+void HardwareDisplayController::GetEnableProps(CommitRequest* commit_request,
+ const DrmOverlayPlane& primary) {
+ TRACE_EVENT0("drm", "HDC::GetEnableProps");
+ // TODO(markyacoub): Simplify and remove the use of empty_mode.
drmModeModeInfo empty_mode = {};
- return ModesetCrtc(primary, /*use_current_crtc_mode=*/true, empty_mode);
+ GetModesetPropsForCrtcs(commit_request, primary,
+ /*use_current_crtc_mode=*/true, empty_mode);
}
-bool HardwareDisplayController::ModesetCrtc(const DrmOverlayPlane& primary,
- bool use_current_crtc_mode,
- const drmModeModeInfo& mode) {
- DCHECK(primary.buffer.get());
- bool status = true;
- for (const auto& controller : crtc_controllers_)
- status &= controller->Modeset(
- primary, use_current_crtc_mode ? controller->mode() : mode,
- owned_hardware_planes_);
+void HardwareDisplayController::GetModesetPropsForCrtcs(
+ CommitRequest* commit_request,
+ const DrmOverlayPlane& primary,
+ bool use_current_crtc_mode,
+ const drmModeModeInfo& mode) {
+ DCHECK(commit_request);
- is_disabled_ = false;
- ResetCursor();
- OnModesetComplete(primary);
- return status;
-}
+ GetDrmDevice()->plane_manager()->BeginFrame(&owned_hardware_planes_);
-void HardwareDisplayController::Disable() {
- TRACE_EVENT0("drm", "HDC::Disable");
+ for (const auto& controller : crtc_controllers_) {
+ drmModeModeInfo modeset_mode =
+ use_current_crtc_mode ? controller->mode() : mode;
- for (const auto& controller : crtc_controllers_)
- // TODO(crbug.com/1015104): Modeset and Disable operations should go
- // together. The current split is due to how the legacy/atomic split
- // evolved. It should be cleaned up under the more generic
- // HardwareDisplayPlaneManager{Legacy,Atomic} calls.
- controller->Disable();
+ DrmOverlayPlaneList overlays;
+ overlays.push_back(primary.Clone());
+
+ CrtcCommitRequest request = CrtcCommitRequest::EnableCrtcRequest(
+ controller->crtc(), controller->connector(), modeset_mode,
+ &owned_hardware_planes_, std::move(overlays));
+ commit_request->push_back(std::move(request));
+ }
+}
- bool ret = GetDrmDevice()->plane_manager()->DisableOverlayPlanes(
- &owned_hardware_planes_);
- LOG_IF(ERROR, !ret) << "Can't disable overlays when disabling HDC.";
+void HardwareDisplayController::GetDisableProps(CommitRequest* commit_request) {
+ TRACE_EVENT0("drm", "HDC::GetDisableProps");
- is_disabled_ = true;
+ for (const auto& controller : crtc_controllers_) {
+ CrtcCommitRequest request = CrtcCommitRequest::DisableCrtcRequest(
+ controller->crtc(), controller->connector(), &owned_hardware_planes_);
+ commit_request->push_back(std::move(request));
+ }
+}
+
+void HardwareDisplayController::UpdateState(
+ bool is_enabled,
+ const DrmOverlayPlane* primary_plane) {
+ // TODO(markyacoub): Update how we report the controller state. Right now, the
+ // controller state is independent of its CRTCs; however, it should reflect
+ // its CRTCs active states.
+ is_disabled_ = !is_enabled;
+
+ if (is_enabled) {
+ DCHECK(primary_plane);
+ // TODO(markyacoub): This should be absorbed in the commit request.
+ ResetCursor();
+ OnModesetComplete(*primary_plane);
+ }
}
void HardwareDisplayController::SchedulePageFlip(
@@ -176,12 +197,13 @@ bool HardwareDisplayController::ScheduleOrTestPageFlip(
bool status = true;
for (const auto& controller : crtc_controllers_) {
- status &= controller->AssignOverlayPlanes(&owned_hardware_planes_,
- pending_planes);
+ status &= controller->AssignOverlayPlanes(
+ &owned_hardware_planes_, pending_planes, /*is_modesetting=*/false);
}
status &= GetDrmDevice()->plane_manager()->Commit(
- &owned_hardware_planes_, page_flip_request, out_fence);
+ &owned_hardware_planes_, /*should_modeset=*/false, page_flip_request,
+ out_fence);
return status;
}
@@ -345,8 +367,10 @@ void HardwareDisplayController::OnPageFlipComplete(
return; // Modeset occured during this page flip.
time_of_last_flip_ = presentation_feedback.timestamp;
current_planes_ = std::move(pending_planes);
- for (const auto& controller : crtc_controllers_)
- controller->OnPageFlipComplete();
+ for (const auto& controller : crtc_controllers_) {
+ GetDrmDevice()->plane_manager()->ResetModesetBufferOfCrtc(
+ controller->crtc());
+ }
page_flip_request_ = nullptr;
}
@@ -357,6 +381,7 @@ void HardwareDisplayController::OnModesetComplete(
// pending planes to the same values so that the callback keeps the correct
// state.
page_flip_request_ = nullptr;
+ owned_hardware_planes_.legacy_page_flips.clear();
current_planes_.clear();
current_planes_.push_back(primary.Clone());
time_of_last_flip_ = base::TimeTicks::Now();
diff --git a/chromium/ui/ozone/platform/drm/gpu/hardware_display_controller.h b/chromium/ui/ozone/platform/drm/gpu/hardware_display_controller.h
index 6fb71b24860..1fbd466dbfc 100644
--- a/chromium/ui/ozone/platform/drm/gpu/hardware_display_controller.h
+++ b/chromium/ui/ozone/platform/drm/gpu/hardware_display_controller.h
@@ -93,15 +93,18 @@ class HardwareDisplayController {
const gfx::Point& origin);
~HardwareDisplayController();
- // Performs the initial CRTC configuration. If successful, it will display the
- // framebuffer for |primary| with |mode|.
- bool Modeset(const DrmOverlayPlane& primary, const drmModeModeInfo& mode);
-
- // Performs a CRTC configuration re-using the modes from the CRTCs.
- bool Enable(const DrmOverlayPlane& primary);
-
- // Disables the CRTC.
- void Disable();
+ // Gets the props required to modeset a CRTC with a |mode| onto
+ // |commit_request|.
+ void GetModesetProps(CommitRequest* commit_request,
+ const DrmOverlayPlane& primary,
+ const drmModeModeInfo& mode);
+ // Gets the props required to enable/disable a CRTC onto |commit_request|.
+ void GetEnableProps(CommitRequest* commit_request,
+ const DrmOverlayPlane& primary);
+ void GetDisableProps(CommitRequest* commit_request);
+
+ // Updates state of the controller after modeset/enable/disable is performed.
+ void UpdateState(bool is_enabled, const DrmOverlayPlane* primary_plane);
// Schedules the |overlays|' framebuffers to be displayed on the next vsync
// event. The event will be posted on the graphics card file descriptor |fd_|
@@ -169,12 +172,12 @@ class HardwareDisplayController {
const gfx::PresentationFeedback& presentation_feedback);
private:
- // If multiple CRTC Controllers exist and they're enabled, each will be
- // enabled with its own mode. Set |use_current_crtc_mode| to Modeset using
- // controller's mode instead of |mode|.
- bool ModesetCrtc(const DrmOverlayPlane& primary,
- bool use_current_crtc_mode,
- const drmModeModeInfo& mode);
+ // Loops over |crtc_controllers_| and save their props into |commit_request|
+ // to be enabled/modeset.
+ void GetModesetPropsForCrtcs(CommitRequest* commit_request,
+ const DrmOverlayPlane& primary,
+ bool use_current_crtc_mode,
+ const drmModeModeInfo& mode);
void OnModesetComplete(const DrmOverlayPlane& primary);
bool ScheduleOrTestPageFlip(const DrmOverlayPlaneList& plane_list,
scoped_refptr<PageFlipRequest> page_flip_request,
diff --git a/chromium/ui/ozone/platform/drm/gpu/hardware_display_controller_unittest.cc b/chromium/ui/ozone/platform/drm/gpu/hardware_display_controller_unittest.cc
index 3f751403fd0..3a69804048c 100644
--- a/chromium/ui/ozone/platform/drm/gpu/hardware_display_controller_unittest.cc
+++ b/chromium/ui/ozone/platform/drm/gpu/hardware_display_controller_unittest.cc
@@ -9,6 +9,7 @@
#include <utility>
#include "base/bind.h"
+#include "base/files/file_util.h"
#include "base/macros.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/skia/include/core/SkCanvas.h"
@@ -30,11 +31,19 @@ namespace {
const drmModeModeInfo kDefaultMode = {0, 6, 0, 0, 0, 0, 4, 0,
0, 0, 0, 0, 0, 0, {'\0'}};
-constexpr uint32_t kCrtcIdBase = 1;
+constexpr uint32_t kCrtcIdBase = 100;
constexpr uint32_t kPrimaryCrtc = kCrtcIdBase;
constexpr uint32_t kSecondaryCrtc = kCrtcIdBase + 1;
-constexpr uint32_t kConnectorIdBase = 10;
-constexpr uint32_t kPlaneOffset = 1000;
+constexpr uint32_t kConnectorIdBase = 200;
+constexpr uint32_t kPlaneOffset = 300;
+constexpr uint32_t kInFormatsBlobPropId = 400;
+
+constexpr uint32_t kActivePropId = 1000;
+constexpr uint32_t kModePropId = 1001;
+constexpr uint32_t kCrtcIdPropId = 2000;
+constexpr uint32_t kFenceFdPropId = 3010;
+constexpr uint32_t kTypePropId = 3011;
+constexpr uint32_t kInFormatsPropId = 3012;
const gfx::Size kDefaultModeSize(kDefaultMode.hdisplay, kDefaultMode.vdisplay);
const gfx::Size kOverlaySize(kDefaultMode.hdisplay / 2,
@@ -43,6 +52,35 @@ const gfx::SizeF kDefaultModeSizeF(1.0, 1.0);
} // namespace
+class FakeFenceFD {
+ public:
+ FakeFenceFD();
+
+ std::unique_ptr<gfx::GpuFence> GetGpuFence() const;
+ void Signal() const;
+
+ private:
+ base::ScopedFD read_fd;
+ base::ScopedFD write_fd;
+};
+
+FakeFenceFD::FakeFenceFD() {
+ int fds[2];
+ base::CreateLocalNonBlockingPipe(fds);
+ read_fd = base::ScopedFD(fds[0]);
+ write_fd = base::ScopedFD(fds[1]);
+}
+
+std::unique_ptr<gfx::GpuFence> FakeFenceFD::GetGpuFence() const {
+ gfx::GpuFenceHandle handle;
+ handle.owned_fd = base::ScopedFD(HANDLE_EINTR(dup(read_fd.get())));
+ return std::make_unique<gfx::GpuFence>(std::move(handle));
+}
+
+void FakeFenceFD::Signal() const {
+ base::WriteFileDescriptor(write_fd.get(), "a", 1);
+}
+
class HardwareDisplayControllerTest : public testing::Test {
public:
HardwareDisplayControllerTest() : page_flips_(0) {}
@@ -73,6 +111,9 @@ class HardwareDisplayControllerTest : public testing::Test {
}
protected:
+ bool ModesetWithPlane(const ui::DrmOverlayPlane& plane);
+ bool DisableController();
+
std::unique_ptr<ui::HardwareDisplayController> controller_;
scoped_refptr<ui::MockDrmDevice> drm_;
@@ -91,11 +132,6 @@ void HardwareDisplayControllerTest::SetUp() {
auto gbm_device = std::make_unique<ui::MockGbmDevice>();
drm_ = new ui::MockDrmDevice(std::move(gbm_device));
InitializeDrmDevice(/* use_atomic= */ true);
-
- controller_ = std::make_unique<ui::HardwareDisplayController>(
- std::make_unique<ui::CrtcController>(drm_.get(), kPrimaryCrtc,
- kConnectorIdBase),
- gfx::Point());
}
void HardwareDisplayControllerTest::TearDown() {
@@ -104,10 +140,6 @@ void HardwareDisplayControllerTest::TearDown() {
}
void HardwareDisplayControllerTest::InitializeDrmDevice(bool use_atomic) {
- constexpr uint32_t kTypePropId = 3010;
- constexpr uint32_t kInFormatsPropId = 3011;
- constexpr uint32_t kInFormatsBlobPropId = 400;
-
std::vector<ui::MockDrmDevice::CrtcProperties> crtc_properties(2);
std::map<uint32_t, std::string> crtc_property_names = {
{1000, "ACTIVE"},
@@ -116,7 +148,7 @@ void HardwareDisplayControllerTest::InitializeDrmDevice(bool use_atomic) {
std::vector<ui::MockDrmDevice::ConnectorProperties> connector_properties(2);
std::map<uint32_t, std::string> connector_property_names = {
- {2000, "CRTC_ID"},
+ {kCrtcIdPropId, "CRTC_ID"},
};
for (size_t i = 0; i < connector_properties.size(); ++i) {
connector_properties[i].id = kConnectorIdBase + i;
@@ -139,6 +171,7 @@ void HardwareDisplayControllerTest::InitializeDrmDevice(bool use_atomic) {
{3007, "SRC_Y"},
{3008, "SRC_W"},
{3009, "SRC_H"},
+ {kFenceFdPropId, "IN_FENCE_FD"},
// Add some optional properties we use for convenience.
{kTypePropId, "type"},
{kInFormatsPropId, "IN_FORMATS"},
@@ -181,8 +214,45 @@ void HardwareDisplayControllerTest::InitializeDrmDevice(bool use_atomic) {
connector_property_names.end());
property_names.insert(plane_property_names.begin(),
plane_property_names.end());
+
+ // This will change the plane_manager of the drm.
+ // HardwareDisplayController is tied to the plane_manager CRTC states.
+ // Destruct the controller before destructing the plane manager its CRTC
+ // controllers are tied to.
+ controller_ = nullptr;
drm_->InitializeState(crtc_properties, connector_properties, plane_properties,
property_names, use_atomic);
+ // Initialize a new HardwareDisplayController with the new Plane Manager of
+ // the DRM.
+ controller_ = std::make_unique<ui::HardwareDisplayController>(
+ std::make_unique<ui::CrtcController>(drm_.get(), kPrimaryCrtc,
+ kConnectorIdBase),
+ gfx::Point());
+}
+
+bool HardwareDisplayControllerTest::ModesetWithPlane(
+ const ui::DrmOverlayPlane& plane) {
+ ui::CommitRequest commit_request;
+ controller_->GetModesetProps(&commit_request, plane, kDefaultMode);
+ ui::CommitRequest request_for_update = commit_request;
+ bool status = drm_->plane_manager()->Commit(std::move(commit_request),
+ DRM_MODE_ATOMIC_ALLOW_MODESET);
+ controller_->UpdateState(
+ /*enabled=*/true,
+ ui::DrmOverlayPlane::GetPrimaryPlane(request_for_update[0].overlays()));
+
+ return status;
+}
+
+bool HardwareDisplayControllerTest::DisableController() {
+ ui::CommitRequest commit_request;
+ controller_->GetDisableProps(&commit_request);
+ ui::CommitRequest request_for_update = commit_request;
+ bool status = drm_->plane_manager()->Commit(std::move(commit_request),
+ DRM_MODE_ATOMIC_ALLOW_MODESET);
+ controller_->UpdateState(/*enabled=*/false, nullptr);
+
+ return status;
}
void HardwareDisplayControllerTest::SchedulePageFlip(
@@ -221,14 +291,148 @@ uint64_t HardwareDisplayControllerTest::GetPlanePropertyValue(
TEST_F(HardwareDisplayControllerTest, CheckModesettingResult) {
ui::DrmOverlayPlane plane(CreateBuffer(), nullptr);
- EXPECT_TRUE(controller_->Modeset(plane, kDefaultMode));
+ EXPECT_TRUE(ModesetWithPlane(plane));
EXPECT_FALSE(plane.buffer->HasOneRef());
}
+TEST_F(HardwareDisplayControllerTest, CheckModesettingSetsProps) {
+ ui::DrmOverlayPlane plane1(CreateBuffer(), nullptr);
+
+ EXPECT_TRUE(ModesetWithPlane(plane1));
+
+ ui::DrmOverlayPlane plane2(CreateBuffer(), nullptr);
+ std::vector<ui::DrmOverlayPlane> planes = {};
+ planes.push_back(plane2.Clone());
+
+ SchedulePageFlip(std::move(planes));
+
+ // Test props values after modesetting.
+ ui::DrmDevice::Property connector_prop_crtc_id = {};
+ ui::ScopedDrmObjectPropertyPtr connector_props =
+ drm_->GetObjectProperties(kConnectorIdBase, DRM_MODE_OBJECT_CONNECTOR);
+ ui::GetDrmPropertyForName(drm_.get(), connector_props.get(), "CRTC_ID",
+ &connector_prop_crtc_id);
+ EXPECT_EQ(kCrtcIdPropId, connector_prop_crtc_id.id);
+ EXPECT_EQ(kCrtcIdBase, connector_prop_crtc_id.value);
+
+ ui::DrmDevice::Property crtc_prop_for_name = {};
+ ui::ScopedDrmObjectPropertyPtr crtc_props =
+ drm_->GetObjectProperties(kPrimaryCrtc, DRM_MODE_OBJECT_CRTC);
+ GetDrmPropertyForName(drm_.get(), crtc_props.get(), "ACTIVE",
+ &crtc_prop_for_name);
+ EXPECT_EQ(kActivePropId, crtc_prop_for_name.id);
+ EXPECT_EQ(1U, crtc_prop_for_name.value);
+
+ GetDrmPropertyForName(drm_.get(), crtc_props.get(), "MODE_ID",
+ &crtc_prop_for_name);
+ EXPECT_EQ(kModePropId, crtc_prop_for_name.id);
+
+ ui::DrmDevice::Property fence_fd_prop = {};
+ ui::ScopedDrmObjectPropertyPtr plane_props =
+ drm_->GetObjectProperties(kPlaneOffset, DRM_MODE_OBJECT_PLANE);
+ ui::GetDrmPropertyForName(drm_.get(), plane_props.get(), "IN_FENCE_FD",
+ &fence_fd_prop);
+ EXPECT_EQ(kFenceFdPropId, fence_fd_prop.id);
+ EXPECT_EQ(base::kInvalidPlatformFile, static_cast<int>(fence_fd_prop.value));
+}
+
+TEST_F(HardwareDisplayControllerTest, FenceFdValueChange) {
+ ui::DrmOverlayPlane plane1(CreateBuffer(), nullptr);
+ EXPECT_TRUE(ModesetWithPlane(plane1));
+
+ // Test invalid fence fd
+ {
+ ui::DrmDevice::Property fence_fd_prop = {};
+ ui::ScopedDrmObjectPropertyPtr plane_props =
+ drm_->GetObjectProperties(kPlaneOffset, DRM_MODE_OBJECT_PLANE);
+ ui::GetDrmPropertyForName(drm_.get(), plane_props.get(), "IN_FENCE_FD",
+ &fence_fd_prop);
+ EXPECT_EQ(kFenceFdPropId, fence_fd_prop.id);
+ EXPECT_EQ(base::kInvalidPlatformFile,
+ static_cast<int>(fence_fd_prop.value));
+ }
+
+ const FakeFenceFD fake_fence_fd;
+ plane1.gpu_fence = fake_fence_fd.GetGpuFence();
+ std::vector<ui::DrmOverlayPlane> planes = {};
+ planes.push_back(plane1.Clone());
+ SchedulePageFlip(std::move(planes));
+
+ // Verify fence FD after a GPU Fence is added to the plane.
+ {
+ ui::DrmDevice::Property fence_fd_prop = {};
+ ui::ScopedDrmObjectPropertyPtr plane_props =
+ drm_->GetObjectProperties(kPlaneOffset, DRM_MODE_OBJECT_PLANE);
+ ui::GetDrmPropertyForName(drm_.get(), plane_props.get(), "IN_FENCE_FD",
+ &fence_fd_prop);
+ EXPECT_EQ(kFenceFdPropId, fence_fd_prop.id);
+ EXPECT_LT(base::kInvalidPlatformFile,
+ static_cast<int>(fence_fd_prop.value));
+ }
+
+ plane1.gpu_fence = nullptr;
+ EXPECT_TRUE(ModesetWithPlane(plane1));
+
+ // Test an invalid FD again after the fence is removed.
+ {
+ ui::DrmDevice::Property fence_fd_prop = {};
+ ui::ScopedDrmObjectPropertyPtr plane_props =
+ drm_->GetObjectProperties(kPlaneOffset, DRM_MODE_OBJECT_PLANE);
+ ui::GetDrmPropertyForName(drm_.get(), plane_props.get(), "IN_FENCE_FD",
+ &fence_fd_prop);
+ EXPECT_EQ(kFenceFdPropId, fence_fd_prop.id);
+ EXPECT_EQ(base::kInvalidPlatformFile,
+ static_cast<int>(fence_fd_prop.value));
+ }
+}
+
+TEST_F(HardwareDisplayControllerTest, CheckDisableResetsProps) {
+ ui::DrmOverlayPlane plane1(CreateBuffer(), nullptr);
+
+ EXPECT_TRUE(ModesetWithPlane(plane1));
+
+ ui::DrmOverlayPlane plane2(CreateBuffer(), nullptr);
+ std::vector<ui::DrmOverlayPlane> planes = {};
+ planes.push_back(plane2.Clone());
+
+ SchedulePageFlip(std::move(planes));
+
+ // Test props values after disabling.
+ DisableController();
+
+ ui::DrmDevice::Property connector_prop_crtc_id;
+ ui::ScopedDrmObjectPropertyPtr connector_props =
+ drm_->GetObjectProperties(kConnectorIdBase, DRM_MODE_OBJECT_CONNECTOR);
+ ui::GetDrmPropertyForName(drm_.get(), connector_props.get(), "CRTC_ID",
+ &connector_prop_crtc_id);
+ EXPECT_EQ(0U, connector_prop_crtc_id.value);
+
+ ui::DrmDevice::Property crtc_prop_for_name;
+ ui::ScopedDrmObjectPropertyPtr crtc_props =
+ drm_->GetObjectProperties(kPrimaryCrtc, DRM_MODE_OBJECT_CRTC);
+ GetDrmPropertyForName(drm_.get(), crtc_props.get(), "ACTIVE",
+ &crtc_prop_for_name);
+ EXPECT_EQ(0U, crtc_prop_for_name.value);
+
+ crtc_props = drm_->GetObjectProperties(kPrimaryCrtc, DRM_MODE_OBJECT_CRTC);
+ GetDrmPropertyForName(drm_.get(), crtc_props.get(), "MODE_ID",
+ &crtc_prop_for_name);
+ EXPECT_EQ(0U, crtc_prop_for_name.value);
+
+ ui::DrmDevice::Property fence_fd_prop = {};
+ ui::ScopedDrmObjectPropertyPtr plane_props =
+ drm_->GetObjectProperties(kPlaneOffset, DRM_MODE_OBJECT_PLANE);
+ ui::GetDrmPropertyForName(drm_.get(), plane_props.get(), "IN_FENCE_FD",
+ &fence_fd_prop);
+ EXPECT_EQ(kFenceFdPropId, fence_fd_prop.id);
+ EXPECT_EQ(base::kInvalidPlatformFile, static_cast<int>(fence_fd_prop.value));
+}
+
TEST_F(HardwareDisplayControllerTest, CheckStateAfterPageFlip) {
ui::DrmOverlayPlane plane1(CreateBuffer(), nullptr);
- EXPECT_TRUE(controller_->Modeset(plane1, kDefaultMode));
+ EXPECT_TRUE(ModesetWithPlane(plane1));
+ EXPECT_EQ(1, drm_->get_commit_count());
ui::DrmOverlayPlane plane2(CreateBuffer(), nullptr);
std::vector<ui::DrmOverlayPlane> planes;
@@ -242,32 +446,19 @@ TEST_F(HardwareDisplayControllerTest, CheckStateAfterPageFlip) {
EXPECT_EQ(gfx::SwapResult::SWAP_ACK, last_swap_result_);
EXPECT_EQ(1, page_flips_);
- EXPECT_EQ(1, drm_->get_commit_count());
+ EXPECT_EQ(2, drm_->get_commit_count());
// Verify only the primary display have a valid framebuffer.
EXPECT_NE(0u, GetPlanePropertyValue(kPlaneOffset, "FB_ID"));
EXPECT_EQ(0u, GetPlanePropertyValue(kPlaneOffset + 1, "FB_ID"));
}
TEST_F(HardwareDisplayControllerTest, CheckStateIfModesetFails) {
+ InitializeDrmDevice(/* use_atomic */ false);
drm_->set_set_crtc_expectation(false);
ui::DrmOverlayPlane plane(CreateBuffer(), nullptr);
- EXPECT_FALSE(controller_->Modeset(plane, kDefaultMode));
-}
-
-TEST_F(HardwareDisplayControllerTest, CheckStateIfPageFlipFails) {
- drm_->set_commit_expectation(false);
-
- ui::DrmOverlayPlane plane1(CreateBuffer(), nullptr);
-
- EXPECT_TRUE(controller_->Modeset(plane1, kDefaultMode));
-
- ui::DrmOverlayPlane plane2(CreateBuffer(), nullptr);
- std::vector<ui::DrmOverlayPlane> planes;
- planes.push_back(plane2.Clone());
- EXPECT_DEATH_IF_SUPPORTED(SchedulePageFlip(std::move(planes)),
- "SchedulePageFlip failed");
+ EXPECT_FALSE(ModesetWithPlane(plane));
}
TEST_F(HardwareDisplayControllerTest, CheckOverlayPresent) {
@@ -276,7 +467,8 @@ TEST_F(HardwareDisplayControllerTest, CheckOverlayPresent) {
CreateOverlayBuffer(), 1, gfx::OVERLAY_TRANSFORM_NONE,
gfx::Rect(kOverlaySize), gfx::RectF(kDefaultModeSizeF), true, nullptr);
- EXPECT_TRUE(controller_->Modeset(plane1, kDefaultMode));
+ EXPECT_TRUE(ModesetWithPlane(plane1));
+ EXPECT_EQ(1, drm_->get_commit_count());
std::vector<ui::DrmOverlayPlane> planes;
planes.push_back(plane1.Clone());
@@ -286,7 +478,7 @@ TEST_F(HardwareDisplayControllerTest, CheckOverlayPresent) {
drm_->RunCallbacks();
EXPECT_EQ(gfx::SwapResult::SWAP_ACK, last_swap_result_);
EXPECT_EQ(1, page_flips_);
- EXPECT_EQ(1, drm_->get_commit_count());
+ EXPECT_EQ(2, drm_->get_commit_count());
// Verify both planes on the primary display have a valid framebuffer.
EXPECT_NE(0u, GetPlanePropertyValue(kPlaneOffset, "FB_ID"));
EXPECT_NE(0u, GetPlanePropertyValue(kPlaneOffset + 1, "FB_ID"));
@@ -298,14 +490,15 @@ TEST_F(HardwareDisplayControllerTest, CheckOverlayTestMode) {
CreateOverlayBuffer(), 1, gfx::OVERLAY_TRANSFORM_NONE,
gfx::Rect(kOverlaySize), gfx::RectF(kDefaultModeSizeF), true, nullptr);
- EXPECT_TRUE(controller_->Modeset(plane1, kDefaultMode));
+ EXPECT_TRUE(ModesetWithPlane(plane1));
+ EXPECT_EQ(1, drm_->get_commit_count());
std::vector<ui::DrmOverlayPlane> planes;
planes.push_back(plane1.Clone());
planes.push_back(plane2.Clone());
SchedulePageFlip(ui::DrmOverlayPlane::Clone(planes));
- EXPECT_EQ(1, drm_->get_commit_count());
+ EXPECT_EQ(2, drm_->get_commit_count());
// Verify both planes on the primary display have a valid framebuffer.
EXPECT_NE(0u, GetPlanePropertyValue(kPlaneOffset, "FB_ID"));
EXPECT_NE(0u, GetPlanePropertyValue(kPlaneOffset + 1, "FB_ID"));
@@ -315,14 +508,14 @@ TEST_F(HardwareDisplayControllerTest, CheckOverlayTestMode) {
drm_->RunCallbacks();
EXPECT_EQ(gfx::SwapResult::SWAP_ACK, last_swap_result_);
EXPECT_EQ(1, page_flips_);
- EXPECT_EQ(2, drm_->get_commit_count());
+ EXPECT_EQ(3, drm_->get_commit_count());
// Regular flips should continue on normally.
SchedulePageFlip(ui::DrmOverlayPlane::Clone(planes));
drm_->RunCallbacks();
EXPECT_EQ(gfx::SwapResult::SWAP_ACK, last_swap_result_);
EXPECT_EQ(2, page_flips_);
- EXPECT_EQ(3, drm_->get_commit_count());
+ EXPECT_EQ(4, drm_->get_commit_count());
// Verify both planes on the primary display have a valid framebuffer.
EXPECT_NE(0u, GetPlanePropertyValue(kPlaneOffset, "FB_ID"));
EXPECT_NE(0u, GetPlanePropertyValue(kPlaneOffset + 1, "FB_ID"));
@@ -334,7 +527,7 @@ TEST_F(HardwareDisplayControllerTest, AcceptUnderlays) {
gfx::Rect(kDefaultModeSize),
gfx::RectF(kDefaultModeSizeF), true, nullptr);
- EXPECT_TRUE(controller_->Modeset(plane1, kDefaultMode));
+ EXPECT_TRUE(ModesetWithPlane(plane1));
std::vector<ui::DrmOverlayPlane> planes;
planes.push_back(plane1.Clone());
@@ -347,13 +540,12 @@ TEST_F(HardwareDisplayControllerTest, AcceptUnderlays) {
}
TEST_F(HardwareDisplayControllerTest, PageflipMirroredControllers) {
- controller_->AddCrtc(
- std::unique_ptr<ui::CrtcController>(new ui::CrtcController(
- drm_.get(), kSecondaryCrtc, kConnectorIdBase + 1)));
+ controller_->AddCrtc(std::make_unique<ui::CrtcController>(
+ drm_.get(), kSecondaryCrtc, kConnectorIdBase + 1));
ui::DrmOverlayPlane plane1(CreateBuffer(), nullptr);
- EXPECT_TRUE(controller_->Modeset(plane1, kDefaultMode));
- EXPECT_EQ(2, drm_->get_set_crtc_call_count());
+ EXPECT_TRUE(ModesetWithPlane(plane1));
+ EXPECT_EQ(1, drm_->get_commit_count());
ui::DrmOverlayPlane plane2(CreateBuffer(), nullptr);
std::vector<ui::DrmOverlayPlane> planes;
@@ -362,7 +554,7 @@ TEST_F(HardwareDisplayControllerTest, PageflipMirroredControllers) {
drm_->RunCallbacks();
EXPECT_EQ(gfx::SwapResult::SWAP_ACK, last_swap_result_);
EXPECT_EQ(1, page_flips_);
- EXPECT_EQ(1, drm_->get_commit_count());
+ EXPECT_EQ(2, drm_->get_commit_count());
// Verify only the displays have a valid framebuffer on the primary plane.
// First display:
EXPECT_NE(0u, GetPlanePropertyValue(kPlaneOffset, "FB_ID"));
@@ -373,12 +565,11 @@ TEST_F(HardwareDisplayControllerTest, PageflipMirroredControllers) {
}
TEST_F(HardwareDisplayControllerTest, PlaneStateAfterRemoveCrtc) {
- controller_->AddCrtc(
- std::unique_ptr<ui::CrtcController>(new ui::CrtcController(
- drm_.get(), kSecondaryCrtc, kConnectorIdBase + 1)));
+ controller_->AddCrtc(std::make_unique<ui::CrtcController>(
+ drm_.get(), kSecondaryCrtc, kConnectorIdBase + 1));
ui::DrmOverlayPlane plane1(CreateBuffer(), nullptr);
- EXPECT_TRUE(controller_->Modeset(plane1, kDefaultMode));
+ EXPECT_TRUE(ModesetWithPlane(plane1));
std::vector<ui::DrmOverlayPlane> planes;
planes.push_back(plane1.Clone());
SchedulePageFlip(ui::DrmOverlayPlane::Clone(planes));
@@ -400,11 +591,10 @@ TEST_F(HardwareDisplayControllerTest, PlaneStateAfterRemoveCrtc) {
EXPECT_EQ(kPrimaryCrtc, primary_crtc_plane->owning_crtc());
EXPECT_EQ(kSecondaryCrtc, secondary_crtc_plane->owning_crtc());
- // Removing the crtc should not free the plane or change ownership.
+ // Removing the crtc should free the plane.
std::unique_ptr<ui::CrtcController> crtc =
controller_->RemoveCrtc(drm_, kPrimaryCrtc);
- EXPECT_TRUE(primary_crtc_plane->in_use());
- EXPECT_EQ(kPrimaryCrtc, primary_crtc_plane->owning_crtc());
+ EXPECT_FALSE(primary_crtc_plane->in_use());
EXPECT_TRUE(secondary_crtc_plane->in_use());
EXPECT_EQ(kSecondaryCrtc, secondary_crtc_plane->owning_crtc());
@@ -414,15 +604,14 @@ TEST_F(HardwareDisplayControllerTest, PlaneStateAfterRemoveCrtc) {
drm_->RunCallbacks();
EXPECT_EQ(gfx::SwapResult::SWAP_ACK, last_swap_result_);
EXPECT_EQ(2, page_flips_);
- EXPECT_TRUE(primary_crtc_plane->in_use());
- EXPECT_EQ(kPrimaryCrtc, primary_crtc_plane->owning_crtc());
+ EXPECT_FALSE(primary_crtc_plane->in_use());
EXPECT_TRUE(secondary_crtc_plane->in_use());
EXPECT_EQ(kSecondaryCrtc, secondary_crtc_plane->owning_crtc());
}
TEST_F(HardwareDisplayControllerTest, PlaneStateAfterDestroyingCrtc) {
ui::DrmOverlayPlane plane1(CreateBuffer(), nullptr);
- EXPECT_TRUE(controller_->Modeset(plane1, kDefaultMode));
+ EXPECT_TRUE(ModesetWithPlane(plane1));
std::vector<ui::DrmOverlayPlane> planes;
planes.push_back(plane1.Clone());
SchedulePageFlip(std::move(planes));
@@ -446,12 +635,11 @@ TEST_F(HardwareDisplayControllerTest, PlaneStateAfterDestroyingCrtc) {
}
TEST_F(HardwareDisplayControllerTest, PlaneStateAfterAddCrtc) {
- controller_->AddCrtc(
- std::unique_ptr<ui::CrtcController>(new ui::CrtcController(
- drm_.get(), kSecondaryCrtc, kConnectorIdBase + 1)));
+ controller_->AddCrtc(std::make_unique<ui::CrtcController>(
+ drm_.get(), kSecondaryCrtc, kConnectorIdBase + 1));
ui::DrmOverlayPlane plane1(CreateBuffer(), nullptr);
- EXPECT_TRUE(controller_->Modeset(plane1, kDefaultMode));
+ EXPECT_TRUE(ModesetWithPlane(plane1));
std::vector<ui::DrmOverlayPlane> planes;
planes.push_back(plane1.Clone());
SchedulePageFlip(ui::DrmOverlayPlane::Clone(planes));
@@ -474,8 +662,7 @@ TEST_F(HardwareDisplayControllerTest, PlaneStateAfterAddCrtc) {
drm_->RunCallbacks();
EXPECT_EQ(gfx::SwapResult::SWAP_ACK, last_swap_result_);
EXPECT_EQ(2, page_flips_);
- EXPECT_TRUE(primary_crtc_plane->in_use());
- EXPECT_EQ(kPrimaryCrtc, primary_crtc_plane->owning_crtc());
+ EXPECT_FALSE(primary_crtc_plane->in_use());
// We reset state of plane here to test that the plane was actually added to
// hdc_controller. In which case, the right state should be set to plane
@@ -497,33 +684,35 @@ TEST_F(HardwareDisplayControllerTest, PlaneStateAfterAddCrtc) {
TEST_F(HardwareDisplayControllerTest, ModesetWhilePageFlipping) {
ui::DrmOverlayPlane plane1(CreateBuffer(), nullptr);
- EXPECT_TRUE(controller_->Modeset(plane1, kDefaultMode));
+ EXPECT_TRUE(ModesetWithPlane(plane1));
std::vector<ui::DrmOverlayPlane> planes;
planes.push_back(plane1.Clone());
SchedulePageFlip(std::move(planes));
- EXPECT_TRUE(controller_->Modeset(plane1, kDefaultMode));
+ EXPECT_TRUE(ModesetWithPlane(plane1));
drm_->RunCallbacks();
EXPECT_EQ(gfx::SwapResult::SWAP_ACK, last_swap_result_);
EXPECT_EQ(1, page_flips_);
}
TEST_F(HardwareDisplayControllerTest, FailPageFlipping) {
- drm_->set_commit_expectation(false);
-
ui::DrmOverlayPlane plane1(CreateBuffer(), nullptr);
- EXPECT_TRUE(controller_->Modeset(plane1, kDefaultMode));
+ EXPECT_TRUE(ModesetWithPlane(plane1));
+
+ drm_->set_commit_expectation(false);
std::vector<ui::DrmOverlayPlane> planes;
planes.push_back(plane1.Clone());
EXPECT_DEATH_IF_SUPPORTED(SchedulePageFlip(std::move(planes)),
"SchedulePageFlip failed");
}
-TEST_F(HardwareDisplayControllerTest, CheckNoPrimaryPlane) {
+TEST_F(HardwareDisplayControllerTest, CheckNoPrimaryPlaneOnFlip) {
+ ui::DrmOverlayPlane modeset_primary_plane(CreateBuffer(), nullptr);
+ EXPECT_TRUE(ModesetWithPlane(modeset_primary_plane));
+
ui::DrmOverlayPlane plane1(CreateBuffer(), 1, gfx::OVERLAY_TRANSFORM_NONE,
gfx::Rect(kDefaultModeSize),
gfx::RectF(0, 0, 1, 1), true, nullptr);
- EXPECT_TRUE(controller_->Modeset(plane1, kDefaultMode));
std::vector<ui::DrmOverlayPlane> planes;
planes.push_back(plane1.Clone());
SchedulePageFlip(std::move(planes));
@@ -535,14 +724,13 @@ TEST_F(HardwareDisplayControllerTest, CheckNoPrimaryPlane) {
TEST_F(HardwareDisplayControllerTest, AddCrtcMidPageFlip) {
ui::DrmOverlayPlane plane1(CreateBuffer(), nullptr);
- EXPECT_TRUE(controller_->Modeset(plane1, kDefaultMode));
+ EXPECT_TRUE(ModesetWithPlane(plane1));
std::vector<ui::DrmOverlayPlane> planes;
planes.push_back(plane1.Clone());
SchedulePageFlip(std::move(planes));
- controller_->AddCrtc(
- std::unique_ptr<ui::CrtcController>(new ui::CrtcController(
- drm_.get(), kSecondaryCrtc, kConnectorIdBase + 1)));
+ controller_->AddCrtc(std::make_unique<ui::CrtcController>(
+ drm_.get(), kSecondaryCrtc, kConnectorIdBase + 1));
drm_->RunCallbacks();
EXPECT_EQ(gfx::SwapResult::SWAP_ACK, last_swap_result_);
@@ -551,7 +739,7 @@ TEST_F(HardwareDisplayControllerTest, AddCrtcMidPageFlip) {
TEST_F(HardwareDisplayControllerTest, RemoveCrtcMidPageFlip) {
ui::DrmOverlayPlane plane1(CreateBuffer(), nullptr);
- EXPECT_TRUE(controller_->Modeset(plane1, kDefaultMode));
+ EXPECT_TRUE(ModesetWithPlane(plane1));
std::vector<ui::DrmOverlayPlane> planes;
planes.push_back(plane1.Clone());
SchedulePageFlip(std::move(planes));
@@ -568,7 +756,7 @@ TEST_F(HardwareDisplayControllerTest, Disable) {
InitializeDrmDevice(/* use_atomic= */ true);
ui::DrmOverlayPlane plane1(CreateBuffer(), nullptr);
- EXPECT_TRUE(controller_->Modeset(plane1, kDefaultMode));
+ EXPECT_TRUE(ModesetWithPlane(plane1));
ui::DrmOverlayPlane plane2(
CreateOverlayBuffer(), 1, gfx::OVERLAY_TRANSFORM_NONE,
@@ -581,13 +769,13 @@ TEST_F(HardwareDisplayControllerTest, Disable) {
drm_->RunCallbacks();
EXPECT_EQ(gfx::SwapResult::SWAP_ACK, last_swap_result_);
- controller_->Disable();
+ EXPECT_TRUE(DisableController());
int planes_in_use = 0;
for (const auto& plane : drm_->plane_manager()->planes()) {
if (plane->in_use())
planes_in_use++;
}
- // Only the primary plane is in use.
- ASSERT_EQ(1, planes_in_use);
+ // No plane should be in use.
+ ASSERT_EQ(0, planes_in_use);
}
diff --git a/chromium/ui/ozone/platform/drm/gpu/hardware_display_plane.cc b/chromium/ui/ozone/platform/drm/gpu/hardware_display_plane.cc
index 272a86d8166..c2a24263831 100644
--- a/chromium/ui/ozone/platform/drm/gpu/hardware_display_plane.cc
+++ b/chromium/ui/ozone/platform/drm/gpu/hardware_display_plane.cc
@@ -12,36 +12,10 @@
#include "ui/ozone/platform/drm/gpu/drm_device.h"
#include "ui/ozone/platform/drm/gpu/drm_gpu_util.h"
-#ifndef DRM_PLANE_TYPE_OVERLAY
-#define DRM_PLANE_TYPE_OVERLAY 0
-#endif
-
-#ifndef DRM_PLANE_TYPE_PRIMARY
-#define DRM_PLANE_TYPE_PRIMARY 1
-#endif
-
-#ifndef DRM_PLANE_TYPE_CURSOR
-#define DRM_PLANE_TYPE_CURSOR 2
-#endif
-
namespace ui {
namespace {
-HardwareDisplayPlane::Type GetPlaneType(int value) {
- switch (value) {
- case DRM_PLANE_TYPE_CURSOR:
- return HardwareDisplayPlane::kCursor;
- case DRM_PLANE_TYPE_PRIMARY:
- return HardwareDisplayPlane::kPrimary;
- case DRM_PLANE_TYPE_OVERLAY:
- return HardwareDisplayPlane::kOverlay;
- default:
- NOTREACHED();
- return HardwareDisplayPlane::kDummy;
- }
-}
-
void ParseSupportedFormatsAndModifiers(
drmModePropertyBlobPtr blob,
std::vector<uint32_t>* supported_formats,
@@ -91,7 +65,7 @@ bool HardwareDisplayPlane::Initialize(DrmDevice* drm) {
}
if (properties_.type.id)
- type_ = GetPlaneType(properties_.type.value);
+ type_ = properties_.type.value;
if (properties_.plane_color_encoding.id) {
color_encoding_bt601_ =
diff --git a/chromium/ui/ozone/platform/drm/gpu/hardware_display_plane.h b/chromium/ui/ozone/platform/drm/gpu/hardware_display_plane.h
index ea614863ba4..aea531a7a2a 100644
--- a/chromium/ui/ozone/platform/drm/gpu/hardware_display_plane.h
+++ b/chromium/ui/ozone/platform/drm/gpu/hardware_display_plane.h
@@ -20,8 +20,6 @@ namespace ui {
class HardwareDisplayPlane {
public:
- enum Type { kDummy, kPrimary, kOverlay, kCursor };
-
HardwareDisplayPlane(uint32_t id);
virtual ~HardwareDisplayPlane();
@@ -39,8 +37,7 @@ class HardwareDisplayPlane {
uint32_t id() const { return id_; }
- Type type() const { return type_; }
- void set_type(const Type type) { type_ = type; }
+ uint32_t type() const { return type_; }
void set_owning_crtc(uint32_t crtc) { owning_crtc_ = crtc; }
uint32_t owning_crtc() const { return owning_crtc_; }
@@ -80,7 +77,7 @@ class HardwareDisplayPlane {
uint32_t owning_crtc_ = 0;
uint32_t last_used_format_ = 0;
bool in_use_ = false;
- Type type_ = kPrimary;
+ uint32_t type_ = DRM_PLANE_TYPE_PRIMARY;
std::vector<uint32_t> supported_formats_;
std::vector<drm_format_modifier> supported_format_modifiers_;
diff --git a/chromium/ui/ozone/platform/drm/gpu/hardware_display_plane_atomic.cc b/chromium/ui/ozone/platform/drm/gpu/hardware_display_plane_atomic.cc
index 7b50c3c8fea..acff6ed2116 100644
--- a/chromium/ui/ozone/platform/drm/gpu/hardware_display_plane_atomic.cc
+++ b/chromium/ui/ozone/platform/drm/gpu/hardware_display_plane_atomic.cc
@@ -38,7 +38,8 @@ uint32_t OverlayTransformToDrmRotationPropertyValue(
// TODO(https://crbug/880464): Remove this.
bool IsRotationTransformSupported(gfx::OverlayTransform transform) {
if ((transform == gfx::OVERLAY_TRANSFORM_ROTATE_90) ||
- (transform == gfx::OVERLAY_TRANSFORM_ROTATE_270)) {
+ (transform == gfx::OVERLAY_TRANSFORM_ROTATE_270) ||
+ (transform == gfx::OVERLAY_TRANSFORM_FLIP_HORIZONTAL)) {
return false;
}
@@ -73,8 +74,7 @@ bool HardwareDisplayPlaneAtomic::Initialize(DrmDevice* drm) {
return ret;
}
-bool HardwareDisplayPlaneAtomic::SetPlaneData(
- drmModeAtomicReq* property_set,
+bool HardwareDisplayPlaneAtomic::AssignPlaneProps(
uint32_t crtc_id,
uint32_t framebuffer,
const gfx::Rect& crtc_rect,
@@ -87,52 +87,65 @@ bool HardwareDisplayPlaneAtomic::SetPlaneData(
if (!IsRotationTransformSupported(transform))
return false;
- properties_.crtc_id.value = crtc_id;
- properties_.crtc_x.value = crtc_rect.x();
- properties_.crtc_y.value = crtc_rect.y();
- properties_.crtc_w.value = crtc_rect.width();
- properties_.crtc_h.value = crtc_rect.height();
- properties_.fb_id.value = framebuffer;
- properties_.src_x.value = src_rect.x();
- properties_.src_y.value = src_rect.y();
- properties_.src_w.value = src_rect.width();
- properties_.src_h.value = src_rect.height();
+ // Make a copy of properties to get the props IDs for the new intermediate
+ // values.
+ assigned_props_ = properties_;
+
+ assigned_props_.crtc_id.value = crtc_id;
+ assigned_props_.crtc_x.value = crtc_rect.x();
+ assigned_props_.crtc_y.value = crtc_rect.y();
+ assigned_props_.crtc_w.value = crtc_rect.width();
+ assigned_props_.crtc_h.value = crtc_rect.height();
+ assigned_props_.fb_id.value = framebuffer;
+ assigned_props_.src_x.value = src_rect.x();
+ assigned_props_.src_y.value = src_rect.y();
+ assigned_props_.src_w.value = src_rect.width();
+ assigned_props_.src_h.value = src_rect.height();
+
+ if (assigned_props_.rotation.id) {
+ assigned_props_.rotation.value =
+ OverlayTransformToDrmRotationPropertyValue(transform);
+ }
+
+ if (assigned_props_.in_fence_fd.id)
+ assigned_props_.in_fence_fd.value = static_cast<uint64_t>(in_fence_fd);
+ return true;
+}
+
+bool HardwareDisplayPlaneAtomic::SetPlaneProps(drmModeAtomicReq* property_set) {
bool plane_set_succeeded =
- AddPropertyIfValid(property_set, id_, properties_.crtc_id) &&
- AddPropertyIfValid(property_set, id_, properties_.crtc_x) &&
- AddPropertyIfValid(property_set, id_, properties_.crtc_y) &&
- AddPropertyIfValid(property_set, id_, properties_.crtc_w) &&
- AddPropertyIfValid(property_set, id_, properties_.crtc_h) &&
- AddPropertyIfValid(property_set, id_, properties_.fb_id) &&
- AddPropertyIfValid(property_set, id_, properties_.src_x) &&
- AddPropertyIfValid(property_set, id_, properties_.src_y) &&
- AddPropertyIfValid(property_set, id_, properties_.src_w) &&
- AddPropertyIfValid(property_set, id_, properties_.src_h);
-
- if (properties_.rotation.id) {
- properties_.rotation.value =
- OverlayTransformToDrmRotationPropertyValue(transform);
- plane_set_succeeded =
- plane_set_succeeded &&
- AddPropertyIfValid(property_set, id_, properties_.rotation);
+ AddPropertyIfValid(property_set, id_, assigned_props_.crtc_id) &&
+ AddPropertyIfValid(property_set, id_, assigned_props_.crtc_x) &&
+ AddPropertyIfValid(property_set, id_, assigned_props_.crtc_y) &&
+ AddPropertyIfValid(property_set, id_, assigned_props_.crtc_w) &&
+ AddPropertyIfValid(property_set, id_, assigned_props_.crtc_h) &&
+ AddPropertyIfValid(property_set, id_, assigned_props_.fb_id) &&
+ AddPropertyIfValid(property_set, id_, assigned_props_.src_x) &&
+ AddPropertyIfValid(property_set, id_, assigned_props_.src_y) &&
+ AddPropertyIfValid(property_set, id_, assigned_props_.src_w) &&
+ AddPropertyIfValid(property_set, id_, assigned_props_.src_h);
+
+ if (assigned_props_.rotation.id) {
+ plane_set_succeeded &=
+ AddPropertyIfValid(property_set, id_, assigned_props_.rotation);
}
- if (properties_.in_fence_fd.id && in_fence_fd >= 0) {
- properties_.in_fence_fd.value = in_fence_fd;
- plane_set_succeeded =
- plane_set_succeeded &&
- AddPropertyIfValid(property_set, id_, properties_.in_fence_fd);
+ if (assigned_props_.in_fence_fd.id) {
+ plane_set_succeeded &=
+ AddPropertyIfValid(property_set, id_, assigned_props_.in_fence_fd);
}
- if (properties_.plane_color_encoding.id) {
- properties_.plane_color_encoding.value = color_encoding_bt601_;
- properties_.plane_color_range.value = color_range_limited_;
- plane_set_succeeded =
- plane_set_succeeded &&
- AddPropertyIfValid(property_set, id_,
- properties_.plane_color_encoding) &&
- AddPropertyIfValid(property_set, id_, properties_.plane_color_range);
+ if (assigned_props_.plane_color_encoding.id) {
+ // TODO(markyacoub): |color_encoding_bt601_| and |color_range_limited_| are
+ // only set in Initialize(). The properties could be set once in there and
+ // these member variables could be removed.
+ assigned_props_.plane_color_encoding.value = color_encoding_bt601_;
+ assigned_props_.plane_color_range.value = color_range_limited_;
+ plane_set_succeeded &= AddPropertyIfValid(
+ property_set, id_, assigned_props_.plane_color_encoding);
+ plane_set_succeeded &= AddPropertyIfValid(
+ property_set, id_, assigned_props_.plane_color_range);
}
if (!plane_set_succeeded) {
@@ -140,7 +153,8 @@ bool HardwareDisplayPlaneAtomic::SetPlaneData(
return false;
}
- crtc_id_ = crtc_id;
+ // Update properties_ if the setting the props succeeded.
+ properties_ = assigned_props_;
return true;
}
@@ -153,4 +167,8 @@ bool HardwareDisplayPlaneAtomic::SetPlaneCtm(drmModeAtomicReq* property_set,
return AddPropertyIfValid(property_set, id_, properties_.plane_ctm);
}
+uint32_t HardwareDisplayPlaneAtomic::AssignedCrtcId() const {
+ return assigned_props_.crtc_id.value;
+}
+
} // namespace ui
diff --git a/chromium/ui/ozone/platform/drm/gpu/hardware_display_plane_atomic.h b/chromium/ui/ozone/platform/drm/gpu/hardware_display_plane_atomic.h
index af874abf6c7..5043b987468 100644
--- a/chromium/ui/ozone/platform/drm/gpu/hardware_display_plane_atomic.h
+++ b/chromium/ui/ozone/platform/drm/gpu/hardware_display_plane_atomic.h
@@ -20,25 +20,28 @@ namespace ui {
class HardwareDisplayPlaneAtomic : public HardwareDisplayPlane {
public:
- HardwareDisplayPlaneAtomic(uint32_t id);
+ explicit HardwareDisplayPlaneAtomic(uint32_t id);
~HardwareDisplayPlaneAtomic() override;
bool Initialize(DrmDevice* drm) override;
- virtual bool SetPlaneData(drmModeAtomicReq* property_set,
- uint32_t crtc_id,
- uint32_t framebuffer,
- const gfx::Rect& crtc_rect,
- const gfx::Rect& src_rect,
- const gfx::OverlayTransform transform,
- int in_fence_fd);
+ // Saves the props locally onto the plane to be committed later.
+ virtual bool AssignPlaneProps(uint32_t crtc_id,
+ uint32_t framebuffer,
+ const gfx::Rect& crtc_rect,
+ const gfx::Rect& src_rect,
+ const gfx::OverlayTransform transform,
+ int in_fence_fd);
+ // Sets the props on |property_set| for commit.
+ bool SetPlaneProps(drmModeAtomicReq* property_set);
bool SetPlaneCtm(drmModeAtomicReq* property_set, uint32_t ctm_blob_id);
- uint32_t crtc_id() { return crtc_id_; }
+ uint32_t AssignedCrtcId() const;
private:
- uint32_t crtc_id_ = 0;
+ // Intermediate variable between Assign()ment and Set()ting.
+ HardwareDisplayPlane::Properties assigned_props_;
DISALLOW_COPY_AND_ASSIGN(HardwareDisplayPlaneAtomic);
};
diff --git a/chromium/ui/ozone/platform/drm/gpu/hardware_display_plane_dummy.cc b/chromium/ui/ozone/platform/drm/gpu/hardware_display_plane_dummy.cc
deleted file mode 100644
index d00a0a1a56a..00000000000
--- a/chromium/ui/ozone/platform/drm/gpu/hardware_display_plane_dummy.cc
+++ /dev/null
@@ -1,26 +0,0 @@
-// Copyright 2018 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 "ui/ozone/platform/drm/gpu/hardware_display_plane_dummy.h"
-
-#include <drm_fourcc.h>
-
-namespace ui {
-
-HardwareDisplayPlaneDummy::HardwareDisplayPlaneDummy(uint32_t id,
- uint32_t crtc_mask)
- : HardwareDisplayPlane(id) {
- crtc_mask_ = crtc_mask;
-}
-
-HardwareDisplayPlaneDummy::~HardwareDisplayPlaneDummy() {}
-
-bool HardwareDisplayPlaneDummy::Initialize(DrmDevice* drm) {
- type_ = kDummy;
- supported_formats_.push_back(DRM_FORMAT_XRGB8888);
- supported_formats_.push_back(DRM_FORMAT_XBGR8888);
- return true;
-}
-
-} // namespace ui
diff --git a/chromium/ui/ozone/platform/drm/gpu/hardware_display_plane_dummy.h b/chromium/ui/ozone/platform/drm/gpu/hardware_display_plane_dummy.h
deleted file mode 100644
index 8aadee80506..00000000000
--- a/chromium/ui/ozone/platform/drm/gpu/hardware_display_plane_dummy.h
+++ /dev/null
@@ -1,27 +0,0 @@
-// Copyright 2018 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.
-
-#ifndef UI_OZONE_PLATFORM_DRM_GPU_HARDWARE_DISPLAY_PLANE_DUMMY_H_
-#define UI_OZONE_PLATFORM_DRM_GPU_HARDWARE_DISPLAY_PLANE_DUMMY_H_
-
-#include "ui/ozone/platform/drm/gpu/hardware_display_plane.h"
-
-namespace ui {
-
-// Fake plane used with DRM legacy when universal planes are not supported and
-// the kernel doesn't report the primary plane.
-class HardwareDisplayPlaneDummy : public HardwareDisplayPlane {
- public:
- HardwareDisplayPlaneDummy(uint32_t id, uint32_t crtc_mask);
- ~HardwareDisplayPlaneDummy() override;
-
- bool Initialize(DrmDevice* drm) override;
-
- private:
- DISALLOW_COPY_AND_ASSIGN(HardwareDisplayPlaneDummy);
-};
-
-} // namespace ui
-
-#endif // UI_OZONE_PLATFORM_DRM_GPU_HARDWARE_DISPLAY_PLANE_DUMMY_H_
diff --git a/chromium/ui/ozone/platform/drm/gpu/hardware_display_plane_manager.cc b/chromium/ui/ozone/platform/drm/gpu/hardware_display_plane_manager.cc
index 0cdaaca15cf..634fb042481 100644
--- a/chromium/ui/ozone/platform/drm/gpu/hardware_display_plane_manager.cc
+++ b/chromium/ui/ozone/platform/drm/gpu/hardware_display_plane_manager.cc
@@ -10,19 +10,16 @@
#include <set>
#include <utility>
+#include "base/containers/flat_set.h"
#include "base/logging.h"
#include "ui/gfx/geometry/rect.h"
+#include "ui/gfx/geometry/rect_conversions.h"
#include "ui/ozone/platform/drm/gpu/drm_device.h"
#include "ui/ozone/platform/drm/gpu/drm_framebuffer.h"
#include "ui/ozone/platform/drm/gpu/drm_gpu_util.h"
#include "ui/ozone/platform/drm/gpu/hardware_display_plane.h"
namespace ui {
-namespace {
-
-constexpr float kFixedPointScaleValue = 1 << 16;
-
-} // namespace
HardwareDisplayPlaneList::HardwareDisplayPlaneList() {
atomic_property_set.reset(drmModeAtomicAlloc());
@@ -51,12 +48,14 @@ HardwareDisplayPlaneManager::HardwareDisplayPlaneManager(DrmDevice* drm)
HardwareDisplayPlaneManager::~HardwareDisplayPlaneManager() = default;
bool HardwareDisplayPlaneManager::Initialize() {
-// Try to get all of the planes if possible, so we don't have to try to
-// discover hidden primary planes.
-#if defined(DRM_CLIENT_CAP_UNIVERSAL_PLANES)
+ // Try to get all of the planes if possible, so we don't have to try to
+ // discover hidden primary planes.
has_universal_planes_ =
drm_->SetCapability(DRM_CLIENT_CAP_UNIVERSAL_PLANES, 1);
-#endif
+
+ // This is to test whether or not it is safe to remove non-universal planes
+ // supporting code in a following CL. See crbug.com/1129546 for more details.
+ CHECK(has_universal_planes_);
if (!InitializeCrtcState())
return false;
@@ -113,7 +112,7 @@ int HardwareDisplayPlaneManager::LookupConnectorIndex(
bool HardwareDisplayPlaneManager::IsCompatible(HardwareDisplayPlane* plane,
const DrmOverlayPlane& overlay,
uint32_t crtc_index) const {
- if (plane->type() == HardwareDisplayPlane::kCursor ||
+ if (plane->type() == DRM_PLANE_TYPE_CURSOR ||
!plane->CanUseForCrtc(crtc_index))
return false;
@@ -154,6 +153,19 @@ void HardwareDisplayPlaneManager::ResetCurrentPlaneList(
plane_list->atomic_property_set.reset(drmModeAtomicAlloc());
}
+void HardwareDisplayPlaneManager::RestoreCurrentPlaneList(
+ HardwareDisplayPlaneList* plane_list) const {
+ for (auto* plane : plane_list->plane_list) {
+ plane->set_in_use(false);
+ }
+ for (auto* plane : plane_list->old_plane_list) {
+ plane->set_in_use(true);
+ }
+ plane_list->plane_list.clear();
+ plane_list->legacy_page_flips.clear();
+ plane_list->atomic_property_set.reset(drmModeAtomicAlloc());
+}
+
void HardwareDisplayPlaneManager::BeginFrame(
HardwareDisplayPlaneList* plane_list) {
for (auto* plane : plane_list->old_plane_list) {
@@ -176,30 +188,23 @@ bool HardwareDisplayPlaneManager::AssignOverlayPlanes(
HardwareDisplayPlane* hw_plane =
FindNextUnusedPlane(&plane_idx, crtc_index, plane);
if (!hw_plane) {
- LOG(ERROR) << "Failed to find a free plane for crtc " << crtc_id;
- ResetCurrentPlaneList(plane_list);
+ RestoreCurrentPlaneList(plane_list);
return false;
}
gfx::Rect fixed_point_rect;
- if (hw_plane->type() != HardwareDisplayPlane::kDummy) {
- const gfx::Size& size = plane.buffer->size();
- gfx::RectF crop_rect = plane.crop_rect;
- crop_rect.Scale(size.width(), size.height());
-
- // This returns a number in 16.16 fixed point, required by the DRM overlay
- // APIs.
- auto to_fixed_point = [](double v) -> uint32_t {
- return v * kFixedPointScaleValue;
- };
- fixed_point_rect = gfx::Rect(to_fixed_point(crop_rect.x()),
- to_fixed_point(crop_rect.y()),
- to_fixed_point(crop_rect.width()),
- to_fixed_point(crop_rect.height()));
- }
+ const gfx::Size& size = plane.buffer->size();
+ gfx::RectF crop_rectf = plane.crop_rect;
+ crop_rectf.Scale(size.width(), size.height());
+ // DrmOverlayManager::CanHandleCandidate guarantees this is safe.
+ gfx::Rect crop_rect = gfx::ToNearestRect(crop_rectf);
+ // Convert to 16.16 fixed point required by the DRM overlay APIs.
+ fixed_point_rect =
+ gfx::Rect(crop_rect.x() << 16, crop_rect.y() << 16,
+ crop_rect.width() << 16, crop_rect.height() << 16);
if (!SetPlaneData(plane_list, hw_plane, plane, crtc_id, fixed_point_rect)) {
- ResetCurrentPlaneList(plane_list);
+ RestoreCurrentPlaneList(plane_list);
return false;
}
@@ -222,7 +227,7 @@ std::vector<uint64_t> HardwareDisplayPlaneManager::GetFormatModifiers(
for (const auto& plane : planes_) {
if (plane->CanUseForCrtc(crtc_index) &&
- plane->type() == HardwareDisplayPlane::kPrimary) {
+ plane->type() == DRM_PLANE_TYPE_PRIMARY) {
return plane->ModifiersForFormat(format);
}
}
@@ -345,6 +350,7 @@ bool HardwareDisplayPlaneManager::InitializeCrtcState() {
return false;
}
+ DisableConnectedConnectorsToCrtcs(resources);
ResetConnectorsCache(resources);
unsigned int num_crtcs_with_out_fence_ptr = 0;
@@ -401,4 +407,85 @@ bool HardwareDisplayPlaneManager::InitializeCrtcState() {
return true;
}
+void HardwareDisplayPlaneManager::DisableConnectedConnectorsToCrtcs(
+ const ScopedDrmResourcesPtr& resources) {
+ // Should only be called when no CRTC state has been set yet because we
+ // hard-disable CRTCs.
+ DCHECK(crtc_state_.empty());
+
+ for (int i = 0; i < resources->count_connectors; ++i) {
+ ScopedDrmConnectorPtr connector =
+ drm_->GetConnector(resources->connectors[i]);
+ if (!connector)
+ continue;
+ // Disable Zombie connectors (disconnected connectors but holding to an
+ // encoder).
+ if (connector->encoder_id &&
+ connector->connection == DRM_MODE_DISCONNECTED) {
+ ScopedDrmEncoderPtr encoder(
+ drmModeGetEncoder(drm_->get_fd(), connector->encoder_id));
+ if (encoder)
+ drm_->DisableCrtc(encoder->crtc_id);
+ }
+ }
+}
+
+const HardwareDisplayPlaneManager::CrtcState&
+HardwareDisplayPlaneManager::GetCrtcStateForCrtcId(uint32_t crtc_id) {
+ return CrtcStateForCrtcId(crtc_id);
+}
+
+HardwareDisplayPlaneManager::CrtcState&
+HardwareDisplayPlaneManager::CrtcStateForCrtcId(uint32_t crtc_id) {
+ int crtc_index = LookupCrtcIndex(crtc_id);
+ DCHECK_GE(crtc_index, 0);
+ return crtc_state_[crtc_index];
+}
+
+void HardwareDisplayPlaneManager::UpdateCrtcAndPlaneStatesAfterModeset(
+ const CommitRequest& commit_request) {
+ base::flat_set<HardwareDisplayPlaneList*> disable_planes_lists;
+
+ for (const auto& crtc_request : commit_request) {
+ bool is_enabled = crtc_request.should_enable();
+
+ int connector_index = LookupConnectorIndex(crtc_request.connector_id());
+ DCHECK_GE(connector_index, 0);
+ ConnectorProperties& connector_props = connectors_props_[connector_index];
+ connector_props.crtc_id.value = is_enabled ? crtc_request.crtc_id() : 0;
+
+ CrtcState& crtc_state = CrtcStateForCrtcId(crtc_request.crtc_id());
+ crtc_state.properties.active.value = static_cast<uint64_t>(is_enabled);
+
+ if (is_enabled) {
+ crtc_state.mode = crtc_request.mode();
+ crtc_state.modeset_framebuffer =
+ DrmOverlayPlane::GetPrimaryPlane(crtc_request.overlays())->buffer;
+ } else {
+ if (crtc_request.plane_list())
+ disable_planes_lists.insert(crtc_request.plane_list());
+
+ // TODO(crbug/1135291): Use atomic APIs to reset cursor plane.
+ if (!drm_->SetCursor(crtc_request.crtc_id(), 0, gfx::Size())) {
+ PLOG(ERROR) << "Failed to drmModeSetCursor: device:"
+ << drm_->device_path().value()
+ << " crtc:" << crtc_request.crtc_id();
+ }
+ }
+ }
+
+ // TODO(markyacoub): DisableOverlayPlanes should be part of the commit
+ // request.
+ for (HardwareDisplayPlaneList* list : disable_planes_lists) {
+ bool status = DisableOverlayPlanes(list);
+ LOG_IF(ERROR, !status) << "Can't disable overlays when disabling HDC.";
+ list->plane_list.clear();
+ }
+}
+
+void HardwareDisplayPlaneManager::ResetModesetBufferOfCrtc(uint32_t crtc_id) {
+ CrtcState& crtc_state = CrtcStateForCrtcId(crtc_id);
+ crtc_state.modeset_framebuffer = nullptr;
+}
+
} // namespace ui
diff --git a/chromium/ui/ozone/platform/drm/gpu/hardware_display_plane_manager.h b/chromium/ui/ozone/platform/drm/gpu/hardware_display_plane_manager.h
index b2443c90b07..dd25a23e0b1 100644
--- a/chromium/ui/ozone/platform/drm/gpu/hardware_display_plane_manager.h
+++ b/chromium/ui/ozone/platform/drm/gpu/hardware_display_plane_manager.h
@@ -14,6 +14,7 @@
#include "base/macros.h"
#include "ui/display/types/gamma_ramp_rgb_entry.h"
#include "ui/ozone/platform/drm/common/scoped_drm_types.h"
+#include "ui/ozone/platform/drm/gpu/crtc_commit_request.h"
#include "ui/ozone/platform/drm/gpu/drm_device.h"
#include "ui/ozone/platform/drm/gpu/drm_overlay_plane.h"
#include "ui/ozone/public/swap_completion_callback.h"
@@ -56,6 +57,42 @@ struct HardwareDisplayPlaneList {
class HardwareDisplayPlaneManager {
public:
+ struct CrtcProperties {
+ // Unique identifier for the CRTC. This must be greater than 0 to be valid.
+ uint32_t id;
+ // Keeps track of the CRTC state. If a surface has been bound, then the
+ // value is set to true. Otherwise it is false.
+ DrmDevice::Property active;
+ DrmDevice::Property mode_id;
+ // Optional properties.
+ DrmDevice::Property ctm;
+ DrmDevice::Property gamma_lut;
+ DrmDevice::Property gamma_lut_size;
+ DrmDevice::Property degamma_lut;
+ DrmDevice::Property degamma_lut_size;
+ DrmDevice::Property out_fence_ptr;
+ DrmDevice::Property background_color;
+ };
+
+ struct CrtcState {
+ CrtcState();
+ ~CrtcState();
+ CrtcState(const CrtcState&) = delete;
+ CrtcState& operator=(const CrtcState&) = delete;
+ CrtcState(CrtcState&&);
+
+ drmModeModeInfo mode = {};
+ scoped_refptr<DrmFramebuffer> modeset_framebuffer;
+
+ CrtcProperties properties = {};
+
+ // Cached blobs for the properties since the CRTC properties are applied on
+ // the next page flip and we need to keep the properties valid until then.
+ ScopedDrmPropertyBlob ctm_blob;
+ ScopedDrmPropertyBlob gamma_lut_blob;
+ ScopedDrmPropertyBlob degamma_lut_blob;
+ };
+
explicit HardwareDisplayPlaneManager(DrmDevice* drm);
virtual ~HardwareDisplayPlaneManager();
@@ -63,14 +100,13 @@ class HardwareDisplayPlaneManager {
// or crtcs found.
bool Initialize();
- // Performs modesetting, either atomic or legacy, depending on the device.
- virtual bool Modeset(uint32_t crtc_id,
- uint32_t framebuffer_id,
- uint32_t connector_id,
- const drmModeModeInfo& mode,
- const HardwareDisplayPlaneList& plane_list) = 0;
-
- virtual bool DisableModeset(uint32_t crtc_id, uint32_t connector) = 0;
+ // |commit_request| contains all the necessary information to build the
+ // atomic/legacy request. It acts as a thin wrapper that looks like the atomic
+ // request. It then gets converted into an atomic request for DRM atomic and
+ // has all the parameters for a legacy request.
+ // TODO(markyacoub): Consolidate this Commit() with the overloaded page flip
+ // Commit() down below.
+ virtual bool Commit(CommitRequest commit_request, uint32_t flags) = 0;
// Clears old frame state out. Must be called before any AssignOverlayPlanes
// calls.
@@ -97,7 +133,7 @@ class HardwareDisplayPlaneManager {
uint32_t crtc_id);
// Commit the plane states in |plane_list|.
- //
+ // if |should_modeset| is set, it only modesets without page flipping.
// If |page_flip_request| is null, this tests the plane configuration without
// submitting it.
// The fence returned in |out_fence| will signal when the currently scanned
@@ -105,6 +141,7 @@ class HardwareDisplayPlaneManager {
// |page_flip_request|. Note that the returned fence may be a nullptr
// if the system doesn't support out fences.
virtual bool Commit(HardwareDisplayPlaneList* plane_list,
+ bool should_modeset,
scoped_refptr<PageFlipRequest> page_flip_request,
std::unique_ptr<gfx::GpuFence>* out_fence) = 0;
@@ -145,44 +182,35 @@ class HardwareDisplayPlaneManager {
// called whenever a DRM hotplug event is received via UDEV.
void ResetConnectorsCache(const ScopedDrmResourcesPtr& resources);
+ // Get Immutable CRTC State.
+ const CrtcState& GetCrtcStateForCrtcId(uint32_t crtc_id);
+
+ // TODO(markyacoub): this seems hacky, this could be cleaned up a bit. Clarify
+ // which resources needed to be tracked internally in
+ // HardwareDisplayPlaneManager and which should be taken care of by the
+ // caller.
+ void ResetModesetBufferOfCrtc(uint32_t crtc_id);
+
protected:
struct ConnectorProperties {
uint32_t id;
DrmDevice::Property crtc_id;
};
- struct CrtcProperties {
- // Unique identifier for the CRTC. This must be greater than 0 to be valid.
- uint32_t id;
- DrmDevice::Property active;
- DrmDevice::Property mode_id;
- // Optional properties.
- DrmDevice::Property ctm;
- DrmDevice::Property gamma_lut;
- DrmDevice::Property gamma_lut_size;
- DrmDevice::Property degamma_lut;
- DrmDevice::Property degamma_lut_size;
- DrmDevice::Property out_fence_ptr;
- DrmDevice::Property background_color;
- };
-
- struct CrtcState {
- CrtcState();
- ~CrtcState();
- CrtcState(CrtcState&&);
-
- CrtcProperties properties = {};
-
- // Cached blobs for the properties since the CRTC properties are applied on
- // the next page flip and we need to keep the properties valid until then.
- ScopedDrmPropertyBlob ctm_blob;
- ScopedDrmPropertyBlob gamma_lut_blob;
- ScopedDrmPropertyBlob degamma_lut_blob;
+ bool InitializeCrtcState();
- DISALLOW_COPY_AND_ASSIGN(CrtcState);
- };
+ void UpdateCrtcAndPlaneStatesAfterModeset(
+ const CommitRequest& commit_request);
- bool InitializeCrtcState();
+ // As the CRTC is being initialized, all connectors connected to it should
+ // be disabled. This is a workaround for a bug on Hatch where Puff enables
+ // a connector in dev mode before Chrome even starts. The kernel maps the HW
+ // state at initial modeset (with a dangling connector attached to a CRTC).
+ // When an Atomic Modeset is performed, it fails to modeset as the CRTC is
+ // already attached to another dead connector. (Analysis: crbug/1067121#c5)
+ // TODO(b/168154314): Remove this call when the bug is fixed.
+ void DisableConnectedConnectorsToCrtcs(
+ const ScopedDrmResourcesPtr& resources);
virtual bool InitializePlanes() = 0;
@@ -206,13 +234,22 @@ class HardwareDisplayPlaneManager {
int LookupCrtcIndex(uint32_t crtc_id) const;
int LookupConnectorIndex(uint32_t connector_idx) const;
+ // Get Mutable CRTC State.
+ CrtcState& CrtcStateForCrtcId(uint32_t crtc_id);
+
// Returns true if |plane| can support |overlay| and compatible with
// |crtc_index|.
virtual bool IsCompatible(HardwareDisplayPlane* plane,
const DrmOverlayPlane& overlay,
uint32_t crtc_index) const;
+ // Resets |plane_list| setting all planes to unused.
+ // Frees any temporary data structure in |plane_list| used for pageflipping.
void ResetCurrentPlaneList(HardwareDisplayPlaneList* plane_list) const;
+ // Restores |plane_list| planes |in_use| flag to what it was before
+ // BeginFrame was called.
+ // Frees any temporary data structure in |plane_list| used for pageflipping.
+ void RestoreCurrentPlaneList(HardwareDisplayPlaneList* plane_list) const;
// Populates scanout formats supported by all planes.
void PopulateSupportedFormats();
diff --git a/chromium/ui/ozone/platform/drm/gpu/hardware_display_plane_manager_atomic.cc b/chromium/ui/ozone/platform/drm/gpu/hardware_display_plane_manager_atomic.cc
index 2bdf60aba9d..7c3a287b4ca 100644
--- a/chromium/ui/ozone/platform/drm/gpu/hardware_display_plane_manager_atomic.cc
+++ b/chromium/ui/ozone/platform/drm/gpu/hardware_display_plane_manager_atomic.cc
@@ -11,6 +11,7 @@
#include <utility>
#include "base/bind.h"
+#include "base/containers/flat_set.h"
#include "base/files/platform_file.h"
#include "base/logging.h"
#include "base/stl_util.h"
@@ -44,14 +45,25 @@ std::unique_ptr<gfx::GpuFence> CreateMergedGpuFenceFromFDs(
if (merged_fd.is_valid()) {
gfx::GpuFenceHandle handle;
- handle.type = gfx::GpuFenceHandleType::kAndroidNativeFenceSync;
- handle.native_fd = base::FileDescriptor(std::move(merged_fd));
- return std::make_unique<gfx::GpuFence>(handle);
+ handle.owned_fd = std::move(merged_fd);
+ return std::make_unique<gfx::GpuFence>(std::move(handle));
}
return nullptr;
}
+std::vector<uint32_t> GetCrtcIdsOfPlanes(
+ const HardwareDisplayPlaneList& plane_list) {
+ std::vector<uint32_t> crtcs;
+ for (HardwareDisplayPlane* plane : plane_list.plane_list) {
+ HardwareDisplayPlaneAtomic* atomic_plane =
+ static_cast<HardwareDisplayPlaneAtomic*>(plane);
+ if (crtcs.empty() || crtcs.back() != atomic_plane->AssignedCrtcId())
+ crtcs.push_back(atomic_plane->AssignedCrtcId());
+ }
+ return crtcs;
+}
+
} // namespace
HardwareDisplayPlaneManagerAtomic::HardwareDisplayPlaneManagerAtomic(
@@ -61,66 +73,144 @@ HardwareDisplayPlaneManagerAtomic::HardwareDisplayPlaneManagerAtomic(
HardwareDisplayPlaneManagerAtomic::~HardwareDisplayPlaneManagerAtomic() =
default;
-bool HardwareDisplayPlaneManagerAtomic::Modeset(
+bool HardwareDisplayPlaneManagerAtomic::SetCrtcProps(
+ drmModeAtomicReq* atomic_request,
uint32_t crtc_id,
- uint32_t framebuffer_id,
+ bool set_active,
+ uint32_t mode_id) {
+ // Only making a copy here to retrieve the the props IDs. The state will be
+ // updated only after a successful modeset.
+ CrtcProperties modeset_props = GetCrtcStateForCrtcId(crtc_id).properties;
+ modeset_props.active.value = static_cast<uint64_t>(set_active);
+ modeset_props.mode_id.value = mode_id;
+
+ bool status =
+ AddPropertyIfValid(atomic_request, crtc_id, modeset_props.active);
+ status &= AddPropertyIfValid(atomic_request, crtc_id, modeset_props.mode_id);
+ return status;
+}
+
+bool HardwareDisplayPlaneManagerAtomic::SetConnectorProps(
+ drmModeAtomicReq* atomic_request,
uint32_t connector_id,
- const drmModeModeInfo& mode,
- const HardwareDisplayPlaneList&) {
- return drm_->SetCrtc(crtc_id, framebuffer_id,
- std::vector<uint32_t>(1, connector_id), mode);
+ uint32_t crtc_id) {
+ int connector_index = LookupConnectorIndex(connector_id);
+ DCHECK_GE(connector_index, 0);
+ // Only making a copy here to retrieve the the props IDs. The state will be
+ // updated only after a successful modeset.
+ ConnectorProperties connector_props = connectors_props_[connector_index];
+ connector_props.crtc_id.value = crtc_id;
+
+ return AddPropertyIfValid(atomic_request, connector_id,
+ connector_props.crtc_id);
}
-bool HardwareDisplayPlaneManagerAtomic::DisableModeset(uint32_t crtc_id,
- uint32_t connector) {
- ScopedDrmAtomicReqPtr property_set(drmModeAtomicAlloc());
+bool HardwareDisplayPlaneManagerAtomic::Commit(CommitRequest commit_request,
+ uint32_t flags) {
+ bool is_testing = flags & DRM_MODE_ATOMIC_TEST_ONLY;
+ bool status = true;
+
+ std::vector<ScopedDrmPropertyBlob> scoped_blobs;
+
+ base::flat_set<HardwareDisplayPlaneList*> enable_planes_lists;
+ base::flat_set<HardwareDisplayPlaneList*> all_planes_lists;
+
+ ScopedDrmAtomicReqPtr atomic_request(drmModeAtomicAlloc());
+
+ for (const auto& crtc_request : commit_request) {
+ if (crtc_request.plane_list())
+ all_planes_lists.insert(crtc_request.plane_list());
+
+ uint32_t mode_id = 0;
+ if (crtc_request.should_enable()) {
+ auto mode_blob = drm_->CreatePropertyBlob(&crtc_request.mode(),
+ sizeof(crtc_request.mode()));
+ status &= (mode_blob != nullptr);
+ if (mode_blob) {
+ scoped_blobs.push_back(std::move(mode_blob));
+ mode_id = scoped_blobs.back()->id();
+ }
+ }
- const int connector_idx = LookupConnectorIndex(connector);
- DCHECK_GE(connector_idx, 0);
- connectors_props_[connector_idx].crtc_id.value = 0UL;
- bool res = AddPropertyIfValid(property_set.get(), connector,
- connectors_props_[connector_idx].crtc_id);
-
- const int crtc_idx = LookupCrtcIndex(crtc_id);
- DCHECK_GE(crtc_idx, 0);
- crtc_state_[crtc_idx].properties.active.value = 0UL;
- crtc_state_[crtc_idx].properties.mode_id.value = 0UL;
- res &= AddPropertyIfValid(property_set.get(), crtc_id,
- crtc_state_[crtc_idx].properties.active);
- res &= AddPropertyIfValid(property_set.get(), crtc_id,
- crtc_state_[crtc_idx].properties.mode_id);
-
- DCHECK(res);
- return drm_->CommitProperties(property_set.get(),
- DRM_MODE_ATOMIC_ALLOW_MODESET, 1, nullptr);
+ uint32_t crtc_id = crtc_request.crtc_id();
+
+ status &= SetCrtcProps(atomic_request.get(), crtc_id,
+ crtc_request.should_enable(), mode_id);
+ status &=
+ SetConnectorProps(atomic_request.get(), crtc_request.connector_id(),
+ crtc_request.should_enable() * crtc_id);
+
+ if (crtc_request.should_enable()) {
+ DCHECK(crtc_request.plane_list());
+ status &= AssignOverlayPlanes(crtc_request.plane_list(),
+ crtc_request.overlays(), crtc_id);
+ enable_planes_lists.insert(crtc_request.plane_list());
+ }
+ }
+
+ // TODO(markyacoub): Ideally this doesn't need to be a separate step. It
+ // should all be handled in Set{Crtc,Connector,Plane}Props() modulo some state
+ // tracking changes that should be done post commit. Break it apart when both
+ // Commit() are consolidated.
+ for (HardwareDisplayPlaneList* list : enable_planes_lists) {
+ SetAtomicPropsForCommit(atomic_request.get(), list,
+ GetCrtcIdsOfPlanes(*list), is_testing);
+ }
+
+ // TODO(markyacoub): failed |status|'s should be made as DCHECKs. The only
+ // reason some of these would be failing is OOM. If we OOM-ed there's no point
+ // in trying to recover.
+ if (!status || !drm_->CommitProperties(atomic_request.get(), flags,
+ commit_request.size(), nullptr)) {
+ if (is_testing)
+ VPLOG(2) << "Modeset Test is rejected.";
+ else
+ PLOG(ERROR) << "Failed to commit properties for modeset.";
+
+ for (HardwareDisplayPlaneList* list : all_planes_lists)
+ ResetCurrentPlaneList(list);
+
+ return false;
+ }
+
+ if (!is_testing)
+ UpdateCrtcAndPlaneStatesAfterModeset(commit_request);
+
+ for (HardwareDisplayPlaneList* list : enable_planes_lists)
+ list->plane_list.clear();
+
+ return true;
}
-bool HardwareDisplayPlaneManagerAtomic::Commit(
+void HardwareDisplayPlaneManagerAtomic::SetAtomicPropsForCommit(
+ drmModeAtomicReq* atomic_request,
HardwareDisplayPlaneList* plane_list,
- scoped_refptr<PageFlipRequest> page_flip_request,
- std::unique_ptr<gfx::GpuFence>* out_fence) {
- bool test_only = !page_flip_request;
+ const std::vector<uint32_t>& crtcs,
+ bool test_only) {
+ for (HardwareDisplayPlane* plane : plane_list->plane_list) {
+ HardwareDisplayPlaneAtomic* atomic_plane =
+ static_cast<HardwareDisplayPlaneAtomic*>(plane);
+ atomic_plane->SetPlaneProps(atomic_request);
+ }
+
for (HardwareDisplayPlane* plane : plane_list->old_plane_list) {
if (!base::Contains(plane_list->plane_list, plane)) {
- // This plane is being released, so we need to zero it.
+ // |plane| is shared state between |old_plane_list| and |plane_list|.
+ // When we call BeginFrame(), we reset in_use since we need to be able to
+ // allocate the planes as needed. The current frame might not need to use
+ // |plane|, thus |plane->in_use()| would be false even though the previous
+ // frame used it. It's existence in |old_plane_list| is sufficient to
+ // signal that |plane| was in use previously.
plane->set_in_use(false);
HardwareDisplayPlaneAtomic* atomic_plane =
static_cast<HardwareDisplayPlaneAtomic*>(plane);
- atomic_plane->SetPlaneData(
- plane_list->atomic_property_set.get(), 0, 0, gfx::Rect(), gfx::Rect(),
- gfx::OVERLAY_TRANSFORM_NONE, base::kInvalidPlatformFile);
+ atomic_plane->AssignPlaneProps(0, 0, gfx::Rect(), gfx::Rect(),
+ gfx::OVERLAY_TRANSFORM_NONE,
+ base::kInvalidPlatformFile);
+ atomic_plane->SetPlaneProps(atomic_request);
}
}
- std::vector<uint32_t> crtcs;
- for (HardwareDisplayPlane* plane : plane_list->plane_list) {
- HardwareDisplayPlaneAtomic* atomic_plane =
- static_cast<HardwareDisplayPlaneAtomic*>(plane);
- if (crtcs.empty() || crtcs.back() != atomic_plane->crtc_id())
- crtcs.push_back(atomic_plane->crtc_id());
- }
-
- drmModeAtomicReqPtr request = plane_list->atomic_property_set.get();
for (uint32_t crtc : crtcs) {
int idx = LookupCrtcIndex(crtc);
@@ -129,29 +219,40 @@ bool HardwareDisplayPlaneManagerAtomic::Commit(
// swap chain for a vsync.
// TODO(dnicoara): See if we can apply these properties async using
// DRM_MODE_ATOMIC_ASYNC_UPDATE flag when committing.
- AddPropertyIfValid(request, crtc, crtc_state_[idx].properties.degamma_lut);
- AddPropertyIfValid(request, crtc, crtc_state_[idx].properties.gamma_lut);
- AddPropertyIfValid(request, crtc, crtc_state_[idx].properties.ctm);
+ AddPropertyIfValid(atomic_request, crtc,
+ crtc_state_[idx].properties.degamma_lut);
+ AddPropertyIfValid(atomic_request, crtc,
+ crtc_state_[idx].properties.gamma_lut);
+ AddPropertyIfValid(atomic_request, crtc, crtc_state_[idx].properties.ctm);
#endif
- AddPropertyIfValid(request, crtc,
+ AddPropertyIfValid(atomic_request, crtc,
crtc_state_[idx].properties.background_color);
}
if (test_only) {
- for (HardwareDisplayPlane* plane : plane_list->plane_list) {
+ for (auto* plane : plane_list->plane_list) {
plane->set_in_use(false);
}
+ for (auto* plane : plane_list->old_plane_list) {
+ plane->set_in_use(true);
+ }
} else {
plane_list->plane_list.swap(plane_list->old_plane_list);
}
+}
- uint32_t flags = 0;
- if (test_only) {
- flags = DRM_MODE_ATOMIC_TEST_ONLY;
- } else {
- flags = DRM_MODE_ATOMIC_NONBLOCK;
- }
+bool HardwareDisplayPlaneManagerAtomic::Commit(
+ HardwareDisplayPlaneList* plane_list,
+ bool should_modeset,
+ scoped_refptr<PageFlipRequest> page_flip_request,
+ std::unique_ptr<gfx::GpuFence>* out_fence) {
+ bool test_only = !should_modeset && !page_flip_request;
+
+ std::vector<uint32_t> crtcs = GetCrtcIdsOfPlanes(*plane_list);
+
+ SetAtomicPropsForCommit(plane_list->atomic_property_set.get(), plane_list,
+ crtcs, test_only);
// After we perform the atomic commit, and if the caller has requested an
// out-fence, the out_fence_fds vector will contain any provided out-fence
@@ -172,6 +273,12 @@ bool HardwareDisplayPlaneManagerAtomic::Commit(
}
}
+ uint32_t flags = 0;
+ if (should_modeset)
+ flags = DRM_MODE_ATOMIC_ALLOW_MODESET;
+ else
+ flags = test_only ? DRM_MODE_ATOMIC_TEST_ONLY : DRM_MODE_ATOMIC_NONBLOCK;
+
if (!drm_->CommitProperties(plane_list->atomic_property_set.get(), flags,
crtcs.size(), page_flip_request)) {
if (!test_only) {
@@ -196,16 +303,15 @@ bool HardwareDisplayPlaneManagerAtomic::Commit(
bool HardwareDisplayPlaneManagerAtomic::DisableOverlayPlanes(
HardwareDisplayPlaneList* plane_list) {
for (HardwareDisplayPlane* plane : plane_list->old_plane_list) {
- if (plane->type() != HardwareDisplayPlane::kOverlay)
- continue;
plane->set_in_use(false);
plane->set_owning_crtc(0);
HardwareDisplayPlaneAtomic* atomic_plane =
static_cast<HardwareDisplayPlaneAtomic*>(plane);
- atomic_plane->SetPlaneData(
- plane_list->atomic_property_set.get(), 0, 0, gfx::Rect(), gfx::Rect(),
- gfx::OVERLAY_TRANSFORM_NONE, base::kInvalidPlatformFile);
+ atomic_plane->AssignPlaneProps(0, 0, gfx::Rect(), gfx::Rect(),
+ gfx::OVERLAY_TRANSFORM_NONE,
+ base::kInvalidPlatformFile);
+ atomic_plane->SetPlaneProps(plane_list->atomic_property_set.get());
}
bool ret = drm_->CommitProperties(plane_list->atomic_property_set.get(),
DRM_MODE_ATOMIC_NONBLOCK, 0, nullptr);
@@ -273,19 +379,12 @@ bool HardwareDisplayPlaneManagerAtomic::SetPlaneData(
if (overlay.gpu_fence) {
const auto& gpu_fence_handle = overlay.gpu_fence->GetGpuFenceHandle();
- if (gpu_fence_handle.type !=
- gfx::GpuFenceHandleType::kAndroidNativeFenceSync) {
- LOG(ERROR) << "Received invalid gpu fence";
- return false;
- }
- fence_fd = gpu_fence_handle.native_fd.fd;
+ fence_fd = gpu_fence_handle.owned_fd.get();
}
- if (!atomic_plane->SetPlaneData(plane_list->atomic_property_set.get(),
- crtc_id, framebuffer_id,
- overlay.display_bounds, src_rect,
- overlay.plane_transform, fence_fd)) {
- LOG(ERROR) << "Failed to set plane properties";
+ if (!atomic_plane->AssignPlaneProps(crtc_id, framebuffer_id,
+ overlay.display_bounds, src_rect,
+ overlay.plane_transform, fence_fd)) {
return false;
}
return true;
@@ -376,7 +475,7 @@ bool HardwareDisplayPlaneManagerAtomic::CommitGammaCorrection(
}
bool HardwareDisplayPlaneManagerAtomic::AddOutFencePtrProperties(
- drmModeAtomicReqPtr property_set,
+ drmModeAtomicReq* property_set,
const std::vector<uint32_t>& crtcs,
std::vector<base::ScopedFD>* out_fence_fds,
std::vector<base::ScopedFD::Receiver>* out_fence_fd_receivers) {
diff --git a/chromium/ui/ozone/platform/drm/gpu/hardware_display_plane_manager_atomic.h b/chromium/ui/ozone/platform/drm/gpu/hardware_display_plane_manager_atomic.h
index 7567a9bab24..b6d717746b3 100644
--- a/chromium/ui/ozone/platform/drm/gpu/hardware_display_plane_manager_atomic.h
+++ b/chromium/ui/ozone/platform/drm/gpu/hardware_display_plane_manager_atomic.h
@@ -19,13 +19,10 @@ class HardwareDisplayPlaneManagerAtomic : public HardwareDisplayPlaneManager {
~HardwareDisplayPlaneManagerAtomic() override;
// HardwareDisplayPlaneManager:
- bool Modeset(uint32_t crtc_id,
- uint32_t framebuffer_id,
- uint32_t connector_id,
- const drmModeModeInfo& mode,
- const HardwareDisplayPlaneList& plane_list) override;
- bool DisableModeset(uint32_t crtc_id, uint32_t connector) override;
+ bool Commit(CommitRequest commit_request, uint32_t flags) override;
+
bool Commit(HardwareDisplayPlaneList* plane_list,
+ bool should_modeset,
scoped_refptr<PageFlipRequest> page_flip_request,
std::unique_ptr<gfx::GpuFence>* out_fence) override;
bool DisableOverlayPlanes(HardwareDisplayPlaneList* plane_list) override;
@@ -49,10 +46,23 @@ class HardwareDisplayPlaneManagerAtomic : public HardwareDisplayPlaneManager {
private:
bool InitializePlanes() override;
std::unique_ptr<HardwareDisplayPlane> CreatePlane(uint32_t plane_id) override;
+ void SetAtomicPropsForCommit(drmModeAtomicReq* atomic_request,
+ HardwareDisplayPlaneList* plane_list,
+ const std::vector<uint32_t>& crtcs,
+ bool test_only);
+
+ bool SetCrtcProps(drmModeAtomicReq* atomic_request,
+ uint32_t crtc_id,
+ bool set_active,
+ uint32_t mode_id);
+ bool SetConnectorProps(drmModeAtomicReq* atomic_request,
+ uint32_t connector_id,
+ uint32_t crtc_id);
+
bool CommitColorMatrix(const CrtcProperties& crtc_props) override;
bool CommitGammaCorrection(const CrtcProperties& crtc_props) override;
bool AddOutFencePtrProperties(
- drmModeAtomicReqPtr property_set,
+ drmModeAtomicReq* property_set,
const std::vector<uint32_t>& crtcs,
std::vector<base::ScopedFD>* out_fence_fds,
std::vector<base::ScopedFD::Receiver>* out_fence_fd_receivers);
diff --git a/chromium/ui/ozone/platform/drm/gpu/hardware_display_plane_manager_legacy.cc b/chromium/ui/ozone/platform/drm/gpu/hardware_display_plane_manager_legacy.cc
index 91926a0d2b2..298908088a0 100644
--- a/chromium/ui/ozone/platform/drm/gpu/hardware_display_plane_manager_legacy.cc
+++ b/chromium/ui/ozone/platform/drm/gpu/hardware_display_plane_manager_legacy.cc
@@ -20,7 +20,6 @@
#include "ui/ozone/platform/drm/gpu/drm_device.h"
#include "ui/ozone/platform/drm/gpu/drm_framebuffer.h"
#include "ui/ozone/platform/drm/gpu/hardware_display_plane.h"
-#include "ui/ozone/platform/drm/gpu/hardware_display_plane_dummy.h"
#include "ui/ozone/platform/drm/gpu/page_flip_request.h"
namespace ui {
@@ -47,25 +46,43 @@ HardwareDisplayPlaneManagerLegacy::HardwareDisplayPlaneManagerLegacy(
HardwareDisplayPlaneManagerLegacy::~HardwareDisplayPlaneManagerLegacy() =
default;
-bool HardwareDisplayPlaneManagerLegacy::Modeset(
- uint32_t crtc_id,
- uint32_t framebuffer_id,
- uint32_t connector_id,
- const drmModeModeInfo& mode,
- const HardwareDisplayPlaneList&) {
- return drm_->SetCrtc(crtc_id, framebuffer_id,
- std::vector<uint32_t>(1, connector_id), mode);
-}
+bool HardwareDisplayPlaneManagerLegacy::Commit(CommitRequest commit_request,
+ uint32_t flags) {
+ if (flags & DRM_MODE_ATOMIC_TEST_ONLY)
+ // Legacy DRM does not support testing.
+ return true;
+
+ bool status = true;
+ for (const auto& crtc_request : commit_request) {
+ if (crtc_request.should_enable()) {
+ // Overlays are not supported in legacy hence why we're only looking at
+ // the primary plane.
+ uint32_t fb_id = DrmOverlayPlane::GetPrimaryPlane(crtc_request.overlays())
+ ->buffer->opaque_framebuffer_id();
+ status &=
+ drm_->SetCrtc(crtc_request.crtc_id(), fb_id,
+ std::vector<uint32_t>(1, crtc_request.connector_id()),
+ crtc_request.mode());
+ } else {
+ drm_->DisableCrtc(crtc_request.crtc_id());
+ }
+ }
-bool HardwareDisplayPlaneManagerLegacy::DisableModeset(uint32_t crtc_id,
- uint32_t connector) {
- return drm_->DisableCrtc(crtc_id);
+ if (status)
+ UpdateCrtcAndPlaneStatesAfterModeset(commit_request);
+
+ return status;
}
bool HardwareDisplayPlaneManagerLegacy::Commit(
HardwareDisplayPlaneList* plane_list,
+ bool should_modeset,
scoped_refptr<PageFlipRequest> page_flip_request,
std::unique_ptr<gfx::GpuFence>* out_fence) {
+ // Legacy Modeset should not call Commit. Ensure the separation between both
+ // Atomic and Legacy and nothing trickles in.
+ DCHECK(!should_modeset);
+
bool test_only = !page_flip_request;
if (test_only) {
for (HardwareDisplayPlane* plane : plane_list->plane_list) {
@@ -114,7 +131,7 @@ bool HardwareDisplayPlaneManagerLegacy::DisableOverlayPlanes(
DCHECK(std::find_if(plane_list->old_plane_list.begin(),
plane_list->old_plane_list.end(),
[](HardwareDisplayPlane* plane) {
- return plane->type() == HardwareDisplayPlane::kOverlay;
+ return plane->type() == DRM_PLANE_TYPE_OVERLAY;
}) == plane_list->old_plane_list.end());
return true;
}
@@ -161,31 +178,12 @@ bool HardwareDisplayPlaneManagerLegacy::InitializePlanes() {
// Overlays are not supported on the legacy path, so ignore all overlay
// planes.
- if (plane->type() == HardwareDisplayPlane::kOverlay)
+ if (plane->type() == DRM_PLANE_TYPE_OVERLAY)
continue;
planes_.push_back(std::move(plane));
}
- // https://crbug.com/464085: if driver reports no primary planes for a crtc,
- // create a dummy plane for which we can assign exactly one overlay.
- if (!has_universal_planes_) {
- for (size_t i = 0; i < crtc_state_.size(); ++i) {
- uint32_t id = crtc_state_[i].properties.id - 1;
- if (std::find_if(
- planes_.begin(), planes_.end(),
- [id](const std::unique_ptr<HardwareDisplayPlane>& plane) {
- return plane->id() == id;
- }) == planes_.end()) {
- std::unique_ptr<HardwareDisplayPlane> dummy_plane(
- new HardwareDisplayPlaneDummy(id, 1 << i));
- if (dummy_plane->Initialize(drm_)) {
- planes_.push_back(std::move(dummy_plane));
- }
- }
- }
- }
-
return true;
}
@@ -201,9 +199,8 @@ bool HardwareDisplayPlaneManagerLegacy::SetPlaneData(
if (plane_list->legacy_page_flips.empty() ||
plane_list->legacy_page_flips.back().crtc_id != crtc_id) {
- plane_list->legacy_page_flips.push_back(
- HardwareDisplayPlaneList::PageFlipInfo(
- crtc_id, overlay.buffer->opaque_framebuffer_id()));
+ plane_list->legacy_page_flips.emplace_back(
+ crtc_id, overlay.buffer->opaque_framebuffer_id());
} else {
return false;
}
@@ -215,7 +212,7 @@ bool HardwareDisplayPlaneManagerLegacy::IsCompatible(
HardwareDisplayPlane* plane,
const DrmOverlayPlane& overlay,
uint32_t crtc_index) const {
- if (plane->type() == HardwareDisplayPlane::kCursor ||
+ if (plane->type() == DRM_PLANE_TYPE_CURSOR ||
!plane->CanUseForCrtc(crtc_index))
return false;
diff --git a/chromium/ui/ozone/platform/drm/gpu/hardware_display_plane_manager_legacy.h b/chromium/ui/ozone/platform/drm/gpu/hardware_display_plane_manager_legacy.h
index 237689dd288..5d03f971f37 100644
--- a/chromium/ui/ozone/platform/drm/gpu/hardware_display_plane_manager_legacy.h
+++ b/chromium/ui/ozone/platform/drm/gpu/hardware_display_plane_manager_legacy.h
@@ -19,13 +19,10 @@ class HardwareDisplayPlaneManagerLegacy : public HardwareDisplayPlaneManager {
~HardwareDisplayPlaneManagerLegacy() override;
// HardwareDisplayPlaneManager:
- bool Modeset(uint32_t crtc_id,
- uint32_t framebuffer_id,
- uint32_t connector_id,
- const drmModeModeInfo& mode,
- const HardwareDisplayPlaneList& plane_list) override;
- bool DisableModeset(uint32_t crtc_id, uint32_t connector) override;
+ bool Commit(CommitRequest commit_request, uint32_t flags) override;
+
bool Commit(HardwareDisplayPlaneList* plane_list,
+ bool should_modeset,
scoped_refptr<PageFlipRequest> page_flip_request,
std::unique_ptr<gfx::GpuFence>* out_fence) override;
bool DisableOverlayPlanes(HardwareDisplayPlaneList* plane_list) override;
diff --git a/chromium/ui/ozone/platform/drm/gpu/hardware_display_plane_manager_unittest.cc b/chromium/ui/ozone/platform/drm/gpu/hardware_display_plane_manager_unittest.cc
index 798ed118db5..4d967114368 100644
--- a/chromium/ui/ozone/platform/drm/gpu/hardware_display_plane_manager_unittest.cc
+++ b/chromium/ui/ozone/platform/drm/gpu/hardware_display_plane_manager_unittest.cc
@@ -37,6 +37,7 @@ constexpr uint32_t kCrtcIdBase = 500;
constexpr uint32_t kConnectorIdBase = 700;
constexpr uint32_t kActivePropId = 1000;
+constexpr uint32_t kModePropId = 1001;
constexpr uint32_t kBackgroundColorPropId = 1002;
constexpr uint32_t kCtmPropId = 1003;
constexpr uint32_t kGammaLutPropId = 1004;
@@ -121,7 +122,7 @@ void HardwareDisplayPlaneManagerTest::InitializeDrmState(
size_t planes_per_crtc) {
std::map<uint32_t, std::string> crtc_property_names = {
{kActivePropId, "ACTIVE"},
- {1001, "MODE_ID"},
+ {kModePropId, "MODE_ID"},
};
std::vector<ui::MockDrmDevice::ConnectorProperties> connector_properties(1);
@@ -226,8 +227,8 @@ void HardwareDisplayPlaneManagerTest::PerformPageFlip(
state, assigns, crtc_properties_[crtc_idx].id));
scoped_refptr<ui::PageFlipRequest> page_flip_request =
base::MakeRefCounted<ui::PageFlipRequest>(base::TimeDelta());
- ASSERT_TRUE(
- fake_drm_->plane_manager()->Commit(state, page_flip_request, nullptr));
+ ASSERT_TRUE(fake_drm_->plane_manager()->Commit(
+ state, /*should_modeset*/ false, page_flip_request, nullptr));
}
uint64_t HardwareDisplayPlaneManagerTest::GetObjectPropertyValue(
@@ -275,13 +276,24 @@ TEST_P(HardwareDisplayPlaneManagerTest, ResettingConnectorCache) {
plane_properties_, property_names_,
/*use_atomic=*/true);
- constexpr uint32_t kFrameBuffer = 2;
ui::HardwareDisplayPlaneList state;
- // Check all 3 connectors exist
- for (size_t i = 0; i < connector_and_crtc_count; ++i) {
- EXPECT_TRUE(fake_drm_->plane_manager()->Modeset(
- crtc_properties_[i].id, kFrameBuffer, connector_properties[i].id,
- kDefaultMode, state));
+
+ {
+ ui::CommitRequest commit_request;
+ fake_drm_->plane_manager()->BeginFrame(&state);
+ // Check all 3 connectors exist
+ for (size_t i = 0; i < connector_and_crtc_count; ++i) {
+ ui::DrmOverlayPlaneList overlays;
+ overlays.push_back(ui::DrmOverlayPlane(fake_buffer_, nullptr));
+
+ ui::CrtcCommitRequest request = ui::CrtcCommitRequest::EnableCrtcRequest(
+ crtc_properties_[i].id, connector_properties[i].id, kDefaultMode,
+ &state, std::move(overlays));
+ commit_request.push_back(std::move(request));
+ }
+
+ EXPECT_TRUE(fake_drm_->plane_manager()->Commit(
+ std::move(commit_request), DRM_MODE_ATOMIC_ALLOW_MODESET));
}
// Replace last connector and update state.
@@ -290,17 +302,34 @@ TEST_P(HardwareDisplayPlaneManagerTest, ResettingConnectorCache) {
plane_properties_, property_names_);
fake_drm_->plane_manager()->ResetConnectorsCache(fake_drm_->GetResources());
- EXPECT_TRUE(fake_drm_->plane_manager()->Modeset(
- crtc_properties_[0].id, kFrameBuffer, kConnectorIdBase, kDefaultMode,
- state));
- EXPECT_TRUE(fake_drm_->plane_manager()->Modeset(
- crtc_properties_[1].id, kFrameBuffer, kConnectorIdBase + 1, kDefaultMode,
- state));
- // TODO(markyacoub): Add a test that fails for kConnectorIdBase +2 when atomic
- // modeset is enabled.
- EXPECT_TRUE(fake_drm_->plane_manager()->Modeset(
- crtc_properties_[2].id, kFrameBuffer, kConnectorIdBase + 3, kDefaultMode,
- state));
+ {
+ ui::CommitRequest commit_request;
+ fake_drm_->plane_manager()->BeginFrame(&state);
+ {
+ ui::DrmOverlayPlaneList overlays;
+ overlays.push_back(ui::DrmOverlayPlane(fake_buffer_, nullptr));
+ commit_request.push_back(ui::CrtcCommitRequest::EnableCrtcRequest(
+ crtc_properties_[0].id, kConnectorIdBase, kDefaultMode, &state,
+ std::move(overlays)));
+ }
+ {
+ ui::DrmOverlayPlaneList overlays;
+ overlays.push_back(ui::DrmOverlayPlane(fake_buffer_, nullptr));
+ commit_request.push_back(ui::CrtcCommitRequest::EnableCrtcRequest(
+ crtc_properties_[1].id, kConnectorIdBase + 1, kDefaultMode, &state,
+ std::move(overlays)));
+ }
+ {
+ ui::DrmOverlayPlaneList overlays;
+ overlays.push_back(ui::DrmOverlayPlane(fake_buffer_, nullptr));
+ commit_request.push_back(ui::CrtcCommitRequest::EnableCrtcRequest(
+ crtc_properties_[2].id, kConnectorIdBase + 3, kDefaultMode, &state,
+ std::move(overlays)));
+ }
+
+ EXPECT_TRUE(fake_drm_->plane_manager()->Commit(
+ std::move(commit_request), DRM_MODE_ATOMIC_ALLOW_MODESET));
+ }
}
TEST_P(HardwareDisplayPlaneManagerLegacyTest, Modeset) {
@@ -310,12 +339,19 @@ TEST_P(HardwareDisplayPlaneManagerLegacyTest, Modeset) {
/*use_atomic=*/false);
fake_drm_->set_set_crtc_expectation(false);
- constexpr uint32_t kFrameBuffer = 2;
ui::HardwareDisplayPlaneList state;
- EXPECT_FALSE(fake_drm_->plane_manager()->Modeset(
- crtc_properties_[0].id, kFrameBuffer, connector_properties_[0].id,
- kDefaultMode, state));
- EXPECT_EQ(kFrameBuffer, fake_drm_->current_framebuffer());
+ ui::DrmOverlayPlane plane(fake_buffer_, nullptr);
+ ui::CommitRequest commit_request;
+
+ ui::DrmOverlayPlaneList overlays;
+ overlays.push_back(plane.Clone());
+ commit_request.push_back(ui::CrtcCommitRequest::EnableCrtcRequest(
+ crtc_properties_[0].id, connector_properties_[0].id, kDefaultMode, &state,
+ std::move(overlays)));
+ EXPECT_FALSE(fake_drm_->plane_manager()->Commit(
+ std::move(commit_request), DRM_MODE_ATOMIC_ALLOW_MODESET));
+
+ EXPECT_EQ(plane.buffer->framebuffer_id(), fake_drm_->current_framebuffer());
EXPECT_EQ(1, fake_drm_->get_set_crtc_call_count());
}
@@ -325,8 +361,12 @@ TEST_P(HardwareDisplayPlaneManagerLegacyTest, DisableModeset) {
plane_properties_, property_names_,
/*use_atomic*/ false);
- EXPECT_TRUE(
- fake_drm_->plane_manager()->DisableModeset(crtc_properties_[0].id, 0));
+ ui::HardwareDisplayPlaneList state;
+ ui::CommitRequest commit_request;
+ commit_request.push_back(ui::CrtcCommitRequest::DisableCrtcRequest(
+ crtc_properties_[0].id, connector_properties_[0].id, &state));
+ EXPECT_TRUE(fake_drm_->plane_manager()->Commit(
+ std::move(commit_request), DRM_MODE_ATOMIC_ALLOW_MODESET));
}
TEST_P(HardwareDisplayPlaneManagerLegacyTest, SinglePlaneAssignment) {
@@ -352,7 +392,7 @@ TEST_P(HardwareDisplayPlaneManagerLegacyTest, AddCursor) {
bool cursor_found = false;
for (const auto& plane : fake_drm_->plane_manager()->planes()) {
- if (plane->type() == ui::HardwareDisplayPlane::kCursor) {
+ if (plane->type() == DRM_PLANE_TYPE_CURSOR) {
cursor_found = true;
break;
}
@@ -449,13 +489,18 @@ TEST_P(HardwareDisplayPlaneManagerAtomicTest, Modeset) {
plane_properties_, property_names_,
/*use_atomic=*/true);
- constexpr uint32_t kFrameBuffer = 2;
ui::HardwareDisplayPlaneList state;
- EXPECT_TRUE(fake_drm_->plane_manager()->Modeset(
- crtc_properties_[0].id, kFrameBuffer, connector_properties_[0].id,
- kDefaultMode, state));
+ ui::CommitRequest commit_request;
+ ui::DrmOverlayPlaneList overlays;
+ overlays.push_back(ui::DrmOverlayPlane(fake_buffer_, nullptr));
- EXPECT_EQ(0, fake_drm_->get_commit_count());
+ commit_request.push_back(ui::CrtcCommitRequest::EnableCrtcRequest(
+ crtc_properties_[0].id, connector_properties_[0].id, kDefaultMode, &state,
+ std::move(overlays)));
+ EXPECT_TRUE(fake_drm_->plane_manager()->Commit(
+ std::move(commit_request), DRM_MODE_ATOMIC_ALLOW_MODESET));
+
+ EXPECT_EQ(1, fake_drm_->get_commit_count());
}
TEST_P(HardwareDisplayPlaneManagerAtomicTest, DisableModeset) {
@@ -464,9 +509,52 @@ TEST_P(HardwareDisplayPlaneManagerAtomicTest, DisableModeset) {
plane_properties_, property_names_,
/*use_atomic*/ true);
- EXPECT_TRUE(fake_drm_->plane_manager()->DisableModeset(
- crtc_properties_[0].id, connector_properties_[0].id));
- EXPECT_EQ(1, fake_drm_->get_commit_count());
+ ui::HardwareDisplayPlaneList state;
+ ui::CommitRequest commit_request;
+ commit_request.push_back(ui::CrtcCommitRequest::DisableCrtcRequest(
+ crtc_properties_[0].id, connector_properties_[0].id, &state));
+ EXPECT_TRUE(fake_drm_->plane_manager()->Commit(
+ std::move(commit_request), DRM_MODE_ATOMIC_ALLOW_MODESET));
+
+ EXPECT_EQ(2, fake_drm_->get_commit_count());
+}
+
+TEST_P(HardwareDisplayPlaneManagerAtomicTest, CheckPropsAfterModeset) {
+ InitializeDrmState(/*crtc_count=*/1, /*planes_per_crtc=*/1);
+ fake_drm_->InitializeState(crtc_properties_, connector_properties_,
+ plane_properties_, property_names_,
+ /*use_atomic=*/true);
+
+ ui::HardwareDisplayPlaneList state;
+ ui::CommitRequest commit_request;
+ ui::DrmOverlayPlaneList overlays;
+ overlays.push_back(ui::DrmOverlayPlane(fake_buffer_, nullptr));
+ commit_request.push_back(ui::CrtcCommitRequest::EnableCrtcRequest(
+ crtc_properties_[0].id, connector_properties_[0].id, kDefaultMode, &state,
+ std::move(overlays)));
+ EXPECT_TRUE(fake_drm_->plane_manager()->Commit(
+ std::move(commit_request), DRM_MODE_ATOMIC_ALLOW_MODESET));
+
+ // Test props values after modesetting.
+ ui::DrmDevice::Property connector_prop_crtc_id;
+ ui::ScopedDrmObjectPropertyPtr connector_props =
+ fake_drm_->GetObjectProperties(kConnectorIdBase,
+ DRM_MODE_OBJECT_CONNECTOR);
+ ui::GetDrmPropertyForName(fake_drm_.get(), connector_props.get(), "CRTC_ID",
+ &connector_prop_crtc_id);
+ EXPECT_EQ(kCrtcIdPropId, connector_prop_crtc_id.id);
+
+ ui::DrmDevice::Property crtc_prop_for_name;
+ ui::ScopedDrmObjectPropertyPtr crtc_props =
+ fake_drm_->GetObjectProperties(kCrtcIdBase, DRM_MODE_OBJECT_CRTC);
+ ui::GetDrmPropertyForName(fake_drm_.get(), crtc_props.get(), "ACTIVE",
+ &crtc_prop_for_name);
+ EXPECT_EQ(kActivePropId, crtc_prop_for_name.id);
+ EXPECT_EQ(1U, crtc_prop_for_name.value);
+
+ ui::GetDrmPropertyForName(fake_drm_.get(), crtc_props.get(), "MODE_ID",
+ &crtc_prop_for_name);
+ EXPECT_EQ(kModePropId, crtc_prop_for_name.id);
}
TEST_P(HardwareDisplayPlaneManagerAtomicTest, CheckPropsAfterDisable) {
@@ -475,15 +563,26 @@ TEST_P(HardwareDisplayPlaneManagerAtomicTest, CheckPropsAfterDisable) {
plane_properties_, property_names_,
/*use_atomic=*/true);
- constexpr uint32_t kFrameBuffer = 2;
ui::HardwareDisplayPlaneList state;
- EXPECT_TRUE(fake_drm_->plane_manager()->Modeset(
- crtc_properties_[0].id, kFrameBuffer, connector_properties_[0].id,
- kDefaultMode, state));
+ {
+ ui::CommitRequest commit_request;
+ ui::DrmOverlayPlaneList overlays;
+ overlays.push_back(ui::DrmOverlayPlane(fake_buffer_, nullptr));
+ commit_request.push_back(ui::CrtcCommitRequest::EnableCrtcRequest(
+ crtc_properties_[0].id, connector_properties_[0].id, kDefaultMode,
+ &state, std::move(overlays)));
+ EXPECT_TRUE(fake_drm_->plane_manager()->Commit(
+ std::move(commit_request), DRM_MODE_ATOMIC_ALLOW_MODESET));
+ }
- // Test props values after disabling.
- EXPECT_TRUE(fake_drm_->plane_manager()->DisableModeset(
- crtc_properties_[0].id, connector_properties_[0].id));
+ // Test props values after disabling.
+ {
+ ui::CommitRequest commit_request;
+ commit_request.push_back(ui::CrtcCommitRequest::DisableCrtcRequest(
+ crtc_properties_[0].id, connector_properties_[0].id, &state));
+ EXPECT_TRUE(fake_drm_->plane_manager()->Commit(
+ std::move(commit_request), DRM_MODE_ATOMIC_ALLOW_MODESET));
+ }
ui::DrmDevice::Property crtc_prop_for_name;
ui::ScopedDrmObjectPropertyPtr crtc_props =
@@ -570,8 +669,8 @@ TEST_P(HardwareDisplayPlaneManagerAtomicTest, UnusedPlanesAreReleased) {
fake_drm_->plane_manager()->BeginFrame(&hdpl);
EXPECT_TRUE(fake_drm_->plane_manager()->AssignOverlayPlanes(
&hdpl, assigns, crtc_properties_[0].id));
- EXPECT_TRUE(
- fake_drm_->plane_manager()->Commit(&hdpl, page_flip_request, nullptr));
+ EXPECT_TRUE(fake_drm_->plane_manager()->Commit(
+ &hdpl, /*should_modeset*/ false, page_flip_request, nullptr));
assigns.clear();
assigns.push_back(ui::DrmOverlayPlane(primary_buffer, nullptr));
fake_drm_->plane_manager()->BeginFrame(&hdpl);
@@ -580,12 +679,78 @@ TEST_P(HardwareDisplayPlaneManagerAtomicTest, UnusedPlanesAreReleased) {
EXPECT_NE(0u, GetPlanePropertyValue(kPlaneOffset, "FB_ID"));
EXPECT_NE(0u, GetPlanePropertyValue(kPlaneOffset + 1, "FB_ID"));
- EXPECT_TRUE(
- fake_drm_->plane_manager()->Commit(&hdpl, page_flip_request, nullptr));
+ EXPECT_TRUE(fake_drm_->plane_manager()->Commit(
+ &hdpl, /*should_modeset*/ false, page_flip_request, nullptr));
EXPECT_NE(0u, GetPlanePropertyValue(kPlaneOffset, "FB_ID"));
EXPECT_EQ(0u, GetPlanePropertyValue(kPlaneOffset + 1, "FB_ID"));
}
+TEST_P(HardwareDisplayPlaneManagerAtomicTest, AssignPlanesRestoresInUse) {
+ InitializeDrmState(/*crtc_count=*/2, /*planes_per_crtc=*/2);
+ fake_drm_->InitializeState(crtc_properties_, connector_properties_,
+ plane_properties_, property_names_, use_atomic_);
+
+ ui::DrmOverlayPlaneList assigns;
+ scoped_refptr<ui::DrmFramebuffer> primary_buffer =
+ CreateBuffer(kDefaultBufferSize);
+ scoped_refptr<ui::DrmFramebuffer> overlay_buffer =
+ CreateBuffer(gfx::Size(1, 1));
+ assigns.push_back(ui::DrmOverlayPlane(primary_buffer, nullptr));
+ assigns.push_back(ui::DrmOverlayPlane(overlay_buffer, nullptr));
+ ui::HardwareDisplayPlaneList hdpl;
+
+ scoped_refptr<ui::PageFlipRequest> page_flip_request =
+ base::MakeRefCounted<ui::PageFlipRequest>(base::TimeDelta());
+ fake_drm_->plane_manager()->BeginFrame(&hdpl);
+ EXPECT_TRUE(fake_drm_->plane_manager()->AssignOverlayPlanes(
+ &hdpl, assigns, crtc_properties_[0].id));
+ EXPECT_TRUE(fake_drm_->plane_manager()->Commit(
+ &hdpl, /*should_modeset*/ false, page_flip_request, nullptr));
+ EXPECT_TRUE(fake_drm_->plane_manager()->planes().front()->in_use());
+ assigns.push_back(ui::DrmOverlayPlane(overlay_buffer, nullptr));
+
+ fake_drm_->plane_manager()->BeginFrame(&hdpl);
+ // Assign overlay planes will fail since there aren't enough planes.
+ EXPECT_FALSE(fake_drm_->plane_manager()->AssignOverlayPlanes(
+ &hdpl, assigns, crtc_properties_[0].id));
+
+ // The primary plane should still be in use since we failed to assign
+ // planes and did not commit a new configuration.
+ EXPECT_TRUE(fake_drm_->plane_manager()->planes().front()->in_use());
+}
+
+TEST_P(HardwareDisplayPlaneManagerAtomicTest, PageflipTestRestoresInUse) {
+ InitializeDrmState(/*crtc_count=*/2, /*planes_per_crtc=*/2);
+ fake_drm_->InitializeState(crtc_properties_, connector_properties_,
+ plane_properties_, property_names_, use_atomic_);
+
+ ui::DrmOverlayPlaneList assigns;
+ scoped_refptr<ui::DrmFramebuffer> primary_buffer =
+ CreateBuffer(kDefaultBufferSize);
+ scoped_refptr<ui::DrmFramebuffer> overlay_buffer =
+ CreateBuffer(gfx::Size(1, 1));
+ assigns.push_back(ui::DrmOverlayPlane(primary_buffer, nullptr));
+ assigns.push_back(ui::DrmOverlayPlane(overlay_buffer, nullptr));
+ ui::HardwareDisplayPlaneList hdpl;
+
+ scoped_refptr<ui::PageFlipRequest> page_flip_request =
+ base::MakeRefCounted<ui::PageFlipRequest>(base::TimeDelta());
+ fake_drm_->plane_manager()->BeginFrame(&hdpl);
+ EXPECT_TRUE(fake_drm_->plane_manager()->AssignOverlayPlanes(
+ &hdpl, assigns, crtc_properties_[0].id));
+ EXPECT_TRUE(fake_drm_->plane_manager()->Commit(
+ &hdpl, /*should_modeset*/ false, page_flip_request, nullptr));
+ assigns.clear();
+ fake_drm_->plane_manager()->BeginFrame(&hdpl);
+ EXPECT_TRUE(fake_drm_->plane_manager()->AssignOverlayPlanes(
+ &hdpl, assigns, crtc_properties_[0].id));
+ EXPECT_TRUE(fake_drm_->plane_manager()->Commit(
+ &hdpl, /*should_modeset*/ false, nullptr, nullptr));
+ // The primary plane should still be in use since the commit was
+ // a pageflip test and did not change any KMS state.
+ EXPECT_TRUE(fake_drm_->plane_manager()->planes().front()->in_use());
+}
+
TEST_P(HardwareDisplayPlaneManagerAtomicTest, MultipleFrames) {
ui::DrmOverlayPlaneList assigns;
assigns.push_back(ui::DrmOverlayPlane(fake_buffer_, nullptr));
@@ -914,8 +1079,8 @@ TEST_P(HardwareDisplayPlaneManagerAtomicTest,
base::MakeRefCounted<ui::PageFlipRequest>(base::TimeDelta());
std::unique_ptr<gfx::GpuFence> out_fence;
- EXPECT_TRUE(fake_drm_->plane_manager()->Commit(&state_, page_flip_request,
- &out_fence));
+ EXPECT_TRUE(fake_drm_->plane_manager()->Commit(
+ &state_, /*should_modeset*/ false, page_flip_request, &out_fence));
EXPECT_EQ(nullptr, out_fence);
}
@@ -1003,10 +1168,8 @@ FakeFenceFD::FakeFenceFD() {
std::unique_ptr<gfx::GpuFence> FakeFenceFD::GetGpuFence() const {
gfx::GpuFenceHandle handle;
- handle.type = gfx::GpuFenceHandleType::kAndroidNativeFenceSync;
- handle.native_fd =
- base::FileDescriptor(HANDLE_EINTR(dup(read_fd.get())), true);
- return std::make_unique<gfx::GpuFence>(handle);
+ handle.owned_fd = base::ScopedFD(HANDLE_EINTR(dup(read_fd.get())));
+ return std::make_unique<gfx::GpuFence>(std::move(handle));
}
void FakeFenceFD::Signal() const {
@@ -1141,18 +1304,83 @@ TEST_F(HardwareDisplayPlaneManagerPlanesReadyTest,
EXPECT_TRUE(callback_called);
}
+TEST_P(HardwareDisplayPlaneManagerAtomicTest, OverlaySourceCrop) {
+ InitializeDrmState(/*crtc_count=*/1, /*planes_per_crtc=*/1);
+ fake_drm_->InitializeState(crtc_properties_, connector_properties_,
+ plane_properties_, property_names_, use_atomic_);
+
+ {
+ ui::DrmOverlayPlaneList assigns;
+ assigns.push_back(ui::DrmOverlayPlane(fake_buffer_, nullptr));
+
+ fake_drm_->plane_manager()->BeginFrame(&state_);
+ EXPECT_TRUE(fake_drm_->plane_manager()->AssignOverlayPlanes(
+ &state_, assigns, crtc_properties_[0].id));
+
+ std::unique_ptr<gfx::GpuFence> out_fence;
+ scoped_refptr<ui::PageFlipRequest> page_flip_request =
+ base::MakeRefCounted<ui::PageFlipRequest>(base::TimeDelta());
+ EXPECT_TRUE(fake_drm_->plane_manager()->Commit(
+ &state_, /*should_modeset*/ false, page_flip_request, &out_fence));
+
+ EXPECT_EQ(2u << 16, GetPlanePropertyValue(kPlaneOffset, "SRC_W"));
+ EXPECT_EQ(2u << 16, GetPlanePropertyValue(kPlaneOffset, "SRC_H"));
+ }
+
+ {
+ ui::DrmOverlayPlaneList assigns;
+ assigns.push_back(ui::DrmOverlayPlane(
+ fake_buffer_, 0, gfx::OverlayTransform::OVERLAY_TRANSFORM_NONE,
+ gfx::Rect(kDefaultBufferSize), gfx::RectF(0, 0, .5, 1), false,
+ nullptr));
+
+ fake_drm_->plane_manager()->BeginFrame(&state_);
+ EXPECT_TRUE(fake_drm_->plane_manager()->AssignOverlayPlanes(
+ &state_, assigns, crtc_properties_[0].id));
+
+ scoped_refptr<ui::PageFlipRequest> page_flip_request =
+ base::MakeRefCounted<ui::PageFlipRequest>(base::TimeDelta());
+ std::unique_ptr<gfx::GpuFence> out_fence;
+ EXPECT_TRUE(fake_drm_->plane_manager()->Commit(
+ &state_, /*should_modeset*/ false, page_flip_request, &out_fence));
+
+ EXPECT_EQ(1u << 16, GetPlanePropertyValue(kPlaneOffset, "SRC_W"));
+ EXPECT_EQ(2u << 16, GetPlanePropertyValue(kPlaneOffset, "SRC_H"));
+ }
+
+ {
+ ui::DrmOverlayPlaneList assigns;
+ assigns.push_back(ui::DrmOverlayPlane(
+ fake_buffer_, 0, gfx::OverlayTransform::OVERLAY_TRANSFORM_NONE,
+ gfx::Rect(kDefaultBufferSize), gfx::RectF(0, 0, .999, .501), false,
+ nullptr));
+
+ fake_drm_->plane_manager()->BeginFrame(&state_);
+ EXPECT_TRUE(fake_drm_->plane_manager()->AssignOverlayPlanes(
+ &state_, assigns, crtc_properties_[0].id));
+
+ scoped_refptr<ui::PageFlipRequest> page_flip_request =
+ base::MakeRefCounted<ui::PageFlipRequest>(base::TimeDelta());
+ std::unique_ptr<gfx::GpuFence> out_fence;
+ EXPECT_TRUE(fake_drm_->plane_manager()->Commit(
+ &state_, /*should_modeset*/ false, page_flip_request, &out_fence));
+
+ EXPECT_EQ(2u << 16, GetPlanePropertyValue(kPlaneOffset, "SRC_W"));
+ EXPECT_EQ(1u << 16, GetPlanePropertyValue(kPlaneOffset, "SRC_H"));
+ }
+}
+
class HardwareDisplayPlaneAtomicMock : public ui::HardwareDisplayPlaneAtomic {
public:
HardwareDisplayPlaneAtomicMock() : ui::HardwareDisplayPlaneAtomic(1) {}
~HardwareDisplayPlaneAtomicMock() override = default;
- bool SetPlaneData(drmModeAtomicReq* property_set,
- uint32_t crtc_id,
- uint32_t framebuffer,
- const gfx::Rect& crtc_rect,
- const gfx::Rect& src_rect,
- const gfx::OverlayTransform transform,
- int in_fence_fd) override {
+ bool AssignPlaneProps(uint32_t crtc_id,
+ uint32_t framebuffer,
+ const gfx::Rect& crtc_rect,
+ const gfx::Rect& src_rect,
+ const gfx::OverlayTransform transform,
+ int in_fence_fd) override {
framebuffer_ = framebuffer;
return true;
}
diff --git a/chromium/ui/ozone/platform/drm/gpu/mock_drm_device.cc b/chromium/ui/ozone/platform/drm/gpu/mock_drm_device.cc
index 9463b821486..ae0984597c2 100644
--- a/chromium/ui/ozone/platform/drm/gpu/mock_drm_device.cc
+++ b/chromium/ui/ozone/platform/drm/gpu/mock_drm_device.cc
@@ -430,8 +430,10 @@ bool MockDrmDevice::CommitProperties(
return false;
for (uint32_t i = 0; i < request->cursor; ++i) {
- EXPECT_TRUE(ValidatePropertyValue(request->items[i].property_id,
- request->items[i].value));
+ bool res = ValidatePropertyValue(request->items[i].property_id,
+ request->items[i].value);
+ if (!res)
+ return false;
}
if (page_flip_request)
@@ -442,9 +444,11 @@ bool MockDrmDevice::CommitProperties(
// Only update values if not testing.
for (uint32_t i = 0; i < request->cursor; ++i) {
- EXPECT_TRUE(UpdateProperty(request->items[i].object_id,
- request->items[i].property_id,
- request->items[i].value));
+ bool res =
+ UpdateProperty(request->items[i].object_id,
+ request->items[i].property_id, request->items[i].value);
+ if (!res)
+ return false;
}
return true;
diff --git a/chromium/ui/ozone/platform/drm/gpu/screen_manager.cc b/chromium/ui/ozone/platform/drm/gpu/screen_manager.cc
index 342bad7004f..b7b4ebbd3ed 100644
--- a/chromium/ui/ozone/platform/drm/gpu/screen_manager.cc
+++ b/chromium/ui/ozone/platform/drm/gpu/screen_manager.cc
@@ -93,14 +93,63 @@ CrtcController* GetCrtcController(HardwareDisplayController* controller,
return nullptr;
}
+inline bool AreAllStatusesTrue(
+ base::flat_map<int64_t, bool>& display_statuses) {
+ auto it = find_if(display_statuses.begin(), display_statuses.end(),
+ [](const auto status) { return status.second == false; });
+ return (it == display_statuses.end());
+}
+
} // namespace
-ScreenManager::ScreenManager() {}
+ScreenManager::ScreenManager() = default;
ScreenManager::~ScreenManager() {
DCHECK(window_map_.empty());
}
+ScreenManager::ControllerConfigParams::ControllerConfigParams(
+ int64_t display_id,
+ scoped_refptr<DrmDevice> drm,
+ uint32_t crtc,
+ uint32_t connector,
+ gfx::Point origin,
+ std::unique_ptr<drmModeModeInfo> pmode)
+ : display_id(display_id),
+ drm(drm),
+ crtc(crtc),
+ connector(connector),
+ origin(origin),
+ mode(std::move(pmode)) {}
+
+ScreenManager::ControllerConfigParams::ControllerConfigParams(
+ const ControllerConfigParams& other)
+ : display_id(other.display_id),
+ drm(other.drm),
+ crtc(other.crtc),
+ connector(other.connector),
+ origin(other.origin) {
+ if (other.mode) {
+ drmModeModeInfo mode_obj = *other.mode.get();
+ mode = std::make_unique<drmModeModeInfo>(mode_obj);
+ }
+}
+
+ScreenManager::ControllerConfigParams::ControllerConfigParams(
+ ControllerConfigParams&& other)
+ : display_id(other.display_id),
+ drm(other.drm),
+ crtc(other.crtc),
+ connector(other.connector),
+ origin(other.origin) {
+ if (other.mode) {
+ drmModeModeInfo mode_obj = *other.mode.get();
+ mode = std::make_unique<drmModeModeInfo>(mode_obj);
+ }
+}
+
+ScreenManager::ControllerConfigParams::~ControllerConfigParams() = default;
+
void ScreenManager::AddDisplayController(const scoped_refptr<DrmDevice>& drm,
uint32_t crtc,
uint32_t connector) {
@@ -115,38 +164,157 @@ void ScreenManager::AddDisplayController(const scoped_refptr<DrmDevice>& drm,
}
controllers_.push_back(std::make_unique<HardwareDisplayController>(
- std::unique_ptr<CrtcController>(new CrtcController(drm, crtc, connector)),
- gfx::Point()));
+ std::make_unique<CrtcController>(drm, crtc, connector), gfx::Point()));
}
-void ScreenManager::RemoveDisplayController(const scoped_refptr<DrmDevice>& drm,
- uint32_t crtc) {
- HardwareDisplayControllers::iterator it = FindDisplayController(drm, crtc);
- if (it != controllers_.end()) {
- bool is_mirrored = (*it)->IsMirrored();
- (*it)->RemoveCrtc(drm, crtc);
- if (!is_mirrored) {
- controllers_.erase(it);
- UpdateControllerToWindowMapping();
+void ScreenManager::RemoveDisplayControllers(
+ const CrtcsWithDrmList& controllers_to_remove) {
+ // Split them to different lists unique to each DRM Device.
+ base::flat_map<scoped_refptr<DrmDevice>, CrtcsWithDrmList>
+ controllers_for_drm_devices;
+ for (const auto& controller : controllers_to_remove) {
+ auto drm = controller.second;
+ auto it = controllers_for_drm_devices.find(drm);
+ if (it == controllers_for_drm_devices.end()) {
+ controllers_for_drm_devices.insert(
+ std::make_pair(drm, CrtcsWithDrmList()));
}
+ controllers_for_drm_devices[drm].emplace_back(controller);
}
+
+ bool should_update_controllers_to_window_mapping = false;
+ for (const auto& controllers_on_drm : controllers_for_drm_devices) {
+ CrtcsWithDrmList controllers_to_remove = controllers_on_drm.second;
+
+ CommitRequest commit_request;
+ auto drm = controllers_on_drm.first;
+ for (const auto& controller : controllers_to_remove) {
+ uint32_t crtc_id = controller.first;
+ auto it = FindDisplayController(drm, crtc_id);
+ if (it == controllers_.end())
+ continue;
+
+ bool is_mirrored = (*it)->IsMirrored();
+
+ std::unique_ptr<CrtcController> crtc = (*it)->RemoveCrtc(drm, crtc_id);
+ if (!crtc->is_disabled()) {
+ commit_request.push_back(CrtcCommitRequest::DisableCrtcRequest(
+ crtc->crtc(), crtc->connector()));
+ }
+
+ if (!is_mirrored) {
+ controllers_.erase(it);
+ should_update_controllers_to_window_mapping = true;
+ }
+ }
+ if (!commit_request.empty()) {
+ drm->plane_manager()->Commit(std::move(commit_request),
+ DRM_MODE_ATOMIC_ALLOW_MODESET);
+ }
+ }
+
+ if (should_update_controllers_to_window_mapping)
+ UpdateControllerToWindowMapping();
}
-bool ScreenManager::ConfigureDisplayController(
- const scoped_refptr<DrmDevice>& drm,
- uint32_t crtc,
- uint32_t connector,
- const gfx::Point& origin,
- const drmModeModeInfo& mode) {
- bool status =
- ActualConfigureDisplayController(drm, crtc, connector, origin, mode);
- if (status)
+base::flat_map<int64_t, bool> ScreenManager::ConfigureDisplayControllers(
+ const std::vector<ScreenManager::ControllerConfigParams>&
+ controllers_params) {
+ // Split them to different lists unique to each DRM Device.
+ base::flat_map<scoped_refptr<DrmDevice>,
+ std::vector<ScreenManager::ControllerConfigParams>>
+ displays_for_drms;
+
+ for (auto& params : controllers_params) {
+ auto it = displays_for_drms.find(params.drm);
+ if (it == displays_for_drms.end()) {
+ displays_for_drms.insert(std::make_pair(
+ params.drm, std::vector<ScreenManager::ControllerConfigParams>()));
+ }
+ displays_for_drms[params.drm].emplace_back(params);
+ }
+
+ base::flat_map<int64_t, bool> statuses;
+ // Perform display configurations together for the same DRM only.
+ for (const auto& configs_on_drm : displays_for_drms) {
+ auto display_statuses = TestAndModeset(configs_on_drm.second);
+ statuses.insert(display_statuses.begin(), display_statuses.end());
+ }
+
+ if (AreAllStatusesTrue(statuses))
UpdateControllerToWindowMapping();
+ return statuses;
+}
+
+base::flat_map<int64_t, bool> ScreenManager::TestAndModeset(
+ const std::vector<ControllerConfigParams>& controllers_params) {
+ if (!TestModeset(controllers_params)) {
+ base::flat_map<int64_t, bool> statuses;
+ for (const auto& params : controllers_params)
+ statuses.insert(std::make_pair(params.display_id, false));
+ return statuses;
+ }
+
+ return Modeset(controllers_params);
+}
+
+bool ScreenManager::TestModeset(
+ const std::vector<ControllerConfigParams>& controllers_params) {
+ CommitRequest commit_request;
+ bool status = true;
+ auto drm = controllers_params[0].drm;
+
+ for (const auto& params : controllers_params) {
+ auto it = FindDisplayController(params.drm, params.crtc);
+ DCHECK(controllers_.end() != it);
+ HardwareDisplayController* controller = it->get();
+
+ if (params.mode) {
+ status &= GetModesetControllerProps(&commit_request, controller,
+ params.origin, *params.mode);
+ } else {
+ controller->GetDisableProps(&commit_request);
+ }
+ }
+ if (status) {
+ status &= drm->plane_manager()->Commit(
+ std::move(commit_request),
+ DRM_MODE_ATOMIC_TEST_ONLY | DRM_MODE_ATOMIC_ALLOW_MODESET);
+ }
return status;
}
-bool ScreenManager::ActualConfigureDisplayController(
+base::flat_map<int64_t, bool> ScreenManager::Modeset(
+ const std::vector<ControllerConfigParams>& controllers_params) {
+ base::flat_map<int64_t, bool> statuses;
+
+ for (const auto& params : controllers_params) {
+ // Commit one controller at a time.
+ CommitRequest commit_request;
+ bool status = params.mode
+ ? SetDisplayControllerForEnableAndGetProps(
+ &commit_request, params.drm, params.crtc,
+ params.connector, params.origin, *params.mode)
+ : SetDisableDisplayControllerForDisableAndGetProps(
+ &commit_request, params.drm, params.crtc);
+ CommitRequest request_for_update = commit_request;
+ if (status) {
+ status &= params.drm->plane_manager()->Commit(
+ std::move(commit_request), DRM_MODE_ATOMIC_ALLOW_MODESET);
+ UpdateControllerStateAfterModeset(params, request_for_update, status);
+ }
+
+ statuses.insert(std::make_pair(params.display_id, status));
+ }
+
+ return statuses;
+}
+
+// TODO(markyacoub): As Mirroring is partially handled in
+// UpdateControllerStateAfterModeset(), this function can be greatly simplified.
+bool ScreenManager::SetDisplayControllerForEnableAndGetProps(
+ CommitRequest* commit_request,
const scoped_refptr<DrmDevice>& drm,
uint32_t crtc,
uint32_t connector,
@@ -170,11 +338,11 @@ bool ScreenManager::ActualConfigureDisplayController(
// If there is an active controller at the same location then start mirror
// mode.
if (mirror != controllers_.end())
- return HandleMirrorMode(it, mirror, drm, crtc, connector, mode);
+ return HandleMirrorMode(commit_request, it, mirror, mode);
}
- // Just re-enable the controller to re-use the current state.
- return EnableController(controller);
+ // Just get props to re-enable the controller re-using the current state.
+ return GetEnableControllerProps(commit_request, controller);
}
// Either the mode or the location of the display changed, so exit mirror
@@ -192,12 +360,13 @@ bool ScreenManager::ActualConfigureDisplayController(
FindActiveDisplayControllerByLocation(drm, modeset_bounds);
// Handle mirror mode.
if (mirror != controllers_.end() && it != mirror)
- return HandleMirrorMode(it, mirror, drm, crtc, connector, mode);
+ return HandleMirrorMode(commit_request, it, mirror, mode);
- return ModesetController(controller, origin, mode);
+ return GetModesetControllerProps(commit_request, controller, origin, mode);
}
-bool ScreenManager::DisableDisplayController(
+bool ScreenManager::SetDisableDisplayControllerForDisableAndGetProps(
+ CommitRequest* commit_request,
const scoped_refptr<DrmDevice>& drm,
uint32_t crtc) {
HardwareDisplayControllers::iterator it = FindDisplayController(drm, crtc);
@@ -209,8 +378,7 @@ bool ScreenManager::DisableDisplayController(
controller = controllers_.back().get();
}
- controller->Disable();
- UpdateControllerToWindowMapping();
+ controller->GetDisableProps(commit_request);
return true;
}
@@ -218,6 +386,33 @@ bool ScreenManager::DisableDisplayController(
return false;
}
+void ScreenManager::UpdateControllerStateAfterModeset(
+ const ControllerConfigParams& config,
+ const CommitRequest& commit_request,
+ bool did_succeed) {
+ for (auto& crtc_request : commit_request) {
+ bool was_enabled = (crtc_request.should_enable());
+
+ HardwareDisplayControllers::iterator it =
+ FindDisplayController(config.drm, crtc_request.crtc_id());
+ if (it != controllers_.end()) {
+ it->get()->UpdateState(was_enabled, DrmOverlayPlane::GetPrimaryPlane(
+ crtc_request.overlays()));
+
+ // If the CRTC is mirrored, move it to the mirror controller.
+ if (did_succeed && was_enabled) {
+ gfx::Rect modeset_bounds(config.origin, ModeSize(*config.mode));
+ HardwareDisplayControllers::iterator mirror =
+ FindActiveDisplayControllerByLocation(config.drm, modeset_bounds);
+ if (mirror != controllers_.end() && it != mirror) {
+ (*mirror)->AddCrtc((*it)->RemoveCrtc(config.drm, config.crtc));
+ controllers_.erase(it);
+ }
+ }
+ }
+ }
+}
+
HardwareDisplayController* ScreenManager::GetDisplayController(
const gfx::Rect& bounds) {
HardwareDisplayControllers::iterator it =
@@ -290,35 +485,18 @@ ScreenManager::FindActiveDisplayControllerByLocation(
}
bool ScreenManager::HandleMirrorMode(
+ CommitRequest* commit_request,
HardwareDisplayControllers::iterator original,
HardwareDisplayControllers::iterator mirror,
- const scoped_refptr<DrmDevice>& drm,
- uint32_t crtc,
- uint32_t connector,
const drmModeModeInfo& mode) {
- gfx::Point last_origin = (*original)->origin();
- // There should only be one CRTC in this controller.
- drmModeModeInfo last_mode = (*original)->crtc_controllers()[0]->mode();
-
// Modeset the CRTC with its mode in the original controller so that only this
// CRTC is affected by the mode. Otherwise it could apply a mode with the same
// resolution and refresh rate but with different timings to the other CRTC.
// TODO(dnicoara): This is hacky, instead the DrmDisplay and CrtcController
// should be merged and picking the mode should be done properly within
// HardwareDisplayController.
- if (ModesetController(original->get(), (*mirror)->origin(), mode)) {
- (*mirror)->AddCrtc((*original)->RemoveCrtc(drm, crtc));
- controllers_.erase(original);
- return true;
- }
-
- LOG(ERROR) << "Failed to switch to mirror mode";
-
- // When things go wrong revert back to the previous configuration since
- // it is expected that the configuration would not have changed if
- // things fail.
- ModesetController(original->get(), last_origin, last_mode);
- return false;
+ return GetModesetControllerProps(commit_request, original->get(),
+ (*mirror)->origin(), mode);
}
void ScreenManager::UpdateControllerToWindowMapping() {
@@ -352,7 +530,10 @@ void ScreenManager::UpdateControllerToWindowMapping() {
// otherwise the controller may be waiting for a page flip while the window
// tries to schedule another buffer.
if (should_enable) {
- EnableController(controller);
+ CommitRequest commit_request;
+ GetEnableControllerProps(&commit_request, controller);
+ controller->GetDrmDevice()->plane_manager()->Commit(
+ std::move(commit_request), DRM_MODE_ATOMIC_ALLOW_MODESET);
}
}
}
@@ -412,31 +593,38 @@ DrmOverlayPlane ScreenManager::GetModesetBuffer(
return DrmOverlayPlane(framebuffer, nullptr);
}
-bool ScreenManager::EnableController(HardwareDisplayController* controller) {
+bool ScreenManager::GetEnableControllerProps(
+ CommitRequest* commit_request,
+ HardwareDisplayController* controller) {
DCHECK(!controller->crtc_controllers().empty());
+
gfx::Rect rect(controller->origin(), controller->GetModeSize());
- DrmOverlayPlane plane = GetModesetBuffer(controller, rect);
- if (!plane.buffer || !controller->Enable(plane)) {
- LOG(ERROR) << "Failed to enable controller";
+ DrmOverlayPlane primary_plane = GetModesetBuffer(controller, rect);
+ if (!primary_plane.buffer) {
+ PLOG(ERROR) << "Failed to find plane buffer for Enable";
return false;
}
+ controller->GetEnableProps(commit_request, primary_plane);
return true;
}
-bool ScreenManager::ModesetController(HardwareDisplayController* controller,
- const gfx::Point& origin,
- const drmModeModeInfo& mode) {
+bool ScreenManager::GetModesetControllerProps(
+ CommitRequest* commit_request,
+ HardwareDisplayController* controller,
+ const gfx::Point& origin,
+ const drmModeModeInfo& mode) {
DCHECK(!controller->crtc_controllers().empty());
- gfx::Rect rect(origin, gfx::Size(mode.hdisplay, mode.vdisplay));
- controller->set_origin(origin);
- DrmOverlayPlane plane = GetModesetBuffer(controller, rect);
- if (!plane.buffer || !controller->Modeset(plane, mode)) {
- LOG(ERROR) << "Failed to modeset controller";
+ gfx::Rect rect(origin, ModeSize(mode));
+ controller->set_origin(origin);
+ DrmOverlayPlane primary_plane = GetModesetBuffer(controller, rect);
+ if (!primary_plane.buffer) {
+ PLOG(ERROR) << "Failed to find plane buffer for Modeset";
return false;
}
+ controller->GetModesetProps(commit_request, primary_plane, mode);
return true;
}
diff --git a/chromium/ui/ozone/platform/drm/gpu/screen_manager.h b/chromium/ui/ozone/platform/drm/gpu/screen_manager.h
index 9b1aeb2ea4a..8ed458cf1d1 100644
--- a/chromium/ui/ozone/platform/drm/gpu/screen_manager.h
+++ b/chromium/ui/ozone/platform/drm/gpu/screen_manager.h
@@ -9,9 +9,11 @@
#include <memory>
#include <unordered_map>
+#include "base/containers/flat_map.h"
#include "base/macros.h"
#include "base/observer_list.h"
#include "ui/gfx/native_widget_types.h"
+#include "ui/ozone/platform/drm/gpu/drm_display.h"
#include "ui/ozone/platform/drm/gpu/hardware_display_controller.h"
typedef struct _drmModeModeInfo drmModeModeInfo;
@@ -29,6 +31,28 @@ class DrmWindow;
// Responsible for keeping track of active displays and configuring them.
class ScreenManager {
public:
+ using CrtcsWithDrmList =
+ std::vector<std::pair<uint32_t, const scoped_refptr<DrmDevice>>>;
+
+ struct ControllerConfigParams {
+ ControllerConfigParams(int64_t display_id,
+ scoped_refptr<DrmDevice> drm,
+ uint32_t crtc,
+ uint32_t connector,
+ gfx::Point origin,
+ std::unique_ptr<drmModeModeInfo> pmode);
+ ControllerConfigParams(const ControllerConfigParams& other);
+ ControllerConfigParams(ControllerConfigParams&& other);
+ ~ControllerConfigParams();
+
+ const int64_t display_id;
+ const scoped_refptr<DrmDevice> drm;
+ const uint32_t crtc;
+ const uint32_t connector;
+ const gfx::Point origin;
+ std::unique_ptr<drmModeModeInfo> mode = nullptr;
+ };
+
ScreenManager();
virtual ~ScreenManager();
@@ -38,23 +62,14 @@ class ScreenManager {
uint32_t crtc,
uint32_t connector);
- // Remove a display controller from the list of active controllers. The
- // controller is removed since it was disconnected.
- void RemoveDisplayController(const scoped_refptr<DrmDevice>& drm,
- uint32_t crtc);
-
- // Configure a display controller. The display controller is identified by
- // (|crtc|, |connector|) and the controller is modeset using |mode|.
- bool ConfigureDisplayController(const scoped_refptr<DrmDevice>& drm,
- uint32_t crtc,
- uint32_t connector,
- const gfx::Point& origin,
- const drmModeModeInfo& mode);
+ // Remove display controllers from the list of active controllers. The
+ // controllers are removed since they were disconnected.
+ void RemoveDisplayControllers(const CrtcsWithDrmList& controllers_to_remove);
- // Disable the display controller identified by |crtc|. Note, the controller
- // may still be connected, so this does not remove the controller.
- bool DisableDisplayController(const scoped_refptr<DrmDevice>& drm,
- uint32_t crtc);
+ // Enables/Disables the display controller based on if a mode exists.
+ base::flat_map<int64_t, bool> ConfigureDisplayControllers(
+ const std::vector<ScreenManager::ControllerConfigParams>&
+ controllers_params);
// Returns a reference to the display controller configured to display within
// |bounds|. If the caller caches the controller it must also register as an
@@ -90,11 +105,39 @@ class ScreenManager {
const scoped_refptr<DrmDevice>& drm,
uint32_t crtc);
- bool ActualConfigureDisplayController(const scoped_refptr<DrmDevice>& drm,
- uint32_t crtc,
- uint32_t connector,
- const gfx::Point& origin,
- const drmModeModeInfo& mode);
+ base::flat_map<int64_t, bool> TestAndModeset(
+ const std::vector<ControllerConfigParams>& controllers_params);
+
+ bool TestModeset(
+ const std::vector<ControllerConfigParams>& controllers_params);
+
+ base::flat_map<int64_t, bool> Modeset(
+ const std::vector<ControllerConfigParams>& controllers_params);
+
+ // Configures a display controller to be enabled. The display controller is
+ // identified by (|crtc|, |connector|) and the controller is to be modeset
+ // using |mode|. Controller modeset props are added into |commit_request|.
+ bool SetDisplayControllerForEnableAndGetProps(
+ CommitRequest* commit_request,
+ const scoped_refptr<DrmDevice>& drm,
+ uint32_t crtc,
+ uint32_t connector,
+ const gfx::Point& origin,
+ const drmModeModeInfo& mode);
+
+ // Configures a display controller to be disabled. The display controller is
+ // identified by |crtc|. Controller modeset props are added into
+ // |commit_request|.
+ // Note: the controller may still be connected, so this does not remove the
+ // controller.
+ bool SetDisableDisplayControllerForDisableAndGetProps(
+ CommitRequest* commit_request,
+ const scoped_refptr<DrmDevice>& drm,
+ uint32_t crtc);
+
+ void UpdateControllerStateAfterModeset(const ControllerConfigParams& config,
+ const CommitRequest& commit_request,
+ bool did_succeed);
// Returns an iterator into |controllers_| for the controller located at
// |origin|.
@@ -107,26 +150,26 @@ class ScreenManager {
const scoped_refptr<DrmDevice>& drm,
const gfx::Rect& bounds);
- // Tries to set the controller identified by (|crtc|, |connector|) to mirror
- // those in |mirror|. |original| is an iterator to the HDC where the
- // controller is currently present.
- bool HandleMirrorMode(HardwareDisplayControllers::iterator original,
+ // Tries to set the |original| controller to mirror those in |mirror|.
+ // |original| is an iterator to the HDC where the controller is currently
+ // present.
+ bool HandleMirrorMode(CommitRequest* commit_request,
+ HardwareDisplayControllers::iterator original,
HardwareDisplayControllers::iterator mirror,
- const scoped_refptr<DrmDevice>& drm,
- uint32_t crtc,
- uint32_t connector,
const drmModeModeInfo& mode);
DrmOverlayPlane GetModesetBuffer(HardwareDisplayController* controller,
const gfx::Rect& bounds);
- bool EnableController(HardwareDisplayController* controller);
-
- // Modeset the |controller| using |origin| and |mode|. If there is a window at
- // the controller location, then we'll re-use the current buffer.
- bool ModesetController(HardwareDisplayController* controller,
- const gfx::Point& origin,
- const drmModeModeInfo& mode);
+ // Gets props for modesetting the |controller| using |origin| and |mode|. If
+ // there is a window at the controller location, then we'll re-use the current
+ // buffer.
+ bool GetModesetControllerProps(CommitRequest* commit_request,
+ HardwareDisplayController* controller,
+ const gfx::Point& origin,
+ const drmModeModeInfo& mode);
+ bool GetEnableControllerProps(CommitRequest* commit_request,
+ HardwareDisplayController* controller);
DrmWindow* FindWindowAt(const gfx::Rect& bounds) const;
diff --git a/chromium/ui/ozone/platform/drm/gpu/screen_manager_unittest.cc b/chromium/ui/ozone/platform/drm/gpu/screen_manager_unittest.cc
index 2cbc6a6bc32..cc923828a64 100644
--- a/chromium/ui/ozone/platform/drm/gpu/screen_manager_unittest.cc
+++ b/chromium/ui/ozone/platform/drm/gpu/screen_manager_unittest.cc
@@ -5,6 +5,7 @@
#include <drm_fourcc.h>
#include <stddef.h>
#include <stdint.h>
+#include <xf86drm.h>
#include <memory>
#include <utility>
@@ -12,9 +13,11 @@
#include "base/files/platform_file.h"
#include "base/macros.h"
#include "testing/gtest/include/gtest/gtest.h"
+#include "ui/gfx/geometry/point.h"
#include "ui/gfx/gpu_fence.h"
#include "ui/gfx/linux/gbm_buffer.h"
#include "ui/gfx/linux/test/mock_gbm_device.h"
+#include "ui/ozone/platform/drm/common/drm_util.h"
#include "ui/ozone/platform/drm/gpu/crtc_controller.h"
#include "ui/ozone/platform/drm/gpu/drm_device_generator.h"
#include "ui/ozone/platform/drm/gpu/drm_device_manager.h"
@@ -31,12 +34,23 @@ namespace {
const drmModeModeInfo kDefaultMode = {0, 6, 0, 0, 0, 0, 4, 0,
0, 0, 0, 0, 0, 0, {'\0'}};
-const uint32_t kPrimaryCrtc = 1;
-const uint32_t kPrimaryConnector = 2;
-const uint32_t kSecondaryCrtc = 3;
-const uint32_t kSecondaryConnector = 4;
+const uint32_t kPrimaryDisplayId = 1;
+const uint32_t kSecondaryDisplayId = 2;
-drmModeModeInfo Mode(uint16_t hdisplay, uint16_t vdisplay) {
+constexpr uint32_t kCrtcIdBase = 100;
+constexpr uint32_t kPrimaryCrtc = kCrtcIdBase;
+constexpr uint32_t kSecondaryCrtc = kCrtcIdBase + 1;
+
+constexpr uint32_t kConnectorIdBase = 200;
+constexpr uint32_t kPrimaryConnector = kConnectorIdBase;
+constexpr uint32_t kSecondaryConnector = kConnectorIdBase + 1;
+constexpr uint32_t kPlaneIdBase = 300;
+constexpr uint32_t kInFormatsBlobPropIdBase = 400;
+
+constexpr uint32_t kTypePropId = 3010;
+constexpr uint32_t kInFormatsPropId = 3011;
+
+drmModeModeInfo ConstructMode(uint16_t hdisplay, uint16_t vdisplay) {
return {0, hdisplay, 0, 0, 0, 0, vdisplay, 0, 0, 0, 0, 0, 0, 0, {'\0'}};
}
@@ -44,6 +58,14 @@ drmModeModeInfo Mode(uint16_t hdisplay, uint16_t vdisplay) {
class ScreenManagerTest : public testing::Test {
public:
+ struct PlaneState {
+ std::vector<uint32_t> formats;
+ };
+
+ struct CrtcState {
+ std::vector<PlaneState> planes;
+ };
+
ScreenManagerTest() = default;
~ScreenManagerTest() override = default;
@@ -57,6 +79,112 @@ class ScreenManagerTest : public testing::Test {
kDefaultMode.vdisplay);
}
+ void InitializeDrmState(ui::MockDrmDevice* drm,
+ const std::vector<CrtcState>& crtc_states,
+ bool is_atomic = true) {
+ std::vector<ui::MockDrmDevice::CrtcProperties> crtc_properties(
+ crtc_states.size());
+ std::map<uint32_t, std::string> crtc_property_names = {
+ {1000, "ACTIVE"},
+ {1001, "MODE_ID"},
+ };
+
+ std::vector<ui::MockDrmDevice::ConnectorProperties> connector_properties(3);
+ std::map<uint32_t, std::string> connector_property_names = {
+ {2000, "CRTC_ID"},
+ };
+ for (size_t i = 0; i < connector_properties.size(); ++i) {
+ connector_properties[i].id = kPrimaryConnector + i;
+ for (const auto& pair : connector_property_names) {
+ connector_properties[i].properties.push_back(
+ {/* .id = */ pair.first, /* .value = */ 0});
+ }
+ }
+
+ std::vector<ui::MockDrmDevice::PlaneProperties> plane_properties;
+ std::map<uint32_t, std::string> plane_property_names = {
+ // Add all required properties.
+ {3000, "CRTC_ID"},
+ {3001, "CRTC_X"},
+ {3002, "CRTC_Y"},
+ {3003, "CRTC_W"},
+ {3004, "CRTC_H"},
+ {3005, "FB_ID"},
+ {3006, "SRC_X"},
+ {3007, "SRC_Y"},
+ {3008, "SRC_W"},
+ {3009, "SRC_H"},
+ // Defines some optional properties we use for convenience.
+ {kTypePropId, "type"},
+ {kInFormatsPropId, "IN_FORMATS"},
+ };
+
+ uint32_t plane_id = kPlaneIdBase;
+ uint32_t property_id = kInFormatsBlobPropIdBase;
+
+ for (size_t crtc_idx = 0; crtc_idx < crtc_states.size(); ++crtc_idx) {
+ crtc_properties[crtc_idx].id = kPrimaryCrtc + crtc_idx;
+ for (const auto& pair : crtc_property_names) {
+ crtc_properties[crtc_idx].properties.push_back(
+ {/* .id = */ pair.first, /* .value = */ 0});
+ }
+
+ std::vector<ui::MockDrmDevice::PlaneProperties> crtc_plane_properties(
+ crtc_states[crtc_idx].planes.size());
+ for (size_t plane_idx = 0;
+ plane_idx < crtc_states[crtc_idx].planes.size(); ++plane_idx) {
+ crtc_plane_properties[plane_idx].id = plane_id++;
+ crtc_plane_properties[plane_idx].crtc_mask = 1 << crtc_idx;
+
+ for (const auto& pair : plane_property_names) {
+ uint64_t value = 0;
+ if (pair.first == kTypePropId) {
+ value = plane_idx == 0 ? DRM_PLANE_TYPE_PRIMARY
+ : DRM_PLANE_TYPE_OVERLAY;
+ } else if (pair.first == kInFormatsPropId) {
+ value = property_id++;
+ drm->SetPropertyBlob(ui::MockDrmDevice::AllocateInFormatsBlob(
+ value, crtc_states[crtc_idx].planes[plane_idx].formats,
+ std::vector<drm_format_modifier>()));
+ }
+
+ crtc_plane_properties[plane_idx].properties.push_back(
+ {/* .id = */ pair.first, /* .value = */ value});
+ }
+ }
+
+ plane_properties.insert(plane_properties.end(),
+ crtc_plane_properties.begin(),
+ crtc_plane_properties.end());
+ }
+
+ std::map<uint32_t, std::string> property_names;
+ property_names.insert(crtc_property_names.begin(),
+ crtc_property_names.end());
+ property_names.insert(connector_property_names.begin(),
+ connector_property_names.end());
+ property_names.insert(plane_property_names.begin(),
+ plane_property_names.end());
+ drm->InitializeState(crtc_properties, connector_properties,
+ plane_properties, property_names, is_atomic);
+ }
+
+ void InitializeDrmStateWithDefault(ui::MockDrmDevice* drm,
+ bool is_atomic = true) {
+ // A Sample of CRTC states.
+ std::vector<CrtcState> crtc_states = {
+ {/* .planes = */
+ {
+ {/* .formats = */ {DRM_FORMAT_XRGB8888}},
+ }},
+ {/* .planes = */
+ {
+ {/* .formats = */ {DRM_FORMAT_XRGB8888}},
+ }},
+ };
+ InitializeDrmState(drm, crtc_states, is_atomic);
+ }
+
void SetUp() override {
auto gbm = std::make_unique<ui::MockGbmDevice>();
drm_ = new ui::MockDrmDevice(std::move(gbm));
@@ -100,10 +228,17 @@ TEST_F(ScreenManagerTest, CheckWithNoControllers) {
}
TEST_F(ScreenManagerTest, CheckWithValidController) {
+ InitializeDrmStateWithDefault(drm_.get());
+
screen_manager_->AddDisplayController(drm_, kPrimaryCrtc, kPrimaryConnector);
- screen_manager_->ConfigureDisplayController(
- drm_, kPrimaryCrtc, kPrimaryConnector, GetPrimaryBounds().origin(),
- kDefaultMode);
+
+ std::vector<ScreenManager::ControllerConfigParams> controllers_to_enable;
+ controllers_to_enable.emplace_back(
+ kPrimaryDisplayId, drm_, kPrimaryCrtc, kPrimaryConnector,
+ GetPrimaryBounds().origin(),
+ std::make_unique<drmModeModeInfo>(kDefaultMode));
+ screen_manager_->ConfigureDisplayControllers(controllers_to_enable);
+
ui::HardwareDisplayController* controller =
screen_manager_->GetDisplayController(GetPrimaryBounds());
@@ -112,51 +247,112 @@ TEST_F(ScreenManagerTest, CheckWithValidController) {
}
TEST_F(ScreenManagerTest, CheckWithInvalidBounds) {
+ InitializeDrmStateWithDefault(drm_.get());
+
screen_manager_->AddDisplayController(drm_, kPrimaryCrtc, kPrimaryConnector);
- screen_manager_->ConfigureDisplayController(
- drm_, kPrimaryCrtc, kPrimaryConnector, GetPrimaryBounds().origin(),
- kDefaultMode);
+
+ std::vector<ScreenManager::ControllerConfigParams> controllers_to_enable;
+ controllers_to_enable.emplace_back(
+ kPrimaryDisplayId, drm_, kPrimaryCrtc, kPrimaryConnector,
+ GetPrimaryBounds().origin(),
+ std::make_unique<drmModeModeInfo>(kDefaultMode));
+ screen_manager_->ConfigureDisplayControllers(controllers_to_enable);
EXPECT_TRUE(screen_manager_->GetDisplayController(GetPrimaryBounds()));
EXPECT_FALSE(screen_manager_->GetDisplayController(GetSecondaryBounds()));
}
TEST_F(ScreenManagerTest, CheckForSecondValidController) {
+ InitializeDrmStateWithDefault(drm_.get());
+
screen_manager_->AddDisplayController(drm_, kPrimaryCrtc, kPrimaryConnector);
- screen_manager_->ConfigureDisplayController(
- drm_, kPrimaryCrtc, kPrimaryConnector, GetPrimaryBounds().origin(),
- kDefaultMode);
screen_manager_->AddDisplayController(drm_, kSecondaryCrtc,
kSecondaryConnector);
- screen_manager_->ConfigureDisplayController(
- drm_, kSecondaryCrtc, kSecondaryConnector, GetSecondaryBounds().origin(),
- kDefaultMode);
+
+ std::vector<ScreenManager::ControllerConfigParams> controllers_to_enable;
+ controllers_to_enable.emplace_back(
+ kPrimaryDisplayId, drm_, kPrimaryCrtc, kPrimaryConnector,
+ GetPrimaryBounds().origin(),
+ std::make_unique<drmModeModeInfo>(kDefaultMode));
+ drmModeModeInfo secondary_mode = kDefaultMode;
+ controllers_to_enable.emplace_back(
+ kSecondaryDisplayId, drm_, kSecondaryCrtc, kSecondaryConnector,
+ GetSecondaryBounds().origin(),
+ std::make_unique<drmModeModeInfo>(secondary_mode));
+ screen_manager_->ConfigureDisplayControllers(controllers_to_enable);
EXPECT_TRUE(screen_manager_->GetDisplayController(GetPrimaryBounds()));
EXPECT_TRUE(screen_manager_->GetDisplayController(GetSecondaryBounds()));
}
TEST_F(ScreenManagerTest, CheckControllerAfterItIsRemoved) {
+ InitializeDrmStateWithDefault(drm_.get());
+
screen_manager_->AddDisplayController(drm_, kPrimaryCrtc, kPrimaryConnector);
- screen_manager_->ConfigureDisplayController(
- drm_, kPrimaryCrtc, kPrimaryConnector, GetPrimaryBounds().origin(),
- kDefaultMode);
+
+ std::vector<ScreenManager::ControllerConfigParams> controllers_to_enable;
+ controllers_to_enable.emplace_back(
+ kPrimaryDisplayId, drm_, kPrimaryCrtc, kPrimaryConnector,
+ GetPrimaryBounds().origin(),
+ std::make_unique<drmModeModeInfo>(kDefaultMode));
+ screen_manager_->ConfigureDisplayControllers(controllers_to_enable);
+
EXPECT_TRUE(screen_manager_->GetDisplayController(GetPrimaryBounds()));
- screen_manager_->RemoveDisplayController(drm_, kPrimaryCrtc);
+ ScreenManager::CrtcsWithDrmList controllers_to_remove;
+
+ controllers_to_remove.emplace_back(kPrimaryCrtc, drm_);
+ screen_manager_->RemoveDisplayControllers(controllers_to_remove);
EXPECT_FALSE(screen_manager_->GetDisplayController(GetPrimaryBounds()));
}
+TEST_F(ScreenManagerTest, CheckMultipleControllersAfterBeingRemoved) {
+ InitializeDrmStateWithDefault(drm_.get());
+
+ screen_manager_->AddDisplayController(drm_, kPrimaryCrtc, kPrimaryConnector);
+ screen_manager_->AddDisplayController(drm_, kSecondaryCrtc,
+ kSecondaryConnector);
+
+ std::vector<ScreenManager::ControllerConfigParams> controllers_to_enable;
+ controllers_to_enable.emplace_back(
+ kPrimaryDisplayId, drm_, kPrimaryCrtc, kPrimaryConnector,
+ GetPrimaryBounds().origin(),
+ std::make_unique<drmModeModeInfo>(kDefaultMode));
+ controllers_to_enable.emplace_back(
+ kSecondaryDisplayId, drm_, kSecondaryCrtc, kSecondaryConnector,
+ GetSecondaryBounds().origin(),
+ std::make_unique<drmModeModeInfo>(kDefaultMode));
+ screen_manager_->ConfigureDisplayControllers(controllers_to_enable);
+
+ ScreenManager::CrtcsWithDrmList controllers_to_remove;
+ controllers_to_remove.emplace_back(kPrimaryCrtc, drm_);
+ controllers_to_remove.emplace_back(kSecondaryCrtc, drm_);
+ screen_manager_->RemoveDisplayControllers(controllers_to_remove);
+
+ EXPECT_FALSE(screen_manager_->GetDisplayController(GetPrimaryBounds()));
+ EXPECT_FALSE(screen_manager_->GetDisplayController(GetSecondaryBounds()));
+}
+
TEST_F(ScreenManagerTest, CheckDuplicateConfiguration) {
+ InitializeDrmStateWithDefault(drm_.get(), /*is_atomic*/ false);
+
screen_manager_->AddDisplayController(drm_, kPrimaryCrtc, kPrimaryConnector);
- screen_manager_->ConfigureDisplayController(
- drm_, kPrimaryCrtc, kPrimaryConnector, GetPrimaryBounds().origin(),
- kDefaultMode);
+
+ std::vector<ScreenManager::ControllerConfigParams> controllers_to_enable;
+ controllers_to_enable.emplace_back(
+ kPrimaryDisplayId, drm_, kPrimaryCrtc, kPrimaryConnector,
+ GetPrimaryBounds().origin(),
+ std::make_unique<drmModeModeInfo>(kDefaultMode));
+ screen_manager_->ConfigureDisplayControllers(controllers_to_enable);
+
uint32_t framebuffer = drm_->current_framebuffer();
- screen_manager_->ConfigureDisplayController(
- drm_, kPrimaryCrtc, kPrimaryConnector, GetPrimaryBounds().origin(),
- kDefaultMode);
+ controllers_to_enable.clear();
+ controllers_to_enable.emplace_back(
+ kPrimaryDisplayId, drm_, kPrimaryCrtc, kPrimaryConnector,
+ GetPrimaryBounds().origin(),
+ std::make_unique<drmModeModeInfo>(kDefaultMode));
+ screen_manager_->ConfigureDisplayControllers(controllers_to_enable);
// Should not hold onto buffers.
EXPECT_NE(framebuffer, drm_->current_framebuffer());
@@ -166,15 +362,30 @@ TEST_F(ScreenManagerTest, CheckDuplicateConfiguration) {
}
TEST_F(ScreenManagerTest, CheckChangingMode) {
+ InitializeDrmStateWithDefault(drm_.get());
+
screen_manager_->AddDisplayController(drm_, kPrimaryCrtc, kPrimaryConnector);
- screen_manager_->ConfigureDisplayController(
- drm_, kPrimaryCrtc, kPrimaryConnector, GetPrimaryBounds().origin(),
- kDefaultMode);
- drmModeModeInfo new_mode = kDefaultMode;
- new_mode.vdisplay = 10;
- screen_manager_->ConfigureDisplayController(
- drm_, kPrimaryCrtc, kPrimaryConnector, GetPrimaryBounds().origin(),
- new_mode);
+
+ // Modeset with default mode.
+ {
+ std::vector<ScreenManager::ControllerConfigParams> controllers_to_enable;
+ controllers_to_enable.emplace_back(
+ kPrimaryDisplayId, drm_, kPrimaryCrtc, kPrimaryConnector,
+ GetPrimaryBounds().origin(),
+ std::make_unique<drmModeModeInfo>(kDefaultMode));
+ screen_manager_->ConfigureDisplayControllers(controllers_to_enable);
+ }
+ auto new_mode = kDefaultMode;
+ new_mode.vdisplay = new_mode.vdisplay++;
+ // Modeset with a changed Mode.
+ {
+ std::vector<ScreenManager::ControllerConfigParams> controllers_to_enable;
+ controllers_to_enable.emplace_back(
+ kPrimaryDisplayId, drm_, kPrimaryCrtc, kPrimaryConnector,
+ GetPrimaryBounds().origin(),
+ std::make_unique<drmModeModeInfo>(new_mode));
+ screen_manager_->ConfigureDisplayControllers(controllers_to_enable);
+ }
gfx::Rect new_bounds(0, 0, new_mode.hdisplay, new_mode.vdisplay);
EXPECT_TRUE(screen_manager_->GetDisplayController(new_bounds));
@@ -187,49 +398,95 @@ TEST_F(ScreenManagerTest, CheckChangingMode) {
}
TEST_F(ScreenManagerTest, CheckForControllersInMirroredMode) {
+ InitializeDrmStateWithDefault(drm_.get());
+
screen_manager_->AddDisplayController(drm_, kPrimaryCrtc, kPrimaryConnector);
- screen_manager_->ConfigureDisplayController(
- drm_, kPrimaryCrtc, kPrimaryConnector, GetPrimaryBounds().origin(),
- kDefaultMode);
screen_manager_->AddDisplayController(drm_, kSecondaryCrtc,
kSecondaryConnector);
- screen_manager_->ConfigureDisplayController(
- drm_, kSecondaryCrtc, kSecondaryConnector, GetPrimaryBounds().origin(),
- kDefaultMode);
+
+ std::vector<ScreenManager::ControllerConfigParams> controllers_to_enable;
+ controllers_to_enable.emplace_back(
+ kPrimaryDisplayId, drm_, kPrimaryCrtc, kPrimaryConnector,
+ GetPrimaryBounds().origin(),
+ std::make_unique<drmModeModeInfo>(kDefaultMode));
+ drmModeModeInfo secondary_mode = kDefaultMode;
+ controllers_to_enable.emplace_back(
+ kSecondaryDisplayId, drm_, kSecondaryCrtc, kSecondaryConnector,
+ GetPrimaryBounds().origin(),
+ std::make_unique<drmModeModeInfo>(secondary_mode));
+ screen_manager_->ConfigureDisplayControllers(controllers_to_enable);
EXPECT_TRUE(screen_manager_->GetDisplayController(GetPrimaryBounds()));
EXPECT_FALSE(screen_manager_->GetDisplayController(GetSecondaryBounds()));
}
TEST_F(ScreenManagerTest, CheckMirrorModeTransitions) {
+ std::vector<CrtcState> crtc_states = {
+ {
+ /* .planes = */
+ {
+ {/* .formats = */ {DRM_FORMAT_XRGB8888}},
+ {/* .formats = */ {DRM_FORMAT_XRGB8888, DRM_FORMAT_NV12}},
+ },
+ },
+ {
+ /* .planes = */
+ {
+ {/* .formats = */ {DRM_FORMAT_XRGB8888}},
+ {/* .formats = */ {DRM_FORMAT_XRGB8888, DRM_FORMAT_NV12}},
+ },
+ },
+ };
+ InitializeDrmState(drm_.get(), crtc_states);
+
screen_manager_->AddDisplayController(drm_, kPrimaryCrtc, kPrimaryConnector);
- screen_manager_->ConfigureDisplayController(
- drm_, kPrimaryCrtc, kPrimaryConnector, GetPrimaryBounds().origin(),
- kDefaultMode);
screen_manager_->AddDisplayController(drm_, kSecondaryCrtc,
kSecondaryConnector);
- screen_manager_->ConfigureDisplayController(
- drm_, kSecondaryCrtc, kSecondaryConnector, GetSecondaryBounds().origin(),
- kDefaultMode);
+
+ std::vector<ScreenManager::ControllerConfigParams> controllers_to_enable;
+ controllers_to_enable.emplace_back(
+ kPrimaryDisplayId, drm_, kPrimaryCrtc, kPrimaryConnector,
+ GetPrimaryBounds().origin(),
+ std::make_unique<drmModeModeInfo>(kDefaultMode));
+ drmModeModeInfo secondary_mode = kDefaultMode;
+ controllers_to_enable.emplace_back(
+ kSecondaryDisplayId, drm_, kSecondaryCrtc, kSecondaryConnector,
+ GetSecondaryBounds().origin(),
+ std::make_unique<drmModeModeInfo>(secondary_mode));
+ screen_manager_->ConfigureDisplayControllers(controllers_to_enable);
EXPECT_TRUE(screen_manager_->GetDisplayController(GetPrimaryBounds()));
EXPECT_TRUE(screen_manager_->GetDisplayController(GetSecondaryBounds()));
- screen_manager_->ConfigureDisplayController(
- drm_, kPrimaryCrtc, kPrimaryConnector, GetPrimaryBounds().origin(),
- kDefaultMode);
- screen_manager_->ConfigureDisplayController(
- drm_, kSecondaryCrtc, kSecondaryConnector, GetPrimaryBounds().origin(),
- kDefaultMode);
+ controllers_to_enable.clear();
+ drmModeModeInfo transition1_primary_mode = kDefaultMode;
+ controllers_to_enable.emplace_back(
+ kPrimaryDisplayId, drm_, kPrimaryCrtc, kPrimaryConnector,
+ GetPrimaryBounds().origin(),
+ std::make_unique<drmModeModeInfo>(transition1_primary_mode));
+ drmModeModeInfo transition1_secondary_mode = kDefaultMode;
+ controllers_to_enable.emplace_back(
+ kSecondaryDisplayId, drm_, kSecondaryCrtc, kSecondaryConnector,
+ GetPrimaryBounds().origin(),
+ std::make_unique<drmModeModeInfo>(transition1_secondary_mode));
+ screen_manager_->ConfigureDisplayControllers(controllers_to_enable);
+
EXPECT_TRUE(screen_manager_->GetDisplayController(GetPrimaryBounds()));
EXPECT_FALSE(screen_manager_->GetDisplayController(GetSecondaryBounds()));
- screen_manager_->ConfigureDisplayController(
- drm_, kPrimaryCrtc, kPrimaryConnector, GetSecondaryBounds().origin(),
- kDefaultMode);
- screen_manager_->ConfigureDisplayController(
- drm_, kSecondaryCrtc, kSecondaryConnector, GetPrimaryBounds().origin(),
- kDefaultMode);
+ controllers_to_enable.clear();
+ drmModeModeInfo transition2_primary_mode = kDefaultMode;
+ controllers_to_enable.emplace_back(
+ kPrimaryDisplayId, drm_, kPrimaryCrtc, kPrimaryConnector,
+ GetSecondaryBounds().origin(),
+ std::make_unique<drmModeModeInfo>(transition2_primary_mode));
+ drmModeModeInfo transition2_secondary_mode = kDefaultMode;
+ controllers_to_enable.emplace_back(
+ kSecondaryDisplayId, drm_, kSecondaryCrtc, kSecondaryConnector,
+ GetPrimaryBounds().origin(),
+ std::make_unique<drmModeModeInfo>(transition2_secondary_mode));
+ screen_manager_->ConfigureDisplayControllers(controllers_to_enable);
+
EXPECT_TRUE(screen_manager_->GetDisplayController(GetPrimaryBounds()));
EXPECT_TRUE(screen_manager_->GetDisplayController(GetSecondaryBounds()));
}
@@ -237,22 +494,27 @@ TEST_F(ScreenManagerTest, CheckMirrorModeTransitions) {
// Make sure we're using each display's mode when doing mirror mode otherwise
// the timings may be off.
TEST_F(ScreenManagerTest, CheckMirrorModeModesettingWithDisplaysMode) {
+ InitializeDrmStateWithDefault(drm_.get());
+
screen_manager_->AddDisplayController(drm_, kPrimaryCrtc, kPrimaryConnector);
- screen_manager_->ConfigureDisplayController(
- drm_, kPrimaryCrtc, kPrimaryConnector, GetPrimaryBounds().origin(),
- kDefaultMode);
+ screen_manager_->AddDisplayController(drm_, kSecondaryCrtc,
+ kSecondaryConnector);
+ std::vector<ScreenManager::ControllerConfigParams> controllers_to_enable;
+ controllers_to_enable.emplace_back(
+ kPrimaryDisplayId, drm_, kPrimaryCrtc, kPrimaryConnector,
+ GetPrimaryBounds().origin(),
+ std::make_unique<drmModeModeInfo>(kDefaultMode));
// Copy the mode and use the copy so we can tell what mode the CRTC was
// configured with. The clock value is modified so we can tell which mode is
// being used.
- drmModeModeInfo kSecondaryMode = kDefaultMode;
- kSecondaryMode.clock++;
-
- screen_manager_->AddDisplayController(drm_, kSecondaryCrtc,
- kSecondaryConnector);
- screen_manager_->ConfigureDisplayController(
- drm_, kSecondaryCrtc, kSecondaryConnector, GetPrimaryBounds().origin(),
- kSecondaryMode);
+ drmModeModeInfo secondary_mode = kDefaultMode;
+ secondary_mode.clock++;
+ controllers_to_enable.emplace_back(
+ kSecondaryDisplayId, drm_, kSecondaryCrtc, kSecondaryConnector,
+ GetPrimaryBounds().origin(),
+ std::make_unique<drmModeModeInfo>(secondary_mode));
+ screen_manager_->ConfigureDisplayControllers(controllers_to_enable);
ui::HardwareDisplayController* controller =
screen_manager_->GetDisplayController(GetPrimaryBounds());
@@ -260,24 +522,34 @@ TEST_F(ScreenManagerTest, CheckMirrorModeModesettingWithDisplaysMode) {
if (crtc->crtc() == kPrimaryCrtc)
EXPECT_EQ(kDefaultMode.clock, crtc->mode().clock);
else if (crtc->crtc() == kSecondaryCrtc)
- EXPECT_EQ(kSecondaryMode.clock, crtc->mode().clock);
+ EXPECT_EQ(secondary_mode.clock, crtc->mode().clock);
else
NOTREACHED();
}
}
TEST_F(ScreenManagerTest, MonitorGoneInMirrorMode) {
+ InitializeDrmStateWithDefault(drm_.get());
+
screen_manager_->AddDisplayController(drm_, kPrimaryCrtc, kPrimaryConnector);
- screen_manager_->ConfigureDisplayController(
- drm_, kPrimaryCrtc, kPrimaryConnector, GetPrimaryBounds().origin(),
- kDefaultMode);
screen_manager_->AddDisplayController(drm_, kSecondaryCrtc,
kSecondaryConnector);
- screen_manager_->ConfigureDisplayController(
- drm_, kSecondaryCrtc, kSecondaryConnector, GetPrimaryBounds().origin(),
- kDefaultMode);
- screen_manager_->RemoveDisplayController(drm_, kSecondaryCrtc);
+ std::vector<ScreenManager::ControllerConfigParams> controllers_to_enable;
+ controllers_to_enable.emplace_back(
+ kPrimaryDisplayId, drm_, kPrimaryCrtc, kPrimaryConnector,
+ GetPrimaryBounds().origin(),
+ std::make_unique<drmModeModeInfo>(kDefaultMode));
+ drmModeModeInfo secondary_mode = kDefaultMode;
+ controllers_to_enable.emplace_back(
+ kSecondaryDisplayId, drm_, kSecondaryCrtc, kSecondaryConnector,
+ GetPrimaryBounds().origin(),
+ std::make_unique<drmModeModeInfo>(secondary_mode));
+ screen_manager_->ConfigureDisplayControllers(controllers_to_enable);
+
+ ScreenManager::CrtcsWithDrmList controllers_to_remove;
+ controllers_to_remove.emplace_back(kSecondaryCrtc, drm_);
+ screen_manager_->RemoveDisplayControllers(controllers_to_remove);
ui::HardwareDisplayController* controller =
screen_manager_->GetDisplayController(GetPrimaryBounds());
@@ -289,17 +561,26 @@ TEST_F(ScreenManagerTest, MonitorGoneInMirrorMode) {
}
TEST_F(ScreenManagerTest, MonitorDisabledInMirrorMode) {
+ InitializeDrmStateWithDefault(drm_.get());
+
screen_manager_->AddDisplayController(drm_, kPrimaryCrtc, kPrimaryConnector);
- screen_manager_->ConfigureDisplayController(
- drm_, kPrimaryCrtc, kPrimaryConnector, GetPrimaryBounds().origin(),
- kDefaultMode);
screen_manager_->AddDisplayController(drm_, kSecondaryCrtc,
kSecondaryConnector);
- screen_manager_->ConfigureDisplayController(
- drm_, kSecondaryCrtc, kSecondaryConnector, GetPrimaryBounds().origin(),
- kDefaultMode);
- screen_manager_->DisableDisplayController(drm_, kSecondaryCrtc);
+ std::vector<ScreenManager::ControllerConfigParams> controllers_to_enable;
+ controllers_to_enable.emplace_back(
+ kPrimaryDisplayId, drm_, kPrimaryCrtc, kPrimaryConnector,
+ GetPrimaryBounds().origin(),
+ std::make_unique<drmModeModeInfo>(kDefaultMode));
+ drmModeModeInfo secondary_mode = kDefaultMode;
+ controllers_to_enable.emplace_back(
+ kSecondaryDisplayId, drm_, kSecondaryCrtc, kSecondaryConnector,
+ GetPrimaryBounds().origin(),
+ std::make_unique<drmModeModeInfo>(secondary_mode));
+ // Disable display Controller.
+ controllers_to_enable.emplace_back(0, drm_, kSecondaryCrtc, 0, gfx::Point(),
+ nullptr);
+ screen_manager_->ConfigureDisplayControllers(controllers_to_enable);
ui::HardwareDisplayController* controller =
screen_manager_->GetDisplayController(GetPrimaryBounds());
@@ -311,87 +592,190 @@ TEST_F(ScreenManagerTest, MonitorDisabledInMirrorMode) {
}
TEST_F(ScreenManagerTest, DoNotEnterMirrorModeUnlessSameBounds) {
+ InitializeDrmStateWithDefault(drm_.get());
+
screen_manager_->AddDisplayController(drm_, kPrimaryCrtc, kPrimaryConnector);
screen_manager_->AddDisplayController(drm_, kSecondaryCrtc,
kSecondaryConnector);
// Configure displays in extended mode.
- screen_manager_->ConfigureDisplayController(
- drm_, kPrimaryCrtc, kPrimaryConnector, GetPrimaryBounds().origin(),
- kDefaultMode);
- screen_manager_->ConfigureDisplayController(
- drm_, kSecondaryCrtc, kSecondaryConnector, GetSecondaryBounds().origin(),
- kDefaultMode);
-
- drmModeModeInfo new_mode = kDefaultMode;
- new_mode.vdisplay = 10;
- // Shouldn't enter mirror mode unless the display bounds are the same.
- screen_manager_->ConfigureDisplayController(
- drm_, kSecondaryCrtc, kSecondaryConnector, GetPrimaryBounds().origin(),
- new_mode);
+ {
+ std::vector<ScreenManager::ControllerConfigParams> controllers_to_enable;
+ controllers_to_enable.emplace_back(
+ kPrimaryDisplayId, drm_, kPrimaryCrtc, kPrimaryConnector,
+ GetPrimaryBounds().origin(),
+ std::make_unique<drmModeModeInfo>(kDefaultMode));
+ drmModeModeInfo secondary_mode = kDefaultMode;
+ controllers_to_enable.emplace_back(
+ kSecondaryDisplayId, drm_, kSecondaryCrtc, kSecondaryConnector,
+ GetSecondaryBounds().origin(),
+ std::make_unique<drmModeModeInfo>(secondary_mode));
+ screen_manager_->ConfigureDisplayControllers(controllers_to_enable);
+ }
+
+ {
+ auto new_mode = std::make_unique<drmModeModeInfo>(kDefaultMode);
+ new_mode->vdisplay = 10;
+ // Shouldn't enter mirror mode unless the display bounds are the same.
+ std::vector<ScreenManager::ControllerConfigParams> controllers_to_enable;
+ controllers_to_enable.emplace_back(
+ kSecondaryDisplayId, drm_, kSecondaryCrtc, kSecondaryConnector,
+ GetPrimaryBounds().origin(), std::move(new_mode));
+ screen_manager_->ConfigureDisplayControllers(controllers_to_enable);
+ }
EXPECT_FALSE(
screen_manager_->GetDisplayController(GetPrimaryBounds())->IsMirrored());
}
TEST_F(ScreenManagerTest, ReuseFramebufferIfDisabledThenReEnabled) {
+ InitializeDrmStateWithDefault(drm_.get(), /*is_atomic=*/false);
+
screen_manager_->AddDisplayController(drm_, kPrimaryCrtc, kPrimaryConnector);
- screen_manager_->ConfigureDisplayController(
- drm_, kPrimaryCrtc, kPrimaryConnector, GetPrimaryBounds().origin(),
- kDefaultMode);
+ std::vector<ScreenManager::ControllerConfigParams> controllers_to_enable;
+ controllers_to_enable.emplace_back(
+ kPrimaryDisplayId, drm_, kPrimaryCrtc, kPrimaryConnector,
+ GetPrimaryBounds().origin(),
+ std::make_unique<drmModeModeInfo>(kDefaultMode));
+ screen_manager_->ConfigureDisplayControllers(controllers_to_enable);
+
uint32_t framebuffer = drm_->current_framebuffer();
- screen_manager_->DisableDisplayController(drm_, kPrimaryCrtc);
+ controllers_to_enable.clear();
+ // Disable display controller.
+ controllers_to_enable.emplace_back(0, drm_, kPrimaryCrtc, 0, gfx::Point(),
+ nullptr);
+ screen_manager_->ConfigureDisplayControllers(controllers_to_enable);
EXPECT_EQ(0u, drm_->current_framebuffer());
- screen_manager_->ConfigureDisplayController(
- drm_, kPrimaryCrtc, kPrimaryConnector, GetPrimaryBounds().origin(),
- kDefaultMode);
+ controllers_to_enable.clear();
+ drmModeModeInfo reenable_mode = kDefaultMode;
+ controllers_to_enable.emplace_back(
+ kPrimaryDisplayId, drm_, kPrimaryCrtc, kPrimaryConnector,
+ GetPrimaryBounds().origin(),
+ std::make_unique<drmModeModeInfo>(reenable_mode));
+ screen_manager_->ConfigureDisplayControllers(controllers_to_enable);
// Buffers are released when disabled.
EXPECT_NE(framebuffer, drm_->current_framebuffer());
}
TEST_F(ScreenManagerTest, CheckMirrorModeAfterBeginReEnabled) {
- screen_manager_->AddDisplayController(drm_, kPrimaryCrtc, kPrimaryConnector);
- screen_manager_->ConfigureDisplayController(
- drm_, kPrimaryCrtc, kPrimaryConnector, GetPrimaryBounds().origin(),
- kDefaultMode);
- screen_manager_->DisableDisplayController(drm_, kPrimaryCrtc);
+ InitializeDrmStateWithDefault(drm_.get());
+ screen_manager_->AddDisplayController(drm_, kPrimaryCrtc, kPrimaryConnector);
screen_manager_->AddDisplayController(drm_, kSecondaryCrtc,
kSecondaryConnector);
- screen_manager_->ConfigureDisplayController(
- drm_, kSecondaryCrtc, kSecondaryConnector, GetPrimaryBounds().origin(),
- kDefaultMode);
+ {
+ std::vector<ScreenManager::ControllerConfigParams> controllers_to_enable;
+ controllers_to_enable.emplace_back(
+ kPrimaryDisplayId, drm_, kPrimaryCrtc, kPrimaryConnector,
+ GetPrimaryBounds().origin(),
+ std::make_unique<drmModeModeInfo>(kDefaultMode));
+ drmModeModeInfo secondary_mode = kDefaultMode;
+ controllers_to_enable.emplace_back(
+ kSecondaryDisplayId, drm_, kSecondaryCrtc, kSecondaryConnector,
+ GetPrimaryBounds().origin(),
+ std::make_unique<drmModeModeInfo>(secondary_mode));
+ screen_manager_->ConfigureDisplayControllers(controllers_to_enable);
+ }
+ {
+ std::vector<ScreenManager::ControllerConfigParams> controllers_to_enable;
+ controllers_to_enable.emplace_back(0, drm_, kPrimaryCrtc, 0, gfx::Point(),
+ nullptr);
+ screen_manager_->ConfigureDisplayControllers(controllers_to_enable);
+ }
ui::HardwareDisplayController* controller =
screen_manager_->GetDisplayController(GetPrimaryBounds());
EXPECT_TRUE(controller);
EXPECT_FALSE(controller->IsMirrored());
- screen_manager_->ConfigureDisplayController(
- drm_, kPrimaryCrtc, kPrimaryConnector, GetPrimaryBounds().origin(),
- kDefaultMode);
+ {
+ std::vector<ScreenManager::ControllerConfigParams> controllers_to_enable;
+ drmModeModeInfo reenable_mode = kDefaultMode;
+ controllers_to_enable.emplace_back(
+ kPrimaryDisplayId, drm_, kPrimaryCrtc, kPrimaryConnector,
+ GetPrimaryBounds().origin(),
+ std::make_unique<drmModeModeInfo>(reenable_mode));
+ screen_manager_->ConfigureDisplayControllers(controllers_to_enable);
+ }
+
EXPECT_TRUE(controller);
EXPECT_TRUE(controller->IsMirrored());
}
+TEST_F(ScreenManagerTest, ConfigureOnDifferentDrmDevices) {
+ auto gbm_device = std::make_unique<ui::MockGbmDevice>();
+ scoped_refptr<ui::MockDrmDevice> drm2 =
+ new ui::MockDrmDevice(std::move(gbm_device));
+
+ InitializeDrmStateWithDefault(drm_.get(), /*is_atomic=*/false);
+ std::vector<CrtcState> crtc_states = {
+ {/* .planes = */
+ {
+ {/* .formats = */ {DRM_FORMAT_XRGB8888}},
+ }},
+ {/* .planes = */
+ {
+ {/* .formats = */ {DRM_FORMAT_XRGB8888}},
+ }},
+ {/* .planes = */
+ {
+ {/* .formats = */ {DRM_FORMAT_XRGB8888}},
+ }}};
+ InitializeDrmState(drm2.get(), crtc_states, /*is_atomic=*/false);
+
+ screen_manager_->AddDisplayController(drm_, kPrimaryCrtc, kPrimaryConnector);
+ screen_manager_->AddDisplayController(drm2, kSecondaryCrtc,
+ kSecondaryConnector);
+ screen_manager_->AddDisplayController(drm2, kSecondaryCrtc + 1,
+ kSecondaryConnector + 1);
+
+ std::vector<ScreenManager::ControllerConfigParams> controllers_to_enable;
+ controllers_to_enable.emplace_back(
+ kPrimaryDisplayId, drm_, kPrimaryCrtc, kPrimaryConnector,
+ GetPrimaryBounds().origin(),
+ std::make_unique<drmModeModeInfo>(kDefaultMode));
+ drmModeModeInfo secondary_mode = kDefaultMode;
+ controllers_to_enable.emplace_back(
+ kSecondaryDisplayId, drm2, kSecondaryCrtc, kSecondaryConnector,
+ GetSecondaryBounds().origin(),
+ std::make_unique<drmModeModeInfo>(secondary_mode));
+ drmModeModeInfo secondary_mode2 = kDefaultMode;
+ controllers_to_enable.emplace_back(
+ kSecondaryDisplayId + 1, drm2, kSecondaryCrtc + 1,
+ kSecondaryConnector + 1, GetSecondaryBounds().origin(),
+ std::make_unique<drmModeModeInfo>(secondary_mode2));
+ screen_manager_->ConfigureDisplayControllers(controllers_to_enable);
+
+ EXPECT_EQ(drm_->get_set_crtc_call_count(), 1);
+ EXPECT_EQ(drm2->get_set_crtc_call_count(), 2);
+}
+
TEST_F(ScreenManagerTest,
CheckProperConfigurationWithDifferentDeviceAndSameCrtc) {
auto gbm_device = std::make_unique<ui::MockGbmDevice>();
scoped_refptr<ui::MockDrmDevice> drm2 =
new ui::MockDrmDevice(std::move(gbm_device));
+ InitializeDrmStateWithDefault(drm_.get());
+ InitializeDrmStateWithDefault(drm2.get());
+
screen_manager_->AddDisplayController(drm_, kPrimaryCrtc, kPrimaryConnector);
screen_manager_->AddDisplayController(drm2, kPrimaryCrtc, kPrimaryConnector);
- screen_manager_->ConfigureDisplayController(
- drm_, kPrimaryCrtc, kPrimaryConnector, GetPrimaryBounds().origin(),
- kDefaultMode);
- screen_manager_->ConfigureDisplayController(
- drm2, kPrimaryCrtc, kPrimaryConnector, GetSecondaryBounds().origin(),
- kDefaultMode);
+ std::vector<ScreenManager::ControllerConfigParams> controllers_to_enable;
+ controllers_to_enable.emplace_back(
+ kPrimaryDisplayId, drm_, kPrimaryCrtc, kPrimaryConnector,
+ GetPrimaryBounds().origin(),
+ std::make_unique<drmModeModeInfo>(kDefaultMode));
+ drmModeModeInfo secondary_mode = kDefaultMode;
+ controllers_to_enable.emplace_back(
+ kSecondaryDisplayId, drm2, kPrimaryCrtc, kPrimaryConnector,
+ GetSecondaryBounds().origin(),
+ std::make_unique<drmModeModeInfo>(secondary_mode));
+ screen_manager_->ConfigureDisplayControllers(controllers_to_enable);
ui::HardwareDisplayController* controller1 =
screen_manager_->GetDisplayController(GetPrimaryBounds());
@@ -404,6 +788,8 @@ TEST_F(ScreenManagerTest,
}
TEST_F(ScreenManagerTest, CheckControllerToWindowMappingWithSameBounds) {
+ InitializeDrmStateWithDefault(drm_.get());
+
std::unique_ptr<ui::DrmWindow> window(
new ui::DrmWindow(1, device_manager_.get(), screen_manager_.get()));
window->Initialize();
@@ -411,9 +797,12 @@ TEST_F(ScreenManagerTest, CheckControllerToWindowMappingWithSameBounds) {
screen_manager_->AddWindow(1, std::move(window));
screen_manager_->AddDisplayController(drm_, kPrimaryCrtc, kPrimaryConnector);
- screen_manager_->ConfigureDisplayController(
- drm_, kPrimaryCrtc, kPrimaryConnector, GetPrimaryBounds().origin(),
- kDefaultMode);
+ std::vector<ScreenManager::ControllerConfigParams> controllers_to_enable;
+ controllers_to_enable.emplace_back(
+ kPrimaryDisplayId, drm_, kPrimaryCrtc, kPrimaryConnector,
+ GetPrimaryBounds().origin(),
+ std::make_unique<drmModeModeInfo>(kDefaultMode));
+ screen_manager_->ConfigureDisplayControllers(controllers_to_enable);
EXPECT_TRUE(screen_manager_->GetWindow(1)->GetController());
@@ -422,6 +811,8 @@ TEST_F(ScreenManagerTest, CheckControllerToWindowMappingWithSameBounds) {
}
TEST_F(ScreenManagerTest, CheckControllerToWindowMappingWithDifferentBounds) {
+ InitializeDrmStateWithDefault(drm_.get());
+
std::unique_ptr<ui::DrmWindow> window(
new ui::DrmWindow(1, device_manager_.get(), screen_manager_.get()));
window->Initialize();
@@ -431,9 +822,12 @@ TEST_F(ScreenManagerTest, CheckControllerToWindowMappingWithDifferentBounds) {
screen_manager_->AddWindow(1, std::move(window));
screen_manager_->AddDisplayController(drm_, kPrimaryCrtc, kPrimaryConnector);
- screen_manager_->ConfigureDisplayController(
- drm_, kPrimaryCrtc, kPrimaryConnector, GetPrimaryBounds().origin(),
- kDefaultMode);
+ std::vector<ScreenManager::ControllerConfigParams> controllers_to_enable;
+ controllers_to_enable.emplace_back(
+ kPrimaryDisplayId, drm_, kPrimaryCrtc, kPrimaryConnector,
+ GetPrimaryBounds().origin(),
+ std::make_unique<drmModeModeInfo>(kDefaultMode));
+ screen_manager_->ConfigureDisplayControllers(controllers_to_enable);
EXPECT_FALSE(screen_manager_->GetWindow(1)->GetController());
@@ -443,6 +837,8 @@ TEST_F(ScreenManagerTest, CheckControllerToWindowMappingWithDifferentBounds) {
TEST_F(ScreenManagerTest,
CheckControllerToWindowMappingWithOverlappingWindows) {
+ InitializeDrmStateWithDefault(drm_.get());
+
const size_t kWindowCount = 2;
for (size_t i = 1; i < kWindowCount + 1; ++i) {
std::unique_ptr<ui::DrmWindow> window(
@@ -453,9 +849,12 @@ TEST_F(ScreenManagerTest,
}
screen_manager_->AddDisplayController(drm_, kPrimaryCrtc, kPrimaryConnector);
- screen_manager_->ConfigureDisplayController(
- drm_, kPrimaryCrtc, kPrimaryConnector, GetPrimaryBounds().origin(),
- kDefaultMode);
+ std::vector<ScreenManager::ControllerConfigParams> controllers_to_enable;
+ controllers_to_enable.emplace_back(
+ kPrimaryDisplayId, drm_, kPrimaryCrtc, kPrimaryConnector,
+ GetPrimaryBounds().origin(),
+ std::make_unique<drmModeModeInfo>(kDefaultMode));
+ screen_manager_->ConfigureDisplayControllers(controllers_to_enable);
bool window1_has_controller = screen_manager_->GetWindow(1)->GetController();
bool window2_has_controller = screen_manager_->GetWindow(2)->GetController();
@@ -469,6 +868,8 @@ TEST_F(ScreenManagerTest,
}
TEST_F(ScreenManagerTest, ShouldDissociateWindowOnControllerRemoval) {
+ InitializeDrmStateWithDefault(drm_.get());
+
gfx::AcceleratedWidget window_id = 1;
std::unique_ptr<ui::DrmWindow> window(new ui::DrmWindow(
window_id, device_manager_.get(), screen_manager_.get()));
@@ -477,13 +878,18 @@ TEST_F(ScreenManagerTest, ShouldDissociateWindowOnControllerRemoval) {
screen_manager_->AddWindow(window_id, std::move(window));
screen_manager_->AddDisplayController(drm_, kPrimaryCrtc, kPrimaryConnector);
- screen_manager_->ConfigureDisplayController(
- drm_, kPrimaryCrtc, kPrimaryConnector, GetPrimaryBounds().origin(),
- kDefaultMode);
+ std::vector<ScreenManager::ControllerConfigParams> controllers_to_enable;
+ controllers_to_enable.emplace_back(
+ kPrimaryDisplayId, drm_, kPrimaryCrtc, kPrimaryConnector,
+ GetPrimaryBounds().origin(),
+ std::make_unique<drmModeModeInfo>(kDefaultMode));
+ screen_manager_->ConfigureDisplayControllers(controllers_to_enable);
EXPECT_TRUE(screen_manager_->GetWindow(window_id)->GetController());
- screen_manager_->RemoveDisplayController(drm_, kPrimaryCrtc);
+ ScreenManager::CrtcsWithDrmList controllers_to_remove;
+ controllers_to_remove.emplace_back(kPrimaryCrtc, drm_);
+ screen_manager_->RemoveDisplayControllers(controllers_to_remove);
EXPECT_FALSE(screen_manager_->GetWindow(window_id)->GetController());
@@ -492,6 +898,8 @@ TEST_F(ScreenManagerTest, ShouldDissociateWindowOnControllerRemoval) {
}
TEST_F(ScreenManagerTest, EnableControllerWhenWindowHasNoBuffer) {
+ InitializeDrmStateWithDefault(drm_.get(), /*is_atomic=*/false);
+
std::unique_ptr<ui::DrmWindow> window(
new ui::DrmWindow(1, device_manager_.get(), screen_manager_.get()));
window->Initialize();
@@ -499,18 +907,24 @@ TEST_F(ScreenManagerTest, EnableControllerWhenWindowHasNoBuffer) {
screen_manager_->AddWindow(1, std::move(window));
screen_manager_->AddDisplayController(drm_, kPrimaryCrtc, kPrimaryConnector);
- screen_manager_->ConfigureDisplayController(
- drm_, kPrimaryCrtc, kPrimaryConnector, GetPrimaryBounds().origin(),
- kDefaultMode);
+ std::vector<ScreenManager::ControllerConfigParams> controllers_to_enable;
+ controllers_to_enable.emplace_back(
+ kPrimaryDisplayId, drm_, kPrimaryCrtc, kPrimaryConnector,
+ GetPrimaryBounds().origin(),
+ std::make_unique<drmModeModeInfo>(kDefaultMode));
+ screen_manager_->ConfigureDisplayControllers(controllers_to_enable);
EXPECT_TRUE(screen_manager_->GetWindow(1)->GetController());
// There is a buffer after initial config.
uint32_t framebuffer = drm_->current_framebuffer();
EXPECT_NE(0U, framebuffer);
- screen_manager_->ConfigureDisplayController(
- drm_, kPrimaryCrtc, kPrimaryConnector, GetPrimaryBounds().origin(),
- kDefaultMode);
+ controllers_to_enable.clear();
+ controllers_to_enable.emplace_back(
+ kPrimaryDisplayId, drm_, kPrimaryCrtc, kPrimaryConnector,
+ GetPrimaryBounds().origin(),
+ std::make_unique<drmModeModeInfo>(kDefaultMode));
+ screen_manager_->ConfigureDisplayControllers(controllers_to_enable);
// There is a new buffer after we configured with the same mode but no
// pending frames on the window.
@@ -521,6 +935,8 @@ TEST_F(ScreenManagerTest, EnableControllerWhenWindowHasNoBuffer) {
}
TEST_F(ScreenManagerTest, EnableControllerWhenWindowHasBuffer) {
+ InitializeDrmStateWithDefault(drm_.get(), /*is_atomic=*/false);
+
std::unique_ptr<ui::DrmWindow> window(
new ui::DrmWindow(1, device_manager_.get(), screen_manager_.get()));
window->Initialize();
@@ -534,9 +950,12 @@ TEST_F(ScreenManagerTest, EnableControllerWhenWindowHasBuffer) {
screen_manager_->AddWindow(1, std::move(window));
screen_manager_->AddDisplayController(drm_, kPrimaryCrtc, kPrimaryConnector);
- screen_manager_->ConfigureDisplayController(
- drm_, kPrimaryCrtc, kPrimaryConnector, GetPrimaryBounds().origin(),
- kDefaultMode);
+ std::vector<ScreenManager::ControllerConfigParams> controllers_to_enable;
+ controllers_to_enable.emplace_back(
+ kPrimaryDisplayId, drm_, kPrimaryCrtc, kPrimaryConnector,
+ GetPrimaryBounds().origin(),
+ std::make_unique<drmModeModeInfo>(kDefaultMode));
+ screen_manager_->ConfigureDisplayControllers(controllers_to_enable);
EXPECT_EQ(buffer->opaque_framebuffer_id(), drm_->current_framebuffer());
@@ -559,9 +978,12 @@ TEST_F(ScreenManagerTest, DISABLED_RejectBufferWithIncompatibleModifiers) {
screen_manager_->AddWindow(1, std::move(window));
screen_manager_->AddDisplayController(drm_, kPrimaryCrtc, kPrimaryConnector);
- screen_manager_->ConfigureDisplayController(
- drm_, kPrimaryCrtc, kPrimaryConnector, GetPrimaryBounds().origin(),
- kDefaultMode);
+ std::vector<ScreenManager::ControllerConfigParams> controllers_to_enable;
+ controllers_to_enable.emplace_back(
+ kPrimaryDisplayId, drm_, kPrimaryCrtc, kPrimaryConnector,
+ GetPrimaryBounds().origin(),
+ std::make_unique<drmModeModeInfo>(kDefaultMode));
+ screen_manager_->ConfigureDisplayControllers(controllers_to_enable);
// ScreenManager::GetModesetBuffer (called to get a buffer to
// modeset the new controller) should reject the buffer with
@@ -575,6 +997,8 @@ TEST_F(ScreenManagerTest, DISABLED_RejectBufferWithIncompatibleModifiers) {
}
TEST_F(ScreenManagerTest, ConfigureDisplayControllerShouldModesetOnce) {
+ InitializeDrmStateWithDefault(drm_.get(), /*is_atomic=*/false);
+
std::unique_ptr<ui::DrmWindow> window(
new ui::DrmWindow(1, device_manager_.get(), screen_manager_.get()));
window->Initialize();
@@ -582,9 +1006,12 @@ TEST_F(ScreenManagerTest, ConfigureDisplayControllerShouldModesetOnce) {
screen_manager_->AddWindow(1, std::move(window));
screen_manager_->AddDisplayController(drm_, kPrimaryCrtc, kPrimaryConnector);
- screen_manager_->ConfigureDisplayController(
- drm_, kPrimaryCrtc, kPrimaryConnector, GetPrimaryBounds().origin(),
- kDefaultMode);
+ std::vector<ScreenManager::ControllerConfigParams> controllers_to_enable;
+ controllers_to_enable.emplace_back(
+ kPrimaryDisplayId, drm_, kPrimaryCrtc, kPrimaryConnector,
+ GetPrimaryBounds().origin(),
+ std::make_unique<drmModeModeInfo>(kDefaultMode));
+ screen_manager_->ConfigureDisplayControllers(controllers_to_enable);
// When a window that had no controller becomes associated with a new
// controller, expect the crtc to be modeset once.
@@ -594,28 +1021,38 @@ TEST_F(ScreenManagerTest, ConfigureDisplayControllerShouldModesetOnce) {
window->Shutdown();
}
-TEST(ScreenManagerTest2, ShouldNotHardwareMirrorDifferentDrmDevices) {
+TEST_F(ScreenManagerTest, ShouldNotHardwareMirrorDifferentDrmDevices) {
auto gbm_device1 = std::make_unique<MockGbmDevice>();
auto drm_device1 =
base::MakeRefCounted<MockDrmDevice>(std::move(gbm_device1));
+ InitializeDrmStateWithDefault(drm_device1.get());
+
auto gbm_device2 = std::make_unique<MockGbmDevice>();
auto drm_device2 =
base::MakeRefCounted<MockDrmDevice>(std::move(gbm_device2));
+ InitializeDrmStateWithDefault(drm_device2.get());
+
DrmDeviceManager drm_device_manager(nullptr);
ScreenManager screen_manager;
- constexpr uint32_t kCrtc19 = 19;
- constexpr uint32_t kConnector28 = 28;
- constexpr uint32_t kCrtc20 = 20;
- constexpr uint32_t kConnector22 = 22;
+ constexpr uint32_t kCrtc1 = kPrimaryCrtc;
+ constexpr uint32_t kConnector1 = kPrimaryConnector;
+ constexpr uint32_t kCrtc2 = kSecondaryCrtc;
+ constexpr uint32_t kConnector2 = kSecondaryConnector;
+
+ drmModeModeInfo k1920x1080Screen = ConstructMode(1920, 1080);
+ std::unique_ptr<drmModeModeInfo> primary_mode =
+ std::make_unique<drmModeModeInfo>(k1920x1080Screen);
+ std::unique_ptr<drmModeModeInfo> secondary_mode =
+ std::make_unique<drmModeModeInfo>(k1920x1080Screen);
// Two displays on different DRM devices must not join a mirror pair.
//
// However, they may have the same bounds in a transitional state.
//
- // This scenario generates the same sequence of display configuration events
- // as a panther (kernel 3.8.11) chromebox with two identical 1080p displays
- // connected, one of them via a DisplayLink adapter.
+ // This scenario generates the same sequence of display configuration
+ // events as a panther (kernel 3.8.11) chromebox with two identical
+ // 1080p displays connected, one of them via a DisplayLink adapter.
// Both displays connect at startup.
{
@@ -624,13 +1061,22 @@ TEST(ScreenManagerTest2, ShouldNotHardwareMirrorDifferentDrmDevices) {
window1->Initialize();
screen_manager.AddWindow(1, std::move(window1));
screen_manager.GetWindow(1)->SetBounds(gfx::Rect(0, 0, 1920, 1080));
- screen_manager.AddDisplayController(drm_device1, kCrtc19, kConnector28);
- screen_manager.AddDisplayController(drm_device2, kCrtc20, kConnector22);
- screen_manager.ConfigureDisplayController(
- drm_device1, kCrtc19, kConnector28, gfx::Point(0, 0), Mode(1920, 1080));
- screen_manager.ConfigureDisplayController(drm_device2, kCrtc20,
- kConnector22, gfx::Point(0, 1140),
- Mode(1920, 1080));
+ screen_manager.AddDisplayController(drm_device1, kCrtc1, kConnector1);
+ screen_manager.AddDisplayController(drm_device2, kCrtc2, kConnector2);
+
+ std::vector<ScreenManager::ControllerConfigParams> controllers_to_enable;
+ std::unique_ptr<drmModeModeInfo> primary_mode =
+ std::make_unique<drmModeModeInfo>(k1920x1080Screen);
+ std::unique_ptr<drmModeModeInfo> secondary_mode =
+ std::make_unique<drmModeModeInfo>(k1920x1080Screen);
+ controllers_to_enable.emplace_back(kPrimaryDisplayId, drm_device1, kCrtc1,
+ kConnector1, gfx::Point(0, 0),
+ std::move(primary_mode));
+ controllers_to_enable.emplace_back(kSecondaryDisplayId, drm_device2, kCrtc2,
+ kConnector2, gfx::Point(0, 1140),
+ std::move(secondary_mode));
+ screen_manager.ConfigureDisplayControllers(controllers_to_enable);
+
auto window2 =
std::make_unique<DrmWindow>(2, &drm_device_manager, &screen_manager);
window2->Initialize();
@@ -645,15 +1091,24 @@ TEST(ScreenManagerTest2, ShouldNotHardwareMirrorDifferentDrmDevices) {
HardwareDisplayController* controller2 =
screen_manager.GetWindow(2)->GetController();
EXPECT_NE(controller1, controller2);
- EXPECT_TRUE(controller1->HasCrtc(drm_device1, kCrtc19));
- EXPECT_TRUE(controller2->HasCrtc(drm_device2, kCrtc20));
+ EXPECT_TRUE(controller1->HasCrtc(drm_device1, kCrtc1));
+ EXPECT_TRUE(controller2->HasCrtc(drm_device2, kCrtc2));
}
// Disconnect first display. Second display moves to origin.
{
- screen_manager.RemoveDisplayController(drm_device1, kCrtc19);
- screen_manager.ConfigureDisplayController(
- drm_device2, kCrtc20, kConnector22, gfx::Point(0, 0), Mode(1920, 1080));
+ ScreenManager::CrtcsWithDrmList controllers_to_remove;
+ controllers_to_remove.emplace_back(kCrtc1, drm_device1);
+ screen_manager.RemoveDisplayControllers(controllers_to_remove);
+
+ std::vector<ScreenManager::ControllerConfigParams> controllers_to_enable;
+ std::unique_ptr<drmModeModeInfo> secondary_mode =
+ std::make_unique<drmModeModeInfo>(k1920x1080Screen);
+ controllers_to_enable.emplace_back(kSecondaryDisplayId, drm_device2, kCrtc2,
+ kConnector2, gfx::Point(0, 0),
+ std::move(secondary_mode));
+ screen_manager.ConfigureDisplayControllers(controllers_to_enable);
+
screen_manager.GetWindow(1)->SetBounds(gfx::Rect(0, 0, 1920, 1080));
screen_manager.GetWindow(1)->SetBounds(gfx::Rect(0, 0, 1920, 1080));
screen_manager.RemoveWindow(2)->Shutdown();
@@ -661,22 +1116,31 @@ TEST(ScreenManagerTest2, ShouldNotHardwareMirrorDifferentDrmDevices) {
// Reconnect first display. Original configuration restored.
{
- screen_manager.AddDisplayController(drm_device1, kCrtc19, kConnector28);
- screen_manager.ConfigureDisplayController(
- drm_device1, kCrtc19, kConnector28, gfx::Point(0, 0), Mode(1920, 1080));
+ screen_manager.AddDisplayController(drm_device1, kCrtc1, kConnector1);
+ std::vector<ScreenManager::ControllerConfigParams> controllers_to_enable;
+ std::unique_ptr<drmModeModeInfo> primary_mode =
+ std::make_unique<drmModeModeInfo>(k1920x1080Screen);
+ controllers_to_enable.emplace_back(kPrimaryDisplayId, drm_device1, kCrtc1,
+ kConnector1, gfx::Point(0, 0),
+ std::move(primary_mode));
+ screen_manager.ConfigureDisplayControllers(controllers_to_enable);
// At this point, both displays are in the same location.
{
HardwareDisplayController* controller =
screen_manager.GetWindow(1)->GetController();
EXPECT_FALSE(controller->IsMirrored());
- // We don't really care which crtc it has, but it should have just one.
+ // We don't really care which crtc it has, but it should have just
EXPECT_EQ(1U, controller->crtc_controllers().size());
- EXPECT_TRUE(controller->HasCrtc(drm_device1, kCrtc19) ||
- controller->HasCrtc(drm_device2, kCrtc20));
+ EXPECT_TRUE(controller->HasCrtc(drm_device1, kCrtc1) ||
+ controller->HasCrtc(drm_device2, kCrtc2));
}
- screen_manager.ConfigureDisplayController(drm_device2, kCrtc20,
- kConnector22, gfx::Point(0, 1140),
- Mode(1920, 1080));
+ controllers_to_enable.clear();
+ std::unique_ptr<drmModeModeInfo> secondary_mode =
+ std::make_unique<drmModeModeInfo>(k1920x1080Screen);
+ controllers_to_enable.emplace_back(kSecondaryDisplayId, drm_device2, kCrtc2,
+ kConnector2, gfx::Point(0, 1140),
+ std::move(secondary_mode));
+ screen_manager.ConfigureDisplayControllers(controllers_to_enable);
auto window3 =
std::make_unique<DrmWindow>(3, &drm_device_manager, &screen_manager);
window3->Initialize();
@@ -694,8 +1158,8 @@ TEST(ScreenManagerTest2, ShouldNotHardwareMirrorDifferentDrmDevices) {
HardwareDisplayController* controller3 =
screen_manager.GetWindow(3)->GetController();
EXPECT_NE(controller1, controller3);
- EXPECT_TRUE(controller1->HasCrtc(drm_device1, kCrtc19));
- EXPECT_TRUE(controller3->HasCrtc(drm_device2, kCrtc20));
+ EXPECT_TRUE(controller1->HasCrtc(drm_device1, kCrtc1));
+ EXPECT_TRUE(controller3->HasCrtc(drm_device2, kCrtc2));
}
// Cleanup.
@@ -704,18 +1168,20 @@ TEST(ScreenManagerTest2, ShouldNotHardwareMirrorDifferentDrmDevices) {
}
// crbug.com/888553
-TEST(ScreenManagerTest2, ShouldNotUnbindFramebufferOnJoiningMirror) {
+TEST_F(ScreenManagerTest, ShouldNotUnbindFramebufferOnJoiningMirror) {
auto gbm_device = std::make_unique<MockGbmDevice>();
auto drm_device = base::MakeRefCounted<MockDrmDevice>(std::move(gbm_device));
+ InitializeDrmStateWithDefault(drm_device.get(), /*is_atomic=*/false);
+
DrmDeviceManager drm_device_manager(nullptr);
ScreenManager screen_manager;
- constexpr uint32_t kCrtc39 = 39;
- constexpr uint32_t kConnector43 = 43;
- constexpr uint32_t kCrtc41 = 41;
- constexpr uint32_t kConnector46 = 46;
+ constexpr uint32_t kCrtc1 = kPrimaryCrtc;
+ constexpr uint32_t kConnector1 = kPrimaryConnector;
+ constexpr uint32_t kCrtc2 = kSecondaryCrtc;
+ constexpr uint32_t kConnector2 = kSecondaryConnector;
- constexpr drmModeModeInfo kMode1080p60 = {
+ constexpr drmModeModeInfo k1080p60Screen = {
/* clock= */ 148500,
/* hdisplay= */ 1920,
/* hsync_start= */ 2008,
@@ -740,16 +1206,25 @@ TEST(ScreenManagerTest2, ShouldNotUnbindFramebufferOnJoiningMirror) {
window1->Initialize();
screen_manager.AddWindow(1, std::move(window1));
screen_manager.GetWindow(1)->SetBounds(gfx::Rect(0, 0, 1920, 1080));
- screen_manager.AddDisplayController(drm_device, kCrtc39, kConnector43);
- screen_manager.AddDisplayController(drm_device, kCrtc41, kConnector46);
- screen_manager.ConfigureDisplayController(drm_device, kCrtc39, kConnector43,
- gfx::Point(0, 0), kMode1080p60);
- screen_manager.ConfigureDisplayController(drm_device, kCrtc41, kConnector46,
- gfx::Point(0, 0), kMode1080p60);
+ screen_manager.AddDisplayController(drm_device, kCrtc1, kConnector1);
+ screen_manager.AddDisplayController(drm_device, kCrtc2, kConnector2);
+
+ std::vector<ScreenManager::ControllerConfigParams> controllers_to_enable;
+ std::unique_ptr<drmModeModeInfo> primary_mode =
+ std::make_unique<drmModeModeInfo>(k1080p60Screen);
+ std::unique_ptr<drmModeModeInfo> secondary_mode =
+ std::make_unique<drmModeModeInfo>(k1080p60Screen);
+ controllers_to_enable.emplace_back(kPrimaryDisplayId, drm_device, kCrtc1,
+ kConnector1, gfx::Point(0, 0),
+ std::move(primary_mode));
+ controllers_to_enable.emplace_back(kSecondaryDisplayId, drm_device, kCrtc2,
+ kConnector2, gfx::Point(0, 0),
+ std::move(secondary_mode));
+ screen_manager.ConfigureDisplayControllers(controllers_to_enable);
}
- EXPECT_NE(0u, drm_device->GetFramebufferForCrtc(kCrtc39));
- EXPECT_NE(0u, drm_device->GetFramebufferForCrtc(kCrtc41));
+ EXPECT_NE(0u, drm_device->GetFramebufferForCrtc(kCrtc1));
+ EXPECT_NE(0u, drm_device->GetFramebufferForCrtc(kCrtc2));
// Cleanup.
screen_manager.RemoveWindow(1)->Shutdown();
diff --git a/chromium/ui/ozone/platform/drm/gpu/vulkan_implementation_gbm.cc b/chromium/ui/ozone/platform/drm/gpu/vulkan_implementation_gbm.cc
index e3792ee932d..fa3d41f7afd 100644
--- a/chromium/ui/ozone/platform/drm/gpu/vulkan_implementation_gbm.cc
+++ b/chromium/ui/ozone/platform/drm/gpu/vulkan_implementation_gbm.cc
@@ -134,10 +134,8 @@ std::unique_ptr<gfx::GpuFence> VulkanImplementationGbm::ExportVkFenceToGpuFence(
}
gfx::GpuFenceHandle gpu_fence_handle;
- gpu_fence_handle.type = gfx::GpuFenceHandleType::kAndroidNativeFenceSync;
- gpu_fence_handle.native_fd =
- base::FileDescriptor(fence_fd, true /* auto_close */);
- return std::make_unique<gfx::GpuFence>(gpu_fence_handle);
+ gpu_fence_handle.owned_fd = base::ScopedFD(fence_fd);
+ return std::make_unique<gfx::GpuFence>(std::move(gpu_fence_handle));
}
VkSemaphore VulkanImplementationGbm::CreateExternalSemaphore(
diff --git a/chromium/ui/ozone/platform/drm/host/drm_display_host.cc b/chromium/ui/ozone/platform/drm/host/drm_display_host.cc
index 23c44ce2e5a..f46106b9c0c 100644
--- a/chromium/ui/ozone/platform/drm/host/drm_display_host.cc
+++ b/chromium/ui/ozone/platform/drm/host/drm_display_host.cc
@@ -38,15 +38,18 @@ void DrmDisplayHost::UpdateDisplaySnapshot(
void DrmDisplayHost::GetHDCPState(display::GetHDCPStateCallback callback) {
get_hdcp_callback_ = std::move(callback);
if (!sender_->GpuGetHDCPState(snapshot_->display_id()))
- OnHDCPStateReceived(false, display::HDCP_STATE_UNDESIRED);
+ OnHDCPStateReceived(false, display::HDCP_STATE_UNDESIRED,
+ display::CONTENT_PROTECTION_METHOD_NONE);
}
-void DrmDisplayHost::OnHDCPStateReceived(bool status,
- display::HDCPState state) {
+void DrmDisplayHost::OnHDCPStateReceived(
+ bool status,
+ display::HDCPState state,
+ display::ContentProtectionMethod protection_method) {
if (!get_hdcp_callback_.is_null()) {
base::ThreadTaskRunnerHandle::Get()->PostTask(
- FROM_HERE,
- base::BindOnce(std::move(get_hdcp_callback_), status, state));
+ FROM_HERE, base::BindOnce(std::move(get_hdcp_callback_), status, state,
+ protection_method));
} else {
LOG(ERROR) << "Got unexpected event for display "
<< snapshot_->display_id();
@@ -55,10 +58,13 @@ void DrmDisplayHost::OnHDCPStateReceived(bool status,
get_hdcp_callback_.Reset();
}
-void DrmDisplayHost::SetHDCPState(display::HDCPState state,
- display::SetHDCPStateCallback callback) {
+void DrmDisplayHost::SetHDCPState(
+ display::HDCPState state,
+ display::ContentProtectionMethod protection_method,
+ display::SetHDCPStateCallback callback) {
set_hdcp_callback_ = std::move(callback);
- if (!sender_->GpuSetHDCPState(snapshot_->display_id(), state))
+ if (!sender_->GpuSetHDCPState(snapshot_->display_id(), state,
+ protection_method))
OnHDCPStateUpdated(false);
}
@@ -103,7 +109,8 @@ void DrmDisplayHost::OnGpuThreadRetired() {}
void DrmDisplayHost::ClearCallbacks() {
if (!get_hdcp_callback_.is_null())
- OnHDCPStateReceived(false, display::HDCP_STATE_UNDESIRED);
+ OnHDCPStateReceived(false, display::HDCP_STATE_UNDESIRED,
+ display::CONTENT_PROTECTION_METHOD_NONE);
if (!set_hdcp_callback_.is_null())
OnHDCPStateUpdated(false);
}
diff --git a/chromium/ui/ozone/platform/drm/host/drm_display_host.h b/chromium/ui/ozone/platform/drm/host/drm_display_host.h
index 5bb6a114ee3..d94fb6d5461 100644
--- a/chromium/ui/ozone/platform/drm/host/drm_display_host.h
+++ b/chromium/ui/ozone/platform/drm/host/drm_display_host.h
@@ -34,6 +34,7 @@ class DrmDisplayHost : public GpuThreadObserver {
void UpdateDisplaySnapshot(std::unique_ptr<display::DisplaySnapshot> params);
void GetHDCPState(display::GetHDCPStateCallback callback);
void SetHDCPState(display::HDCPState state,
+ display::ContentProtectionMethod protection_method,
display::SetHDCPStateCallback callback);
void SetColorMatrix(const std::vector<float>& color_matrix);
void SetGammaCorrection(
@@ -43,7 +44,9 @@ class DrmDisplayHost : public GpuThreadObserver {
// Called when the IPC from the GPU process arrives to answer the above
// commands.
- void OnHDCPStateReceived(bool status, display::HDCPState state);
+ void OnHDCPStateReceived(bool status,
+ display::HDCPState state,
+ display::ContentProtectionMethod protection_method);
void OnHDCPStateUpdated(bool status);
// GpuThreadObserver:
diff --git a/chromium/ui/ozone/platform/drm/host/drm_display_host_manager.cc b/chromium/ui/ozone/platform/drm/host/drm_display_host_manager.cc
index e3429cbce13..975da5c6ab3 100644
--- a/chromium/ui/ozone/platform/drm/host/drm_display_host_manager.cc
+++ b/chromium/ui/ozone/platform/drm/host/drm_display_host_manager.cc
@@ -412,12 +412,14 @@ void DrmDisplayHostManager::GpuHasUpdatedNativeDisplays(
}
}
-void DrmDisplayHostManager::GpuReceivedHDCPState(int64_t display_id,
- bool status,
- display::HDCPState state) {
+void DrmDisplayHostManager::GpuReceivedHDCPState(
+ int64_t display_id,
+ bool status,
+ display::HDCPState state,
+ display::ContentProtectionMethod protection_method) {
DrmDisplayHost* display = GetDisplay(display_id);
if (display)
- display->OnHDCPStateReceived(status, state);
+ display->OnHDCPStateReceived(status, state, protection_method);
else
LOG(ERROR) << "Couldn't find display with id=" << display_id;
}
diff --git a/chromium/ui/ozone/platform/drm/host/drm_display_host_manager.h b/chromium/ui/ozone/platform/drm/host/drm_display_host_manager.h
index bddc9b5beac..96279fd74af 100644
--- a/chromium/ui/ozone/platform/drm/host/drm_display_host_manager.h
+++ b/chromium/ui/ozone/platform/drm/host/drm_display_host_manager.h
@@ -68,7 +68,8 @@ class DrmDisplayHostManager : public DeviceEventObserver, GpuThreadObserver {
void GpuHasUpdatedNativeDisplays(MovableDisplaySnapshots displays);
void GpuReceivedHDCPState(int64_t display_id,
bool status,
- display::HDCPState state);
+ display::HDCPState state,
+ display::ContentProtectionMethod protection_method);
void GpuUpdatedHDCPState(int64_t display_id, bool status);
void GpuTookDisplayControl(bool status);
void GpuRelinquishedDisplayControl(bool status);
diff --git a/chromium/ui/ozone/platform/drm/host/drm_native_display_delegate.cc b/chromium/ui/ozone/platform/drm/host/drm_native_display_delegate.cc
index c239f99e51d..4c127b24b5f 100644
--- a/chromium/ui/ozone/platform/drm/host/drm_native_display_delegate.cc
+++ b/chromium/ui/ozone/platform/drm/host/drm_native_display_delegate.cc
@@ -66,9 +66,10 @@ void DrmNativeDisplayDelegate::GetHDCPState(
void DrmNativeDisplayDelegate::SetHDCPState(
const display::DisplaySnapshot& output,
display::HDCPState state,
+ display::ContentProtectionMethod protection_method,
display::SetHDCPStateCallback callback) {
DrmDisplayHost* display = display_manager_->GetDisplay(output.display_id());
- display->SetHDCPState(state, std::move(callback));
+ display->SetHDCPState(state, protection_method, std::move(callback));
}
bool DrmNativeDisplayDelegate::SetColorMatrix(
diff --git a/chromium/ui/ozone/platform/drm/host/drm_native_display_delegate.h b/chromium/ui/ozone/platform/drm/host/drm_native_display_delegate.h
index fd141f1fdc6..b2ee384fc3c 100644
--- a/chromium/ui/ozone/platform/drm/host/drm_native_display_delegate.h
+++ b/chromium/ui/ozone/platform/drm/host/drm_native_display_delegate.h
@@ -36,6 +36,7 @@ class DrmNativeDisplayDelegate : public display::NativeDisplayDelegate {
display::GetHDCPStateCallback callback) override;
void SetHDCPState(const display::DisplaySnapshot& output,
display::HDCPState state,
+ display::ContentProtectionMethod protection_method,
display::SetHDCPStateCallback callback) override;
bool SetColorMatrix(int64_t display_id,
const std::vector<float>& color_matrix) override;
diff --git a/chromium/ui/ozone/platform/drm/host/gpu_thread_adapter.h b/chromium/ui/ozone/platform/drm/host/gpu_thread_adapter.h
index c782923ddf1..aa64e27b463 100644
--- a/chromium/ui/ozone/platform/drm/host/gpu_thread_adapter.h
+++ b/chromium/ui/ozone/platform/drm/host/gpu_thread_adapter.h
@@ -48,8 +48,10 @@ class GpuThreadAdapter {
const std::vector<display::DisplayConfigurationParams>& config_requests,
display::ConfigureCallback callback) = 0;
virtual bool GpuGetHDCPState(int64_t display_id) = 0;
- virtual bool GpuSetHDCPState(int64_t display_id,
- display::HDCPState state) = 0;
+ virtual bool GpuSetHDCPState(
+ int64_t display_id,
+ display::HDCPState state,
+ display::ContentProtectionMethod protection_method) = 0;
virtual bool GpuSetColorMatrix(int64_t display_id,
const std::vector<float>& color_matrix) = 0;
virtual bool GpuSetGammaCorrection(
diff --git a/chromium/ui/ozone/platform/drm/host/host_drm_device.cc b/chromium/ui/ozone/platform/drm/host/host_drm_device.cc
index 960df0d3905..627db7ce4f8 100644
--- a/chromium/ui/ozone/platform/drm/host/host_drm_device.cc
+++ b/chromium/ui/ozone/platform/drm/host/host_drm_device.cc
@@ -208,14 +208,17 @@ bool HostDrmDevice::GpuGetHDCPState(int64_t display_id) {
return true;
}
-bool HostDrmDevice::GpuSetHDCPState(int64_t display_id,
- display::HDCPState state) {
+bool HostDrmDevice::GpuSetHDCPState(
+ int64_t display_id,
+ display::HDCPState state,
+ display::ContentProtectionMethod protection_method) {
DCHECK_CALLED_ON_VALID_THREAD(on_ui_thread_);
if (!IsConnected())
return false;
auto callback = base::BindOnce(&HostDrmDevice::GpuSetHDCPStateCallback, this);
- drm_device_->SetHDCPState(display_id, state, std::move(callback));
+ drm_device_->SetHDCPState(display_id, state, protection_method,
+ std::move(callback));
return true;
}
@@ -267,11 +270,14 @@ void HostDrmDevice::GpuRelinquishDisplayControlCallback(bool success) const {
display_manager_->GpuRelinquishedDisplayControl(success);
}
-void HostDrmDevice::GpuGetHDCPStateCallback(int64_t display_id,
- bool success,
- display::HDCPState state) const {
+void HostDrmDevice::GpuGetHDCPStateCallback(
+ int64_t display_id,
+ bool success,
+ display::HDCPState state,
+ display::ContentProtectionMethod protection_method) const {
DCHECK_CALLED_ON_VALID_THREAD(on_ui_thread_);
- display_manager_->GpuReceivedHDCPState(display_id, success, state);
+ display_manager_->GpuReceivedHDCPState(display_id, success, state,
+ protection_method);
}
void HostDrmDevice::GpuSetHDCPStateCallback(int64_t display_id,
diff --git a/chromium/ui/ozone/platform/drm/host/host_drm_device.h b/chromium/ui/ozone/platform/drm/host/host_drm_device.h
index 2484d706c9e..18170a0bc2f 100644
--- a/chromium/ui/ozone/platform/drm/host/host_drm_device.h
+++ b/chromium/ui/ozone/platform/drm/host/host_drm_device.h
@@ -69,7 +69,10 @@ class HostDrmDevice : public base::RefCountedThreadSafe<HostDrmDevice>,
const std::vector<display::DisplayConfigurationParams>& config_requests,
display::ConfigureCallback callback) override;
bool GpuGetHDCPState(int64_t display_id) override;
- bool GpuSetHDCPState(int64_t display_id, display::HDCPState state) override;
+ bool GpuSetHDCPState(
+ int64_t display_id,
+ display::HDCPState state,
+ display::ContentProtectionMethod protection_method) override;
bool GpuSetColorMatrix(int64_t display_id,
const std::vector<float>& color_matrix) override;
bool GpuSetGammaCorrection(
@@ -96,9 +99,11 @@ class HostDrmDevice : public base::RefCountedThreadSafe<HostDrmDevice>,
void GpuRefreshNativeDisplaysCallback(MovableDisplaySnapshots displays) const;
void GpuTakeDisplayControlCallback(bool success) const;
void GpuRelinquishDisplayControlCallback(bool success) const;
- void GpuGetHDCPStateCallback(int64_t display_id,
- bool success,
- display::HDCPState state) const;
+ void GpuGetHDCPStateCallback(
+ int64_t display_id,
+ bool success,
+ display::HDCPState state,
+ display::ContentProtectionMethod protection_method) const;
void GpuSetHDCPStateCallback(int64_t display_id, bool success) const;
void OnGpuServiceLaunchedOnUIThread(
diff --git a/chromium/ui/ozone/platform/drm/ozone_platform_gbm.cc b/chromium/ui/ozone/platform/drm/ozone_platform_drm.cc
index 4e81e147590..8a6442257df 100644
--- a/chromium/ui/ozone/platform/drm/ozone_platform_gbm.cc
+++ b/chromium/ui/ozone/platform/drm/ozone_platform_drm.cc
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "ui/ozone/platform/drm/ozone_platform_gbm.h"
+#include "ui/ozone/platform/drm/ozone_platform_drm.h"
#include <gbm.h>
#include <stdlib.h>
@@ -68,10 +68,10 @@ namespace ui {
namespace {
-class OzonePlatformGbm : public OzonePlatform {
+class OzonePlatformDrm : public OzonePlatform {
public:
- OzonePlatformGbm() = default;
- ~OzonePlatformGbm() override = default;
+ OzonePlatformDrm() = default;
+ ~OzonePlatformDrm() override = default;
// OzonePlatform:
ui::SurfaceFactoryOzone* GetSurfaceFactoryOzone() override {
@@ -91,7 +91,7 @@ class OzonePlatformGbm : public OzonePlatform {
}
GpuPlatformSupportHost* GetGpuPlatformSupportHost() override {
- return drm_device_connector_.get();
+ return drm_device_connector_.get();
}
std::unique_ptr<SystemInputInjector> CreateSystemInputInjector() override {
@@ -110,7 +110,7 @@ class OzonePlatformGbm : public OzonePlatform {
// method after drm_thread is started.
binders->Add<ozone::mojom::DrmDevice>(
base::BindRepeating(
- &OzonePlatformGbm::CreateDrmDeviceReceiverOnGpuThread,
+ &OzonePlatformDrm::CreateDrmDeviceReceiverOnGpuThread,
weak_factory_.GetWeakPtr()),
gpu_task_runner_);
} else {
@@ -123,7 +123,7 @@ class OzonePlatformGbm : public OzonePlatform {
// Binder callbacks should directly run on DRM thread.
binders->Add<ozone::mojom::DrmDevice>(
base::BindRepeating(
- &OzonePlatformGbm::CreateDrmDeviceReceiverOnDrmThread,
+ &OzonePlatformDrm::CreateDrmDeviceReceiverOnDrmThread,
weak_factory_.GetWeakPtr()),
drm_thread_proxy_->GetDrmThreadTaskRunner());
}
@@ -295,7 +295,7 @@ class OzonePlatformGbm : public OzonePlatform {
DrainReceiverRequests();
} else {
auto safe_receiver_request_drainer = CreateSafeOnceCallback(
- base::BindOnce(&OzonePlatformGbm::DrainReceiverRequests,
+ base::BindOnce(&OzonePlatformDrm::DrainReceiverRequests,
weak_factory_.GetWeakPtr()));
drm_thread_proxy_->StartDrmThread(
std::move(safe_receiver_request_drainer));
@@ -336,15 +336,15 @@ class OzonePlatformGbm : public OzonePlatform {
std::unique_ptr<DrmDisplayHostManager> display_manager_;
InitializedHostProperties host_properties_;
- base::WeakPtrFactory<OzonePlatformGbm> weak_factory_{this};
-
- DISALLOW_COPY_AND_ASSIGN(OzonePlatformGbm);
+ base::WeakPtrFactory<OzonePlatformDrm> weak_factory_{this};
+ OzonePlatformDrm(const OzonePlatformDrm&) = delete;
+ OzonePlatformDrm& operator=(const OzonePlatformDrm&) = delete;
};
} // namespace
-OzonePlatform* CreateOzonePlatformGbm() {
- return new OzonePlatformGbm;
+OzonePlatform* CreateOzonePlatformDrm() {
+ return new OzonePlatformDrm;
}
} // namespace ui
diff --git a/chromium/ui/ozone/platform/drm/ozone_platform_gbm.h b/chromium/ui/ozone/platform/drm/ozone_platform_drm.h
index 324535d91d4..39cfa0d87c5 100644
--- a/chromium/ui/ozone/platform/drm/ozone_platform_gbm.h
+++ b/chromium/ui/ozone/platform/drm/ozone_platform_drm.h
@@ -2,16 +2,16 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#ifndef UI_OZONE_PLATFORM_DRM_OZONE_PLATFORM_GBM_H_
-#define UI_OZONE_PLATFORM_DRM_OZONE_PLATFORM_GBM_H_
+#ifndef UI_OZONE_PLATFORM_DRM_OZONE_PLATFORM_DRM_H_
+#define UI_OZONE_PLATFORM_DRM_OZONE_PLATFORM_DRM_H_
namespace ui {
class OzonePlatform;
// Constructor hook for use in ozone_platform_list.cc
-OzonePlatform* CreateOzonePlatformGbm();
+OzonePlatform* CreateOzonePlatformDrm();
} // namespace ui
-#endif // UI_OZONE_PLATFORM_DRM_OZONE_PLATFORM_GBM_H_
+#endif // UI_OZONE_PLATFORM_DRM_OZONE_PLATFORM_DRM_H_
diff --git a/chromium/ui/ozone/platform/scenic/BUILD.gn b/chromium/ui/ozone/platform/scenic/BUILD.gn
index 32792aaf31a..616316662ad 100644
--- a/chromium/ui/ozone/platform/scenic/BUILD.gn
+++ b/chromium/ui/ozone/platform/scenic/BUILD.gn
@@ -18,6 +18,8 @@ source_set("scenic") {
"scenic_gpu_host.h",
"scenic_gpu_service.cc",
"scenic_gpu_service.h",
+ "scenic_overlay_view.cc",
+ "scenic_overlay_view.h",
"scenic_screen.cc",
"scenic_screen.h",
"scenic_surface.cc",
diff --git a/chromium/ui/ozone/platform/scenic/ozone_platform_scenic.cc b/chromium/ui/ozone/platform/scenic/ozone_platform_scenic.cc
index ec639a62722..b7c7dae3c40 100644
--- a/chromium/ui/ozone/platform/scenic/ozone_platform_scenic.cc
+++ b/chromium/ui/ozone/platform/scenic/ozone_platform_scenic.cc
@@ -12,6 +12,7 @@
#include "base/macros.h"
#include "base/memory/ptr_util.h"
#include "base/message_loop/message_pump_type.h"
+#include "base/no_destructor.h"
#include "base/notreached.h"
#include "base/task/current_thread.h"
#include "mojo/public/cpp/bindings/pending_remote.h"
@@ -43,14 +44,6 @@ namespace ui {
namespace {
-constexpr OzonePlatform::PlatformProperties kScenicPlatformProperties{
- .needs_view_token = true,
- .custom_frame_pref_default = false,
- .use_system_title_bar = false,
- .message_pump_type_for_gpu = base::MessagePumpType::IO,
- .supports_vulkan_swap_chain = true,
-};
-
class ScenicPlatformEventSource : public ui::PlatformEventSource {
public:
ScenicPlatformEventSource() = default;
@@ -105,7 +98,17 @@ class OzonePlatformScenic : public OzonePlatform,
}
const PlatformProperties& GetPlatformProperties() override {
- return kScenicPlatformProperties;
+ static base::NoDestructor<OzonePlatform::PlatformProperties> properties;
+ static bool initialised = false;
+ if (!initialised) {
+ properties->needs_view_token = true;
+ properties->message_pump_type_for_gpu = base::MessagePumpType::IO;
+ properties->supports_vulkan_swap_chain = true;
+
+ initialised = true;
+ }
+
+ return *properties;
}
std::unique_ptr<display::NativeDisplayDelegate> CreateNativeDisplayDelegate()
diff --git a/chromium/ui/ozone/platform/scenic/scenic_overlay_view.cc b/chromium/ui/ozone/platform/scenic/scenic_overlay_view.cc
new file mode 100644
index 00000000000..15e00dcea3a
--- /dev/null
+++ b/chromium/ui/ozone/platform/scenic/scenic_overlay_view.cc
@@ -0,0 +1,77 @@
+// Copyright 2020 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 "ui/ozone/platform/scenic/scenic_overlay_view.h"
+
+#include <lib/ui/scenic/cpp/commands.h>
+#include <lib/ui/scenic/cpp/view_token_pair.h>
+
+#include "base/fuchsia/fuchsia_logging.h"
+
+namespace ui {
+
+namespace {
+
+// |buffer_collection_id| that is passed to ImagePipe::AddBufferCollection() if
+// SysmemBufferCollection instance is registered with one.
+static const uint32_t kImagePipeBufferCollectionId = 1;
+static const std::string kSessionDebugName = "chromium scenic overlay";
+
+fuchsia::ui::views::ViewToken CreateViewToken(
+ fuchsia::ui::views::ViewHolderToken* holder_token) {
+ auto token_pair = scenic::ViewTokenPair::New();
+ *holder_token = std::move(token_pair.view_holder_token);
+ return std::move(token_pair.view_token);
+}
+
+} // namespace
+
+ScenicOverlayView::ScenicOverlayView(
+ scenic::SessionPtrAndListenerRequest session_and_listener_request)
+ : scenic_session_(std::move(session_and_listener_request)),
+ view_(&scenic_session_,
+ CreateViewToken(&view_holder_token_),
+ kSessionDebugName) {
+ scenic_session_.SetDebugName(kSessionDebugName);
+ scenic_session_.set_error_handler([](zx_status_t status) {
+ ZX_LOG(FATAL, status) << "Lost connection to scenic session.";
+ });
+}
+
+ScenicOverlayView::~ScenicOverlayView() = default;
+
+void ScenicOverlayView::Initialize(
+ fidl::InterfaceHandle<fuchsia::sysmem::BufferCollectionToken>
+ collection_token) {
+ DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+ uint32_t image_pipe_id = scenic_session_.AllocResourceId();
+ scenic_session_.Enqueue(
+ scenic::NewCreateImagePipe2Cmd(image_pipe_id, image_pipe_.NewRequest()));
+ image_pipe_.set_error_handler([](zx_status_t status) {
+ ZX_LOG(FATAL, status) << "ImagePipe disconnected";
+ });
+
+ scenic::Material image_material(&scenic_session_);
+ image_material.SetTexture(image_pipe_id);
+
+ scenic::ShapeNode shape(&scenic_session_);
+ shape.SetShape(scenic::Rectangle(&scenic_session_, 1.f, 1.f));
+ shape.SetMaterial(image_material);
+
+ view_.AddChild(shape);
+ scenic_session_.ReleaseResource(image_pipe_id);
+ scenic_session_.Present2(
+ /*requested_presentation_time=*/0,
+ /*requested_prediction_span=*/0,
+ [](fuchsia::scenic::scheduling::FuturePresentationTimes info) {});
+
+ // Since there is one ImagePipe for each BufferCollection, it is ok to use a
+ // fixed buffer_collection_id.
+ // TODO(emircan): Consider using one ImagePipe per video decoder instead.
+ image_pipe_->AddBufferCollection(kImagePipeBufferCollectionId,
+ std::move(collection_token));
+ LOG(ERROR) << __func__;
+}
+
+} // namespace ui
diff --git a/chromium/ui/ozone/platform/scenic/scenic_overlay_view.h b/chromium/ui/ozone/platform/scenic/scenic_overlay_view.h
new file mode 100644
index 00000000000..ee32472ea9d
--- /dev/null
+++ b/chromium/ui/ozone/platform/scenic/scenic_overlay_view.h
@@ -0,0 +1,43 @@
+// Copyright 2020 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.
+
+#ifndef UI_OZONE_PLATFORM_SCENIC_SCENIC_OVERLAY_VIEW_H_
+#define UI_OZONE_PLATFORM_SCENIC_SCENIC_OVERLAY_VIEW_H_
+
+#include <fuchsia/ui/scenic/cpp/fidl.h>
+#include <lib/ui/scenic/cpp/resources.h>
+#include <lib/ui/scenic/cpp/session.h>
+
+#include "base/threading/thread_checker.h"
+
+namespace ui {
+
+// Holder for scenic::Session and scenic::View that owns an Image Pipe.
+//
+// This class allows the callers to access an ImagePipe and a scenic::View that
+// displays only that ImagePipe. This is used inside SysmemBufferCollection
+// instances to display overlays.
+class ScenicOverlayView {
+ public:
+ ScenicOverlayView(
+ scenic::SessionPtrAndListenerRequest session_and_listener_request);
+ ~ScenicOverlayView();
+ ScenicOverlayView(const ScenicOverlayView&) = delete;
+ ScenicOverlayView& operator=(const ScenicOverlayView&) = delete;
+
+ void Initialize(fidl::InterfaceHandle<fuchsia::sysmem::BufferCollectionToken>
+ collection_token);
+
+ private:
+ scenic::Session scenic_session_;
+ fuchsia::ui::views::ViewHolderToken view_holder_token_;
+ scenic::View view_;
+ fuchsia::images::ImagePipe2Ptr image_pipe_;
+
+ THREAD_CHECKER(thread_checker_);
+};
+
+} // namespace ui
+
+#endif // UI_OZONE_PLATFORM_SCENIC_SCENIC_OVERLAY_VIEW_H_
diff --git a/chromium/ui/ozone/platform/scenic/scenic_surface_factory.cc b/chromium/ui/ozone/platform/scenic/scenic_surface_factory.cc
index 0b5749ee013..ba0b5e7a2da 100644
--- a/chromium/ui/ozone/platform/scenic/scenic_surface_factory.cc
+++ b/chromium/ui/ozone/platform/scenic/scenic_surface_factory.cc
@@ -138,6 +138,7 @@ fuchsia::sysmem::AllocatorHandle ConnectSysmemAllocator() {
ScenicSurfaceFactory::ScenicSurfaceFactory()
: egl_implementation_(std::make_unique<GLOzoneEGLScenic>(this)),
+ sysmem_buffer_manager_(this),
weak_ptr_factory_(this) {}
ScenicSurfaceFactory::~ScenicSurfaceFactory() {
diff --git a/chromium/ui/ozone/platform/scenic/scenic_surface_factory.h b/chromium/ui/ozone/platform/scenic/scenic_surface_factory.h
index 0a2e11de524..b0454ac45cb 100644
--- a/chromium/ui/ozone/platform/scenic/scenic_surface_factory.h
+++ b/chromium/ui/ozone/platform/scenic/scenic_surface_factory.h
@@ -85,10 +85,10 @@ class ScenicSurfaceFactory : public SurfaceFactoryOzone {
ScenicSurface* GetSurface(gfx::AcceleratedWidget widget)
LOCKS_EXCLUDED(surface_lock_);
- private:
// Creates a new scenic session on any thread.
scenic::SessionPtrAndListenerRequest CreateScenicSession();
+ private:
// Links a surface to its parent window in the host process.
void AttachSurfaceToWindow(
gfx::AcceleratedWidget window,
diff --git a/chromium/ui/ozone/platform/scenic/sysmem_buffer_collection.cc b/chromium/ui/ozone/platform/scenic/sysmem_buffer_collection.cc
index 300e188712e..e84f242d08e 100644
--- a/chromium/ui/ozone/platform/scenic/sysmem_buffer_collection.cc
+++ b/chromium/ui/ozone/platform/scenic/sysmem_buffer_collection.cc
@@ -10,6 +10,7 @@
#include "gpu/vulkan/vulkan_function_pointers.h"
#include "ui/gfx/buffer_format_util.h"
#include "ui/gfx/native_pixmap.h"
+#include "ui/ozone/platform/scenic/scenic_surface_factory.h"
namespace ui {
@@ -129,13 +130,15 @@ SysmemBufferCollection::SysmemBufferCollection(gfx::SysmemBufferCollectionId id)
bool SysmemBufferCollection::Initialize(
fuchsia::sysmem::Allocator_Sync* allocator,
+ ScenicSurfaceFactory* scenic_surface_factory,
zx::channel token_handle,
gfx::Size size,
gfx::BufferFormat format,
gfx::BufferUsage usage,
VkDevice vk_device,
size_t min_buffer_count,
- bool force_protected) {
+ bool force_protected,
+ bool register_with_image_pipe) {
DCHECK(IsNativePixmapConfigSupported(format, usage));
DCHECK(!collection_);
DCHECK(!vk_buffer_collection_);
@@ -165,6 +168,10 @@ bool SysmemBufferCollection::Initialize(
vk_device_ = vk_device;
is_protected_ = force_protected;
+ if (register_with_image_pipe) {
+ scenic_overlay_view_.emplace(scenic_surface_factory->CreateScenicSession());
+ }
+
fuchsia::sysmem::BufferCollectionTokenSyncPtr collection_token;
if (token_handle) {
collection_token.Bind(std::move(token_handle));
@@ -365,12 +372,26 @@ bool SysmemBufferCollection::InitializeInternal(
collection_token_for_vulkan;
collection_token->Duplicate(ZX_RIGHT_SAME_RIGHTS,
collection_token_for_vulkan.NewRequest());
+
+ // Duplicate one more token for Scenic if this collection can be used as an
+ // overlay.
+ fidl::InterfaceHandle<fuchsia::sysmem::BufferCollectionToken>
+ collection_token_for_scenic;
+ if (scenic_overlay_view_.has_value()) {
+ collection_token->Duplicate(ZX_RIGHT_SAME_RIGHTS,
+ collection_token_for_scenic.NewRequest());
+ }
+
zx_status_t status = collection_token->Sync();
if (status != ZX_OK) {
ZX_DLOG(ERROR, status) << "fuchsia.sysmem.BufferCollectionToken.Sync()";
return false;
}
+ if (scenic_overlay_view_.has_value()) {
+ scenic_overlay_view_->Initialize(std::move(collection_token_for_scenic));
+ }
+
status = allocator->BindSharedCollection(std::move(collection_token),
collection_.NewRequest());
if (status != ZX_OK) {
diff --git a/chromium/ui/ozone/platform/scenic/sysmem_buffer_collection.h b/chromium/ui/ozone/platform/scenic/sysmem_buffer_collection.h
index 38f9e12e1bf..07cb267c082 100644
--- a/chromium/ui/ozone/platform/scenic/sysmem_buffer_collection.h
+++ b/chromium/ui/ozone/platform/scenic/sysmem_buffer_collection.h
@@ -6,17 +6,20 @@
#define UI_OZONE_PLATFORM_SCENIC_SYSMEM_BUFFER_COLLECTION_H_
#include <fuchsia/sysmem/cpp/fidl.h>
+#include <lib/ui/scenic/cpp/session.h>
#include <vulkan/vulkan.h>
#include "base/callback.h"
#include "base/macros.h"
#include "base/memory/ref_counted.h"
+#include "base/optional.h"
#include "base/threading/thread_checker.h"
#include "gpu/ipc/common/vulkan_ycbcr_info.h"
#include "gpu/vulkan/fuchsia/vulkan_fuchsia_ext.h"
#include "ui/gfx/buffer_types.h"
#include "ui/gfx/geometry/size.h"
#include "ui/gfx/native_pixmap_handle.h"
+#include "ui/ozone/platform/scenic/scenic_overlay_view.h"
namespace gfx {
class NativePixmap;
@@ -24,6 +27,8 @@ class NativePixmap;
namespace ui {
+class ScenicSurfaceFactory;
+
// SysmemBufferCollection keeps sysmem.BufferCollection interface along with the
// corresponding VkBufferCollectionFUCHSIA. It allows to create either
// gfx::NativePixmap or VkImage from the buffers in the collection.
@@ -44,14 +49,18 @@ class SysmemBufferCollection
// collection is created. |size| may be empty. In that case |token_handle|
// must not be null and the image size is determined by the other sysmem
// participants.
+ // If |register_with_image_pipe| is true, new ScenicOverlayView instance is
+ // created and |token_handle| gets duplicated to be added to its ImagePipe.
bool Initialize(fuchsia::sysmem::Allocator_Sync* allocator,
+ ScenicSurfaceFactory* scenic_surface_factory,
zx::channel token_handle,
gfx::Size size,
gfx::BufferFormat format,
gfx::BufferUsage usage,
VkDevice vk_device,
size_t min_buffer_count,
- bool force_protected);
+ bool force_protected,
+ bool register_with_image_pipe);
// Must not be called more than once.
void SetOnDeletedCallback(base::OnceClosure on_deleted);
@@ -117,6 +126,11 @@ class SysmemBufferCollection
// that is referenced by |collection_|.
VkBufferCollectionFUCHSIA vk_buffer_collection_ = VK_NULL_HANDLE;
+ // If ScenicOverlayView is created and its ImagePipe is added as a participant
+ // in buffer allocation negotiations, the associated images can be displayed
+ // as overlays.
+ base::Optional<ScenicOverlayView> scenic_overlay_view_;
+
// Thread checker used to verify that CreateVkImage() is always called from
// the same thread. It may be unsafe to use vk_buffer_collection_ on different
// threads.
@@ -133,4 +147,4 @@ class SysmemBufferCollection
} // namespace ui
-#endif // UI_OZONE_PLATFORM_SCENIC_SYSMEM_BUFFER_COLLECTION_H_ \ No newline at end of file
+#endif // UI_OZONE_PLATFORM_SCENIC_SYSMEM_BUFFER_COLLECTION_H_
diff --git a/chromium/ui/ozone/platform/scenic/sysmem_buffer_manager.cc b/chromium/ui/ozone/platform/scenic/sysmem_buffer_manager.cc
index 8138ded3e55..8d55a71262b 100644
--- a/chromium/ui/ozone/platform/scenic/sysmem_buffer_manager.cc
+++ b/chromium/ui/ozone/platform/scenic/sysmem_buffer_manager.cc
@@ -12,7 +12,9 @@
namespace ui {
-SysmemBufferManager::SysmemBufferManager() = default;
+SysmemBufferManager::SysmemBufferManager(
+ ScenicSurfaceFactory* scenic_surface_factory)
+ : scenic_surface_factory_(scenic_surface_factory) {}
SysmemBufferManager::~SysmemBufferManager() {
Shutdown();
@@ -39,9 +41,11 @@ scoped_refptr<SysmemBufferCollection> SysmemBufferManager::CreateCollection(
gfx::BufferUsage usage,
size_t min_buffer_count) {
auto result = base::MakeRefCounted<SysmemBufferCollection>();
- if (!result->Initialize(allocator_.get(), /*token_channel=*/zx::channel(),
- size, format, usage, vk_device, min_buffer_count,
- /*force_protected=*/false)) {
+ if (!result->Initialize(allocator_.get(), scenic_surface_factory_,
+ /*token_channel=*/zx::channel(), size, format, usage,
+ vk_device, min_buffer_count,
+ /*force_protected=*/false,
+ /*register_with_image_pipe=*/false)) {
return nullptr;
}
RegisterCollection(result.get());
@@ -57,11 +61,13 @@ SysmemBufferManager::ImportSysmemBufferCollection(
gfx::BufferFormat format,
gfx::BufferUsage usage,
size_t min_buffer_count,
- bool force_protected) {
+ bool force_protected,
+ bool register_with_image_pipe) {
auto result = base::MakeRefCounted<SysmemBufferCollection>(id);
- if (!result->Initialize(allocator_.get(), std::move(token), size, format,
- usage, vk_device, min_buffer_count,
- force_protected)) {
+ if (!result->Initialize(allocator_.get(), scenic_surface_factory_,
+ std::move(token), size, format, usage, vk_device,
+ min_buffer_count, force_protected,
+ register_with_image_pipe)) {
return nullptr;
}
RegisterCollection(result.get());
diff --git a/chromium/ui/ozone/platform/scenic/sysmem_buffer_manager.h b/chromium/ui/ozone/platform/scenic/sysmem_buffer_manager.h
index 6845d8d8df7..eb2dbaa6f5f 100644
--- a/chromium/ui/ozone/platform/scenic/sysmem_buffer_manager.h
+++ b/chromium/ui/ozone/platform/scenic/sysmem_buffer_manager.h
@@ -6,6 +6,7 @@
#define UI_OZONE_PLATFORM_SCENIC_SYSMEM_BUFFER_MANAGER_H_
#include <fuchsia/sysmem/cpp/fidl.h>
+#include <lib/ui/scenic/cpp/session.h>
#include <vulkan/vulkan.h>
#include <unordered_map>
@@ -23,10 +24,11 @@
namespace ui {
class SysmemBufferCollection;
+class ScenicSurfaceFactory;
class SysmemBufferManager {
public:
- explicit SysmemBufferManager();
+ explicit SysmemBufferManager(ScenicSurfaceFactory* scenic_surface_factory);
~SysmemBufferManager();
// Initializes the buffer manager with a connection to the sysmem service.
@@ -51,7 +53,8 @@ class SysmemBufferManager {
gfx::BufferFormat format,
gfx::BufferUsage usage,
size_t min_buffer_count,
- bool force_protected);
+ bool force_protected,
+ bool register_with_image_pipe);
scoped_refptr<SysmemBufferCollection> GetCollectionById(
gfx::SysmemBufferCollectionId id);
@@ -60,6 +63,7 @@ class SysmemBufferManager {
void RegisterCollection(SysmemBufferCollection* collection);
void OnCollectionDestroyed(gfx::SysmemBufferCollectionId id);
+ ScenicSurfaceFactory* const scenic_surface_factory_;
fuchsia::sysmem::AllocatorSyncPtr allocator_;
base::small_map<std::unordered_map<gfx::SysmemBufferCollectionId,
diff --git a/chromium/ui/ozone/platform/scenic/vulkan_implementation_scenic.cc b/chromium/ui/ozone/platform/scenic/vulkan_implementation_scenic.cc
index 6f3d23999e5..507c9032f24 100644
--- a/chromium/ui/ozone/platform/scenic/vulkan_implementation_scenic.cc
+++ b/chromium/ui/ozone/platform/scenic/vulkan_implementation_scenic.cc
@@ -302,14 +302,16 @@ VulkanImplementationScenic::RegisterSysmemBufferCollection(
gfx::BufferFormat format,
gfx::BufferUsage usage,
gfx::Size size,
- size_t min_buffer_count) {
+ size_t min_buffer_count,
+ bool register_with_image_pipe) {
// SCANOUT images must be protected in protected mode.
bool force_protected =
usage == gfx::BufferUsage::SCANOUT && enforce_protected_memory();
+ fuchsia::images::ImagePipe2Ptr image_pipe = nullptr;
auto buffer_collection = sysmem_buffer_manager_->ImportSysmemBufferCollection(
device, id, std::move(token), size, format, usage, min_buffer_count,
- force_protected);
+ force_protected, register_with_image_pipe);
if (!buffer_collection)
return nullptr;
diff --git a/chromium/ui/ozone/platform/scenic/vulkan_implementation_scenic.h b/chromium/ui/ozone/platform/scenic/vulkan_implementation_scenic.h
index d92869e733d..04c371db8d1 100644
--- a/chromium/ui/ozone/platform/scenic/vulkan_implementation_scenic.h
+++ b/chromium/ui/ozone/platform/scenic/vulkan_implementation_scenic.h
@@ -60,7 +60,8 @@ class VulkanImplementationScenic : public gpu::VulkanImplementation {
gfx::BufferFormat format,
gfx::BufferUsage usage,
gfx::Size size,
- size_t min_buffer_count) override;
+ size_t min_buffer_count,
+ bool register_with_image_pipe) override;
private:
ScenicSurfaceFactory* const scenic_surface_factory_;
diff --git a/chromium/ui/ozone/platform/wayland/BUILD.gn b/chromium/ui/ozone/platform/wayland/BUILD.gn
index 6b87d5ca7c6..e61680b4a38 100644
--- a/chromium/ui/ozone/platform/wayland/BUILD.gn
+++ b/chromium/ui/ozone/platform/wayland/BUILD.gn
@@ -4,10 +4,12 @@
visibility = [ "//ui/ozone/*" ]
+import("//build/config/chromeos/ui_mode.gni")
import("//build/config/linux/gtk/gtk.gni")
import("//build/config/linux/pkg_config.gni")
import("//gpu/vulkan/features.gni")
import("//testing/libfuzzer/fuzzer_test.gni")
+import("//third_party/wayland/features.gni")
import("//ui/ozone/platform/wayland/wayland.gni")
source_set("wayland") {
@@ -16,6 +18,8 @@ source_set("wayland") {
"client_native_pixmap_factory_wayland.h",
"common/data_util.cc",
"common/data_util.h",
+ "common/wayland.cc",
+ "common/wayland.h",
"common/wayland_object.cc",
"common/wayland_object.h",
"common/wayland_util.cc",
@@ -122,6 +126,8 @@ source_set("wayland") {
"host/wayland_window_observer.h",
"host/wayland_zwp_linux_dmabuf.cc",
"host/wayland_zwp_linux_dmabuf.h",
+ "host/xdg_foreign_wrapper.cc",
+ "host/xdg_foreign_wrapper.h",
"host/xdg_popup_wrapper_impl.cc",
"host/xdg_popup_wrapper_impl.h",
"host/xdg_surface_wrapper_impl.cc",
@@ -140,19 +146,22 @@ source_set("wayland") {
deps = [
"//base",
- "//build:lacros_buildflags",
+ "//build:chromeos_buildflags",
"//build/config/linux/libdrm",
"//components/exo/wayland/protocol:aura_shell_protocol",
"//mojo/public/cpp/bindings",
"//mojo/public/cpp/system",
"//skia",
- "//third_party/wayland:wayland_egl",
"//third_party/wayland-protocols:gtk_primary_selection_protocol",
"//third_party/wayland-protocols:keyboard_extension_protocol",
"//third_party/wayland-protocols:linux_dmabuf_protocol",
+ "//third_party/wayland-protocols:linux_explicit_synchronization_protocol",
"//third_party/wayland-protocols:presentation_time_protocol",
"//third_party/wayland-protocols:text_input_protocol",
+ "//third_party/wayland-protocols:viewporter_protocol",
"//third_party/wayland-protocols:wayland_drm_protocol",
+ "//third_party/wayland-protocols:xdg_decoration_protocol",
+ "//third_party/wayland-protocols:xdg_foreign",
"//third_party/wayland-protocols:xdg_shell_protocol",
"//ui/base",
"//ui/base:buildflags",
@@ -177,18 +186,6 @@ source_set("wayland") {
"//ui/platform_window/wm",
]
- # TODO(msisov): we should do the following once support for Trusty and Jessie
- # are dropped:
- # 1. Remove libs=["wayland-client"] and
- # add deps+=["//third_party/wayland:wayland_client"]
- # 2. Set use_system_libwayland=true for is_desktop_linux.
- libs = []
- if (!is_chromeos) {
- libs = [ "wayland-client" ]
- } else {
- deps += [ "//third_party/wayland:wayland_client" ]
- }
-
if (is_linux && !is_chromeos) {
deps += [ "//ui/base/ime/linux" ]
}
@@ -204,8 +201,23 @@ source_set("wayland") {
]
}
+ # TODO(crbug.com/1052397): Rename chromeos_is_browser_only to is_lacros.
+ if (chromeos_is_browser_only) {
+ deps += [ "//chromeos/crosapi/cpp" ]
+ }
+
defines = [ "OZONE_IMPLEMENTATION" ]
+ if (use_system_libwayland) {
+ defines += [ "USE_LIBWAYLAND_STUBS" ]
+ deps += [ "//third_party/wayland:wayland_stubs" ]
+ } else {
+ deps += [
+ "//third_party/wayland:wayland_client",
+ "//third_party/wayland:wayland_egl",
+ ]
+ }
+
if (use_wayland_gbm) {
defines += [ "WAYLAND_GBM" ]
sources += [
@@ -291,6 +303,10 @@ source_set("test_support") {
"test/test_subsurface.h",
"test/test_touch.cc",
"test/test_touch.h",
+ "test/test_viewport.cc",
+ "test/test_viewport.h",
+ "test/test_viewporter.cc",
+ "test/test_viewporter.h",
"test/test_wayland_server_thread.cc",
"test/test_wayland_server_thread.h",
"test/test_xdg_popup.cc",
@@ -313,6 +329,7 @@ source_set("test_support") {
"//third_party/wayland-protocols:linux_dmabuf_protocol",
"//third_party/wayland-protocols:presentation_time_protocol",
"//third_party/wayland-protocols:text_input_protocol",
+ "//third_party/wayland-protocols:viewporter_protocol",
"//third_party/wayland-protocols:xdg_shell_protocol",
"//ui/gfx/geometry:geometry",
]
diff --git a/chromium/ui/ozone/platform/wayland/DEPS b/chromium/ui/ozone/platform/wayland/DEPS
index 44ef7beabfd..1eeae79d79e 100644
--- a/chromium/ui/ozone/platform/wayland/DEPS
+++ b/chromium/ui/ozone/platform/wayland/DEPS
@@ -4,6 +4,7 @@ include_rules = [
"+ui/base/ui_base_features.h",
"+ui/gtk/gtk_ui_delegate.h",
"+mojo/public",
+ "+third_party/wayland",
"+ui/base/clipboard/clipboard_constants.h",
"+ui/base/dragdrop/drag_drop_types.h",
"+ui/base/dragdrop/file_info/file_info.h",
diff --git a/chromium/ui/ozone/platform/wayland/common/wayland.cc b/chromium/ui/ozone/platform/wayland/common/wayland.cc
new file mode 100644
index 00000000000..8a20e3a7be3
--- /dev/null
+++ b/chromium/ui/ozone/platform/wayland/common/wayland.cc
@@ -0,0 +1,24 @@
+// Copyright 2020 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 "ui/ozone/platform/wayland/common/wayland.h"
+
+namespace wl {
+
+void* bind_registry(struct wl_registry* registry,
+ uint32_t name,
+ const struct wl_interface* interface,
+ uint32_t version) {
+ if (dlsym(RTLD_DEFAULT, "wl_proxy_marshal_constructor_versioned")) {
+ return wl_registry_bind(registry, name, interface, version);
+ } else {
+ return wl_proxy_marshal_constructor(reinterpret_cast<wl_proxy*>(registry),
+ WL_REGISTRY_BIND, interface, name,
+ interface->name, version, nullptr);
+ }
+ NOTREACHED();
+ return nullptr;
+}
+
+} // namespace wl
diff --git a/chromium/ui/ozone/platform/wayland/common/wayland.h b/chromium/ui/ozone/platform/wayland/common/wayland.h
new file mode 100644
index 00000000000..c645346ddcb
--- /dev/null
+++ b/chromium/ui/ozone/platform/wayland/common/wayland.h
@@ -0,0 +1,31 @@
+// Copyright 2020 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.
+
+#ifndef UI_OZONE_PLATFORM_WAYLAND_COMMON_WAYLAND_H_
+#define UI_OZONE_PLATFORM_WAYLAND_COMMON_WAYLAND_H_
+
+#include <dlfcn.h>
+// This header includes wayland-client-core.h and wayland-client-protocol.h
+#include <wayland-client.h>
+
+#include "base/notreached.h"
+
+namespace wl {
+
+template <typename T>
+uint32_t get_version_of_object(T* obj) {
+ if (dlsym(RTLD_DEFAULT, "wl_proxy_get_version"))
+ return wl_proxy_get_version(reinterpret_cast<wl_proxy*>(obj));
+ // Older version of the libwayland-client didn't support version of objects.
+ return 0;
+}
+
+void* bind_registry(struct wl_registry* registry,
+ uint32_t name,
+ const struct wl_interface* interface,
+ uint32_t version);
+
+} // namespace wl
+
+#endif // UI_OZONE_PLATFORM_WAYLAND_COMMON_WAYLAND_H_
diff --git a/chromium/ui/ozone/platform/wayland/common/wayland_object.cc b/chromium/ui/ozone/platform/wayland/common/wayland_object.cc
index a71f25d42b7..6d9c7536c7e 100644
--- a/chromium/ui/ozone/platform/wayland/common/wayland_object.cc
+++ b/chromium/ui/ozone/platform/wayland/common/wayland_object.cc
@@ -8,10 +8,13 @@
#include <gtk-primary-selection-client-protocol.h>
#include <keyboard-extension-unstable-v1-client-protocol.h>
#include <linux-dmabuf-unstable-v1-client-protocol.h>
+#include <linux-explicit-synchronization-unstable-v1-client-protocol.h>
#include <presentation-time-client-protocol.h>
#include <text-input-unstable-v1-client-protocol.h>
-#include <wayland-client.h>
+#include <viewporter-client-protocol.h>
#include <wayland-drm-client-protocol.h>
+#include <xdg-decoration-unstable-v1-client-protocol.h>
+#include <xdg-foreign-unstable-v1-client-protocol.h>
#include <xdg-shell-client-protocol.h>
#include <xdg-shell-unstable-v6-client-protocol.h>
@@ -19,35 +22,35 @@ namespace wl {
namespace {
void delete_keyboard(wl_keyboard* keyboard) {
- if (wl_keyboard_get_version(keyboard) >= WL_KEYBOARD_RELEASE_SINCE_VERSION)
+ if (wl::get_version_of_object(keyboard) >= WL_KEYBOARD_RELEASE_SINCE_VERSION)
wl_keyboard_release(keyboard);
else
wl_keyboard_destroy(keyboard);
}
void delete_pointer(wl_pointer* pointer) {
- if (wl_pointer_get_version(pointer) >= WL_POINTER_RELEASE_SINCE_VERSION)
+ if (wl::get_version_of_object(pointer) >= WL_POINTER_RELEASE_SINCE_VERSION)
wl_pointer_release(pointer);
else
wl_pointer_destroy(pointer);
}
void delete_seat(wl_seat* seat) {
- if (wl_seat_get_version(seat) >= WL_SEAT_RELEASE_SINCE_VERSION)
+ if (wl::get_version_of_object(seat) >= WL_SEAT_RELEASE_SINCE_VERSION)
wl_seat_release(seat);
else
wl_seat_destroy(seat);
}
void delete_touch(wl_touch* touch) {
- if (wl_touch_get_version(touch) >= WL_TOUCH_RELEASE_SINCE_VERSION)
+ if (wl::get_version_of_object(touch) >= WL_TOUCH_RELEASE_SINCE_VERSION)
wl_touch_release(touch);
else
wl_touch_destroy(touch);
}
void delete_data_device(wl_data_device* data_device) {
- if (wl_data_device_get_version(data_device) >=
+ if (wl::get_version_of_object(data_device) >=
WL_DATA_DEVICE_RELEASE_SINCE_VERSION) {
wl_data_device_release(data_device);
} else {
@@ -57,6 +60,16 @@ void delete_data_device(wl_data_device* data_device) {
} // namespace
+const wl_interface* ObjectTraits<zxdg_decoration_manager_v1>::interface =
+ &zxdg_decoration_manager_v1_interface;
+void (*ObjectTraits<zxdg_decoration_manager_v1>::deleter)(
+ zxdg_decoration_manager_v1*) = &zxdg_decoration_manager_v1_destroy;
+
+const wl_interface* ObjectTraits<zxdg_toplevel_decoration_v1>::interface =
+ &zxdg_toplevel_decoration_v1_interface;
+void (*ObjectTraits<zxdg_toplevel_decoration_v1>::deleter)(
+ zxdg_toplevel_decoration_v1*) = &zxdg_toplevel_decoration_v1_destroy;
+
const wl_interface*
ObjectTraits<gtk_primary_selection_device_manager>::interface =
&gtk_primary_selection_device_manager_interface;
@@ -170,6 +183,15 @@ const wl_interface* ObjectTraits<struct wp_presentation_feedback>::interface =
void (*ObjectTraits<struct wp_presentation_feedback>::deleter)(
struct wp_presentation_feedback*) = &wp_presentation_feedback_destroy;
+const wl_interface* ObjectTraits<wp_viewport>::interface =
+ &wp_viewport_interface;
+void (*ObjectTraits<wp_viewport>::deleter)(wp_viewport*) = &wp_viewport_destroy;
+
+const wl_interface* ObjectTraits<wp_viewporter>::interface =
+ &wp_viewporter_interface;
+void (*ObjectTraits<wp_viewporter>::deleter)(wp_viewporter*) =
+ &wp_viewporter_destroy;
+
const wl_interface* ObjectTraits<xdg_wm_base>::interface =
&xdg_wm_base_interface;
void (*ObjectTraits<xdg_wm_base>::deleter)(xdg_wm_base*) = &xdg_wm_base_destroy;
@@ -215,6 +237,25 @@ const wl_interface* ObjectTraits<zwp_linux_dmabuf_v1>::interface =
void (*ObjectTraits<zwp_linux_dmabuf_v1>::deleter)(zwp_linux_dmabuf_v1*) =
&zwp_linux_dmabuf_v1_destroy;
+const wl_interface* ObjectTraits<zwp_linux_buffer_release_v1>::interface =
+ &zwp_linux_buffer_release_v1_interface;
+void (*ObjectTraits<zwp_linux_buffer_release_v1>::deleter)(
+ zwp_linux_buffer_release_v1*) = &zwp_linux_buffer_release_v1_destroy;
+
+const wl_interface*
+ ObjectTraits<zwp_linux_explicit_synchronization_v1>::interface =
+ &zwp_linux_explicit_synchronization_v1_interface;
+void (*ObjectTraits<zwp_linux_explicit_synchronization_v1>::deleter)(
+ zwp_linux_explicit_synchronization_v1*) =
+ &zwp_linux_explicit_synchronization_v1_destroy;
+
+const wl_interface*
+ ObjectTraits<zwp_linux_surface_synchronization_v1>::interface =
+ &zwp_linux_surface_synchronization_v1_interface;
+void (*ObjectTraits<zwp_linux_surface_synchronization_v1>::deleter)(
+ zwp_linux_surface_synchronization_v1*) =
+ &zwp_linux_surface_synchronization_v1_destroy;
+
const wl_interface* ObjectTraits<zxdg_shell_v6>::interface =
&zxdg_shell_v6_interface;
void (*ObjectTraits<zxdg_shell_v6>::deleter)(zxdg_shell_v6*) =
@@ -250,4 +291,14 @@ const wl_interface* ObjectTraits<zwp_text_input_v1>::interface =
void (*ObjectTraits<zwp_text_input_v1>::deleter)(zwp_text_input_v1*) =
&zwp_text_input_v1_destroy;
+const wl_interface* ObjectTraits<zxdg_exporter_v1>::interface =
+ &zxdg_exporter_v1_interface;
+void (*ObjectTraits<zxdg_exporter_v1>::deleter)(zxdg_exporter_v1*) =
+ &zxdg_exporter_v1_destroy;
+
+const wl_interface* ObjectTraits<zxdg_exported_v1>::interface =
+ &zxdg_exported_v1_interface;
+void (*ObjectTraits<zxdg_exported_v1>::deleter)(zxdg_exported_v1*) =
+ &zxdg_exported_v1_destroy;
+
} // namespace wl
diff --git a/chromium/ui/ozone/platform/wayland/common/wayland_object.h b/chromium/ui/ozone/platform/wayland/common/wayland_object.h
index faabaed2de3..bfc61f88f84 100644
--- a/chromium/ui/ozone/platform/wayland/common/wayland_object.h
+++ b/chromium/ui/ozone/platform/wayland/common/wayland_object.h
@@ -5,9 +5,10 @@
#ifndef UI_OZONE_PLATFORM_WAYLAND_COMMON_WAYLAND_OBJECT_H_
#define UI_OZONE_PLATFORM_WAYLAND_COMMON_WAYLAND_OBJECT_H_
-#include <wayland-client-core.h>
#include <memory>
+#include "ui/ozone/platform/wayland/common/wayland.h"
+
struct gtk_primary_selection_device;
struct gtk_primary_selection_device_manager;
struct gtk_primary_selection_offer;
@@ -34,6 +35,8 @@ struct wl_surface;
struct wl_touch;
struct wp_presentation;
struct wp_presentation_feedback;
+struct wp_viewport;
+struct wp_viewporter;
struct xdg_wm_base;
struct xdg_surface;
struct xdg_toplevel;
@@ -44,6 +47,9 @@ struct zaura_surface;
struct zcr_keyboard_extension_v1;
struct zcr_extended_keyboard_v1;
struct zwp_linux_dmabuf_v1;
+struct zwp_linux_buffer_release_v1;
+struct zwp_linux_explicit_synchronization_v1;
+struct zwp_linux_surface_synchronization_v1;
struct zxdg_shell_v6;
struct zxdg_surface_v6;
struct zxdg_toplevel_v6;
@@ -51,6 +57,10 @@ struct zxdg_popup_v6;
struct zxdg_positioner_v6;
struct zwp_text_input_manager_v1;
struct zwp_text_input_v1;
+struct zxdg_exporter_v1;
+struct zxdg_exported_v1;
+struct zxdg_decoration_manager_v1;
+struct zxdg_toplevel_decoration_v1;
namespace wl {
@@ -58,6 +68,18 @@ template <typename T>
struct ObjectTraits;
template <>
+struct ObjectTraits<zxdg_decoration_manager_v1> {
+ static const wl_interface* interface;
+ static void (*deleter)(zxdg_decoration_manager_v1*);
+};
+
+template <>
+struct ObjectTraits<zxdg_toplevel_decoration_v1> {
+ static const wl_interface* interface;
+ static void (*deleter)(zxdg_toplevel_decoration_v1*);
+};
+
+template <>
struct ObjectTraits<gtk_primary_selection_device_manager> {
static const wl_interface* interface;
static void (*deleter)(gtk_primary_selection_device_manager*);
@@ -220,6 +242,18 @@ struct ObjectTraits<wp_presentation_feedback> {
};
template <>
+struct ObjectTraits<wp_viewport> {
+ static const wl_interface* interface;
+ static void (*deleter)(wp_viewport*);
+};
+
+template <>
+struct ObjectTraits<wp_viewporter> {
+ static const wl_interface* interface;
+ static void (*deleter)(wp_viewporter*);
+};
+
+template <>
struct ObjectTraits<xdg_wm_base> {
static const wl_interface* interface;
static void (*deleter)(xdg_wm_base*);
@@ -280,6 +314,24 @@ struct ObjectTraits<zwp_linux_dmabuf_v1> {
};
template <>
+struct ObjectTraits<zwp_linux_buffer_release_v1> {
+ static const wl_interface* interface;
+ static void (*deleter)(zwp_linux_buffer_release_v1*);
+};
+
+template <>
+struct ObjectTraits<zwp_linux_explicit_synchronization_v1> {
+ static const wl_interface* interface;
+ static void (*deleter)(zwp_linux_explicit_synchronization_v1*);
+};
+
+template <>
+struct ObjectTraits<zwp_linux_surface_synchronization_v1> {
+ static const wl_interface* interface;
+ static void (*deleter)(zwp_linux_surface_synchronization_v1*);
+};
+
+template <>
struct ObjectTraits<zxdg_shell_v6> {
static const wl_interface* interface;
static void (*deleter)(zxdg_shell_v6*);
@@ -321,6 +373,18 @@ struct ObjectTraits<zwp_text_input_v1> {
static void (*deleter)(zwp_text_input_v1*);
};
+template <>
+struct ObjectTraits<zxdg_exporter_v1> {
+ static const wl_interface* interface;
+ static void (*deleter)(zxdg_exporter_v1*);
+};
+
+template <>
+struct ObjectTraits<zxdg_exported_v1> {
+ static const wl_interface* interface;
+ static void (*deleter)(zxdg_exported_v1*);
+};
+
struct Deleter {
template <typename T>
void operator()(T* obj) {
@@ -343,7 +407,7 @@ class Object : public std::unique_ptr<T, Deleter> {
template <typename T>
wl::Object<T> Bind(wl_registry* registry, uint32_t name, uint32_t version) {
return wl::Object<T>(static_cast<T*>(
- wl_registry_bind(registry, name, ObjectTraits<T>::interface, version)));
+ wl::bind_registry(registry, name, ObjectTraits<T>::interface, version)));
}
} // namespace wl
diff --git a/chromium/ui/ozone/platform/wayland/common/wayland_util.cc b/chromium/ui/ozone/platform/wayland/common/wayland_util.cc
index 3b0b8829a95..042cfc8e96b 100644
--- a/chromium/ui/ozone/platform/wayland/common/wayland_util.cc
+++ b/chromium/ui/ozone/platform/wayland/common/wayland_util.cc
@@ -157,6 +157,98 @@ gfx::Rect TranslateBoundsToTopLevelCoordinates(const gfx::Rect& child_bounds,
child_bounds.size());
}
+wl_output_transform ToWaylandTransform(gfx::OverlayTransform transform) {
+ switch (transform) {
+ case gfx::OVERLAY_TRANSFORM_NONE:
+ return WL_OUTPUT_TRANSFORM_NORMAL;
+ case gfx::OVERLAY_TRANSFORM_FLIP_HORIZONTAL:
+ return WL_OUTPUT_TRANSFORM_FLIPPED;
+ case gfx::OVERLAY_TRANSFORM_FLIP_VERTICAL:
+ return WL_OUTPUT_TRANSFORM_FLIPPED_180;
+ case gfx::OVERLAY_TRANSFORM_ROTATE_90:
+ return WL_OUTPUT_TRANSFORM_90;
+ case gfx::OVERLAY_TRANSFORM_ROTATE_180:
+ return WL_OUTPUT_TRANSFORM_180;
+ case gfx::OVERLAY_TRANSFORM_ROTATE_270:
+ return WL_OUTPUT_TRANSFORM_270;
+ default:
+ break;
+ }
+ NOTREACHED();
+ return WL_OUTPUT_TRANSFORM_NORMAL;
+}
+
+gfx::Rect ApplyWaylandTransform(const gfx::Rect& rect,
+ const gfx::Size& bounds,
+ wl_output_transform transform) {
+ gfx::Rect result = rect;
+ switch (transform) {
+ case WL_OUTPUT_TRANSFORM_NORMAL:
+ break;
+ case WL_OUTPUT_TRANSFORM_FLIPPED:
+ result.set_x(bounds.width() - rect.x() - rect.width());
+ break;
+ case WL_OUTPUT_TRANSFORM_FLIPPED_90:
+ result.set_x(rect.y());
+ result.set_y(rect.x());
+ result.set_width(rect.height());
+ result.set_height(rect.width());
+ break;
+ case WL_OUTPUT_TRANSFORM_FLIPPED_180:
+ result.set_y(bounds.height() - rect.y() - rect.height());
+ break;
+ case WL_OUTPUT_TRANSFORM_FLIPPED_270:
+ result.set_x(bounds.height() - rect.y() - rect.height());
+ result.set_y(bounds.width() - rect.x() - rect.width());
+ result.set_width(rect.height());
+ result.set_height(rect.width());
+ break;
+ case WL_OUTPUT_TRANSFORM_90:
+ result.set_x(rect.y());
+ result.set_y(bounds.width() - rect.x() - rect.width());
+ result.set_width(rect.height());
+ result.set_height(rect.width());
+ break;
+ case WL_OUTPUT_TRANSFORM_180:
+ result.set_x(bounds.width() - rect.x() - rect.width());
+ result.set_y(bounds.height() - rect.y() - rect.height());
+ break;
+ case WL_OUTPUT_TRANSFORM_270:
+ result.set_x(bounds.height() - rect.y() - rect.height());
+ result.set_y(rect.x());
+ result.set_width(rect.height());
+ result.set_height(rect.width());
+ break;
+ default:
+ NOTREACHED();
+ break;
+ }
+ return result;
+}
+
+gfx::Size ApplyWaylandTransform(const gfx::Size& size,
+ wl_output_transform transform) {
+ gfx::Size result = size;
+ switch (transform) {
+ case WL_OUTPUT_TRANSFORM_NORMAL:
+ case WL_OUTPUT_TRANSFORM_FLIPPED:
+ case WL_OUTPUT_TRANSFORM_FLIPPED_180:
+ case WL_OUTPUT_TRANSFORM_180:
+ break;
+ case WL_OUTPUT_TRANSFORM_FLIPPED_90:
+ case WL_OUTPUT_TRANSFORM_FLIPPED_270:
+ case WL_OUTPUT_TRANSFORM_90:
+ case WL_OUTPUT_TRANSFORM_270:
+ result.set_width(size.height());
+ result.set_height(size.width());
+ break;
+ default:
+ NOTREACHED();
+ break;
+ }
+ return result;
+}
+
bool IsMenuType(ui::PlatformWindowType type) {
return type == ui::PlatformWindowType::kMenu ||
type == ui::PlatformWindowType::kPopup;
diff --git a/chromium/ui/ozone/platform/wayland/common/wayland_util.h b/chromium/ui/ozone/platform/wayland/common/wayland_util.h
index 582a3c7b0ba..d755de9e0ba 100644
--- a/chromium/ui/ozone/platform/wayland/common/wayland_util.h
+++ b/chromium/ui/ozone/platform/wayland/common/wayland_util.h
@@ -7,13 +7,12 @@
#include <vector>
-#include <wayland-client.h>
-
#include "base/callback.h"
#include "base/containers/flat_map.h"
#include "base/files/scoped_file.h"
#include "base/macros.h"
#include "ui/gfx/geometry/rect.h"
+#include "ui/gfx/overlay_transform.h"
#include "ui/ozone/platform/wayland/common/wayland_object.h"
#include "ui/platform_window/platform_window_init_properties.h"
@@ -60,6 +59,21 @@ gfx::Rect TranslateBoundsToParentCoordinates(const gfx::Rect& child_bounds,
gfx::Rect TranslateBoundsToTopLevelCoordinates(const gfx::Rect& child_bounds,
const gfx::Rect& parent_bounds);
+// Returns wl_output_transform corresponding |transform|. |transform| is an
+// enumeration of a fixed selection of transformations.
+wl_output_transform ToWaylandTransform(gfx::OverlayTransform transform);
+
+// |bounds| contains |rect|. ApplyWaylandTransform() returns the resulted
+// |rect| after transformation is applied to |bounds| containing |rect| as a
+// whole.
+gfx::Rect ApplyWaylandTransform(const gfx::Rect& rect,
+ const gfx::Size& bounds,
+ wl_output_transform transform);
+
+// Applies transformation to |size|.
+gfx::Size ApplyWaylandTransform(const gfx::Size& size,
+ wl_output_transform transform);
+
// Says if the type is kPopup or kMenu.
bool IsMenuType(ui::PlatformWindowType type);
diff --git a/chromium/ui/ozone/platform/wayland/gpu/gbm_surfaceless_wayland.cc b/chromium/ui/ozone/platform/wayland/gpu/gbm_surfaceless_wayland.cc
index 8ee69e5b401..b77c13b5e75 100644
--- a/chromium/ui/ozone/platform/wayland/gpu/gbm_surfaceless_wayland.cc
+++ b/chromium/ui/ozone/platform/wayland/gpu/gbm_surfaceless_wayland.cc
@@ -46,8 +46,10 @@ GbmSurfacelessWayland::GbmSurfacelessWayland(
}
void GbmSurfacelessWayland::QueueOverlayPlane(OverlayPlane plane,
- uint32_t buffer_id) {
- unsubmitted_frames_.back()->planes.push_back({std::move(plane), buffer_id});
+ BufferId buffer_id) {
+ auto result =
+ unsubmitted_frames_.back()->planes.emplace(buffer_id, std::move(plane));
+ DCHECK(result.second);
}
bool GbmSurfacelessWayland::ScheduleOverlayPlane(
@@ -100,7 +102,7 @@ void GbmSurfacelessWayland::SwapBuffersAsync(
return;
}
- // TODO(dcastagna): remove glFlush since eglImageFlushExternalEXT called on
+ // TODO(fangzhoug): remove glFlush since eglImageFlushExternalEXT called on
// the image should be enough (https://crbug.com/720045).
if (!no_gl_flush_for_tests_)
glFlush();
@@ -123,16 +125,16 @@ void GbmSurfacelessWayland::SwapBuffersAsync(
// Uset in-fences provided in the overlays. If there are none, we insert our
// own fence and wait.
for (auto& plane : frame->planes) {
- if (plane.plane.gpu_fence)
- fences.push_back(std::move(plane.plane.gpu_fence));
+ if (plane.second.gpu_fence)
+ fences.push_back(std::move(plane.second.gpu_fence));
}
base::OnceClosure fence_wait_task;
if (!fences.empty()) {
fence_wait_task = base::BindOnce(&WaitForGpuFences, std::move(fences));
} else {
- // TODO: the following should be replaced by a per surface flush as it gets
- // implemented in GL drivers.
+ // TODO(fangzhoug): the following should be replaced by a per surface flush
+ // as it gets implemented in GL drivers.
EGLSyncKHR fence = InsertFence(has_implicit_external_sync_);
CHECK_NE(fence, EGL_NO_SYNC_KHR) << "eglCreateSyncKHR failed";
@@ -238,18 +240,14 @@ void GbmSurfacelessWayland::MaybeSubmitFrames() {
std::vector<ui::ozone::mojom::WaylandOverlayConfigPtr> overlay_configs;
for (const auto& plane : submitted_frame->planes) {
overlay_configs.push_back(
- ui::ozone::mojom::WaylandOverlayConfig::From(plane.plane));
- overlay_configs.back()->buffer_id = plane.buffer_id;
- if (plane.plane.z_order == 0) {
+ ui::ozone::mojom::WaylandOverlayConfig::From(plane.second));
+ overlay_configs.back()->buffer_id = plane.first;
+ if (plane.second.z_order == 0) {
overlay_configs.back()->damage_region = submitted_frame->damage_region_;
- submitted_frame->buffer_id = plane.buffer_id;
+ submitted_frame->buffer_id = plane.first;
}
}
buffer_manager_->CommitOverlays(widget_, std::move(overlay_configs));
-
- submitted_frame->unacked_submissions = submitted_frame->planes.size();
- submitted_frame->unacked_presentations = submitted_frame->planes.size();
- submitted_frame->planes.clear();
submitted_frames_.push_back(std::move(submitted_frame));
}
}
@@ -271,22 +269,46 @@ void GbmSurfacelessWayland::SetNoGLFlushForTests() {
no_gl_flush_for_tests_ = true;
}
-void GbmSurfacelessWayland::OnSubmission(uint32_t buffer_id,
+void GbmSurfacelessWayland::OnSubmission(BufferId buffer_id,
const gfx::SwapResult& swap_result) {
// submitted_frames_ may temporarily have more than one buffer in it if
// buffers are released out of order by the Wayland server.
DCHECK(!submitted_frames_.empty());
- if (--submitted_frames_.front()->unacked_submissions)
- return;
-
- auto submitted_frame = std::move(submitted_frames_.front());
- submitted_frames_.erase(submitted_frames_.begin());
- submitted_frame->overlays.clear();
- std::move(submitted_frame->completion_callback)
- .Run(gfx::SwapCompletionResult(swap_result));
-
- pending_presentation_frames_.push_back(std::move(submitted_frame));
+ size_t erased = 0;
+ for (auto& submitted_frame : submitted_frames_) {
+ if ((erased = submitted_frame->planes.erase(buffer_id)) > 0) {
+ // |completion_callback| only takes 1 SwapResult. It's possible that only
+ // one of the buffers in a frame gets a SWAP_FAILED or
+ // SWAP_NAK_RECREATE_BUFFERS. Don't replace a failed swap_result with
+ // SWAP_ACK. If both SWAP_FAILED and SWAP_NAK_RECREATE_BUFFERS happens,
+ // this swap is treated as SWAP_FAILED.
+ if (submitted_frame->swap_result == gfx::SwapResult::SWAP_ACK ||
+ swap_result == gfx::SwapResult::SWAP_FAILED) {
+ submitted_frame->swap_result = swap_result;
+ }
+ submitted_frame->pending_presentation_buffers.insert(buffer_id);
+ break;
+ }
+ }
+ DCHECK(erased);
+
+ // Following while loop covers below scenario:
+ // frame_1 submitted a buffer_1 for overlay; frame_2 submitted a buffer_2
+ // for primary plane. This can happen at the end of a single-on-top overlay.
+ // buffer_1 is not attached immediately due to unack'ed wl_frame_callback.
+ // buffer_2 is attached immediately Onsubmission() of buffer_2 runs.
+ while (!submitted_frames_.empty() &&
+ submitted_frames_.front()->planes.empty()) {
+ auto submitted_frame = std::move(submitted_frames_.front());
+ submitted_frames_.erase(submitted_frames_.begin());
+ submitted_frame->overlays.clear();
+
+ std::move(submitted_frame->completion_callback)
+ .Run(gfx::SwapCompletionResult(submitted_frame->swap_result));
+
+ pending_presentation_frames_.push_back(std::move(submitted_frame));
+ }
if (swap_result != gfx::SwapResult::SWAP_ACK) {
last_swap_buffers_result_ = false;
@@ -297,10 +319,20 @@ void GbmSurfacelessWayland::OnSubmission(uint32_t buffer_id,
}
void GbmSurfacelessWayland::OnPresentation(
- uint32_t buffer_id,
+ BufferId buffer_id,
const gfx::PresentationFeedback& feedback) {
+ DCHECK(!submitted_frames_.empty() || !pending_presentation_frames_.empty());
+
+ size_t erased = 0;
+ for (auto& frame : pending_presentation_frames_) {
+ if ((erased = frame->pending_presentation_buffers.erase(buffer_id)) > 0) {
+ frame->feedback = feedback;
+ break;
+ }
+ }
+
// Items in |submitted_frames_| will not be moved to
- // |pending_presentation_frames_| until |unacked_submissions| decrements to 0.
+ // |pending_presentation_frames_| until |planes| is empty.
// Example:
// A SwapBuffers that submitted 2 buffers (buffer_1 and buffer_2) will push
// a submitted_frame expecting 2 submission feedbacks and 2 presentation
@@ -312,24 +344,26 @@ void GbmSurfacelessWayland::OnPresentation(
// buffer_1:submission > buffer_1:presentation > buffer_2:submission >
// buffer_2:presentation
// In this case, we have to find the item in |submitted_frames_| and
- // decrement |unacked_presentations| there.
- // TODO(fangzhoug): This solution is sub-optimal and confusing. It increases
- // the number of IPCs from browser to gpu. The barrier logic should be in the
- // browser process.
- if (pending_presentation_frames_.empty()) {
- auto it = submitted_frames_.begin();
- for (; !(*it)->unacked_presentations; ++it)
- ;
- --(*it)->unacked_presentations;
- return;
+ // remove from |pending_presentation_buffers| there.
+ if (!erased) {
+ for (auto& frame : submitted_frames_) {
+ if ((erased = frame->pending_presentation_buffers.erase(buffer_id)) > 0) {
+ frame->feedback = feedback;
+ break;
+ }
+ }
}
- auto* frame = pending_presentation_frames_.front().get();
- if (--frame->unacked_presentations)
- return;
+ DCHECK(erased);
- std::move(frame->presentation_callback).Run(feedback);
- pending_presentation_frames_.erase(pending_presentation_frames_.begin());
+ while (!pending_presentation_frames_.empty() &&
+ pending_presentation_frames_.front()
+ ->pending_presentation_buffers.empty()) {
+ auto* frame = pending_presentation_frames_.front().get();
+ DCHECK(frame->planes.empty());
+ std::move(frame->presentation_callback).Run(frame->feedback);
+ pending_presentation_frames_.erase(pending_presentation_frames_.begin());
+ }
}
} // namespace ui
diff --git a/chromium/ui/ozone/platform/wayland/gpu/gbm_surfaceless_wayland.h b/chromium/ui/ozone/platform/wayland/gpu/gbm_surfaceless_wayland.h
index 13dbd84ab90..910b9a7056e 100644
--- a/chromium/ui/ozone/platform/wayland/gpu/gbm_surfaceless_wayland.h
+++ b/chromium/ui/ozone/platform/wayland/gpu/gbm_surfaceless_wayland.h
@@ -7,6 +7,7 @@
#include <memory>
+#include "base/containers/small_map.h"
#include "base/macros.h"
#include "base/memory/weak_ptr.h"
#include "ui/gfx/native_widget_types.h"
@@ -19,6 +20,8 @@ namespace ui {
class WaylandBufferManagerGpu;
+using BufferId = uint32_t;
+
// A GLSurface for Wayland Ozone platform that uses surfaceless drawing. Drawing
// and displaying happens directly through NativePixmap buffers. CC would call
// into SurfaceFactoryOzone to allocate the buffers and then call
@@ -29,7 +32,7 @@ class GbmSurfacelessWayland : public gl::SurfacelessEGL,
GbmSurfacelessWayland(WaylandBufferManagerGpu* buffer_manager,
gfx::AcceleratedWidget widget);
- void QueueOverlayPlane(OverlayPlane plane, uint32_t buffer_id);
+ void QueueOverlayPlane(OverlayPlane plane, BufferId buffer_id);
// gl::GLSurface:
bool ScheduleOverlayPlane(int z_order,
@@ -62,22 +65,19 @@ class GbmSurfacelessWayland : public gl::SurfacelessEGL,
private:
FRIEND_TEST_ALL_PREFIXES(WaylandSurfaceFactoryTest,
GbmSurfacelessWaylandCheckOrderOfCallbacksTest);
+ FRIEND_TEST_ALL_PREFIXES(WaylandSurfaceFactoryTest,
+ GbmSurfacelessWaylandCommitOverlaysCallbacksTest);
+ FRIEND_TEST_ALL_PREFIXES(WaylandSurfaceFactoryTest,
+ GbmSurfacelessWaylandGroupOnSubmissionCallbacksTest);
~GbmSurfacelessWayland() override;
// WaylandSurfaceGpu overrides:
- void OnSubmission(uint32_t buffer_id,
+ void OnSubmission(BufferId buffer_id,
const gfx::SwapResult& swap_result) override;
- void OnPresentation(uint32_t buffer_id,
+ void OnPresentation(BufferId buffer_id,
const gfx::PresentationFeedback& feedback) override;
- struct PlaneData {
- OverlayPlane plane;
- // The id of the buffer, which represents buffer that backs this overlay
- // plane.
- const uint32_t buffer_id;
- };
-
struct PendingFrame {
PendingFrame();
~PendingFrame();
@@ -89,24 +89,25 @@ class GbmSurfacelessWayland : public gl::SurfacelessEGL,
bool ready = false;
// The id of the buffer, which represents this frame.
- uint32_t buffer_id = 0;
+ BufferId buffer_id = 0;
// A region of the updated content in a corresponding frame. It's used to
// advice Wayland which part of a buffer is going to be updated. Passing {0,
// 0, 0, 0} results in a whole buffer update on the Wayland compositor side.
gfx::Rect damage_region_ = gfx::Rect();
+ // TODO(fangzhoug): This should be changed to support Vulkan.
std::vector<gl::GLSurfaceOverlay> overlays;
SwapCompletionCallback completion_callback;
PresentationCallback presentation_callback;
bool schedule_planes_succeeded = false;
- std::vector<PlaneData> planes;
- // TODO(fangzhoug): This is a temporary solution to barrier swap/present
- // acks of a frame that contains multiple buffer commits. Next step is to
- // barrier in browser process to avoid extra IPC hops.
- size_t unacked_submissions;
- size_t unacked_presentations;
+ // Maps |buffer_id| to an OverlayPlane, used for committing overlays and
+ // wait for OnSubmission's.
+ base::small_map<std::map<BufferId, OverlayPlane>> planes;
+ base::flat_set<BufferId> pending_presentation_buffers;
+ gfx::SwapResult swap_result = gfx::SwapResult::SWAP_ACK;
+ gfx::PresentationFeedback feedback;
};
void MaybeSubmitFrames();
diff --git a/chromium/ui/ozone/platform/wayland/gpu/wayland_buffer_manager_gpu.cc b/chromium/ui/ozone/platform/wayland/gpu/wayland_buffer_manager_gpu.cc
index 42fd8192f00..9897b51fd91 100644
--- a/chromium/ui/ozone/platform/wayland/gpu/wayland_buffer_manager_gpu.cc
+++ b/chromium/ui/ozone/platform/wayland/gpu/wayland_buffer_manager_gpu.cc
@@ -28,9 +28,8 @@ TypeConverter<ui::ozone::mojom::WaylandOverlayConfigPtr,
wayland_overlay_config->enable_blend = input.enable_blend;
wayland_overlay_config->access_fence_handle =
!input.gpu_fence || input.gpu_fence->GetGpuFenceHandle().is_null()
- ? base::Optional<gfx::GpuFenceHandle>()
- : base::Optional<gfx::GpuFenceHandle>(
- gfx::CloneHandleForIPC(input.gpu_fence->GetGpuFenceHandle()));
+ ? gfx::GpuFenceHandle()
+ : input.gpu_fence->GetGpuFenceHandle().Clone();
return wayland_overlay_config;
}
diff --git a/chromium/ui/ozone/platform/wayland/gpu/wayland_surface_factory_unittest.cc b/chromium/ui/ozone/platform/wayland/gpu/wayland_surface_factory_unittest.cc
index ebec5b49347..1c506265172 100644
--- a/chromium/ui/ozone/platform/wayland/gpu/wayland_surface_factory_unittest.cc
+++ b/chromium/ui/ozone/platform/wayland/gpu/wayland_surface_factory_unittest.cc
@@ -19,6 +19,7 @@
#include "ui/ozone/platform/wayland/gpu/wayland_buffer_manager_gpu.h"
#include "ui/ozone/platform/wayland/gpu/wayland_surface_factory.h"
#include "ui/ozone/platform/wayland/host/wayland_buffer_manager_host.h"
+#include "ui/ozone/platform/wayland/host/wayland_subsurface.h"
#include "ui/ozone/platform/wayland/host/wayland_window.h"
#include "ui/ozone/platform/wayland/test/mock_surface.h"
#include "ui/ozone/platform/wayland/test/scoped_wl_array.h"
@@ -125,19 +126,23 @@ class CallbacksHelper {
// that 1) the image has been sent to be shown after being scheduled 2) the
// image is displayed. This sort of mimics a buffer queue, but in a simpliear
// way.
- void FinishSwapBuffersAsync(uint32_t local_swap_id,
- scoped_refptr<FakeGLImageNativePixmap> gl_image,
- gfx::SwapCompletionResult result) {
+ void FinishSwapBuffersAsync(
+ uint32_t local_swap_id,
+ std::vector<scoped_refptr<FakeGLImageNativePixmap>> gl_images,
+ gfx::SwapCompletionResult result) {
last_finish_swap_id_ = pending_local_swap_ids_.front();
pending_local_swap_ids_.pop();
- EXPECT_EQ(gl_image->GetAssociateWithSwapId(), last_finish_swap_id_);
- EXPECT_TRUE(gl_image->busy() && !gl_image->displayed());
- if (displayed_image_)
- displayed_image_->SetDisplayed(false);
- displayed_image_ = gl_image;
- displayed_image_->SetBusy(false);
- displayed_image_->SetDisplayed(true);
+ for (auto& gl_image : gl_images) {
+ EXPECT_EQ(gl_image->GetAssociateWithSwapId(), last_finish_swap_id_);
+ EXPECT_TRUE(gl_image->busy() && !gl_image->displayed());
+ gl_image->SetBusy(false);
+ gl_image->SetDisplayed(true);
+ }
+
+ for (auto& displayed_image : displayed_images_)
+ displayed_image->SetDisplayed(false);
+ displayed_images_ = std::move(gl_images);
}
void BufferPresented(uint64_t local_swap_id,
@@ -156,7 +161,7 @@ class CallbacksHelper {
base::queue<uint64_t> pending_local_swap_ids_;
// Keeps track of a displayed image.
- scoped_refptr<FakeGLImageNativePixmap> displayed_image_;
+ std::vector<scoped_refptr<FakeGLImageNativePixmap>> displayed_images_;
};
} // namespace
@@ -253,10 +258,13 @@ TEST_P(WaylandSurfaceFactoryTest,
0, gfx::OverlayTransform::OVERLAY_TRANSFORM_FLIP_VERTICAL,
gl_image.get(), window_->GetBounds(), {}, false, nullptr);
+ std::vector<scoped_refptr<FakeGLImageNativePixmap>> gl_images;
+ gl_images.push_back(gl_image);
+
// And submit each image. They will be executed in FIFO manner.
gl_surface->SwapBuffersAsync(
base::BindOnce(&CallbacksHelper::FinishSwapBuffersAsync,
- base::Unretained(&cbs_helper), swap_id, gl_image),
+ base::Unretained(&cbs_helper), swap_id, gl_images),
base::BindOnce(&CallbacksHelper::BufferPresented,
base::Unretained(&cbs_helper), swap_id));
}
@@ -402,6 +410,473 @@ TEST_P(WaylandSurfaceFactoryTest,
mock_surface->SendFrameCallback();
}
+TEST_P(WaylandSurfaceFactoryTest,
+ GbmSurfacelessWaylandCommitOverlaysCallbacksTest) {
+ // GbmSurfacelessWaylandCheckOrderOfCallbacksTest tests with one buffer per
+ // frame. This tests multiple buffers per-frame and order of
+ // SwapCompletionCallbacks. Even when all OnSubmission from later frames are
+ // called, their SwapCompletionCallbacks should not run until previous frames'
+ // SwapCompletionCallbacks run.
+ gl::SetGLImplementation(gl::kGLImplementationEGLGLES2);
+
+ buffer_manager_gpu_->set_gbm_device(std::make_unique<MockGbmDevice>());
+
+ auto* gl_ozone = surface_factory_->GetGLOzone(gl::kGLImplementationEGLGLES2);
+ auto gl_surface = gl_ozone->CreateSurfacelessViewGLSurface(widget_);
+ EXPECT_TRUE(gl_surface);
+ gl_surface->SetRelyOnImplicitSync();
+ static_cast<ui::GbmSurfacelessWayland*>(gl_surface.get())
+ ->SetNoGLFlushForTests();
+
+ // Expect to create 4 buffers.
+ EXPECT_CALL(*server_.zwp_linux_dmabuf_v1(), CreateParams(_, _, _)).Times(4);
+
+ // Create buffers and FakeGlImageNativePixmap.
+ std::vector<scoped_refptr<FakeGLImageNativePixmap>> fake_gl_image;
+ for (int i = 0; i < 4; ++i) {
+ auto native_pixmap = surface_factory_->CreateNativePixmap(
+ widget_, nullptr, window_->GetBounds().size(),
+ gfx::BufferFormat::BGRA_8888, gfx::BufferUsage::SCANOUT);
+ fake_gl_image.push_back(base::MakeRefCounted<FakeGLImageNativePixmap>(
+ native_pixmap, window_->GetBounds().size()));
+
+ Sync();
+
+ // Create one buffer at a time.
+ auto params_vector = server_.zwp_linux_dmabuf_v1()->buffer_params();
+ DCHECK_EQ(params_vector.size(), 1u);
+ zwp_linux_buffer_params_v1_send_created(
+ params_vector.front()->resource(),
+ params_vector.front()->buffer_resource());
+
+ Sync();
+ }
+
+ auto* mock_primary_surface = server_.GetObject<wl::MockSurface>(
+ window_->root_surface()->GetSurfaceId());
+
+ CallbacksHelper cbs_helper;
+ // Submit a frame with only primary plane
+ {
+ // Associate each image with swap id so that we could track released
+ // buffers.
+ auto swap_id = cbs_helper.GetNextLocalSwapId();
+ // Associate the image with the next swap id so that we can easily track if
+ // it became free to reuse.
+ fake_gl_image[0]->AssociateWithSwapId(swap_id);
+ // And set it to be busy...
+ fake_gl_image[0]->SetBusy(true);
+
+ // Prepare overlay plane.
+ gl_surface->ScheduleOverlayPlane(
+ 0, gfx::OverlayTransform::OVERLAY_TRANSFORM_NONE,
+ fake_gl_image[0].get(), window_->GetBounds(), {}, false, nullptr);
+
+ std::vector<scoped_refptr<FakeGLImageNativePixmap>> gl_images;
+ gl_images.push_back(fake_gl_image[0]);
+
+ // And submit each image. They will be executed in FIFO manner.
+ gl_surface->SwapBuffersAsync(
+ base::BindOnce(&CallbacksHelper::FinishSwapBuffersAsync,
+ base::Unretained(&cbs_helper), swap_id, gl_images),
+ base::BindOnce(&CallbacksHelper::BufferPresented,
+ base::Unretained(&cbs_helper), swap_id));
+ }
+
+ // Let's sync so that 1) GbmSurfacelessWayland submits the buffer according to
+ // internal queue and fake server processes the request.
+
+ // Also, we expect only one buffer to be committed.
+ EXPECT_CALL(*mock_primary_surface, Attach(_, _, _)).Times(1);
+ EXPECT_CALL(*mock_primary_surface, Frame(_)).Times(1);
+ EXPECT_CALL(*mock_primary_surface, DamageBuffer(_, _, _, _)).Times(1);
+ EXPECT_CALL(*mock_primary_surface, Commit()).Times(1);
+
+ Sync();
+
+ testing::Mock::VerifyAndClearExpectations(&mock_primary_surface);
+
+ // Give mojo the chance to pass the callbacks.
+ base::RunLoop().RunUntilIdle();
+
+ // We have just received Attach/DamageBuffer/Commit for buffer with swap
+ // id=0u. The SwapCompletionCallback must be executed automatically as long as
+ // we didn't have any buffers attached to the surface before.
+ EXPECT_EQ(cbs_helper.GetLastFinishedSwapId(), 0u);
+
+ cbs_helper.ResetLastFinishedSwapId();
+
+ for (const auto& gl_image : fake_gl_image) {
+ // All the images except the first one, which was associated with swap
+ // id=0u, must be busy and not displayed. The first one must be displayed.
+ if (gl_image->GetAssociateWithSwapId() == 0u) {
+ EXPECT_FALSE(gl_image->busy());
+ EXPECT_TRUE(gl_image->displayed());
+ } else {
+ EXPECT_FALSE(gl_image->displayed());
+ }
+ }
+
+ // Submit another frame with only primary plane
+ {
+ // Associate each image with swap id so that we could track released
+ // buffers.
+ auto swap_id = cbs_helper.GetNextLocalSwapId();
+ // Associate the image with the next swap id so that we can easily track if
+ // it became free to reuse.
+ fake_gl_image[1]->AssociateWithSwapId(swap_id);
+ // And set it to be busy...
+ fake_gl_image[1]->SetBusy(true);
+
+ // Prepare overlay plane.
+ gl_surface->ScheduleOverlayPlane(
+ 0, gfx::OverlayTransform::OVERLAY_TRANSFORM_NONE,
+ fake_gl_image[1].get(), window_->GetBounds(), {}, false, nullptr);
+
+ std::vector<scoped_refptr<FakeGLImageNativePixmap>> gl_images;
+ gl_images.push_back(fake_gl_image[1]);
+
+ // And submit each image. They will be executed in FIFO manner.
+ gl_surface->SwapBuffersAsync(
+ base::BindOnce(&CallbacksHelper::FinishSwapBuffersAsync,
+ base::Unretained(&cbs_helper), swap_id, gl_images),
+ base::BindOnce(&CallbacksHelper::BufferPresented,
+ base::Unretained(&cbs_helper), swap_id));
+ }
+
+ // Expect one buffer to be committed.
+ EXPECT_CALL(*mock_primary_surface, Attach(_, _, _)).Times(1);
+ EXPECT_CALL(*mock_primary_surface, Frame(_)).Times(1);
+ EXPECT_CALL(*mock_primary_surface, DamageBuffer(_, _, _, _)).Times(1);
+ EXPECT_CALL(*mock_primary_surface, Commit()).Times(1);
+
+ // Send the frame callback so that pending buffer for swap id=1u is processed
+ // and swapped.
+ mock_primary_surface->SendFrameCallback();
+
+ Sync();
+
+ testing::Mock::VerifyAndClearExpectations(&mock_primary_surface);
+
+ // Give mojo the chance to pass the callbacks.
+ base::RunLoop().RunUntilIdle();
+
+ // Even though the second buffer was submitted, we mustn't receive
+ // SwapCompletionCallback until the previous buffer is released.
+ EXPECT_EQ(cbs_helper.GetLastFinishedSwapId(),
+ std::numeric_limits<uint32_t>::max());
+
+ // Submit another frame with 2 overlays, 0 primary plane.
+ {
+ // Associate each image with swap id so that we could track released
+ // buffers.
+ auto swap_id = cbs_helper.GetNextLocalSwapId();
+ // Associate the image with the next swap id so that we can easily track if
+ // it became free to reuse.
+ fake_gl_image[2]->AssociateWithSwapId(swap_id);
+ // And set it to be busy...
+ fake_gl_image[2]->SetBusy(true);
+
+ // Prepare overlay plane.
+ gl_surface->ScheduleOverlayPlane(
+ -1, gfx::OverlayTransform::OVERLAY_TRANSFORM_NONE,
+ fake_gl_image[2].get(), window_->GetBounds(), {}, false, nullptr);
+
+ // Associate the image with the next swap id so that we can easily track if
+ // it became free to reuse.
+ fake_gl_image[3]->AssociateWithSwapId(swap_id);
+ // And set it to be busy...
+ fake_gl_image[3]->SetBusy(true);
+
+ // Prepare overlay plane.
+ gl_surface->ScheduleOverlayPlane(
+ 1, gfx::OverlayTransform::OVERLAY_TRANSFORM_NONE,
+ fake_gl_image[3].get(), window_->GetBounds(), {}, false, nullptr);
+
+ std::vector<scoped_refptr<FakeGLImageNativePixmap>> gl_images;
+ gl_images.push_back(fake_gl_image[2]);
+ gl_images.push_back(fake_gl_image[3]);
+
+ // And submit each image. They will be executed in FIFO manner.
+ gl_surface->SwapBuffersAsync(
+ base::BindOnce(&CallbacksHelper::FinishSwapBuffersAsync,
+ base::Unretained(&cbs_helper), swap_id, gl_images),
+ base::BindOnce(&CallbacksHelper::BufferPresented,
+ base::Unretained(&cbs_helper), swap_id));
+ }
+ // Expect parent surface to be committed without a buffer.
+ EXPECT_CALL(*mock_primary_surface, Attach(_, _, _)).Times(0);
+ EXPECT_CALL(*mock_primary_surface, Frame(_)).Times(1);
+ EXPECT_CALL(*mock_primary_surface, DamageBuffer(_, _, _, _)).Times(0);
+ EXPECT_CALL(*mock_primary_surface, Commit()).Times(1);
+
+ // Send the frame callback so that pending buffer for swap id=2u is processed
+ // and swapped.
+ mock_primary_surface->SendFrameCallback();
+
+ Sync();
+
+ // Give mojo the chance to pass the callbacks.
+ base::RunLoop().RunUntilIdle();
+
+ // Even though OnSubmission can come back because 2 overlays are submitted to
+ // new wl_surfaces so OnSubmission for third frame has already run,
+ // GbmSurfacelessWayland should not run SwapCompletionCallback out of order.
+ EXPECT_EQ(cbs_helper.GetLastFinishedSwapId(),
+ std::numeric_limits<uint32_t>::max());
+
+ // This will result in Wayland server releasing previously attached buffer for
+ // swap id=1u and calling OnSubmission for buffer with swap id=1u.
+ mock_primary_surface->ReleaseBuffer(
+ mock_primary_surface->prev_attached_buffer());
+
+ Sync();
+
+ // Give mojo the chance to pass the callbacks.
+ base::RunLoop().RunUntilIdle();
+
+ // We should expect next 2 SwapCompletionCallbacks for the next 2 swap ids
+ // consecutively.
+ EXPECT_EQ(cbs_helper.GetLastFinishedSwapId(), 2u);
+
+ cbs_helper.ResetLastFinishedSwapId();
+
+ for (const auto& gl_image : fake_gl_image) {
+ if (gl_image->GetAssociateWithSwapId() == 2u) {
+ EXPECT_TRUE(gl_image->displayed());
+ EXPECT_FALSE(gl_image->busy());
+ } else {
+ EXPECT_FALSE(gl_image->displayed());
+ }
+ }
+}
+
+TEST_P(WaylandSurfaceFactoryTest,
+ GbmSurfacelessWaylandGroupOnSubmissionCallbacksTest) {
+ // This tests multiple buffers per-frame. GbmSurfacelessWayland should wait
+ // for all OnSubmission calls targeting the same frame before running
+ // SwapCompletionCallbacks.
+ gl::SetGLImplementation(gl::kGLImplementationEGLGLES2);
+
+ buffer_manager_gpu_->set_gbm_device(std::make_unique<MockGbmDevice>());
+
+ auto* gl_ozone = surface_factory_->GetGLOzone(gl::kGLImplementationEGLGLES2);
+ auto gl_surface = gl_ozone->CreateSurfacelessViewGLSurface(widget_);
+ EXPECT_TRUE(gl_surface);
+ gl_surface->SetRelyOnImplicitSync();
+ static_cast<ui::GbmSurfacelessWayland*>(gl_surface.get())
+ ->SetNoGLFlushForTests();
+
+ // Expect to create 4 buffers.
+ EXPECT_CALL(*server_.zwp_linux_dmabuf_v1(), CreateParams(_, _, _)).Times(4);
+
+ // Create buffers and FakeGlImageNativePixmap.
+ std::vector<scoped_refptr<FakeGLImageNativePixmap>> fake_gl_image;
+ for (int i = 0; i < 4; ++i) {
+ auto native_pixmap = surface_factory_->CreateNativePixmap(
+ widget_, nullptr, window_->GetBounds().size(),
+ gfx::BufferFormat::BGRA_8888, gfx::BufferUsage::SCANOUT);
+ fake_gl_image.push_back(base::MakeRefCounted<FakeGLImageNativePixmap>(
+ native_pixmap, window_->GetBounds().size()));
+
+ Sync();
+
+ // Create one buffer at a time.
+ auto params_vector = server_.zwp_linux_dmabuf_v1()->buffer_params();
+ DCHECK_EQ(params_vector.size(), 1u);
+ zwp_linux_buffer_params_v1_send_created(
+ params_vector.front()->resource(),
+ params_vector.front()->buffer_resource());
+
+ Sync();
+ }
+
+ auto* mock_primary_surface = server_.GetObject<wl::MockSurface>(
+ window_->root_surface()->GetSurfaceId());
+
+ CallbacksHelper cbs_helper;
+ // Submit a frame with 1 primary plane and 1 overlay
+ {
+ // Associate each image with swap id so that we could track released
+ // buffers.
+ auto swap_id = cbs_helper.GetNextLocalSwapId();
+ // Associate the image with the next swap id so that we can easily track if
+ // it became free to reuse.
+ fake_gl_image[0]->AssociateWithSwapId(swap_id);
+ // And set it to be busy...
+ fake_gl_image[0]->SetBusy(true);
+
+ // Prepare overlay plane.
+ gl_surface->ScheduleOverlayPlane(
+ 0, gfx::OverlayTransform::OVERLAY_TRANSFORM_NONE,
+ fake_gl_image[0].get(), window_->GetBounds(), {}, false, nullptr);
+
+ // Associate the image with the next swap id so that we can easily track if
+ // it became free to reuse.
+ fake_gl_image[1]->AssociateWithSwapId(swap_id);
+ // And set it to be busy...
+ fake_gl_image[1]->SetBusy(true);
+
+ // Prepare overlay plane.
+ gl_surface->ScheduleOverlayPlane(
+ 1, gfx::OverlayTransform::OVERLAY_TRANSFORM_NONE,
+ fake_gl_image[1].get(), window_->GetBounds(), {}, false, nullptr);
+
+ std::vector<scoped_refptr<FakeGLImageNativePixmap>> gl_images;
+ gl_images.push_back(fake_gl_image[0]);
+ gl_images.push_back(fake_gl_image[1]);
+
+ // And submit each image. They will be executed in FIFO manner.
+ gl_surface->SwapBuffersAsync(
+ base::BindOnce(&CallbacksHelper::FinishSwapBuffersAsync,
+ base::Unretained(&cbs_helper), swap_id, gl_images),
+ base::BindOnce(&CallbacksHelper::BufferPresented,
+ base::Unretained(&cbs_helper), swap_id));
+ }
+
+ // Let's sync so that 1) GbmSurfacelessWayland submits the buffer according to
+ // internal queue and fake server processes the request.
+
+ // Also, we expect only one buffer to be committed.
+ EXPECT_CALL(*mock_primary_surface, Attach(_, _, _)).Times(1);
+ EXPECT_CALL(*mock_primary_surface, Frame(_)).Times(1);
+ EXPECT_CALL(*mock_primary_surface, DamageBuffer(_, _, _, _)).Times(1);
+ EXPECT_CALL(*mock_primary_surface, Commit()).Times(1);
+
+ Sync();
+
+ testing::Mock::VerifyAndClearExpectations(&mock_primary_surface);
+ auto* subsurface = window_->wayland_subsurfaces().begin()->get();
+ auto* mock_overlay_surface = server_.GetObject<wl::MockSurface>(
+ subsurface->wayland_surface()->GetSurfaceId());
+
+ // Give mojo the chance to pass the callbacks.
+ base::RunLoop().RunUntilIdle();
+
+ // We have just received Attach/DamageBuffer/Commit for buffer with swap
+ // id=0u. The SwapCompletionCallback must be executed automatically as long as
+ // we didn't have any buffers attached to the surface before.
+ EXPECT_EQ(cbs_helper.GetLastFinishedSwapId(), 0u);
+
+ cbs_helper.ResetLastFinishedSwapId();
+
+ for (const auto& gl_image : fake_gl_image) {
+ // All the images except the first one, which was associated with swap
+ // id=0u, must be busy and not displayed. The first one must be displayed.
+ if (gl_image->GetAssociateWithSwapId() == 0u) {
+ EXPECT_FALSE(gl_image->busy());
+ EXPECT_TRUE(gl_image->displayed());
+ } else {
+ EXPECT_FALSE(gl_image->displayed());
+ }
+ }
+
+ // Submit another frame with 1 primary plane and 1 overlay
+ {
+ // Associate each image with swap id so that we could track released
+ // buffers.
+ auto swap_id = cbs_helper.GetNextLocalSwapId();
+ // Associate the image with the next swap id so that we can easily track if
+ // it became free to reuse.
+ fake_gl_image[2]->AssociateWithSwapId(swap_id);
+ // And set it to be busy...
+ fake_gl_image[2]->SetBusy(true);
+
+ // Prepare overlay plane.
+ gl_surface->ScheduleOverlayPlane(
+ 0, gfx::OverlayTransform::OVERLAY_TRANSFORM_NONE,
+ fake_gl_image[2].get(), window_->GetBounds(), {}, false, nullptr);
+
+ // Associate the image with the next swap id so that we can easily track if
+ // it became free to reuse.
+ fake_gl_image[3]->AssociateWithSwapId(swap_id);
+ // And set it to be busy...
+ fake_gl_image[3]->SetBusy(true);
+
+ // Prepare overlay plane.
+ gl_surface->ScheduleOverlayPlane(
+ 1, gfx::OverlayTransform::OVERLAY_TRANSFORM_NONE,
+ fake_gl_image[3].get(), window_->GetBounds(), {}, false, nullptr);
+
+ std::vector<scoped_refptr<FakeGLImageNativePixmap>> gl_images;
+ gl_images.push_back(fake_gl_image[2]);
+ gl_images.push_back(fake_gl_image[3]);
+
+ // And submit each image. They will be executed in FIFO manner.
+ gl_surface->SwapBuffersAsync(
+ base::BindOnce(&CallbacksHelper::FinishSwapBuffersAsync,
+ base::Unretained(&cbs_helper), swap_id, gl_images),
+ base::BindOnce(&CallbacksHelper::BufferPresented,
+ base::Unretained(&cbs_helper), swap_id));
+ }
+
+ // Expect one buffer to be committed.
+ EXPECT_CALL(*mock_primary_surface, Attach(_, _, _)).Times(1);
+ EXPECT_CALL(*mock_primary_surface, Frame(_)).Times(1);
+ EXPECT_CALL(*mock_primary_surface, DamageBuffer(_, _, _, _)).Times(1);
+ EXPECT_CALL(*mock_primary_surface, Commit()).Times(1);
+
+ // Expect one buffer to be committed.
+ EXPECT_CALL(*mock_overlay_surface, Attach(_, _, _)).Times(1);
+ EXPECT_CALL(*mock_overlay_surface, Frame(_)).Times(0);
+ EXPECT_CALL(*mock_overlay_surface, DamageBuffer(_, _, _, _)).Times(1);
+ EXPECT_CALL(*mock_overlay_surface, Commit()).Times(1);
+
+ // Send the frame callback so that pending buffer for swap id=1u is processed
+ // and swapped.
+ mock_primary_surface->SendFrameCallback();
+
+ Sync();
+
+ testing::Mock::VerifyAndClearExpectations(&mock_primary_surface);
+
+ // Give mojo the chance to pass the callbacks.
+ base::RunLoop().RunUntilIdle();
+
+ // Even though the second frame was submitted, we mustn't receive
+ // SwapCompletionCallback until the previous frame's buffers are released.
+ EXPECT_EQ(cbs_helper.GetLastFinishedSwapId(),
+ std::numeric_limits<uint32_t>::max());
+
+ // This will result in Wayland server releasing one of the previously attached
+ // buffers for swap id=0u and calling OnSubmission for a buffer with swap
+ // id=1u attached to the primary surface.
+ mock_primary_surface->ReleaseBuffer(
+ mock_primary_surface->prev_attached_buffer());
+
+ Sync();
+
+ // Give mojo the chance to pass the callbacks.
+ base::RunLoop().RunUntilIdle();
+
+ // OnSubmission was only called for one of the buffers with swap id=1u, so
+ // SwapCompletionCallback should not run.
+ EXPECT_EQ(cbs_helper.GetLastFinishedSwapId(),
+ std::numeric_limits<uint32_t>::max());
+
+ // Release the another buffer.
+ mock_overlay_surface->ReleaseBuffer(
+ mock_overlay_surface->prev_attached_buffer());
+
+ Sync();
+
+ // Give mojo the chance to pass the callbacks.
+ base::RunLoop().RunUntilIdle();
+
+ // OnSubmission was called for both of the buffers with swap id=1u, so
+ // SwapCompletionCallback should run.
+ EXPECT_EQ(cbs_helper.GetLastFinishedSwapId(), 1u);
+
+ for (const auto& gl_image : fake_gl_image) {
+ if (gl_image->GetAssociateWithSwapId() == 1u) {
+ EXPECT_TRUE(gl_image->displayed());
+ EXPECT_FALSE(gl_image->busy());
+ } else {
+ EXPECT_FALSE(gl_image->displayed());
+ }
+ }
+}
+
TEST_P(WaylandSurfaceFactoryTest, Canvas) {
auto canvas = CreateCanvas(widget_);
ASSERT_TRUE(canvas);
diff --git a/chromium/ui/ozone/platform/wayland/host/DEPS b/chromium/ui/ozone/platform/wayland/host/DEPS
new file mode 100644
index 00000000000..1741810f122
--- /dev/null
+++ b/chromium/ui/ozone/platform/wayland/host/DEPS
@@ -0,0 +1,4 @@
+include_rules = [
+ # For Lacros.
+ "+chromeos/crosapi/cpp/crosapi_constants.h",
+]
diff --git a/chromium/ui/ozone/platform/wayland/host/gtk_ui_delegate_wayland.cc b/chromium/ui/ozone/platform/wayland/host/gtk_ui_delegate_wayland.cc
index e5017840921..0a0e4712910 100644
--- a/chromium/ui/ozone/platform/wayland/host/gtk_ui_delegate_wayland.cc
+++ b/chromium/ui/ozone/platform/wayland/host/gtk_ui_delegate_wayland.cc
@@ -7,9 +7,21 @@
#include <gdk/gdkwayland.h>
#include <gtk/gtk.h>
+#include <memory>
+
+#include "base/bind.h"
#include "base/logging.h"
#include "ui/gfx/native_widget_types.h"
#include "ui/ozone/platform/wayland/host/wayland_connection.h"
+#include "ui/ozone/platform/wayland/host/wayland_surface.h"
+#include "ui/ozone/platform/wayland/host/wayland_window.h"
+#include "ui/ozone/platform/wayland/host/wayland_window_manager.h"
+#include "ui/ozone/platform/wayland/host/xdg_foreign_wrapper.h"
+#include "ui/platform_window/platform_window_init_properties.h"
+
+#define WEAK_GTK_FN(x) extern "C" __attribute__((weak)) decltype(x) x
+
+WEAK_GTK_FN(gdk_wayland_window_set_transient_for_exported);
namespace ui {
@@ -39,12 +51,29 @@ GdkWindow* GtkUiDelegateWayland::GetGdkWindow(
bool GtkUiDelegateWayland::SetGdkWindowTransientFor(
GdkWindow* window,
gfx::AcceleratedWidget parent) {
- NOTIMPLEMENTED_LOG_ONCE();
- return false;
+ if (!gdk_wayland_window_set_transient_for_exported) {
+ LOG(WARNING) << "set_transient_for_exported not supported in GTK version "
+ << GTK_MAJOR_VERSION << '.' << GTK_MINOR_VERSION << '.'
+ << GTK_MICRO_VERSION;
+ return false;
+ }
+
+ auto* parent_window =
+ connection_->wayland_window_manager()->GetWindow(parent);
+ auto* foreign = connection_->xdg_foreign();
+ if (!parent_window || !foreign)
+ return false;
+
+ DCHECK_EQ(parent_window->type(), PlatformWindowType::kWindow);
+
+ foreign->ExportSurfaceToForeign(
+ parent_window, base::BindOnce(&GtkUiDelegateWayland::OnHandle,
+ weak_factory_.GetWeakPtr(), window));
+ return true;
}
void GtkUiDelegateWayland::ClearTransientFor(gfx::AcceleratedWidget parent) {
- NOTIMPLEMENTED_LOG_ONCE();
+ // Nothing to do here.
}
void GtkUiDelegateWayland::ShowGtkWindow(GtkWindow* window) {
@@ -53,4 +82,10 @@ void GtkUiDelegateWayland::ShowGtkWindow(GtkWindow* window) {
gtk_window_present(window);
}
+void GtkUiDelegateWayland::OnHandle(GdkWindow* window,
+ const std::string& handle) {
+ gdk_wayland_window_set_transient_for_exported(
+ window, const_cast<char*>(handle.c_str()));
+}
+
} // namespace ui
diff --git a/chromium/ui/ozone/platform/wayland/host/gtk_ui_delegate_wayland.h b/chromium/ui/ozone/platform/wayland/host/gtk_ui_delegate_wayland.h
index 4f3f606c5ac..e5e23aeddac 100644
--- a/chromium/ui/ozone/platform/wayland/host/gtk_ui_delegate_wayland.h
+++ b/chromium/ui/ozone/platform/wayland/host/gtk_ui_delegate_wayland.h
@@ -5,6 +5,9 @@
#ifndef UI_OZONE_PLATFORM_WAYLAND_HOST_GTK_UI_DELEGATE_WAYLAND_H_
#define UI_OZONE_PLATFORM_WAYLAND_HOST_GTK_UI_DELEGATE_WAYLAND_H_
+#include <string>
+
+#include "base/memory/weak_ptr.h"
#include "ui/gfx/native_widget_types.h"
#include "ui/gtk/gtk_ui_delegate.h"
@@ -29,7 +32,13 @@ class GtkUiDelegateWayland : public GtkUiDelegate {
void ShowGtkWindow(GtkWindow* window) override;
private:
+ // Called when xdg-foreign exports a parent window passed in
+ // SetGdkWindowTransientFor.
+ void OnHandle(GdkWindow* window, const std::string& handle);
+
WaylandConnection* const connection_;
+
+ base::WeakPtrFactory<GtkUiDelegateWayland> weak_factory_{this};
};
} // namespace ui
diff --git a/chromium/ui/ozone/platform/wayland/host/wayland_auxiliary_window.cc b/chromium/ui/ozone/platform/wayland/host/wayland_auxiliary_window.cc
index c5e31fd5b9d..50cbee6cad2 100644
--- a/chromium/ui/ozone/platform/wayland/host/wayland_auxiliary_window.cc
+++ b/chromium/ui/ozone/platform/wayland/host/wayland_auxiliary_window.cc
@@ -102,13 +102,16 @@ void WaylandAuxiliaryWindow::CreateSubsurface() {
bool WaylandAuxiliaryWindow::OnInitialize(
PlatformWindowInitProperties properties) {
+ DCHECK(!parent_window());
+
// If we do not have parent window provided, we must always use a focused
// window or a window that entered drag whenever the subsurface is created.
- if (properties.parent_widget == gfx::kNullAcceleratedWidget) {
- DCHECK(!parent_window());
+ if (properties.parent_widget == gfx::kNullAcceleratedWidget)
return true;
- }
- set_parent_window(GetParentWindow(properties.parent_widget));
+
+ set_parent_window(
+ connection()->wayland_window_manager()->FindParentForNewWindow(
+ properties.parent_widget));
return true;
}
diff --git a/chromium/ui/ozone/platform/wayland/host/wayland_buffer_manager_host.cc b/chromium/ui/ozone/platform/wayland/host/wayland_buffer_manager_host.cc
index c60c35e4ab4..5fa747f3301 100644
--- a/chromium/ui/ozone/platform/wayland/host/wayland_buffer_manager_host.cc
+++ b/chromium/ui/ozone/platform/wayland/host/wayland_buffer_manager_host.cc
@@ -25,6 +25,9 @@ namespace ui {
namespace {
+// Use |kInvalidBufferId| to commit surface state without updating wl_buffer.
+constexpr uint32_t kInvalidBufferId = 0u;
+
uint32_t GetPresentationKindFlags(uint32_t flags) {
// Wayland spec has different meaning of VSync. In Chromium, VSync means to
// update the begin frame vsync timing based on presentation feedback.
@@ -65,11 +68,20 @@ class WaylandBufferManagerHost::Surface {
buffer_manager_(buffer_manager) {}
~Surface() = default;
- bool CommitBuffer(uint32_t buffer_id, const gfx::Rect& damage_region) {
+ bool CommitBuffer(uint32_t buffer_id,
+ const gfx::Rect& damage_region,
+ bool wait_for_frame_callback) {
// The window has already been destroyed.
if (!wayland_surface_)
return true;
+ // This is a buffer-less commit, do not lookup buffers.
+ if (buffer_id == kInvalidBufferId) {
+ pending_commits_.push_back({nullptr, wait_for_frame_callback});
+ MaybeProcessPendingBuffer();
+ return true;
+ }
+
WaylandBuffer* buffer = GetBuffer(buffer_id);
if (!buffer) {
// Get the anonymous_wl_buffer aka the buffer that has not been attached
@@ -95,17 +107,11 @@ class WaylandBufferManagerHost::Surface {
if (buffer->attached && !buffer->wl_buffer)
return false;
- pending_buffers_.push_back(buffer);
+ pending_commits_.push_back({buffer, wait_for_frame_callback});
MaybeProcessPendingBuffer();
return true;
}
- bool CreateBuffer(const gfx::Size& size, uint32_t buffer_id) {
- auto result = buffers_.emplace(
- buffer_id, std::make_unique<WaylandBuffer>(size, buffer_id));
- return result.second;
- }
-
size_t DestroyBuffer(uint32_t buffer_id) {
auto* buffer = GetBuffer(buffer_id);
@@ -114,7 +120,11 @@ class WaylandBufferManagerHost::Surface {
if (buffer) {
buffer->released = true;
MaybeProcessSubmittedBuffers();
- base::Erase(pending_buffers_, buffer);
+ for (auto it = pending_commits_.begin(); it != pending_commits_.end();
+ ++it) {
+ if (it->buffer == buffer)
+ pending_commits_.erase(it++);
+ }
}
return buffers_.erase(buffer_id);
@@ -145,7 +155,7 @@ class WaylandBufferManagerHost::Surface {
ResetSurfaceContents();
submitted_buffers_.clear();
- pending_buffers_.clear();
+ pending_commits_.clear();
connection_->ScheduleFlush();
}
@@ -210,7 +220,16 @@ class WaylandBufferManagerHost::Surface {
bool acked;
};
- bool CommitBufferInternal(WaylandBuffer* buffer) {
+ // Represents a pending surface commit.
+ struct PendingCommit {
+ // If null, means this commit will not attach buffer.
+ WaylandBuffer* buffer = nullptr;
+ // Whether this commit must wait for a wl_frame_callback and setup another
+ // wl_frame_callback.
+ bool wait_for_callback = false;
+ };
+
+ bool CommitBufferInternal(WaylandBuffer* buffer, bool wait_for_callback) {
DCHECK(buffer && wayland_surface_);
// If the same buffer has been submitted again right after the client
@@ -231,7 +250,8 @@ class WaylandBufferManagerHost::Surface {
DamageBuffer(buffer);
- SetupFrameCallback();
+ if (wait_for_callback)
+ SetupFrameCallback();
SetupPresentationFeedback(buffer->buffer_id);
CommitSurface();
@@ -252,7 +272,8 @@ class WaylandBufferManagerHost::Surface {
pending_damage_region.set_size(buffer->size);
DCHECK(!pending_damage_region.size().IsEmpty());
- wayland_surface_->Damage(pending_damage_region);
+ wayland_surface_->UpdateBufferDamageRegion(pending_damage_region,
+ buffer->size);
}
void AttachBuffer(WaylandBuffer* buffer) {
@@ -509,10 +530,10 @@ class WaylandBufferManagerHost::Surface {
}
void MaybeProcessPendingBuffer() {
- DCHECK_LE(pending_buffers_.size(), 6u);
+ DCHECK_LE(pending_commits_.size(), 6u);
// There is nothing to process if there is no pending buffer or the window
// has been destroyed.
- if (pending_buffers_.empty() || !wayland_surface_)
+ if (pending_commits_.empty() || !wayland_surface_)
return;
// This request may come earlier than the Wayland compositor has imported a
@@ -529,12 +550,27 @@ class WaylandBufferManagerHost::Surface {
//
// The third case happens if the window hasn't been configured until a
// request to attach a buffer to its surface is sent.
- auto* pending_buffer = pending_buffers_.front();
- if (!pending_buffer->wl_buffer || wl_frame_callback_ || !configured_)
+ auto pending_commit = std::move(pending_commits_.front());
+ if ((pending_commit.buffer && !pending_commit.buffer->wl_buffer) ||
+ (wl_frame_callback_ && pending_commit.wait_for_callback) ||
+ !configured_) {
+ return;
+ }
+
+ // A Commit without attaching buffers only needs to setup wl_frame_callback.
+ if (!pending_commit.buffer) {
+ pending_commits_.erase(pending_commits_.begin());
+ if (pending_commit.wait_for_callback)
+ SetupFrameCallback();
+ CommitSurface();
+ connection_->ScheduleFlush();
+ MaybeProcessSubmittedBuffers();
return;
+ }
- pending_buffers_.erase(pending_buffers_.begin());
- CommitBufferInternal(pending_buffer);
+ pending_commits_.erase(pending_commits_.begin());
+ CommitBufferInternal(pending_commit.buffer,
+ pending_commit.wait_for_callback);
}
// Widget this helper surface backs and has 1:1 relationship with the
@@ -557,9 +593,9 @@ class WaylandBufferManagerHost::Surface {
// operation.
wl::Object<wl_callback> wl_frame_callback_;
- // Queue of buffers which are pending to be submitted (look the comment
+ // Queue of commits which are pending to be submitted (look the comment
// in the CommitBuffer method).
- std::vector<WaylandBuffer*> pending_buffers_;
+ std::list<PendingCommit> pending_commits_;
// Queue of buffers which have been submitted and are waiting to be
// acked (send OnSubmission)
@@ -639,6 +675,13 @@ void WaylandBufferManagerHost::OnSubsurfaceRemoved(
surfaces_.erase(it);
}
+void WaylandBufferManagerHost::SetSurfaceConfigured(WaylandSurface* surface) {
+ DCHECK(surface);
+ auto it = surfaces_.find(surface);
+ DCHECK(it != surfaces_.end());
+ it->second->OnSurfaceConfigured();
+}
+
void WaylandBufferManagerHost::SetTerminateGpuCallback(
base::OnceCallback<void(std::string)> terminate_callback) {
terminate_gpu_cb_ = std::move(terminate_callback);
@@ -668,12 +711,13 @@ void WaylandBufferManagerHost::OnChannelDestroyed() {
wl::BufferFormatsWithModifiersMap
WaylandBufferManagerHost::GetSupportedBufferFormats() const {
+#if defined(WAYLAND_GBM)
if (connection_->zwp_dmabuf())
return connection_->zwp_dmabuf()->supported_buffer_formats();
else if (connection_->drm())
return connection_->drm()->supported_buffer_formats();
- else
- return {};
+#endif
+ return {};
}
bool WaylandBufferManagerHost::SupportsDmabuf() const {
@@ -760,14 +804,16 @@ void WaylandBufferManagerHost::CreateShmBasedBuffer(mojo::PlatformHandle shm_fd,
bool WaylandBufferManagerHost::CommitBufferInternal(
WaylandSurface* wayland_surface,
uint32_t buffer_id,
- const gfx::Rect& damage_region) {
+ const gfx::Rect& damage_region,
+ bool wait_for_frame_callback) {
DCHECK(base::CurrentUIThread::IsSet());
Surface* surface = GetSurface(wayland_surface);
if (!surface || !ValidateBufferIdFromGpu(buffer_id))
return false;
- if (!surface->CommitBuffer(buffer_id, damage_region)) {
+ if (!surface->CommitBuffer(buffer_id, damage_region,
+ wait_for_frame_callback)) {
error_message_ =
base::StrCat({"Buffer with ", NumberToString(buffer_id),
" id does not exist or failed to be created."});
@@ -778,6 +824,24 @@ bool WaylandBufferManagerHost::CommitBufferInternal(
return true;
}
+bool WaylandBufferManagerHost::CommitWithoutBufferInternal(
+ WaylandSurface* wayland_surface,
+ bool wait_for_frame_callback) {
+ DCHECK(base::CurrentUIThread::IsSet());
+
+ Surface* surface = GetSurface(wayland_surface);
+ if (!surface)
+ return false;
+
+ bool result = surface->CommitBuffer(kInvalidBufferId, gfx::Rect(),
+ wait_for_frame_callback);
+ DCHECK(result);
+
+ if (!error_message_.empty())
+ TerminateGpuProcess();
+ return true;
+}
+
void WaylandBufferManagerHost::CommitBuffer(gfx::AcceleratedWidget widget,
uint32_t buffer_id,
const gfx::Rect& damage_region) {
diff --git a/chromium/ui/ozone/platform/wayland/host/wayland_buffer_manager_host.h b/chromium/ui/ozone/platform/wayland/host/wayland_buffer_manager_host.h
index 20a974e1a5c..28dc77dc8d0 100644
--- a/chromium/ui/ozone/platform/wayland/host/wayland_buffer_manager_host.h
+++ b/chromium/ui/ozone/platform/wayland/host/wayland_buffer_manager_host.h
@@ -89,6 +89,9 @@ class WaylandBufferManagerHost : public ozone::mojom::WaylandBufferManagerHost,
void OnSubsurfaceRemoved(WaylandWindow* window,
WaylandSubsurface* subsurface) override;
+ // Start allowing attaching buffers to |surface|, same as
+ // OnWindowConfigured(), but for WaylandSurface.
+ void SetSurfaceConfigured(WaylandSurface* surface);
void SetTerminateGpuCallback(
base::OnceCallback<void(std::string)> terminate_gpu_cb);
@@ -154,9 +157,22 @@ class WaylandBufferManagerHost : public ozone::mojom::WaylandBufferManagerHost,
// |buffer_id| to a WaylandSurface.
// Calls OnSubmission and OnPresentation on successful swap and pixels
// presented.
+ // |wait_for_frame_callback| instructs that a surface should wait for previous
+ // wl_frame_callback. This is primarily used for sync wl_subsurfaces case
+ // where buffer updates within a frame should be seen together. A root_surface
+ // commit will move an entire wl_surface tree from pending state to ready
+ // state. This root_surface commit must wait for wl_frame_callback, such that
+ // in effect all other surface updates wait for this wl_frame_callback, too.
bool CommitBufferInternal(WaylandSurface* wayland_surface,
uint32_t buffer_id,
- const gfx::Rect& damage_region);
+ const gfx::Rect& damage_region,
+ bool wait_for_frame_callback = true);
+
+ // Does a wl_surface commit without attaching any buffers. This commit will
+ // still wait for previous wl_frame_callback. Similar to above but for
+ // commits that do not change the root_surface.
+ bool CommitWithoutBufferInternal(WaylandSurface* wayland_surface,
+ bool wait_for_frame_callback = true);
// When a surface is hidden, the client may want to detach the buffer attached
// to the surface to ensure Wayland does not present those contents and do not
@@ -236,8 +252,13 @@ class WaylandBufferManagerHost : public ozone::mojom::WaylandBufferManagerHost,
base::OnceCallback<void(std::string)> terminate_gpu_cb_;
// Contains anonymous buffers aka buffers that are not attached to any of the
- // existing surfaces and that will be mapped to surfaces later. Typically
- // created when CreateAnonymousImage is called on the gpu process side.
+ // existing surfaces and that will be mapped to surfaces later.
+ // Typically created when CreateAnonymousImage is called on the gpu process
+ // side.
+ // We assume that a buffer_id/wl_buffer will never be used on multiple
+ // wl_surfaces so we never re-map buffers to surfaces. If we ever need to use
+ // the same buffer for 2 surfaces at the same time, create multiple wl_buffers
+ // referencing the same dmabuf or underlying storage.
base::flat_map<uint32_t, std::unique_ptr<WaylandBuffer>> anonymous_buffers_;
base::WeakPtrFactory<WaylandBufferManagerHost> weak_factory_;
diff --git a/chromium/ui/ozone/platform/wayland/host/wayland_clipboard.cc b/chromium/ui/ozone/platform/wayland/host/wayland_clipboard.cc
index 7e1cdf1aee4..e39d1ee03fb 100644
--- a/chromium/ui/ozone/platform/wayland/host/wayland_clipboard.cc
+++ b/chromium/ui/ozone/platform/wayland/host/wayland_clipboard.cc
@@ -74,8 +74,7 @@ class ClipboardImpl final : public Clipboard, public DataSource::Delegate {
source_.reset();
} else {
data_ = *data;
- if (!source_)
- source_ = manager_->CreateSource(this);
+ source_ = manager_->CreateSource(this);
source_->Offer(GetMimeTypes());
GetDevice()->SetSelectionSource(source_.get());
}
diff --git a/chromium/ui/ozone/platform/wayland/host/wayland_connection.cc b/chromium/ui/ozone/platform/wayland/host/wayland_connection.cc
index febebefad2c..4c99dc8612c 100644
--- a/chromium/ui/ozone/platform/wayland/host/wayland_connection.cc
+++ b/chromium/ui/ozone/platform/wayland/host/wayland_connection.cc
@@ -38,6 +38,13 @@
#include "ui/ozone/platform/wayland/host/wayland_window.h"
#include "ui/ozone/platform/wayland/host/wayland_window_drag_controller.h"
#include "ui/ozone/platform/wayland/host/wayland_zwp_linux_dmabuf.h"
+#include "ui/ozone/platform/wayland/host/xdg_foreign_wrapper.h"
+
+#if defined(USE_LIBWAYLAND_STUBS)
+#include <dlfcn.h>
+
+#include "third_party/wayland/libwayland_stubs.h" // nogncheck
+#endif
namespace ui {
@@ -46,15 +53,18 @@ constexpr uint32_t kMaxCompositorVersion = 4;
constexpr uint32_t kMaxGtkPrimarySelectionDeviceManagerVersion = 1;
constexpr uint32_t kMaxKeyboardExtensionVersion = 1;
constexpr uint32_t kMaxLinuxDmabufVersion = 3;
-constexpr uint32_t kMaxSeatVersion = 4;
+constexpr uint32_t kMaxSeatVersion = 5;
constexpr uint32_t kMaxShmVersion = 1;
constexpr uint32_t kMaxXdgShellVersion = 1;
constexpr uint32_t kMaxDeviceManagerVersion = 3;
constexpr uint32_t kMaxWpPresentationVersion = 1;
+constexpr uint32_t kMaxWpViewporterVersion = 1;
constexpr uint32_t kMaxTextInputManagerVersion = 1;
+constexpr uint32_t kMaxExplicitSyncVersion = 2;
constexpr uint32_t kMinAuraShellVersion = 10;
constexpr uint32_t kMinWlDrmVersion = 2;
constexpr uint32_t kMinWlOutputVersion = 2;
+constexpr uint32_t kMaxXdgDecorationVersion = 1;
} // namespace
WaylandConnection::WaylandConnection() = default;
@@ -62,6 +72,21 @@ WaylandConnection::WaylandConnection() = default;
WaylandConnection::~WaylandConnection() = default;
bool WaylandConnection::Initialize() {
+#if defined(USE_LIBWAYLAND_STUBS)
+ // Use RTLD_NOW to load all symbols, since the stubs will try to load all of
+ // them anyway. Use RTLD_GLOBAL to add the symbols to the global namespace.
+ auto dlopen_flags = RTLD_NOW | RTLD_GLOBAL;
+ if (void* libwayland_client =
+ dlopen("libwayland-client.so.0", dlopen_flags)) {
+ third_party_wayland::InitializeLibwaylandclient(libwayland_client);
+ } else {
+ LOG(ERROR) << "Failed to load wayland client libraries.";
+ return false;
+ }
+ if (void* libwayland_egl = dlopen("libwayland-egl.so.1", dlopen_flags))
+ third_party_wayland::InitializeLibwaylandegl(libwayland_egl);
+#endif
+
static const wl_registry_listener registry_listener = {
&WaylandConnection::Global,
&WaylandConnection::GlobalRemove,
@@ -128,11 +153,15 @@ void WaylandConnection::ScheduleFlush() {
}
}
+void WaylandConnection::SetShutdownCb(base::OnceCallback<void()> shutdown_cb) {
+ event_source()->SetShutdownCb(std::move(shutdown_cb));
+}
+
void WaylandConnection::SetCursorBitmap(const std::vector<SkBitmap>& bitmaps,
const gfx::Point& location) {
if (!cursor_)
return;
- cursor_->UpdateBitmap(bitmaps, location, serial_);
+ cursor_->UpdateBitmap(bitmaps, location, serial());
}
bool WaylandConnection::IsDragInProgress() const {
@@ -279,8 +308,7 @@ void WaylandConnection::Global(void* data,
}
zxdg_shell_v6_add_listener(connection->shell_v6_.get(), &shell_v6_listener,
connection);
- } else if (!connection->shell_v6_ && !connection->shell_ &&
- strcmp(interface, "xdg_wm_base") == 0) {
+ } else if (!connection->shell_ && strcmp(interface, "xdg_wm_base") == 0) {
connection->shell_ = wl::Bind<xdg_wm_base>(
registry, name, std::min(version, kMaxXdgShellVersion));
if (!connection->shell_) {
@@ -331,6 +359,12 @@ void WaylandConnection::Global(void* data,
connection->primary_selection_device_manager_ =
std::make_unique<GtkPrimarySelectionDeviceManager>(manager.release(),
connection);
+ } else if (!connection->linux_explicit_synchronization_ &&
+ (strcmp(interface, "zwp_linux_explicit_synchronization_v1") ==
+ 0)) {
+ connection->linux_explicit_synchronization_ =
+ wl::Bind<zwp_linux_explicit_synchronization_v1>(
+ registry, name, std::min(version, kMaxExplicitSyncVersion));
} else if (!connection->zwp_dmabuf_ &&
(strcmp(interface, "zwp_linux_dmabuf_v1") == 0)) {
wl::Object<zwp_linux_dmabuf_v1> zwp_linux_dmabuf =
@@ -342,6 +376,10 @@ void WaylandConnection::Global(void* data,
(strcmp(interface, "wp_presentation") == 0)) {
connection->presentation_ =
wl::Bind<wp_presentation>(registry, name, kMaxWpPresentationVersion);
+ } else if (!connection->viewporter_ &&
+ (strcmp(interface, "wp_viewporter") == 0)) {
+ connection->viewporter_ =
+ wl::Bind<wp_viewporter>(registry, name, kMaxWpViewporterVersion);
} else if (!connection->keyboard_extension_v1_ &&
strcmp(interface, "zcr_keyboard_extension_v1") == 0) {
connection->keyboard_extension_v1_ = wl::Bind<zcr_keyboard_extension_v1>(
@@ -361,6 +399,10 @@ void WaylandConnection::Global(void* data,
LOG(ERROR) << "Failed to bind to zwp_text_input_manager_v1 global";
return;
}
+ } else if (!connection->xdg_foreign_ &&
+ strcmp(interface, "zxdg_exporter_v1") == 0) {
+ connection->xdg_foreign_ = std::make_unique<XdgForeignWrapper>(
+ connection, wl::Bind<zxdg_exporter_v1>(registry, name, version));
} else if (!connection->drm_ && (strcmp(interface, "wl_drm") == 0) &&
version >= kMinWlDrmVersion) {
auto wayland_drm = wl::Bind<struct wl_drm>(registry, name, version);
@@ -375,6 +417,11 @@ void WaylandConnection::Global(void* data,
LOG(ERROR) << "Failed to bind zaura_shell";
return;
}
+ } else if (!connection->xdg_decoration_manager_ &&
+ strcmp(interface, "zxdg_decoration_manager_v1") == 0) {
+ connection->xdg_decoration_manager_ =
+ wl::Bind<struct zxdg_decoration_manager_v1>(registry, name,
+ kMaxXdgDecorationVersion);
}
connection->ScheduleFlush();
diff --git a/chromium/ui/ozone/platform/wayland/host/wayland_connection.h b/chromium/ui/ozone/platform/wayland/host/wayland_connection.h
index 6dfc5b7a560..ec7beb98b17 100644
--- a/chromium/ui/ozone/platform/wayland/host/wayland_connection.h
+++ b/chromium/ui/ozone/platform/wayland/host/wayland_connection.h
@@ -9,6 +9,7 @@
#include <vector>
#include "third_party/skia/include/core/SkBitmap.h"
+#include "ui/events/event.h"
#include "ui/ozone/platform/wayland/common/wayland_object.h"
#include "ui/ozone/platform/wayland/host/wayland_clipboard.h"
#include "ui/ozone/platform/wayland/host/wayland_data_drag_controller.h"
@@ -35,9 +36,16 @@ class WaylandDataDeviceManager;
class WaylandCursorPosition;
class WaylandWindowDragController;
class GtkPrimarySelectionDeviceManager;
+class XdgForeignWrapper;
class WaylandConnection {
public:
+ // Stores the last serial and the event type it is associated with.
+ struct EventSerial {
+ uint32_t serial = 0;
+ EventType event_type = EventType::ET_UNKNOWN;
+ };
+
WaylandConnection();
WaylandConnection(const WaylandConnection&) = delete;
WaylandConnection& operator=(const WaylandConnection&) = delete;
@@ -48,10 +56,15 @@ class WaylandConnection {
// Schedules a flush of the Wayland connection.
void ScheduleFlush();
+ // Sets a callback that that shutdowns the browser in case of unrecoverable
+ // error. Called by WaylandEventWatcher.
+ void SetShutdownCb(base::OnceCallback<void()> shutdown_cb);
+
wl_display* display() const { return display_.get(); }
wl_compositor* compositor() const { return compositor_.get(); }
uint32_t compositor_version() const { return compositor_version_; }
wl_subcompositor* subcompositor() const { return subcompositor_.get(); }
+ wp_viewporter* viewporter() const { return viewporter_.get(); }
xdg_wm_base* shell() const { return shell_.get(); }
zxdg_shell_v6* shell_v6() const { return shell_v6_.get(); }
zaura_shell* aura_shell() const { return aura_shell_.get(); }
@@ -60,9 +73,19 @@ class WaylandConnection {
zwp_text_input_manager_v1* text_input_manager_v1() const {
return text_input_manager_v1_.get();
}
+ zwp_linux_explicit_synchronization_v1* linux_explicit_synchronization_v1()
+ const {
+ return linux_explicit_synchronization_.get();
+ }
+ zxdg_decoration_manager_v1* xdg_decoration_manager_v1() const {
+ return xdg_decoration_manager_.get();
+ }
- void set_serial(uint32_t serial) { serial_ = serial; }
- uint32_t serial() const { return serial_; }
+ void set_serial(uint32_t serial, EventType event_type) {
+ serial_ = {serial, event_type};
+ }
+ uint32_t serial() const { return serial_.serial; }
+ EventSerial event_serial() const { return serial_; }
void SetCursorBitmap(const std::vector<SkBitmap>& bitmaps,
const gfx::Point& location);
@@ -119,6 +142,8 @@ class WaylandConnection {
return window_drag_controller_.get();
}
+ XdgForeignWrapper* xdg_foreign() const { return xdg_foreign_.get(); }
+
// Returns true when dragging is entered or started.
bool IsDragInProgress() const;
@@ -164,9 +189,13 @@ class WaylandConnection {
wl::Object<xdg_wm_base> shell_;
wl::Object<zxdg_shell_v6> shell_v6_;
wl::Object<wp_presentation> presentation_;
+ wl::Object<wp_viewporter> viewporter_;
wl::Object<zcr_keyboard_extension_v1> keyboard_extension_v1_;
wl::Object<zwp_text_input_manager_v1> text_input_manager_v1_;
wl::Object<zaura_shell> aura_shell_;
+ wl::Object<zwp_linux_explicit_synchronization_v1>
+ linux_explicit_synchronization_;
+ wl::Object<zxdg_decoration_manager_v1> xdg_decoration_manager_;
// Event source instance. Must be declared before input objects so it
// outlives them so thus being able to properly handle their destruction.
@@ -186,6 +215,7 @@ class WaylandConnection {
std::unique_ptr<WaylandDrm> drm_;
std::unique_ptr<WaylandShm> shm_;
std::unique_ptr<WaylandBufferManagerHost> buffer_manager_host_;
+ std::unique_ptr<XdgForeignWrapper> xdg_foreign_;
std::unique_ptr<GtkPrimarySelectionDeviceManager>
primary_selection_device_manager_;
@@ -198,7 +228,7 @@ class WaylandConnection {
bool scheduled_flush_ = false;
- uint32_t serial_ = 0;
+ EventSerial serial_;
};
} // namespace ui
diff --git a/chromium/ui/ozone/platform/wayland/host/wayland_cursor.h b/chromium/ui/ozone/platform/wayland/host/wayland_cursor.h
index 1f73050be9b..bb4978d2d3d 100644
--- a/chromium/ui/ozone/platform/wayland/host/wayland_cursor.h
+++ b/chromium/ui/ozone/platform/wayland/host/wayland_cursor.h
@@ -5,8 +5,6 @@
#ifndef UI_OZONE_PLATFORM_WAYLAND_HOST_WAYLAND_CURSOR_H_
#define UI_OZONE_PLATFORM_WAYLAND_HOST_WAYLAND_CURSOR_H_
-#include <wayland-client.h>
-
#include <vector>
#include "base/containers/flat_map.h"
diff --git a/chromium/ui/ozone/platform/wayland/host/wayland_data_device.cc b/chromium/ui/ozone/platform/wayland/host/wayland_data_device.cc
index f80738e5e34..8f4b62fa68e 100644
--- a/chromium/ui/ozone/platform/wayland/host/wayland_data_device.cc
+++ b/chromium/ui/ozone/platform/wayland/host/wayland_data_device.cc
@@ -109,14 +109,20 @@ void WaylandDataDevice::OnEnter(void* data,
wl_fixed_t x,
wl_fixed_t y,
wl_data_offer* offer) {
+ auto* self = static_cast<WaylandDataDevice*>(data);
WaylandWindow* window = wl::RootWindowFromWlSurface(surface);
+
+ // During Chrome's tab dragging, when a browser window is quickly snapped in
+ // and out, it might get destroyed before the wl_data_device::enter event is
+ // processed for a drag offer. If this happens, |window| will be null here, so
+ // destroy |new_offer_| here, as some compositors assume it. Such behavior has
+ // been observed in Exosphere compositor, for example.
if (!window) {
- LOG(ERROR) << "Failed to get window.";
+ self->new_offer_.reset();
+ VLOG(1) << "Failed to get window.";
return;
}
- auto* self = static_cast<WaylandDataDevice*>(data);
-
// Null |drag_delegate_| here means that the DND session has been initiated by
// an external application. In this case, use the default data drag delegate.
if (!self->drag_delegate_)
diff --git a/chromium/ui/ozone/platform/wayland/host/wayland_data_device.h b/chromium/ui/ozone/platform/wayland/host/wayland_data_device.h
index 12b84cf9cb1..f43ba2e8dfa 100644
--- a/chromium/ui/ozone/platform/wayland/host/wayland_data_device.h
+++ b/chromium/ui/ozone/platform/wayland/host/wayland_data_device.h
@@ -5,8 +5,6 @@
#ifndef UI_OZONE_PLATFORM_WAYLAND_HOST_WAYLAND_DATA_DEVICE_H_
#define UI_OZONE_PLATFORM_WAYLAND_HOST_WAYLAND_DATA_DEVICE_H_
-#include <wayland-client.h>
-
#include <cstdint>
#include <memory>
#include <string>
diff --git a/chromium/ui/ozone/platform/wayland/host/wayland_data_device_manager.cc b/chromium/ui/ozone/platform/wayland/host/wayland_data_device_manager.cc
index 6c283794473..f800dcbd4fc 100644
--- a/chromium/ui/ozone/platform/wayland/host/wayland_data_device_manager.cc
+++ b/chromium/ui/ozone/platform/wayland/host/wayland_data_device_manager.cc
@@ -4,8 +4,6 @@
#include "ui/ozone/platform/wayland/host/wayland_data_device_manager.h"
-#include <wayland-client-protocol.h>
-
#include <memory>
#include "ui/ozone/platform/wayland/host/wayland_connection.h"
diff --git a/chromium/ui/ozone/platform/wayland/host/wayland_data_drag_controller.cc b/chromium/ui/ozone/platform/wayland/host/wayland_data_drag_controller.cc
index e4337897d54..736c40d3cbe 100644
--- a/chromium/ui/ozone/platform/wayland/host/wayland_data_drag_controller.cc
+++ b/chromium/ui/ozone/platform/wayland/host/wayland_data_drag_controller.cc
@@ -4,8 +4,6 @@
#include "ui/ozone/platform/wayland/host/wayland_data_drag_controller.h"
-#include <wayland-client-protocol.h>
-
#include <cstdint>
#include "base/check.h"
diff --git a/chromium/ui/ozone/platform/wayland/host/wayland_data_offer.cc b/chromium/ui/ozone/platform/wayland/host/wayland_data_offer.cc
index 1b274192123..84d29d32b60 100644
--- a/chromium/ui/ozone/platform/wayland/host/wayland_data_offer.cc
+++ b/chromium/ui/ozone/platform/wayland/host/wayland_data_offer.cc
@@ -26,7 +26,7 @@ WaylandDataOffer::~WaylandDataOffer() {
void WaylandDataOffer::SetAction(uint32_t dnd_actions,
uint32_t preferred_action) {
- if (wl_data_offer_get_version(data_offer_.get()) >=
+ if (wl::get_version_of_object(data_offer_.get()) >=
WL_DATA_OFFER_SET_ACTIONS_SINCE_VERSION) {
wl_data_offer_set_actions(data_offer_.get(), dnd_actions, preferred_action);
}
@@ -62,9 +62,10 @@ base::ScopedFD WaylandDataOffer::Receive(const std::string& mime_type) {
}
void WaylandDataOffer::FinishOffer() {
- if (wl_data_offer_get_version(data_offer_.get()) >=
- WL_DATA_OFFER_FINISH_SINCE_VERSION)
+ if (wl::get_version_of_object(data_offer_.get()) >=
+ WL_DATA_OFFER_FINISH_SINCE_VERSION) {
wl_data_offer_finish(data_offer_.get());
+ }
}
uint32_t WaylandDataOffer::source_actions() const {
diff --git a/chromium/ui/ozone/platform/wayland/host/wayland_data_offer.h b/chromium/ui/ozone/platform/wayland/host/wayland_data_offer.h
index f79bc7b3b71..a724709c9c1 100644
--- a/chromium/ui/ozone/platform/wayland/host/wayland_data_offer.h
+++ b/chromium/ui/ozone/platform/wayland/host/wayland_data_offer.h
@@ -5,8 +5,6 @@
#ifndef UI_OZONE_PLATFORM_WAYLAND_HOST_WAYLAND_DATA_OFFER_H_
#define UI_OZONE_PLATFORM_WAYLAND_HOST_WAYLAND_DATA_OFFER_H_
-#include <wayland-client.h>
-
#include <string>
#include "base/files/scoped_file.h"
diff --git a/chromium/ui/ozone/platform/wayland/host/wayland_data_source.cc b/chromium/ui/ozone/platform/wayland/host/wayland_data_source.cc
index 1d66a9f74cb..aaaf384f3e9 100644
--- a/chromium/ui/ozone/platform/wayland/host/wayland_data_source.cc
+++ b/chromium/ui/ozone/platform/wayland/host/wayland_data_source.cc
@@ -5,7 +5,6 @@
#include "ui/ozone/platform/wayland/host/wayland_data_source.h"
#include <gtk-primary-selection-client-protocol.h>
-#include <wayland-client-protocol.h>
#include <cstdint>
#include <vector>
@@ -111,7 +110,7 @@ void DataSource<T>::SetAction(int operation) {
template <>
void DataSource<wl_data_source>::SetAction(int operation) {
- if (wl_data_source_get_version(data_source_.get()) >=
+ if (wl::get_version_of_object(data_source_.get()) >=
WL_DATA_SOURCE_SET_ACTIONS_SINCE_VERSION) {
uint32_t dnd_actions = WL_DATA_DEVICE_MANAGER_DND_ACTION_NONE;
if (operation & ui::DragDropTypes::DRAG_COPY)
diff --git a/chromium/ui/ozone/platform/wayland/host/wayland_event_source.cc b/chromium/ui/ozone/platform/wayland/host/wayland_event_source.cc
index 41f186362f9..15eb6b6e2c2 100644
--- a/chromium/ui/ozone/platform/wayland/host/wayland_event_source.cc
+++ b/chromium/ui/ozone/platform/wayland/host/wayland_event_source.cc
@@ -37,6 +37,12 @@ bool HasAnyPointerButtonFlag(int flags) {
EF_FORWARD_MOUSE_BUTTON)) != 0;
}
+// Number of fingers for scroll gestures.
+constexpr int kGestureScrollFingerCount = 2;
+
+// Maximum size of the stored recent pointer frame information.
+constexpr int kRecentPointerFrameMaxSize = 20;
+
} // namespace
struct WaylandEventSource::TouchPoint {
@@ -67,6 +73,10 @@ WaylandEventSource::WaylandEventSource(wl_display* display,
WaylandEventSource::~WaylandEventSource() = default;
+void WaylandEventSource::SetShutdownCb(base::OnceCallback<void()> shutdown_cb) {
+ event_watcher_->SetShutdownCb(std::move(shutdown_cb));
+}
+
bool WaylandEventSource::StartProcessingEvents() {
return event_watcher_->StartProcessingEvents();
}
@@ -98,17 +108,15 @@ void WaylandEventSource::OnKeyboardModifiersChanged(int modifiers) {
uint32_t WaylandEventSource::OnKeyboardKeyEvent(EventType type,
DomCode dom_code,
- DomKey dom_key,
- KeyboardCode key_code,
bool repeat,
base::TimeTicks timestamp) {
DCHECK(type == ET_KEY_PRESSED || type == ET_KEY_RELEASED);
if (!keyboard_)
return POST_DISPATCH_NONE;
- // try to decode key, if not yet.
- if (dom_key == DomKey::NONE &&
- !keyboard_->Decode(dom_code, keyboard_modifiers_, &dom_key, &key_code)) {
+ DomKey dom_key;
+ KeyboardCode key_code;
+ if (!keyboard_->Decode(dom_code, keyboard_modifiers_, &dom_key, &key_code)) {
LOG(ERROR) << "Failed to decode key event.";
return POST_DISPATCH_NONE;
}
@@ -200,6 +208,51 @@ void WaylandEventSource::OnPointerAxisEvent(const gfx::Vector2d& offset) {
MouseWheelEvent event(offset, pointer_location_, pointer_location_,
EventTimeForNow(), flags, 0);
DispatchEvent(&event);
+ current_pointer_frame_.dx += offset.x();
+ current_pointer_frame_.dy += offset.y();
+}
+
+void WaylandEventSource::OnPointerFrameEvent() {
+ base::TimeTicks now = EventTimeForNow();
+ current_pointer_frame_.dt = now - last_pointer_frame_time_;
+ last_pointer_frame_time_ = now;
+
+ // Dispatch Fling event if pointer.axis_stop is notified and the recent
+ // pointer.axis events meets the criteria to start fling scroll.
+ if (current_pointer_frame_.dx == 0 && current_pointer_frame_.dy == 0 &&
+ current_pointer_frame_.is_axis_stop) {
+ gfx::Vector2dF initial_velocity = ComputeFlingVelocity();
+ float vx = initial_velocity.x();
+ float vy = initial_velocity.y();
+ ScrollEvent event(
+ vx == 0 && vy == 0 ? ET_SCROLL_FLING_CANCEL : ET_SCROLL_FLING_START,
+ pointer_location_, pointer_location_, now,
+ pointer_flags_ | keyboard_modifiers_, vx, vy, vx, vy,
+ kGestureScrollFingerCount);
+ DispatchEvent(&event);
+ recent_pointer_frames_.clear();
+ } else {
+ if (recent_pointer_frames_.size() + 1 > kRecentPointerFrameMaxSize)
+ recent_pointer_frames_.pop_back();
+ recent_pointer_frames_.push_front(current_pointer_frame_);
+ }
+ // Reset |current_pointer_frame_|.
+ current_pointer_frame_.dx = 0;
+ current_pointer_frame_.dy = 0;
+ current_pointer_frame_.is_axis_stop = false;
+}
+
+void WaylandEventSource::OnPointerAxisSourceEvent(uint32_t axis_source) {
+ current_pointer_frame_.axis_source = axis_source;
+}
+
+void WaylandEventSource::OnPointerAxisStopEvent(uint32_t axis) {
+ if (axis == WL_POINTER_AXIS_VERTICAL_SCROLL) {
+ current_pointer_frame_.dy = 0;
+ } else if (axis == WL_POINTER_AXIS_HORIZONTAL_SCROLL) {
+ current_pointer_frame_.dx = 0;
+ }
+ current_pointer_frame_.is_axis_stop = true;
}
void WaylandEventSource::OnTouchCreated(WaylandTouch* touch) {
@@ -359,4 +412,28 @@ bool WaylandEventSource::ShouldUnsetTouchFocus(WaylandWindow* win,
return result == touch_points_.end();
}
+gfx::Vector2dF WaylandEventSource::ComputeFlingVelocity() {
+ // Return average velocity in the last 200ms.
+ // TODO(fukino): Make the formula similar to libgestures's
+ // RegressScrollVelocity(). crbug.com/1129263.
+ base::TimeDelta dt;
+ float dx = 0.0f;
+ float dy = 0.0f;
+ for (auto& frame : recent_pointer_frames_) {
+ if (frame.axis_source != WL_POINTER_AXIS_SOURCE_FINGER)
+ break;
+ if (frame.dx == 0 && frame.dy == 0)
+ break;
+ if (dt + frame.dt > base::TimeDelta::FromMilliseconds(200))
+ break;
+
+ dx += frame.dx;
+ dy += frame.dy;
+ dt += frame.dt;
+ }
+ float dt_inv = 1.0f / dt.InSecondsF();
+ return dt.is_zero() ? gfx::Vector2dF()
+ : gfx::Vector2dF(dx * dt_inv, dy * dt_inv);
+}
+
} // namespace ui
diff --git a/chromium/ui/ozone/platform/wayland/host/wayland_event_source.h b/chromium/ui/ozone/platform/wayland/host/wayland_event_source.h
index e646df4fd4d..dfda62810e5 100644
--- a/chromium/ui/ozone/platform/wayland/host/wayland_event_source.h
+++ b/chromium/ui/ozone/platform/wayland/host/wayland_event_source.h
@@ -5,6 +5,7 @@
#ifndef UI_OZONE_PLATFORM_WAYLAND_HOST_WAYLAND_EVENT_SOURCE_H_
#define UI_OZONE_PLATFORM_WAYLAND_HOST_WAYLAND_EVENT_SOURCE_H_
+#include <deque>
#include <memory>
#include "base/containers/flat_map.h"
@@ -12,8 +13,6 @@
#include "base/time/time.h"
#include "ui/events/event_constants.h"
#include "ui/events/keycodes/dom/dom_code.h"
-#include "ui/events/keycodes/dom/dom_key.h"
-#include "ui/events/keycodes/keyboard_codes.h"
#include "ui/events/platform/platform_event_source.h"
#include "ui/events/pointer_details.h"
#include "ui/events/types/event_type.h"
@@ -61,6 +60,10 @@ class WaylandEventSource : public PlatformEventSource,
int keyboard_modifiers() const { return keyboard_modifiers_; }
+ // Sets a callback that that shutdowns the browser in case of unrecoverable
+ // error. Called by WaylandEventWatcher.
+ void SetShutdownCb(base::OnceCallback<void()> shutdown_cb);
+
// Starts polling for events from the wayland connection file descriptor.
// This method assumes connection is already estabilished and input objects
// are already bound and properly initialized.
@@ -84,8 +87,6 @@ class WaylandEventSource : public PlatformEventSource,
void OnKeyboardModifiersChanged(int modifiers) override;
uint32_t OnKeyboardKeyEvent(EventType type,
DomCode dom_code,
- DomKey dom_key,
- KeyboardCode key_code,
bool repeat,
base::TimeTicks timestamp) override;
@@ -99,6 +100,9 @@ class WaylandEventSource : public PlatformEventSource,
WaylandWindow* window = nullptr) override;
void OnPointerMotionEvent(const gfx::PointF& location) override;
void OnPointerAxisEvent(const gfx::Vector2d& offset) override;
+ void OnPointerFrameEvent() override;
+ void OnPointerAxisSourceEvent(uint32_t axis_source) override;
+ void OnPointerAxisStopEvent(uint32_t axis) override;
// WaylandTouch::Delegate
void OnTouchCreated(WaylandTouch* touch) override;
@@ -114,6 +118,13 @@ class WaylandEventSource : public PlatformEventSource,
void OnTouchCancelEvent() override;
private:
+ struct PointerFrame {
+ uint32_t axis_source = WL_POINTER_AXIS_SOURCE_WHEEL;
+ float dx = 0.0f;
+ float dy = 0.0f;
+ base::TimeDelta dt;
+ bool is_axis_stop = false;
+ };
struct TouchPoint;
// PlatformEventSource:
@@ -130,6 +141,9 @@ class WaylandEventSource : public PlatformEventSource,
base::Optional<PointerId> id = base::nullopt);
bool ShouldUnsetTouchFocus(WaylandWindow* window, PointerId id);
+ // Computes initial velocity of fling scroll based on recent frames.
+ gfx::Vector2dF ComputeFlingVelocity();
+
WaylandWindowManager* const window_manager_;
// Input device objects. Owned by WaylandConnection.
@@ -149,6 +163,16 @@ class WaylandEventSource : public PlatformEventSource,
// Last known pointer location.
gfx::PointF pointer_location_;
+ // Current frame
+ PointerFrame current_pointer_frame_;
+
+ // Time of the last pointer frame event.
+ base::TimeTicks last_pointer_frame_time_;
+
+ // Recent pointer frames to compute fling scroll.
+ // Front is newer, and back is older.
+ std::deque<PointerFrame> recent_pointer_frames_;
+
// The window the pointer is over.
WaylandWindow* window_with_pointer_focus_ = nullptr;
diff --git a/chromium/ui/ozone/platform/wayland/host/wayland_event_source_unittest.cc b/chromium/ui/ozone/platform/wayland/host/wayland_event_source_unittest.cc
index 34bf114fa03..fe57fe1421e 100644
--- a/chromium/ui/ozone/platform/wayland/host/wayland_event_source_unittest.cc
+++ b/chromium/ui/ozone/platform/wayland/host/wayland_event_source_unittest.cc
@@ -3,8 +3,6 @@
// found in the LICENSE file.
#include <linux/input.h>
-#include <wayland-client-protocol.h>
-#include <wayland-server-core.h>
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/ozone/platform/wayland/host/wayland_event_source.h"
diff --git a/chromium/ui/ozone/platform/wayland/host/wayland_event_watcher.cc b/chromium/ui/ozone/platform/wayland/host/wayland_event_watcher.cc
index 52f5eb0e870..9fd65bd9afa 100644
--- a/chromium/ui/ozone/platform/wayland/host/wayland_event_watcher.cc
+++ b/chromium/ui/ozone/platform/wayland/host/wayland_event_watcher.cc
@@ -4,13 +4,11 @@
#include "ui/ozone/platform/wayland/host/wayland_event_watcher.h"
-#include <wayland-client-core.h>
-#include <wayland-client-protocol.h>
-
#include "base/bind.h"
#include "base/check.h"
#include "base/task/current_thread.h"
#include "ui/events/event.h"
+#include "ui/ozone/platform/wayland/common/wayland.h"
namespace ui {
@@ -23,6 +21,12 @@ WaylandEventWatcher::~WaylandEventWatcher() {
StopProcessingEvents();
}
+void WaylandEventWatcher::SetShutdownCb(
+ base::OnceCallback<void()> shutdown_cb) {
+ DCHECK(shutdown_cb_.is_null());
+ shutdown_cb_ = std::move(shutdown_cb);
+}
+
bool WaylandEventWatcher::StartProcessingEvents() {
DCHECK(display_);
if (watching_)
@@ -44,6 +48,11 @@ bool WaylandEventWatcher::StopProcessingEvents() {
}
void WaylandEventWatcher::OnFileCanReadWithoutBlocking(int fd) {
+ if (!CheckForErrors()) {
+ StopProcessingEvents();
+ return;
+ }
+
if (prepared_) {
prepared_ = false;
if (wl_display_read_events(display_) == -1)
@@ -104,4 +113,15 @@ void WaylandEventWatcher::MaybePrepareReadQueue() {
wl_display_dispatch_pending(display_);
}
+bool WaylandEventWatcher::CheckForErrors() {
+ int err = wl_display_get_error(display_);
+ if (err == EPROTO) {
+ // This can be null in tests.
+ if (!shutdown_cb_.is_null())
+ std::move(shutdown_cb_).Run();
+ return false;
+ }
+ return true;
+}
+
} // namespace ui
diff --git a/chromium/ui/ozone/platform/wayland/host/wayland_event_watcher.h b/chromium/ui/ozone/platform/wayland/host/wayland_event_watcher.h
index 9960855cd5a..6a13ea92f4b 100644
--- a/chromium/ui/ozone/platform/wayland/host/wayland_event_watcher.h
+++ b/chromium/ui/ozone/platform/wayland/host/wayland_event_watcher.h
@@ -5,6 +5,7 @@
#ifndef UI_OZONE_PLATFORM_WAYLAND_HOST_WAYLAND_EVENT_WATCHER_H_
#define UI_OZONE_PLATFORM_WAYLAND_HOST_WAYLAND_EVENT_WATCHER_H_
+#include "base/callback.h"
#include "base/message_loop/message_pump_for_ui.h"
#include "base/message_loop/watchable_io_message_pump_posix.h"
@@ -23,6 +24,10 @@ class WaylandEventWatcher : public base::MessagePumpForUI::FdWatcher {
WaylandEventWatcher& operator=(const WaylandEventWatcher&) = delete;
~WaylandEventWatcher() override;
+ // Sets a callback that that shutdowns the browser in case of unrecoverable
+ // error. Can only be set once.
+ void SetShutdownCb(base::OnceCallback<void()> shutdown_cb);
+
// Starts polling for events from the wayland connection file descriptor.
// This method assumes connection is already estabilished and input objects
// are already bound and properly initialized.
@@ -39,12 +44,18 @@ class WaylandEventWatcher : public base::MessagePumpForUI::FdWatcher {
bool StartWatchingFd(base::WatchableIOMessagePumpPosix::Mode mode);
void MaybePrepareReadQueue();
+ // Checks if |display_| has any error set. If so, |shutdown_cb_| is executed
+ // and false is returned.
+ bool CheckForErrors();
+
base::MessagePumpForUI::FdWatchController controller_;
wl_display* const display_; // Owned by WaylandConnection.
bool watching_ = false;
bool prepared_ = false;
+
+ base::OnceCallback<void()> shutdown_cb_;
};
} // namespace ui
diff --git a/chromium/ui/ozone/platform/wayland/host/wayland_input_method_context.cc b/chromium/ui/ozone/platform/wayland/host/wayland_input_method_context.cc
index d03e64f34a7..8669a18a8b5 100644
--- a/chromium/ui/ozone/platform/wayland/host/wayland_input_method_context.cc
+++ b/chromium/ui/ozone/platform/wayland/host/wayland_input_method_context.cc
@@ -15,10 +15,7 @@
#include "ui/events/event.h"
#include "ui/events/keycodes/dom/dom_code.h"
#include "ui/events/keycodes/dom/keycode_converter.h"
-#include "ui/events/keycodes/keyboard_code_conversion.h"
-#include "ui/events/keycodes/keyboard_code_conversion_xkb.h"
-#include "ui/events/ozone/layout/keyboard_layout_engine.h"
-#include "ui/events/ozone/layout/keyboard_layout_engine_manager.h"
+#include "ui/events/ozone/evdev/keyboard_util_evdev.h"
#include "ui/events/types/event_type.h"
#include "ui/gfx/range/range.h"
#include "ui/ozone/platform/wayland/host/wayland_connection.h"
@@ -27,12 +24,6 @@
namespace ui {
-namespace {
-
-constexpr int kXkbKeycodeOffset = 8;
-
-} // namespace
-
WaylandInputMethodContext::WaylandInputMethodContext(
WaylandConnection* connection,
WaylandKeyboard::Delegate* key_delegate,
@@ -160,18 +151,16 @@ void WaylandInputMethodContext::OnDeleteSurroundingText(int32_t index,
void WaylandInputMethodContext::OnKeysym(uint32_t key,
uint32_t state,
uint32_t modifiers) {
- DomKey dom_key = NonPrintableXKeySymToDomKey(key);
- KeyboardCode key_code = NonPrintableDomKeyToKeyboardCode(dom_key);
DomCode dom_code =
- KeycodeConverter::NativeKeycodeToDomCode(key_code + kXkbKeycodeOffset);
+ KeycodeConverter::NativeKeycodeToDomCode(EvdevCodeToNativeCode(key));
if (dom_code == ui::DomCode::NONE)
return;
// TODO(crbug.com/1079353): Handle modifiers.
EventType type =
state == WL_KEYBOARD_KEY_STATE_PRESSED ? ET_KEY_PRESSED : ET_KEY_RELEASED;
- key_delegate_->OnKeyboardKeyEvent(type, dom_code, dom_key, key_code,
- /*repeat=*/false, EventTimeForNow());
+ key_delegate_->OnKeyboardKeyEvent(type, dom_code, /*repeat=*/false,
+ EventTimeForNow());
}
} // namespace ui
diff --git a/chromium/ui/ozone/platform/wayland/host/wayland_keyboard.cc b/chromium/ui/ozone/platform/wayland/host/wayland_keyboard.cc
index a4c905b7895..dee622c3f50 100644
--- a/chromium/ui/ozone/platform/wayland/host/wayland_keyboard.cc
+++ b/chromium/ui/ozone/platform/wayland/host/wayland_keyboard.cc
@@ -130,9 +130,9 @@ void WaylandKeyboard::Key(void* data,
WaylandKeyboard* keyboard = static_cast<WaylandKeyboard*>(data);
DCHECK(keyboard);
- keyboard->connection_->set_serial(serial);
-
bool down = state == WL_KEYBOARD_KEY_STATE_PRESSED;
+ if (down)
+ keyboard->connection_->set_serial(serial, ET_KEY_PRESSED);
int device_id = keyboard->device_id();
keyboard->auto_repeat_handler_.UpdateKeyRepeat(
@@ -201,8 +201,7 @@ void WaylandKeyboard::DispatchKey(uint32_t key,
// Pass empty DomKey and KeyboardCode here so the delegate can pre-process
// and decode it when needed.
uint32_t result = delegate_->OnKeyboardKeyEvent(
- down ? ET_KEY_PRESSED : ET_KEY_RELEASED, dom_code, DomKey::NONE,
- KeyboardCode::VKEY_UNKNOWN, repeat, timestamp);
+ down ? ET_KEY_PRESSED : ET_KEY_RELEASED, dom_code, repeat, timestamp);
if (extended_keyboard_v1_) {
bool handled = result & POST_DISPATCH_STOP_PROPAGATION;
diff --git a/chromium/ui/ozone/platform/wayland/host/wayland_keyboard.h b/chromium/ui/ozone/platform/wayland/host/wayland_keyboard.h
index e449da0be85..abedf290672 100644
--- a/chromium/ui/ozone/platform/wayland/host/wayland_keyboard.h
+++ b/chromium/ui/ozone/platform/wayland/host/wayland_keyboard.h
@@ -6,7 +6,6 @@
#define UI_OZONE_PLATFORM_WAYLAND_HOST_WAYLAND_KEYBOARD_H_
#include <keyboard-extension-unstable-v1-client-protocol.h>
-#include <wayland-client.h>
#include "base/time/time.h"
#include "ui/base/buildflags.h"
@@ -117,8 +116,6 @@ class WaylandKeyboard::Delegate {
// dispatched.
virtual uint32_t OnKeyboardKeyEvent(EventType type,
DomCode dom_code,
- DomKey dom_key,
- KeyboardCode key_code,
bool repeat,
base::TimeTicks timestamp) = 0;
diff --git a/chromium/ui/ozone/platform/wayland/host/wayland_output.cc b/chromium/ui/ozone/platform/wayland/host/wayland_output.cc
index 7a4067df952..92d0f5be651 100644
--- a/chromium/ui/ozone/platform/wayland/host/wayland_output.cc
+++ b/chromium/ui/ozone/platform/wayland/host/wayland_output.cc
@@ -4,8 +4,6 @@
#include "ui/ozone/platform/wayland/host/wayland_output.h"
-#include <wayland-client.h>
-
#include "ui/gfx/color_space.h"
#include "ui/ozone/platform/wayland/host/wayland_connection.h"
diff --git a/chromium/ui/ozone/platform/wayland/host/wayland_pointer.cc b/chromium/ui/ozone/platform/wayland/host/wayland_pointer.cc
index 13cb8c0a3fc..b4fb4f09c5c 100644
--- a/chromium/ui/ozone/platform/wayland/host/wayland_pointer.cc
+++ b/chromium/ui/ozone/platform/wayland/host/wayland_pointer.cc
@@ -5,8 +5,6 @@
#include "ui/ozone/platform/wayland/host/wayland_pointer.h"
#include <linux/input.h>
-#include <wayland-client-protocol.h>
-#include <wayland-client.h>
#include "ui/events/event.h"
#include "ui/events/types/event_type.h"
@@ -23,9 +21,11 @@ WaylandPointer::WaylandPointer(wl_pointer* pointer,
Delegate* delegate)
: obj_(pointer), connection_(connection), delegate_(delegate) {
static const wl_pointer_listener listener = {
- &WaylandPointer::Enter, &WaylandPointer::Leave, &WaylandPointer::Motion,
- &WaylandPointer::Button, &WaylandPointer::Axis,
- };
+ &WaylandPointer::Enter, &WaylandPointer::Leave,
+ &WaylandPointer::Motion, &WaylandPointer::Button,
+ &WaylandPointer::Axis, &WaylandPointer::Frame,
+ &WaylandPointer::AxisSource, &WaylandPointer::AxisStop,
+ &WaylandPointer::AxisDiscrete};
DCHECK(delegate_);
delegate_->OnPointerCreated(this);
@@ -105,14 +105,10 @@ void WaylandPointer::Button(void* data,
return;
}
- // Set serial only on button presses. Popup windows can be created on
- // button/touch presses, and, thus, require the serial of the last serial when
- // the button was pressed. Otherwise, Wayland server dismisses the popup
- // requests (see the protocol definition).
- if (state == WL_POINTER_BUTTON_STATE_PRESSED)
- pointer->connection_->set_serial(serial);
EventType type = state == WL_POINTER_BUTTON_STATE_PRESSED ? ET_MOUSE_PRESSED
: ET_MOUSE_RELEASED;
+ if (type == ET_MOUSE_PRESSED)
+ pointer->connection_->set_serial(serial, type);
pointer->delegate_->OnPointerButtonEvent(type, changed_button);
}
@@ -142,4 +138,37 @@ void WaylandPointer::Axis(void* data,
pointer->delegate_->OnPointerAxisEvent(offset);
}
+// static
+void WaylandPointer::Frame(void* data, wl_pointer* obj) {
+ WaylandPointer* pointer = static_cast<WaylandPointer*>(data);
+ pointer->delegate_->OnPointerFrameEvent();
+}
+
+// static
+void WaylandPointer::AxisSource(void* data,
+ wl_pointer* obj,
+ uint32_t axis_source) {
+ WaylandPointer* pointer = static_cast<WaylandPointer*>(data);
+ pointer->delegate_->OnPointerAxisSourceEvent(axis_source);
+}
+
+// static
+void WaylandPointer::AxisStop(void* data,
+ wl_pointer* obj,
+ uint32_t time,
+ uint32_t axis) {
+ WaylandPointer* pointer = static_cast<WaylandPointer*>(data);
+ pointer->delegate_->OnPointerAxisStopEvent(axis);
+}
+
+// static
+void WaylandPointer::AxisDiscrete(void* data,
+ wl_pointer* obj,
+ uint32_t axis,
+ int32_t discrete) {
+ // TODO(fukino): Use this events for better handling of mouse wheel events.
+ // crbug.com/1129259.
+ NOTIMPLEMENTED_LOG_ONCE();
+}
+
} // namespace ui
diff --git a/chromium/ui/ozone/platform/wayland/host/wayland_pointer.h b/chromium/ui/ozone/platform/wayland/host/wayland_pointer.h
index c5cf9f7dccc..2ebb8419769 100644
--- a/chromium/ui/ozone/platform/wayland/host/wayland_pointer.h
+++ b/chromium/ui/ozone/platform/wayland/host/wayland_pointer.h
@@ -60,6 +60,16 @@ class WaylandPointer {
uint32_t time,
uint32_t axis,
wl_fixed_t value);
+ static void Frame(void* data, wl_pointer* obj);
+ static void AxisSource(void* data, wl_pointer* obj, uint32_t axis_source);
+ static void AxisStop(void* data,
+ wl_pointer* obj,
+ uint32_t time,
+ uint32_t axis);
+ static void AxisDiscrete(void* data,
+ wl_pointer* obj,
+ uint32_t axis,
+ int32_t discrete);
wl::Object<wl_pointer> obj_;
WaylandConnection* const connection_;
@@ -79,6 +89,9 @@ class WaylandPointer::Delegate {
WaylandWindow* window = nullptr) = 0;
virtual void OnPointerMotionEvent(const gfx::PointF& location) = 0;
virtual void OnPointerAxisEvent(const gfx::Vector2d& offset) = 0;
+ virtual void OnPointerFrameEvent() = 0;
+ virtual void OnPointerAxisSourceEvent(uint32_t axis_source) = 0;
+ virtual void OnPointerAxisStopEvent(uint32_t axis) = 0;
};
} // namespace ui
diff --git a/chromium/ui/ozone/platform/wayland/host/wayland_pointer_unittest.cc b/chromium/ui/ozone/platform/wayland/host/wayland_pointer_unittest.cc
index 41dfb730784..8e6fd03896b 100644
--- a/chromium/ui/ozone/platform/wayland/host/wayland_pointer_unittest.cc
+++ b/chromium/ui/ozone/platform/wayland/host/wayland_pointer_unittest.cc
@@ -4,6 +4,8 @@
#include <linux/input.h>
#include <wayland-server.h>
+
+#include <cmath>
#include <memory>
#include "testing/gmock/include/gmock/gmock.h"
@@ -49,6 +51,35 @@ class WaylandPointerTest : public WaylandTest {
DISALLOW_COPY_AND_ASSIGN(WaylandPointerTest);
};
+void SendAxisEvents(struct wl_resource* resource,
+ uint32_t time_ms,
+ uint32_t axis_source,
+ uint32_t axis,
+ int offset) {
+ wl_pointer_send_axis_source(resource, axis_source);
+ wl_pointer_send_axis(resource, time_ms, axis, wl_fixed_from_int(offset));
+ wl_pointer_send_frame(resource);
+}
+
+void SendDiagonalAxisEvents(struct wl_resource* resource,
+ uint32_t time_ms,
+ uint32_t axis_source,
+ int offset_x,
+ int offset_y) {
+ wl_pointer_send_axis_source(resource, axis_source);
+ wl_pointer_send_axis(resource, time_ms, WL_POINTER_AXIS_VERTICAL_SCROLL,
+ wl_fixed_from_int(offset_y));
+ wl_pointer_send_axis(resource, time_ms, WL_POINTER_AXIS_HORIZONTAL_SCROLL,
+ wl_fixed_from_int(offset_x));
+ wl_pointer_send_frame(resource);
+}
+
+void SendAxisStopEvents(struct wl_resource* resource, uint32_t time) {
+ wl_pointer_send_axis_stop(resource, time, WL_POINTER_AXIS_VERTICAL_SCROLL);
+ wl_pointer_send_axis_stop(resource, time, WL_POINTER_AXIS_HORIZONTAL_SCROLL);
+ wl_pointer_send_frame(resource);
+}
+
ACTION_P(CloneEvent, ptr) {
*ptr = Event::Clone(*arg0);
}
@@ -262,6 +293,216 @@ TEST_P(WaylandPointerTest, SetBitmapOnPointerFocus) {
Mock::VerifyAndClearExpectations(pointer_);
}
+TEST_P(WaylandPointerTest, FlingVertical) {
+ uint32_t serial = 0;
+ uint32_t time = 1001;
+ wl_pointer_send_enter(pointer_->resource(), ++serial, surface_->resource(),
+ wl_fixed_from_int(50), wl_fixed_from_int(75));
+ wl_pointer_send_button(pointer_->resource(), ++serial, ++time, BTN_RIGHT,
+ WL_POINTER_BUTTON_STATE_PRESSED);
+
+ Sync();
+
+ std::unique_ptr<Event> event1, event2, event3;
+ EXPECT_CALL(delegate_, DispatchEvent(_))
+ .Times(3)
+ .WillOnce(CloneEvent(&event1))
+ .WillOnce(CloneEvent(&event2))
+ .WillOnce(CloneEvent(&event3));
+ // 1st axis event.
+ SendAxisEvents(pointer_->resource(), ++time, WL_POINTER_AXIS_SOURCE_FINGER,
+ WL_POINTER_AXIS_VERTICAL_SCROLL, 10);
+ // 2nd axis event.
+ SendAxisEvents(pointer_->resource(), ++time, WL_POINTER_AXIS_SOURCE_FINGER,
+ WL_POINTER_AXIS_VERTICAL_SCROLL, 10);
+ // axis_stop event which should trigger fling scroll.
+ SendAxisStopEvents(pointer_->resource(), ++time);
+
+ Sync();
+
+ // Usual axis events should follow before the fling event.
+ ASSERT_TRUE(event1);
+ ASSERT_TRUE(event1->IsMouseWheelEvent());
+ ASSERT_TRUE(event2);
+ ASSERT_TRUE(event2->IsMouseWheelEvent());
+
+ // The third dispatched event should be FLING_START.
+ ASSERT_TRUE(event3);
+ ASSERT_TRUE(event3->IsScrollEvent());
+ auto* scroll_event = event3->AsScrollEvent();
+ EXPECT_EQ(ET_SCROLL_FLING_START, scroll_event->type());
+ EXPECT_EQ(gfx::PointF(50, 75), scroll_event->location_f());
+ EXPECT_EQ(0.0f, scroll_event->x_offset());
+ // Initial vertical velocity depends on the implementation outside of
+ // WaylandPointer, but it should be negative value based on the direction of
+ // recent two axis events.
+ EXPECT_GT(0.0f, scroll_event->y_offset());
+ EXPECT_EQ(0.0f, scroll_event->x_offset_ordinal());
+ EXPECT_GT(0.0f, scroll_event->y_offset_ordinal());
+}
+
+TEST_P(WaylandPointerTest, FlingHorizontal) {
+ uint32_t serial = 0;
+ uint32_t time = 1001;
+ wl_pointer_send_enter(pointer_->resource(), ++serial, surface_->resource(),
+ wl_fixed_from_int(50), wl_fixed_from_int(75));
+ wl_pointer_send_button(pointer_->resource(), ++serial, ++time, BTN_RIGHT,
+ WL_POINTER_BUTTON_STATE_PRESSED);
+
+ Sync();
+
+ std::unique_ptr<Event> event1, event2, event3;
+ EXPECT_CALL(delegate_, DispatchEvent(_))
+ .Times(3)
+ .WillOnce(CloneEvent(&event1))
+ .WillOnce(CloneEvent(&event2))
+ .WillOnce(CloneEvent(&event3));
+ // 1st axis event.
+ SendAxisEvents(pointer_->resource(), ++time, WL_POINTER_AXIS_SOURCE_FINGER,
+ WL_POINTER_AXIS_HORIZONTAL_SCROLL, 10);
+ // 2nd axis event.
+ SendAxisEvents(pointer_->resource(), ++time, WL_POINTER_AXIS_SOURCE_FINGER,
+ WL_POINTER_AXIS_HORIZONTAL_SCROLL, 10);
+ // axis_stop event which should trigger fling scroll.
+ SendAxisStopEvents(pointer_->resource(), ++time);
+
+ Sync();
+
+ // Usual axis events should follow before the fling event.
+ ASSERT_TRUE(event1);
+ ASSERT_TRUE(event1->IsMouseWheelEvent());
+ ASSERT_TRUE(event2);
+ ASSERT_TRUE(event2->IsMouseWheelEvent());
+
+ // The third dispatched event should be FLING_START.
+ ASSERT_TRUE(event3);
+ ASSERT_TRUE(event3->IsScrollEvent());
+ auto* scroll_event = event3->AsScrollEvent();
+ EXPECT_EQ(ET_SCROLL_FLING_START, scroll_event->type());
+ EXPECT_EQ(gfx::PointF(50, 75), scroll_event->location_f());
+ // Initial horizontal velocity depends on the implementation outside of
+ // WaylandPointer, but it should be positive value based on the direction of
+ // recent two axis events.
+ EXPECT_LT(0.0f, scroll_event->x_offset());
+ EXPECT_EQ(0.0f, scroll_event->y_offset());
+ EXPECT_LT(0.0f, scroll_event->x_offset_ordinal());
+ EXPECT_EQ(0.0f, scroll_event->y_offset_ordinal());
+}
+
+TEST_P(WaylandPointerTest, FlingCancel) {
+ uint32_t serial = 0;
+ uint32_t time = 1001;
+ wl_pointer_send_enter(pointer_->resource(), ++serial, surface_->resource(),
+ wl_fixed_from_int(50), wl_fixed_from_int(75));
+ wl_pointer_send_button(pointer_->resource(), ++serial, ++time, BTN_RIGHT,
+ WL_POINTER_BUTTON_STATE_PRESSED);
+
+ Sync();
+
+ std::unique_ptr<Event> event1, event2, event3, event4;
+ EXPECT_CALL(delegate_, DispatchEvent(_))
+ .Times(4)
+ .WillOnce(CloneEvent(&event1))
+ .WillOnce(CloneEvent(&event2))
+ .WillOnce(CloneEvent(&event3))
+ .WillOnce(CloneEvent(&event4));
+ // 1st axis event.
+ SendAxisEvents(pointer_->resource(), ++time, WL_POINTER_AXIS_SOURCE_FINGER,
+ WL_POINTER_AXIS_VERTICAL_SCROLL, 10);
+ // 2nd axis event.
+ SendAxisEvents(pointer_->resource(), ++time, WL_POINTER_AXIS_SOURCE_FINGER,
+ WL_POINTER_AXIS_VERTICAL_SCROLL, 10);
+ // 3rd axis event, whose offset is 0, should make the following axis_stop
+ // trigger fling cancel.
+ SendAxisEvents(pointer_->resource(), ++time, WL_POINTER_AXIS_SOURCE_FINGER,
+ WL_POINTER_AXIS_VERTICAL_SCROLL, 0);
+ // axis_stop event which should trigger fling cancel.
+ SendAxisStopEvents(pointer_->resource(), ++time);
+
+ Sync();
+
+ // Usual axis events should follow before the fling event.
+ ASSERT_TRUE(event1);
+ ASSERT_TRUE(event1->IsMouseWheelEvent());
+ ASSERT_TRUE(event2);
+ ASSERT_TRUE(event2->IsMouseWheelEvent());
+
+ // The 3rd axis event's offset is 0.
+ ASSERT_TRUE(event3);
+ ASSERT_TRUE(event3->IsMouseWheelEvent());
+ auto* mouse_wheel_event = event3->AsMouseWheelEvent();
+ EXPECT_EQ(gfx::Vector2d(0, 0), mouse_wheel_event->offset());
+
+ // The 4th event should be FLING_CANCEL.
+ ASSERT_TRUE(event4);
+ ASSERT_TRUE(event4->IsScrollEvent());
+ auto* scroll_event = event4->AsScrollEvent();
+ EXPECT_EQ(ET_SCROLL_FLING_CANCEL, scroll_event->type());
+ EXPECT_EQ(gfx::PointF(50, 75), scroll_event->location_f());
+ EXPECT_EQ(0.0f, scroll_event->x_offset());
+ EXPECT_EQ(0.0f, scroll_event->y_offset());
+ EXPECT_EQ(0.0f, scroll_event->x_offset_ordinal());
+ EXPECT_EQ(0.0f, scroll_event->y_offset_ordinal());
+}
+
+TEST_P(WaylandPointerTest, FlingDiagonal) {
+ uint32_t serial = 0;
+ uint32_t time = 1001;
+ wl_pointer_send_enter(pointer_->resource(), ++serial, surface_->resource(),
+ wl_fixed_from_int(50), wl_fixed_from_int(75));
+ wl_pointer_send_button(pointer_->resource(), ++serial, ++time, BTN_RIGHT,
+ WL_POINTER_BUTTON_STATE_PRESSED);
+
+ Sync();
+
+ std::unique_ptr<Event> event1, event2, event3, event4, event5;
+ EXPECT_CALL(delegate_, DispatchEvent(_))
+ .Times(5)
+ .WillOnce(CloneEvent(&event1))
+ .WillOnce(CloneEvent(&event2))
+ .WillOnce(CloneEvent(&event3))
+ .WillOnce(CloneEvent(&event4))
+ .WillOnce(CloneEvent(&event5));
+ // 1st axis event notifies scrolls both in vertical and horizontal.
+ SendDiagonalAxisEvents(pointer_->resource(), ++time,
+ WL_POINTER_AXIS_SOURCE_FINGER, 20, 10);
+ // 2st axis event notifies scrolls both in vertical and horizontal.
+ SendDiagonalAxisEvents(pointer_->resource(), ++time,
+ WL_POINTER_AXIS_SOURCE_FINGER, 20, 10);
+ // axis_stop event which should trigger fling scroll.
+ SendAxisStopEvents(pointer_->resource(), ++time);
+
+ Sync();
+
+ // Usual axis events should follow before the fling event.
+ ASSERT_TRUE(event1);
+ ASSERT_TRUE(event1->IsMouseWheelEvent());
+ ASSERT_TRUE(event2);
+ ASSERT_TRUE(event2->IsMouseWheelEvent());
+ ASSERT_TRUE(event3);
+ ASSERT_TRUE(event3->IsMouseWheelEvent());
+ ASSERT_TRUE(event4);
+ ASSERT_TRUE(event4->IsMouseWheelEvent());
+
+ // The third dispatched event should be FLING_START.
+ ASSERT_TRUE(event5);
+ ASSERT_TRUE(event5->IsScrollEvent());
+ auto* scroll_event = event5->AsScrollEvent();
+ EXPECT_EQ(ET_SCROLL_FLING_START, scroll_event->type());
+ EXPECT_EQ(gfx::PointF(50, 75), scroll_event->location_f());
+ // Check the offset direction. It should non-zero in both directions.
+ EXPECT_LT(0.0f, scroll_event->x_offset());
+ EXPECT_GT(0.0f, scroll_event->y_offset());
+ EXPECT_LT(0.0f, scroll_event->x_offset_ordinal());
+ EXPECT_GT(0.0f, scroll_event->y_offset_ordinal());
+ // Horizontal offset should be larger than vertical one, given the scroll
+ // offset in each direction.
+ EXPECT_GT(std::abs(scroll_event->x_offset()),
+ std::abs(scroll_event->y_offset()));
+ EXPECT_GT(std::abs(scroll_event->x_offset_ordinal()),
+ std::abs(scroll_event->y_offset_ordinal()));
+}
+
INSTANTIATE_TEST_SUITE_P(XdgVersionStableTest,
WaylandPointerTest,
::testing::Values(kXdgShellStable));
diff --git a/chromium/ui/ozone/platform/wayland/host/wayland_popup.cc b/chromium/ui/ozone/platform/wayland/host/wayland_popup.cc
index f1f7c8d43e5..d4d60cb9d41 100644
--- a/chromium/ui/ozone/platform/wayland/host/wayland_popup.cc
+++ b/chromium/ui/ozone/platform/wayland/host/wayland_popup.cc
@@ -19,9 +19,6 @@ WaylandPopup::WaylandPopup(PlatformWindowDelegate* delegate,
WaylandPopup::~WaylandPopup() = default;
bool WaylandPopup::CreateShellPopup() {
- if (GetBounds().IsEmpty())
- return false;
-
DCHECK(parent_window() && !shell_popup_);
auto subsurface_bounds_dip =
@@ -131,15 +128,8 @@ void WaylandPopup::OnCloseRequest() {
}
bool WaylandPopup::OnInitialize(PlatformWindowInitProperties properties) {
- if (!wl::IsMenuType(type()))
- return false;
-
- set_parent_window(GetParentWindow(properties.parent_widget));
- if (!parent_window()) {
- LOG(ERROR) << "Failed to get a parent window for this popup";
- return false;
- }
- // If parent window is known in advanced, we may set the scale early.
+ DCHECK(wl::IsMenuType(type()));
+ DCHECK(parent_window());
root_surface()->SetBufferScale(parent_window()->buffer_scale(), false);
set_ui_scale(parent_window()->ui_scale());
return true;
diff --git a/chromium/ui/ozone/platform/wayland/host/wayland_screen.cc b/chromium/ui/ozone/platform/wayland/host/wayland_screen.cc
index fc4d4fac5ca..9beaf27f2a5 100644
--- a/chromium/ui/ozone/platform/wayland/host/wayland_screen.cc
+++ b/chromium/ui/ozone/platform/wayland/host/wayland_screen.cc
@@ -8,13 +8,18 @@
#include <vector>
#include "base/stl_util.h"
+#include "build/build_config.h"
+#include "build/chromeos_buildflags.h"
#include "ui/display/display.h"
#include "ui/display/display_finder.h"
#include "ui/display/display_list.h"
#include "ui/display/display_observer.h"
+#include "ui/gfx/buffer_types.h"
+#include "ui/gfx/display_color_spaces.h"
#include "ui/gfx/geometry/point.h"
#include "ui/gfx/geometry/rect.h"
#include "ui/gfx/native_widget_types.h"
+#include "ui/ozone/platform/wayland/host/wayland_buffer_manager_host.h"
#include "ui/ozone/platform/wayland/host/wayland_connection.h"
#include "ui/ozone/platform/wayland/host/wayland_cursor_position.h"
#include "ui/ozone/platform/wayland/host/wayland_window.h"
@@ -24,6 +29,45 @@ namespace ui {
WaylandScreen::WaylandScreen(WaylandConnection* connection)
: connection_(connection), weak_factory_(this) {
DCHECK(connection_);
+
+ // Chromium specifies either RGBA_8888 or BGRA_8888 as initial image format
+ // for alpha case and RGBX_8888 for no alpha case. Figure out
+ // which one is supported and use that. If RGBX_8888 is not supported, the
+ // format that |have_format_alpha| uses will be used by default (RGBA_8888 or
+ // BGRA_8888).
+ auto buffer_formats =
+ connection_->buffer_manager_host()->GetSupportedBufferFormats();
+ for (const auto& buffer_format : buffer_formats) {
+ auto format = buffer_format.first;
+
+ // TODO(crbug.com/1127822): Investigate a better fix for this.
+#if !BUILDFLAG(IS_LACROS)
+ // RGBA_8888 is the preferred format, except when running on ChromiumOS. See
+ // crbug.com/1127558.
+ if (format == gfx::BufferFormat::RGBA_8888)
+ image_format_alpha_ = gfx::BufferFormat::RGBA_8888;
+
+ // TODO(1128997): |image_format_no_alpha_| should use RGBX_8888 when it's
+ // available, but for some reason Chromium gets broken when it's used.
+ // Though, we can import RGBX_8888 dma buffer to EGLImage successfully.
+ // Enable that back when the issue is resolved.
+#endif // !BUILDFLAG(IS_LACROS)
+
+ if (!image_format_alpha_ && format == gfx::BufferFormat::BGRA_8888)
+ image_format_alpha_ = gfx::BufferFormat::BGRA_8888;
+
+ if (image_format_alpha_ && image_format_no_alpha_)
+ break;
+ }
+
+ // If no buffer formats are found (neither wl_drm nor zwp_linux_dmabuf are
+ // supported or the system has very limited set of supported buffer formats),
+ // RGBA_8888 is used by default. On Wayland, that seems to be the most
+ // supported.
+ if (!image_format_alpha_)
+ image_format_alpha_ = gfx::BufferFormat::RGBA_8888;
+ if (!image_format_no_alpha_)
+ image_format_no_alpha_ = image_format_alpha_;
}
WaylandScreen::~WaylandScreen() = default;
@@ -61,12 +105,17 @@ void WaylandScreen::AddOrUpdateDisplay(uint32_t output_id,
changed_display.set_bounds(new_bounds);
changed_display.set_work_area(new_bounds);
+ gfx::DisplayColorSpaces color_spaces;
+ color_spaces.SetOutputBufferFormats(image_format_no_alpha_.value(),
+ image_format_alpha_.value());
+ changed_display.set_color_spaces(color_spaces);
+
// There are 2 cases where |changed_display| must be set as primary:
// 1. When it is the first one being added to the |display_list_|. Or
- // 2. If it is nearest the origin than the previous primary or has the same
- // origin as it. When an user, for example, swaps two side-by-side displays,
- // at some point, as the notification come in, both will have the same
- // origin.
+ // 2. If it is nearest the origin than the previous primary or has the
+ // same origin as it. When an user, for example, swaps two side-by-side
+ // displays, at some point, as the notification come in, both will have
+ // the same origin.
auto type = display::DisplayList::Type::NOT_PRIMARY;
if (display_list_.displays().empty()) {
type = display::DisplayList::Type::PRIMARY;
@@ -109,14 +158,14 @@ display::Display WaylandScreen::GetDisplayForAcceleratedWidget(
const auto entered_outputs_ids = window->entered_outputs_ids();
// Although spec says a surface receives enter/leave surface events on
// create/move/resize actions, this might be called right after a window is
- // created, but it has not been configured by a Wayland compositor and it has
- // not received enter surface events yet. Another case is when a user switches
- // between displays in a single output mode - Wayland may not send enter
- // events immediately, which can result in empty container of entered ids
- // (check comments in WaylandWindow::RemoveEnteredOutputId). In this case,
- // it's also safe to return the primary display.
- // A child window will most probably enter the same display than its parent
- // so we return the parent's display if there is a parent.
+ // created, but it has not been configured by a Wayland compositor and it
+ // has not received enter surface events yet. Another case is when a user
+ // switches between displays in a single output mode - Wayland may not send
+ // enter events immediately, which can result in empty container of entered
+ // ids (check comments in WaylandWindow::RemoveEnteredOutputId). In this
+ // case, it's also safe to return the primary display. A child window will
+ // most probably enter the same display than its parent so we return the
+ // parent's display if there is a parent.
if (entered_outputs_ids.empty()) {
if (parent_window)
return GetDisplayForAcceleratedWidget(parent_window->GetWidget());
@@ -125,9 +174,9 @@ display::Display WaylandScreen::GetDisplayForAcceleratedWidget(
DCHECK(!display_list_.displays().empty());
- // A widget can be located on two or more displays. It would be better if the
- // most in DIP occupied display was returned, but it's impossible to do so in
- // Wayland. Thus, return the one that was used the earliest.
+ // A widget can be located on two or more displays. It would be better if
+ // the most in DIP occupied display was returned, but it's impossible to do
+ // so in Wayland. Thus, return the one that was used the earliest.
for (const auto& display : display_list_.displays()) {
if (display.id() == *entered_outputs_ids.begin())
return display;
@@ -140,13 +189,13 @@ display::Display WaylandScreen::GetDisplayForAcceleratedWidget(
gfx::Point WaylandScreen::GetCursorScreenPoint() const {
// Wayland does not provide either location of surfaces in global space
// coordinate system or location of a pointer. Instead, only locations of
- // mouse/touch events are known. Given that Chromium assumes top-level windows
- // are located at origin, always provide a cursor point in regards to
- // surfaces' location.
+ // mouse/touch events are known. Given that Chromium assumes top-level
+ // windows are located at origin, always provide a cursor point in regards
+ // to surfaces' location.
//
- // If a pointer is located in any of the existing wayland windows, return the
- // last known cursor position. Otherwise, return such a point, which is not
- // contained by any of the windows.
+ // If a pointer is located in any of the existing wayland windows, return
+ // the last known cursor position. Otherwise, return such a point, which is
+ // not contained by any of the windows.
auto* cursor_position = connection_->wayland_cursor_position();
if (connection_->wayland_window_manager()->GetCurrentFocusedWindow() &&
cursor_position)
diff --git a/chromium/ui/ozone/platform/wayland/host/wayland_screen.h b/chromium/ui/ozone/platform/wayland/host/wayland_screen.h
index 55993fc2a1a..a8dced4e2db 100644
--- a/chromium/ui/ozone/platform/wayland/host/wayland_screen.h
+++ b/chromium/ui/ozone/platform/wayland/host/wayland_screen.h
@@ -10,7 +10,9 @@
#include "base/memory/weak_ptr.h"
#include "base/observer_list.h"
+#include "base/optional.h"
#include "ui/display/display_list.h"
+#include "ui/gfx/buffer_types.h"
#include "ui/gfx/geometry/point.h"
#include "ui/ozone/public/platform_screen.h"
@@ -66,6 +68,9 @@ class WaylandScreen : public PlatformScreen {
base::ObserverList<display::DisplayObserver> observers_;
+ base::Optional<gfx::BufferFormat> image_format_alpha_;
+ base::Optional<gfx::BufferFormat> image_format_no_alpha_;
+
base::WeakPtrFactory<WaylandScreen> weak_factory_;
};
diff --git a/chromium/ui/ozone/platform/wayland/host/wayland_shm_buffer.h b/chromium/ui/ozone/platform/wayland/host/wayland_shm_buffer.h
index a33bf7d1549..1a1a958b093 100644
--- a/chromium/ui/ozone/platform/wayland/host/wayland_shm_buffer.h
+++ b/chromium/ui/ozone/platform/wayland/host/wayland_shm_buffer.h
@@ -5,8 +5,6 @@
#ifndef UI_OZONE_PLATFORM_WAYLAND_HOST_WAYLAND_SHM_BUFFER_H_
#define UI_OZONE_PLATFORM_WAYLAND_HOST_WAYLAND_SHM_BUFFER_H_
-#include <wayland-client.h>
-
#include <memory>
#include "base/macros.h"
diff --git a/chromium/ui/ozone/platform/wayland/host/wayland_subsurface.cc b/chromium/ui/ozone/platform/wayland/host/wayland_subsurface.cc
index 11d37ab75e1..9b27f61778d 100644
--- a/chromium/ui/ozone/platform/wayland/host/wayland_subsurface.cc
+++ b/chromium/ui/ozone/platform/wayland/host/wayland_subsurface.cc
@@ -4,7 +4,6 @@
#include "ui/ozone/platform/wayland/host/wayland_subsurface.h"
-#include <wayland-client.h>
#include <cstdint>
#include "ui/ozone/platform/wayland/common/wayland_util.h"
@@ -44,6 +43,7 @@ WaylandSubsurface::WaylandSubsurface(WaylandConnection* connection,
LOG(ERROR) << "Failed to create wl_surface";
return;
}
+ wayland_surface_.Initialize();
}
WaylandSubsurface::~WaylandSubsurface() = default;
@@ -70,11 +70,9 @@ bool WaylandSubsurface::IsVisible() const {
}
void WaylandSubsurface::UpdateOpaqueRegion() {
- gfx::Size region_size = enable_blend_ ? gfx::Size() : bounds_px_.size();
- wl::Object<wl_region> region(
- wl_compositor_create_region(connection_->compositor()));
- wl_region_add(region.get(), 0, 0, region_size.width(), region_size.height());
- wl_surface_set_opaque_region(surface(), region.get());
+ gfx::Rect region_px =
+ enable_blend_ ? gfx::Rect() : gfx::Rect(bounds_px_.size());
+ wayland_surface()->SetOpaqueRegion(region_px);
}
void WaylandSubsurface::SetBounds(const gfx::Rect& bounds) {
@@ -116,21 +114,22 @@ void WaylandSubsurface::CreateSubsurface() {
wl_compositor_create_region(connection_->compositor()));
wl_region_add(region.get(), 0, 0, 0, 0);
wl_surface_set_input_region(surface(), region.get());
+
+ connection_->buffer_manager_host()->SetSurfaceConfigured(wayland_surface());
}
void WaylandSubsurface::ConfigureAndShowSurface(
gfx::OverlayTransform transform,
+ const gfx::RectF& src_rect,
const gfx::Rect& bounds_rect,
bool enable_blend,
const WaylandSurface* reference_below,
const WaylandSurface* reference_above) {
+ wayland_surface()->SetBufferTransform(transform);
wayland_surface()->SetBufferScale(parent_->buffer_scale(), false);
- gfx::Rect bounds_px{
- bounds_rect.origin() + parent_->GetBounds().origin().OffsetFromOrigin(),
- bounds_rect.size()};
auto old_bounds = bounds_px_;
- SetBounds(bounds_px);
+ SetBounds(bounds_rect);
if (old_bounds != bounds_px_ || enable_blend_ != enable_blend) {
enable_blend_ = enable_blend;
@@ -145,6 +144,9 @@ void WaylandSubsurface::ConfigureAndShowSurface(
} else if (reference_above) {
wl_subsurface_place_below(subsurface_.get(), reference_above->surface());
}
+
+ wayland_surface()->SetViewportSource(src_rect);
+ wayland_surface()->SetViewportDestination(bounds_rect.size());
}
} // namespace ui
diff --git a/chromium/ui/ozone/platform/wayland/host/wayland_subsurface.h b/chromium/ui/ozone/platform/wayland/host/wayland_subsurface.h
index 50098b21715..26a4c589bee 100644
--- a/chromium/ui/ozone/platform/wayland/host/wayland_subsurface.h
+++ b/chromium/ui/ozone/platform/wayland/host/wayland_subsurface.h
@@ -34,7 +34,23 @@ class WaylandSubsurface {
// Sets up wl_surface and wl_subsurface. Allows an overlay to be shown
// correctly once a wl_buffer is attached.
+ // |transform|: specifies the wl_surface buffer_transform.
+ // |src_rect|: specifies the displayable content (wp_viewport.src) of
+ // upcoming attached buffers.
+ // |bounds_rect|: The contents of the source rectangle are scaled to the
+ // destination size (wp_viewport.dst).
+ // |enable_blend|: whether the wl_surface will be transluscent.
+ // |reference_below| & |reference_above|: this subsurface is taken from the
+ // subsurface stack and inserted back to be immediately below/above the
+ // reference subsurface.
+ //
+ // The coordinate transformations from buffer pixel coordinates up to the
+ // surface-local coordinates happen in the following order:
+ // 1. buffer_transform
+ // 2. buffer_scale
+ // 3. crop and scale of viewport
void ConfigureAndShowSurface(gfx::OverlayTransform transform,
+ const gfx::RectF& src_rect,
const gfx::Rect& bounds_rect,
bool enable_blend,
const WaylandSurface* reference_below,
diff --git a/chromium/ui/ozone/platform/wayland/host/wayland_surface.cc b/chromium/ui/ozone/platform/wayland/host/wayland_surface.cc
index 0300a7bcacc..3cfccaa7138 100644
--- a/chromium/ui/ozone/platform/wayland/host/wayland_surface.cc
+++ b/chromium/ui/ozone/platform/wayland/host/wayland_surface.cc
@@ -4,6 +4,11 @@
#include "ui/ozone/platform/wayland/host/wayland_surface.h"
+#include <viewporter-client-protocol.h>
+
+#include "ui/gfx/geometry/rect_conversions.h"
+#include "ui/gfx/native_widget_types.h"
+#include "ui/ozone/platform/wayland/common/wayland_util.h"
#include "ui/ozone/platform/wayland/host/wayland_connection.h"
#include "ui/ozone/platform/wayland/host/wayland_window.h"
@@ -15,12 +20,7 @@ WaylandSurface::WaylandSurface(WaylandConnection* connection,
root_window_(root_window),
surface_(connection->CreateSurface()) {}
-WaylandSurface::~WaylandSurface() {
- if (surface_) {
- wl_surface_add_listener(surface_.get(), nullptr, nullptr);
- wl_surface_set_user_data(surface_.get(), nullptr);
- }
-}
+WaylandSurface::~WaylandSurface() = default;
uint32_t WaylandSurface::GetSurfaceId() const {
if (!surface_)
@@ -29,24 +29,36 @@ uint32_t WaylandSurface::GetSurfaceId() const {
}
gfx::AcceleratedWidget WaylandSurface::GetWidget() const {
- return root_window_->GetWidget();
+ return root_window_ ? root_window_->GetWidget() : gfx::kNullAcceleratedWidget;
}
bool WaylandSurface::Initialize() {
if (!surface_)
return false;
- wl_surface_set_user_data(surface_.get(), this);
-
static struct wl_surface_listener surface_listener = {
&WaylandSurface::Enter,
&WaylandSurface::Leave,
};
wl_surface_add_listener(surface_.get(), &surface_listener, this);
+ if (connection_->viewporter()) {
+ viewport_.reset(
+ wp_viewporter_get_viewport(connection_->viewporter(), surface()));
+ if (!viewport_) {
+ LOG(ERROR) << "Failed to create wp_viewport";
+ return false;
+ }
+ }
+
return true;
}
+void WaylandSurface::UnsetRootWindow() {
+ DCHECK(surface_);
+ root_window_ = nullptr;
+}
+
void WaylandSurface::AttachBuffer(wl_buffer* buffer) {
// The logic in DamageBuffer currently relies on attachment coordinates of
// (0, 0). If this changes, then the calculation in DamageBuffer will also
@@ -55,7 +67,39 @@ void WaylandSurface::AttachBuffer(wl_buffer* buffer) {
connection_->ScheduleFlush();
}
-void WaylandSurface::Damage(const gfx::Rect& pending_damage_region) {
+void WaylandSurface::UpdateBufferDamageRegion(
+ const gfx::Rect& pending_damage_region,
+ const gfx::Size& buffer_size) {
+ // Buffer-local coordinates are in pixels, surface coordinates are in DIP.
+ // The coordinate transformations from buffer pixel coordinates up to
+ // the surface-local coordinates happen in the following order:
+ // 1. buffer_transform (wl_surface.set_buffer_transform)
+ // 2. buffer_scale (wl_surface.set_buffer_scale)
+ // 3. crop and scale (wp_viewport.set*)
+ // Apply buffer_transform (wl_surface.set_buffer_transform).
+ gfx::Size bounds = wl::ApplyWaylandTransform(
+ buffer_size, wl::ToWaylandTransform(buffer_transform_));
+ // Apply buffer_scale (wl_surface.set_buffer_scale).
+ bounds = gfx::ScaleToCeiledSize(bounds, 1.f / buffer_scale_);
+ // Apply crop (wp_viewport.set_source).
+ gfx::Rect viewport_src = gfx::Rect(bounds);
+ if (!crop_rect_.IsEmpty()) {
+ viewport_src = gfx::ToEnclosedRect(
+ gfx::ScaleRect(crop_rect_, bounds.width(), bounds.height()));
+ wp_viewport_set_source(viewport(), wl_fixed_from_int(viewport_src.x()),
+ wl_fixed_from_int(viewport_src.y()),
+ wl_fixed_from_int(viewport_src.width()),
+ wl_fixed_from_int(viewport_src.height()));
+ }
+ // Apply viewport scale (wp_viewport.set_destination).
+ gfx::Size viewport_dst = bounds;
+ if (!display_size_px_.IsEmpty()) {
+ viewport_dst =
+ gfx::ScaleToCeiledSize(display_size_px_, 1.f / buffer_scale_);
+ wp_viewport_set_destination(viewport(), viewport_dst.width(),
+ viewport_dst.height());
+ }
+
if (connection_->compositor_version() >=
WL_SURFACE_DAMAGE_BUFFER_SINCE_VERSION) {
// wl_surface_damage_buffer relies on compositor API version 4. See
@@ -66,20 +110,29 @@ void WaylandSurface::Damage(const gfx::Rect& pending_damage_region) {
surface_.get(), pending_damage_region.x(), pending_damage_region.y(),
pending_damage_region.width(), pending_damage_region.height());
} else {
- // The calculation for damage region relies on two assumptions:
- // 1) The buffer is always attached at surface location (0, 0)
- // 2) The API wl_surface::set_buffer_transform is not used.
- // It's possible to write logic that accounts for both cases above, but
- // it's currently unnecessary.
- //
- // Note: The damage region may not be an integer multiple of scale. To
- // keep the implementation simple, the x() and y() coordinates round down,
- // and the width() and height() calculations always add an extra pixel.
- wl_surface_damage(surface_.get(), pending_damage_region.x() / buffer_scale_,
- pending_damage_region.y() / buffer_scale_,
- pending_damage_region.width() / buffer_scale_ + 1,
- pending_damage_region.height() / buffer_scale_ + 1);
+ // Calculate the damage region in surface coordinates.
+ // The calculation for damage region relies on the assumption: The buffer is
+ // always attached at surface location (0, 0).
+ // It's possible to write logic that accounts for attaching buffer at other
+ // locations, but it's currently unnecessary.
+
+ // Apply buffer_transform (wl_surface.set_buffer_transform).
+ gfx::Rect damage =
+ wl::ApplyWaylandTransform(pending_damage_region, buffer_size,
+ wl::ToWaylandTransform(buffer_transform_));
+ // Apply buffer_scale (wl_surface.set_buffer_scale).
+ damage = gfx::ScaleToEnclosingRect(damage, 1.f / buffer_scale_);
+ // Adjust coordinates to |viewport_src| (wp_viewport.set_source).
+ damage = wl::TranslateBoundsToParentCoordinates(damage, viewport_src);
+ // Apply viewport scale (wp_viewport.set_destination).
+ damage = gfx::ScaleToEnclosingRect(
+ damage, static_cast<float>(viewport_dst.width()) / viewport_src.width(),
+ static_cast<float>(viewport_dst.height()) / viewport_src.height());
+
+ wl_surface_damage(surface_.get(), damage.x(), damage.y(), damage.width(),
+ damage.height());
}
+
connection_->ScheduleFlush();
}
@@ -88,6 +141,16 @@ void WaylandSurface::Commit() {
connection_->ScheduleFlush();
}
+void WaylandSurface::SetBufferTransform(gfx::OverlayTransform transform) {
+ DCHECK(transform != gfx::OVERLAY_TRANSFORM_INVALID);
+ if (buffer_transform_ == transform)
+ return;
+
+ buffer_transform_ = transform;
+ wl_output_transform wl_transform = wl::ToWaylandTransform(buffer_transform_);
+ wl_surface_set_buffer_transform(surface_.get(), wl_transform);
+}
+
void WaylandSurface::SetBufferScale(int32_t new_scale, bool update_bounds) {
DCHECK_GT(new_scale, 0);
@@ -99,21 +162,46 @@ void WaylandSurface::SetBufferScale(int32_t new_scale, bool update_bounds) {
connection_->ScheduleFlush();
}
-void WaylandSurface::SetBounds(const gfx::Rect& bounds_px) {
+void WaylandSurface::SetOpaqueRegion(const gfx::Rect& region_px) {
// It's important to set opaque region for opaque windows (provides
// optimization hint for the Wayland compositor).
- if (!root_window_->IsOpaqueWindow())
+ if (!root_window_ || !root_window_->IsOpaqueWindow())
return;
wl::Object<wl_region> region(
wl_compositor_create_region(connection_->compositor()));
- wl_region_add(region.get(), 0, 0, bounds_px.width(), bounds_px.height());
+ gfx::Rect region_dip =
+ gfx::ScaleToEnclosingRect(region_px, 1.f / buffer_scale_);
+ wl_region_add(region.get(), region_dip.x(), region_dip.y(),
+ region_dip.width(), region_dip.height());
wl_surface_set_opaque_region(surface_.get(), region.get());
connection_->ScheduleFlush();
}
+void WaylandSurface::SetViewportSource(const gfx::RectF& src_rect) {
+ if (src_rect == crop_rect_) {
+ return;
+ } else if (src_rect.IsEmpty() || src_rect == gfx::RectF{0.f, 0.f, 1.f, 1.f}) {
+ wp_viewport_set_source(viewport(), wl_fixed_from_int(-1),
+ wl_fixed_from_int(-1), wl_fixed_from_int(-1),
+ wl_fixed_from_int(-1));
+ return;
+ }
+
+ crop_rect_ = src_rect;
+}
+
+void WaylandSurface::SetViewportDestination(const gfx::Size& dest_size_px) {
+ if (dest_size_px == display_size_px_) {
+ return;
+ } else if (dest_size_px.IsEmpty()) {
+ wp_viewport_set_destination(viewport(), -1, -1);
+ }
+ display_size_px_ = dest_size_px;
+}
+
wl::Object<wl_subsurface> WaylandSurface::CreateSubsurface(
WaylandSurface* parent) {
DCHECK(parent);
@@ -128,15 +216,16 @@ wl::Object<wl_subsurface> WaylandSurface::CreateSubsurface(
void WaylandSurface::Enter(void* data,
struct wl_surface* wl_surface,
struct wl_output* output) {
- static_cast<WaylandSurface*>(data)->root_window_->AddEnteredOutputId(output);
+ if (auto* root_window = static_cast<WaylandSurface*>(data)->root_window_)
+ root_window->AddEnteredOutputId(output);
}
// static
void WaylandSurface::Leave(void* data,
struct wl_surface* wl_surface,
struct wl_output* output) {
- static_cast<WaylandSurface*>(data)->root_window_->RemoveEnteredOutputId(
- output);
+ if (auto* root_window = static_cast<WaylandSurface*>(data)->root_window_)
+ root_window->RemoveEnteredOutputId(output);
}
} // namespace ui
diff --git a/chromium/ui/ozone/platform/wayland/host/wayland_surface.h b/chromium/ui/ozone/platform/wayland/host/wayland_surface.h
index 37755f9ac3d..7747c6e9250 100644
--- a/chromium/ui/ozone/platform/wayland/host/wayland_surface.h
+++ b/chromium/ui/ozone/platform/wayland/host/wayland_surface.h
@@ -8,7 +8,9 @@
#include <cstdint>
#include "ui/gfx/geometry/rect.h"
+#include "ui/gfx/geometry/rect_f.h"
#include "ui/gfx/native_widget_types.h"
+#include "ui/gfx/overlay_transform.h"
#include "ui/ozone/platform/wayland/common/wayland_object.h"
namespace ui {
@@ -26,6 +28,7 @@ class WaylandSurface {
WaylandWindow* root_window() const { return root_window_; }
wl_surface* surface() const { return surface_.get(); }
+ wp_viewport* viewport() const { return viewport_.get(); }
int32_t buffer_scale() const { return buffer_scale_; }
void set_buffer_scale(int32_t scale) { buffer_scale_ = scale; }
@@ -39,22 +42,43 @@ class WaylandSurface {
// This may return false if a wl_surface could not be created, for example.
bool Initialize();
+ // Unsets |root_window_|. This is intended to be used in special cases, where
+ // the underlying wl_surface must be kept alive with no root window associated
+ // (e.g: window/tab dragging sessions).
+ void UnsetRootWindow();
+
// Attaches the given wl_buffer to the underlying wl_surface at (0, 0).
void AttachBuffer(wl_buffer* buffer);
- // Damages the surface according to |pending_damage_region|, which should be
- // in surface coordinates (dp).
- void Damage(const gfx::Rect& pending_damage_region);
+ // Describes where the surface needs to be repainted according to
+ // |buffer_pending_damage_region|, which should be in buffer coordinates (px).
+ void UpdateBufferDamageRegion(const gfx::Rect& buffer_pending_damage_region,
+ const gfx::Size& buffer_size);
// Commits the underlying wl_surface.
void Commit();
+ // Sets an optional transformation for how the Wayland compositor interprets
+ // the contents of the buffer attached to this surface.
+ void SetBufferTransform(gfx::OverlayTransform transform);
+
// Sets the buffer scale for this surface.
void SetBufferScale(int32_t scale, bool update_bounds);
- // Sets the bounds on this surface. This is used for determining the opaque
- // region.
- void SetBounds(const gfx::Rect& bounds_px);
+ // Sets the region that is opaque on this surface in physical pixels. This is
+ // expected to be called whenever the region that the surface span changes or
+ // the opacity changes.
+ void SetOpaqueRegion(const gfx::Rect& bounds_px);
+
+ // Set the source rectangle of the associated wl_surface.
+ // See:
+ // https://cgit.freedesktop.org/wayland/wayland-protocols/tree/stable/viewporter/viewporter.xml
+ // If |src_rect| is empty, the source rectangle is unset.
+ void SetViewportSource(const gfx::RectF& src_rect);
+
+ // Set the destination size of the associated wl_surface according to
+ // |dest_size_px|, which should be in physical pixels.
+ void SetViewportDestination(const gfx::Size& dest_size_px);
// Creates a wl_subsurface relating this surface and a parent surface,
// |parent|. Callers take ownership of the wl_subsurface.
@@ -62,13 +86,30 @@ class WaylandSurface {
private:
WaylandConnection* const connection_;
- WaylandWindow* const root_window_;
+ WaylandWindow* root_window_ = nullptr;
wl::Object<wl_surface> surface_;
+ wl::Object<wp_viewport> viewport_;
+
+ // Transformation for how the compositor interprets the contents of the
+ // buffer.
+ gfx::OverlayTransform buffer_transform_ = gfx::OVERLAY_TRANSFORM_NONE;
- // Wayland's scale factor for the output that this window currently belongs
+ // Wayland's scale factor for the output that this surface currently belongs
// to.
int32_t buffer_scale_ = 1;
+ // Following fields are used to help determine the damage_region in
+ // surface-local coordinates if wl_surface_damage_buffer() is not available.
+ // Normalized bounds of the buffer to be displayed in |display_size_px_|.
+ // If empty, no cropping is applied.
+ gfx::RectF crop_rect_ = gfx::RectF();
+
+ // Current size of the destination of the viewport in physical pixels. Wayland
+ // compositor will scale the (cropped) buffer content to fit the
+ // |display_size_px_|.
+ // If empty, no scaling is applied.
+ gfx::Size display_size_px_ = gfx::Size();
+
// wl_surface_listener
static void Enter(void* data,
struct wl_surface* wl_surface,
diff --git a/chromium/ui/ozone/platform/wayland/host/wayland_toplevel_window.cc b/chromium/ui/ozone/platform/wayland/host/wayland_toplevel_window.cc
index 86bab661269..0af423cb801 100644
--- a/chromium/ui/ozone/platform/wayland/host/wayland_toplevel_window.cc
+++ b/chromium/ui/ozone/platform/wayland/host/wayland_toplevel_window.cc
@@ -4,9 +4,11 @@
#include "ui/ozone/platform/wayland/host/wayland_toplevel_window.h"
+#include <aura-shell-client-protocol.h>
+
#include "base/run_loop.h"
#include "base/unguessable_token.h"
-#include "build/lacros_buildflags.h"
+#include "build/chromeos_buildflags.h"
#include "ui/base/dragdrop/drag_drop_types.h"
#include "ui/base/dragdrop/os_exchange_data.h"
#include "ui/base/hit_test.h"
@@ -22,6 +24,12 @@
#include "ui/platform_window/extensions/wayland_extension.h"
#include "ui/platform_window/wm/wm_drop_handler.h"
+#if BUILDFLAG(IS_LACROS)
+// TODO(jamescook): The nogncheck is to work around false-positive failures on
+// the code search bot. Remove after https://crrev.com/c/2432137 lands.
+#include "chromeos/crosapi/cpp/crosapi_constants.h" // nogncheck
+#endif
+
namespace ui {
WaylandToplevelWindow::WaylandToplevelWindow(PlatformWindowDelegate* delegate,
@@ -336,15 +344,21 @@ bool WaylandToplevelWindow::OnInitialize(
PlatformWindowInitProperties properties) {
#if BUILDFLAG(IS_LACROS)
auto token = base::UnguessableToken::Create();
- window_unique_id_ = "org.chromium.lacros." + token.ToString();
+ window_unique_id_ =
+ std::string(crosapi::kLacrosAppIdPrefix) + token.ToString();
#else
wm_class_class_ = properties.wm_class_class;
#endif
SetWaylandExtension(this, static_cast<WaylandExtension*>(this));
SetWmMoveLoopHandler(this, static_cast<WmMoveLoopHandler*>(this));
+ InitializeAuraShell();
return true;
}
+bool WaylandToplevelWindow::IsActive() const {
+ return is_active_;
+}
+
bool WaylandToplevelWindow::RunMoveLoop(const gfx::Vector2d& drag_offset) {
DCHECK(connection()->window_drag_controller());
return connection()->window_drag_controller()->Drag(this, drag_offset);
@@ -416,4 +430,14 @@ void WaylandToplevelWindow::SetOrResetRestoredBounds() {
}
}
+void WaylandToplevelWindow::InitializeAuraShell() {
+ if (connection()->aura_shell()) {
+ DCHECK(!aura_surface_);
+ aura_surface_.reset(zaura_shell_get_aura_surface(
+ connection()->aura_shell(), root_surface()->surface()));
+ zaura_surface_set_fullscreen_mode(aura_surface_.get(),
+ ZAURA_SURFACE_FULLSCREEN_MODE_IMMERSIVE);
+ }
+}
+
} // namespace ui
diff --git a/chromium/ui/ozone/platform/wayland/host/wayland_toplevel_window.h b/chromium/ui/ozone/platform/wayland/host/wayland_toplevel_window.h
index 4c0a6a7d013..7f091d3f48f 100644
--- a/chromium/ui/ozone/platform/wayland/host/wayland_toplevel_window.h
+++ b/chromium/ui/ozone/platform/wayland/host/wayland_toplevel_window.h
@@ -5,7 +5,7 @@
#ifndef UI_OZONE_PLATFORM_WAYLAND_HOST_WAYLAND_TOPLEVEL_WINDOW_H_
#define UI_OZONE_PLATFORM_WAYLAND_HOST_WAYLAND_TOPLEVEL_WINDOW_H_
-#include "build/lacros_buildflags.h"
+#include "build/chromeos_buildflags.h"
#include "ui/gfx/geometry/vector2d.h"
#include "ui/ozone/platform/wayland/host/wayland_window.h"
#include "ui/platform_window/extensions/wayland_extension.h"
@@ -76,6 +76,7 @@ class WaylandToplevelWindow : public WaylandWindow,
void OnDragLeave() override;
void OnDragSessionClose(uint32_t dnd_action) override;
bool OnInitialize(PlatformWindowInitProperties properties) override;
+ bool IsActive() const override;
// WmMoveLoopHandler:
bool RunMoveLoop(const gfx::Vector2d& drag_offset) override;
@@ -97,6 +98,9 @@ class WaylandToplevelWindow : public WaylandWindow,
void SetOrResetRestoredBounds();
+ // Initializes the aura-shell EXO extension, if available.
+ void InitializeAuraShell();
+
// Wrappers around shell surface.
std::unique_ptr<ShellSurfaceWrapper> shell_surface_;
@@ -142,6 +146,8 @@ class WaylandToplevelWindow : public WaylandWindow,
base::OnceClosure drag_loop_quit_closure_;
+ wl::Object<zaura_surface> aura_surface_;
+
base::WeakPtrFactory<WaylandToplevelWindow> weak_ptr_factory_{this};
};
diff --git a/chromium/ui/ozone/platform/wayland/host/wayland_touch.cc b/chromium/ui/ozone/platform/wayland/host/wayland_touch.cc
index 9298a43d67d..6bb9802ed9a 100644
--- a/chromium/ui/ozone/platform/wayland/host/wayland_touch.cc
+++ b/chromium/ui/ozone/platform/wayland/host/wayland_touch.cc
@@ -4,9 +4,8 @@
#include "ui/ozone/platform/wayland/host/wayland_touch.h"
-#include <wayland-client.h>
-
#include "base/time/time.h"
+#include "ui/events/types/event_type.h"
#include "ui/gfx/geometry/point_f.h"
#include "ui/ozone/platform/wayland/common/wayland_util.h"
#include "ui/ozone/platform/wayland/host/wayland_connection.h"
@@ -46,7 +45,7 @@ void WaylandTouch::Down(void* data,
WaylandTouch* touch = static_cast<WaylandTouch*>(data);
DCHECK(touch);
- touch->connection_->set_serial(serial);
+ touch->connection_->set_serial(serial, ET_TOUCH_PRESSED);
WaylandWindow* window = wl::RootWindowFromWlSurface(surface);
gfx::PointF location(wl_fixed_to_double(x), wl_fixed_to_double(y));
@@ -63,6 +62,8 @@ void WaylandTouch::Up(void* data,
WaylandTouch* touch = static_cast<WaylandTouch*>(data);
DCHECK(touch);
+ touch->connection_->set_serial(serial, ET_TOUCH_RELEASED);
+
base::TimeTicks timestamp =
base::TimeTicks() + base::TimeDelta::FromMilliseconds(time);
touch->delegate_->OnTouchReleaseEvent(timestamp, id);
diff --git a/chromium/ui/ozone/platform/wayland/host/wayland_window.cc b/chromium/ui/ozone/platform/wayland/host/wayland_window.cc
index 2e436462afb..f7e6ae5d8dd 100644
--- a/chromium/ui/ozone/platform/wayland/host/wayland_window.cc
+++ b/chromium/ui/ozone/platform/wayland/host/wayland_window.cc
@@ -4,8 +4,6 @@
#include "ui/ozone/platform/wayland/host/wayland_window.h"
-#include <wayland-client.h>
-
#include <algorithm>
#include <memory>
@@ -136,7 +134,7 @@ void WaylandWindow::SetBounds(const gfx::Rect& bounds_px) {
return;
bounds_px_ = bounds_px;
- root_surface_->SetBounds(bounds_px);
+ root_surface_->SetOpaqueRegion(bounds_px);
delegate_->OnBoundsChanged(bounds_px_);
}
@@ -255,6 +253,8 @@ bool WaylandWindow::CanDispatchEvent(const PlatformEvent& event) {
return has_keyboard_focus_;
if (event->IsTouchEvent())
return has_touch_focus_;
+ if (event->IsScrollEvent())
+ return has_pointer_focus_;
return false;
}
@@ -358,33 +358,11 @@ bool WaylandWindow::Initialize(PlatformWindowInitProperties properties) {
// Will do nothing for menus because they have got their scale above.
UpdateBufferScale(false);
- root_surface_->SetBounds(bounds_px_);
+ root_surface_->SetOpaqueRegion(bounds_px_);
return true;
}
-WaylandWindow* WaylandWindow::GetParentWindow(
- gfx::AcceleratedWidget parent_widget) {
- auto* parent_window =
- connection_->wayland_window_manager()->GetWindow(parent_widget);
-
- // If propagated parent has already had a child, it means that |this| is a
- // submenu of a 3-dot menu. In aura, the parent of a 3-dot menu and its
- // submenu is the main native widget, which is the main window. In contrast,
- // Wayland requires a menu window to be a parent of a submenu window. Thus,
- // check if the suggested parent has a child. If yes, take its child as a
- // parent of |this|.
- // Another case is a notifcation window or a drop down window, which do not
- // have a parent in aura. In this case, take the current focused window as a
- // parent.
-
- if (!parent_window)
- parent_window =
- connection_->wayland_window_manager()->GetCurrentFocusedWindow();
-
- return parent_window ? parent_window->GetTopMostChildWindow() : nullptr;
-}
-
WaylandWindow* WaylandWindow::GetRootParentWindow() {
return parent_window_ ? parent_window_->GetRootParentWindow() : this;
}
@@ -469,6 +447,11 @@ bool WaylandWindow::IsOpaqueWindow() const {
return opacity_ == ui::PlatformWindowOpacity::kOpaqueWindow;
}
+bool WaylandWindow::IsActive() const {
+ // Please read the comment where the IsActive method is declared.
+ return false;
+}
+
uint32_t WaylandWindow::DispatchEventToDelegate(
const PlatformEvent& native_event) {
auto* event = static_cast<Event*>(native_event);
@@ -484,6 +467,7 @@ uint32_t WaylandWindow::DispatchEventToDelegate(
std::unique_ptr<WaylandSurface> WaylandWindow::TakeWaylandSurface() {
DCHECK(shutting_down_);
DCHECK(root_surface_);
+ root_surface_->UnsetRootWindow();
return std::move(root_surface_);
}
@@ -540,8 +524,9 @@ bool WaylandWindow::CommitOverlays(
ozone::mojom::WaylandOverlayConfig::New();
auto split = std::lower_bound(overlays.begin(), overlays.end(), value,
OverlayStackOrderCompare);
- CHECK((*split)->z_order >= 0);
- size_t num_primary_planes = (*split)->z_order == 0 ? 1 : 0;
+ CHECK(split == overlays.end() || (*split)->z_order >= 0);
+ size_t num_primary_planes =
+ (split != overlays.end() && (*split)->z_order == 0) ? 1 : 0;
size_t above = (overlays.end() - split) - num_primary_planes;
size_t below = split - overlays.begin();
@@ -567,11 +552,12 @@ bool WaylandWindow::CommitOverlays(
reference_above = (*std::next(iter))->wayland_surface();
}
(*iter)->ConfigureAndShowSurface(
- (*overlay_iter)->transform, (*overlay_iter)->bounds_rect,
- (*overlay_iter)->enable_blend, nullptr, reference_above);
+ (*overlay_iter)->transform, (*overlay_iter)->crop_rect,
+ (*overlay_iter)->bounds_rect, (*overlay_iter)->enable_blend,
+ nullptr, reference_above);
connection_->buffer_manager_host()->CommitBufferInternal(
- (*iter)->wayland_surface(), (*overlay_iter)->buffer_id,
- gfx::Rect());
+ (*iter)->wayland_surface(), (*overlay_iter)->buffer_id, gfx::Rect(),
+ /*wait_for_frame_callback=*/false);
} else {
// If there're more subsurfaces requested that we don't need at the
// moment, hide them.
@@ -595,11 +581,12 @@ bool WaylandWindow::CommitOverlays(
reference_below = (*std::prev(iter))->wayland_surface();
}
(*iter)->ConfigureAndShowSurface(
- (*overlay_iter)->transform, (*overlay_iter)->bounds_rect,
- (*overlay_iter)->enable_blend, reference_below, nullptr);
+ (*overlay_iter)->transform, (*overlay_iter)->crop_rect,
+ (*overlay_iter)->bounds_rect, (*overlay_iter)->enable_blend,
+ reference_below, nullptr);
connection_->buffer_manager_host()->CommitBufferInternal(
- (*iter)->wayland_surface(), (*overlay_iter)->buffer_id,
- gfx::Rect());
+ (*iter)->wayland_surface(), (*overlay_iter)->buffer_id, gfx::Rect(),
+ /*wait_for_frame_callback=*/false);
} else {
// If there're more subsurfaces requested that we don't need at the
// moment, hide them.
@@ -609,16 +596,16 @@ bool WaylandWindow::CommitOverlays(
}
if (num_primary_planes) {
- // TODO: forward fence.
connection_->buffer_manager_host()->CommitBufferInternal(
- root_surface(), (*split)->buffer_id, (*split)->damage_region);
+ root_surface(), (*split)->buffer_id, (*split)->damage_region,
+ /*wait_for_frame_callback=*/true);
} else {
- // Subsurfaces are set to desync, above operations will only take effects
+ // Subsurfaces are set to sync, above operations will only take effects
// when root_surface is committed.
- root_surface()->Commit();
+ connection_->buffer_manager_host()->CommitWithoutBufferInternal(
+ root_surface(), /*wait_for_frame_callback=*/true);
}
- // commit all;
return true;
}
diff --git a/chromium/ui/ozone/platform/wayland/host/wayland_window.h b/chromium/ui/ozone/platform/wayland/host/wayland_window.h
index cd9f1e9fb35..c341ddb148a 100644
--- a/chromium/ui/ozone/platform/wayland/host/wayland_window.h
+++ b/chromium/ui/ozone/platform/wayland/host/wayland_window.h
@@ -183,6 +183,11 @@ class WaylandWindow : public PlatformWindow, public PlatformEventDispatcher {
// Returns true iff this window is opaque.
bool IsOpaqueWindow() const;
+ // Says if the current window is set as active by the Wayland server. This
+ // only applies to toplevel surfaces (surfaces such as popups, subsurfaces do
+ // not support that).
+ virtual bool IsActive() const;
+
protected:
WaylandWindow(PlatformWindowDelegate* delegate,
WaylandConnection* connection);
@@ -193,9 +198,6 @@ class WaylandWindow : public PlatformWindow, public PlatformEventDispatcher {
// Sets bounds in dip.
void SetBoundsDip(const gfx::Rect& bounds_dip);
- // Gets a parent window for this window.
- WaylandWindow* GetParentWindow(gfx::AcceleratedWidget parent_widget);
-
void set_ui_scale(int32_t ui_scale) { ui_scale_ = ui_scale; }
private:
diff --git a/chromium/ui/ozone/platform/wayland/host/wayland_window_drag_controller.cc b/chromium/ui/ozone/platform/wayland/host/wayland_window_drag_controller.cc
index 64ffd8b4845..548359854c5 100644
--- a/chromium/ui/ozone/platform/wayland/host/wayland_window_drag_controller.cc
+++ b/chromium/ui/ozone/platform/wayland/host/wayland_window_drag_controller.cc
@@ -155,6 +155,7 @@ void WaylandWindowDragController::OnDragEnter(WaylandWindow* window,
// Forward focus change event to the input delegate, so other components, such
// as WaylandScreen, are able to properly retrieve focus related info during
// window dragging sesstions.
+ pointer_location_ = location;
pointer_delegate_->OnPointerFocusChanged(window, location);
VLOG(1) << "OnEnter. widget=" << window->GetWidget();
@@ -179,6 +180,7 @@ void WaylandWindowDragController::OnDragMotion(const gfx::PointF& location) {
VLOG(2) << "OnMotion. location=" << location.ToString();
// Forward cursor location update info to the input handling delegate.
+ pointer_location_ = location;
pointer_delegate_->OnPointerMotionEvent(location);
}
@@ -207,12 +209,15 @@ void WaylandWindowDragController::OnDragLeave() {
// As Wayland clients are only aware of surface-local coordinates and there is
// no implicit grab during DND sessions, a fake motion event with negative
- // coordinates must be used here to make it possible for higher level UI
- // components to detect when a window should be detached. E.g: On Chrome,
- // dragging a tab all the way up to the top edge of the window won't work
- // without this fake motion event upon wl_data_device::leave events.
+ // y coordinate is used here to allow higher level UI components to detect
+ // when a window should be detached. E.g: On Chrome, dragging a tab all the
+ // way up to the top edge of the window won't work without this fake motion
+ // event upon wl_data_device::leave events. This is a workaround and should
+ // ideally be reworked in the future, at higher level layers such that they
+ // properly handle platforms that do not support global screen coordinates,
+ // like Wayland.
if (state_ == State::kAttached)
- pointer_delegate_->OnPointerMotionEvent({-1, -1});
+ pointer_delegate_->OnPointerMotionEvent({pointer_location_.x(), -1});
}
void WaylandWindowDragController::OnDragDrop() {
diff --git a/chromium/ui/ozone/platform/wayland/host/wayland_window_drag_controller.h b/chromium/ui/ozone/platform/wayland/host/wayland_window_drag_controller.h
index fa3ed531119..fcbfae4ad36 100644
--- a/chromium/ui/ozone/platform/wayland/host/wayland_window_drag_controller.h
+++ b/chromium/ui/ozone/platform/wayland/host/wayland_window_drag_controller.h
@@ -113,6 +113,9 @@ class WaylandWindowDragController : public WaylandDataDevice::DragDelegate,
State state_ = State::kIdle;
gfx::Vector2d drag_offset_;
+ // The last known pointer location in DIP.
+ gfx::PointF pointer_location_;
+
std::unique_ptr<WaylandDataSource> data_source_;
std::unique_ptr<WaylandDataOffer> data_offer_;
diff --git a/chromium/ui/ozone/platform/wayland/host/wayland_window_drag_controller_unittest.cc b/chromium/ui/ozone/platform/wayland/host/wayland_window_drag_controller_unittest.cc
index 4f24aadffb4..9e6b6e29013 100644
--- a/chromium/ui/ozone/platform/wayland/host/wayland_window_drag_controller_unittest.cc
+++ b/chromium/ui/ozone/platform/wayland/host/wayland_window_drag_controller_unittest.cc
@@ -548,12 +548,16 @@ TEST_P(WaylandWindowDragControllerTest, DragExitAttached) {
Sync();
EXPECT_EQ(State::kAttached, drag_controller()->state());
- // Emulate a wl_data_device::leave and make sure a motion event is dispatched
- // in response.
+ // Emulate a [motion => leave] event sequence and make sure the correct
+ // ui::Events are dispatched in response.
+ SendDndMotion({50, 50});
+ EXPECT_CALL(delegate_, DispatchEvent(_)).Times(1);
+ Sync();
+
SendDndLeave();
EXPECT_CALL(delegate_, DispatchEvent(_)).WillOnce([&](Event* event) {
EXPECT_EQ(ET_MOUSE_DRAGGED, event->type());
- EXPECT_EQ(gfx::Point(-1, -1).ToString(),
+ EXPECT_EQ(gfx::Point(50, -1).ToString(),
event->AsMouseEvent()->location().ToString());
});
Sync();
diff --git a/chromium/ui/ozone/platform/wayland/host/wayland_window_factory.cc b/chromium/ui/ozone/platform/wayland/host/wayland_window_factory.cc
index 7854b05b999..7cca6ba6a82 100644
--- a/chromium/ui/ozone/platform/wayland/host/wayland_window_factory.cc
+++ b/chromium/ui/ozone/platform/wayland/host/wayland_window_factory.cc
@@ -22,28 +22,41 @@ std::unique_ptr<WaylandWindow> WaylandWindow::Create(
switch (properties.type) {
case PlatformWindowType::kMenu:
case PlatformWindowType::kPopup:
- // We are unable to create a popup or menu window, because they require a
- // parent window to be set. Thus, create a normal window instead then.
- if (properties.parent_widget == gfx::kNullAcceleratedWidget &&
- !connection->wayland_window_manager()->GetCurrentFocusedWindow()) {
- window.reset(new WaylandToplevelWindow(delegate, connection));
- } else if (connection->IsDragInProgress()) {
+ if (connection->IsDragInProgress()) {
// We are in the process of drag and requested a popup. Most probably,
// it is an arrow window.
- window.reset(new WaylandAuxiliaryWindow(delegate, connection));
+ window = std::make_unique<WaylandAuxiliaryWindow>(delegate, connection);
} else {
- window.reset(new WaylandPopup(delegate, connection));
+ auto* parent_window =
+ connection->wayland_window_manager()->FindParentForNewWindow(
+ properties.parent_widget);
+ if (parent_window) {
+ // Set the parent window in advance otherwise it is not possible to
+ // know if the WaylandPopup is able to find one and if
+ // WaylandWindow::Initialize() fails or not. Otherwise,
+ // WaylandWindow::Create() returns nullptr and makes the browser to
+ // fail. To fix this problem, search for the parent window and if
+ // one is not found, create WaylandToplevelWindow instead. It's
+ // also worth noting that searching twice (one time here and another
+ // by WaylandPopup) is a bad practice, and the parent window is set
+ // here instead.
+ window = std::make_unique<WaylandPopup>(delegate, connection);
+ window->set_parent_window(parent_window);
+ } else {
+ window =
+ std::make_unique<WaylandToplevelWindow>(delegate, connection);
+ }
}
break;
case PlatformWindowType::kTooltip:
- window.reset(new WaylandAuxiliaryWindow(delegate, connection));
+ window = std::make_unique<WaylandAuxiliaryWindow>(delegate, connection);
break;
case PlatformWindowType::kWindow:
case PlatformWindowType::kBubble:
case PlatformWindowType::kDrag:
// TODO(msisov): Figure out what kind of surface we need to create for
// bubble and drag windows.
- window.reset(new WaylandToplevelWindow(delegate, connection));
+ window = std::make_unique<WaylandToplevelWindow>(delegate, connection);
break;
default:
NOTREACHED();
diff --git a/chromium/ui/ozone/platform/wayland/host/wayland_window_manager.cc b/chromium/ui/ozone/platform/wayland/host/wayland_window_manager.cc
index 0c9b86e81fc..ac1549a20a8 100644
--- a/chromium/ui/ozone/platform/wayland/host/wayland_window_manager.cc
+++ b/chromium/ui/ozone/platform/wayland/host/wayland_window_manager.cc
@@ -82,6 +82,37 @@ WaylandWindow* WaylandWindowManager::GetCurrentKeyboardFocusedWindow() const {
return nullptr;
}
+WaylandWindow* WaylandWindowManager::FindParentForNewWindow(
+ gfx::AcceleratedWidget parent_widget) const {
+ auto* parent_window = GetWindow(parent_widget);
+
+ // If propagated parent has already had a child, it means that |this| is a
+ // submenu of a 3-dot menu. In aura, the parent of a 3-dot menu and its
+ // submenu is the main native widget, which is the main window. In contrast,
+ // Wayland requires a menu window to be a parent of a submenu window. Thus,
+ // check if the suggested parent has a child. If yes, take its child as a
+ // parent of |this|.
+ // Another case is a notification window or a drop down window, which does not
+ // have a parent in aura. In this case, take the current focused window as a
+ // parent.
+ if (!parent_window)
+ parent_window = GetCurrentFocusedWindow();
+
+ // If there is no current focused window, figure out the current active window
+ // set by the Wayland server. Only one window at a time can be set as active.
+ if (!parent_window) {
+ auto windows = GetAllWindows();
+ for (auto* window : windows) {
+ if (window->IsActive()) {
+ parent_window = window;
+ break;
+ }
+ }
+ }
+
+ return parent_window ? parent_window->GetTopMostChildWindow() : nullptr;
+}
+
std::vector<WaylandWindow*> WaylandWindowManager::GetWindowsOnOutput(
uint32_t output_id) {
std::vector<WaylandWindow*> result;
diff --git a/chromium/ui/ozone/platform/wayland/host/wayland_window_manager.h b/chromium/ui/ozone/platform/wayland/host/wayland_window_manager.h
index ca32c24833f..47abf725740 100644
--- a/chromium/ui/ozone/platform/wayland/host/wayland_window_manager.h
+++ b/chromium/ui/ozone/platform/wayland/host/wayland_window_manager.h
@@ -10,6 +10,7 @@
#include "base/containers/flat_map.h"
#include "base/macros.h"
#include "base/observer_list.h"
+#include "ui/gfx/geometry/size_f.h"
#include "ui/gfx/native_widget_types.h"
#include "ui/ozone/platform/wayland/host/wayland_window_observer.h"
@@ -55,6 +56,13 @@ class WaylandWindowManager {
// Returns a current focused window by keyboard.
WaylandWindow* GetCurrentKeyboardFocusedWindow() const;
+ // Returns a parent window suitable for newly created non-toplevel windows. If
+ // the |parent_widget| is gfx::kNullAcceleratedWidget, either the currently
+ // focused or the active window is used. If the found parent has children
+ // windows, the one on top the of the stack is used as a parent.
+ WaylandWindow* FindParentForNewWindow(
+ gfx::AcceleratedWidget parent_widget) const;
+
// TODO(crbug.com/971525): remove this in favor of targeted subscription of
// windows to their outputs.
std::vector<WaylandWindow*> GetWindowsOnOutput(uint32_t output_id);
diff --git a/chromium/ui/ozone/platform/wayland/host/wayland_window_unittest.cc b/chromium/ui/ozone/platform/wayland/host/wayland_window_unittest.cc
index 2626222a427..c081c9c3514 100644
--- a/chromium/ui/ozone/platform/wayland/host/wayland_window_unittest.cc
+++ b/chromium/ui/ozone/platform/wayland/host/wayland_window_unittest.cc
@@ -19,6 +19,7 @@
#include "ui/base/hit_test.h"
#include "ui/events/base_event_utils.h"
#include "ui/events/event.h"
+#include "ui/gfx/native_widget_types.h"
#include "ui/gfx/overlay_transform.h"
#include "ui/ozone/platform/wayland/common/wayland_util.h"
#include "ui/ozone/platform/wayland/host/wayland_subsurface.h"
@@ -2028,7 +2029,28 @@ TEST_P(WaylandWindowTest, CreatesPopupOnTouchDownSerial) {
auto* test_popup = GetPopupByWindow(popup.get());
ASSERT_TRUE(test_popup);
- EXPECT_NE(test_popup->grab_serial(), touch_up_serial);
+
+ // Touch events are the exception. We can't use the serial that was sent
+ // before the "up" event. Otherwise, some compositors may dismiss popups.
+ // Thus, no serial must be used.
+ EXPECT_EQ(test_popup->grab_serial(), 0U);
+
+ popup->Hide();
+
+ // Send a single down event now.
+ wl_touch_send_down(server_.seat()->touch()->resource(), touch_down_serial, 0,
+ surface_->resource(), 0 /* id */, wl_fixed_from_int(50),
+ wl_fixed_from_int(100));
+
+ Sync();
+
+ popup->Show(false);
+
+ Sync();
+
+ test_popup = GetPopupByWindow(popup.get());
+ ASSERT_TRUE(test_popup);
+
EXPECT_EQ(test_popup->grab_serial(), touch_down_serial);
}
@@ -2107,8 +2129,9 @@ TEST_P(WaylandWindowTest, OneWaylandSubsurface) {
auto* mock_surface_subsurface = server_.GetObject<wl::MockSurface>(
wayland_subsurface->wayland_surface()->GetSurfaceId());
EXPECT_TRUE(mock_surface_subsurface);
- wayland_subsurface->ConfigureAndShowSurface(
- gfx::OVERLAY_TRANSFORM_NONE, subsurface_bounds, true, nullptr, nullptr);
+ wayland_subsurface->ConfigureAndShowSurface(gfx::OVERLAY_TRANSFORM_NONE,
+ gfx::RectF(), subsurface_bounds,
+ true, nullptr, nullptr);
connection_->ScheduleFlush();
Sync();
@@ -2122,6 +2145,117 @@ TEST_P(WaylandWindowTest, OneWaylandSubsurface) {
EXPECT_TRUE(test_subsurface->sync());
}
+TEST_P(WaylandWindowTest, UsesCorrectParentForChildrenWindows) {
+ uint32_t serial = 0;
+
+ MockPlatformWindowDelegate window_delegate;
+ std::unique_ptr<WaylandWindow> window = CreateWaylandWindowWithParams(
+ PlatformWindowType::kWindow, gfx::kNullAcceleratedWidget,
+ gfx::Rect(10, 10, 100, 100), &window_delegate);
+ EXPECT_TRUE(window);
+
+ window->Show(false);
+
+ std::unique_ptr<WaylandWindow> another_window = CreateWaylandWindowWithParams(
+ PlatformWindowType::kWindow, gfx::kNullAcceleratedWidget,
+ gfx::Rect(10, 10, 300, 400), &window_delegate);
+ EXPECT_TRUE(another_window);
+
+ another_window->Show(false);
+
+ Sync();
+
+ auto* window1 = window.get();
+ auto* window2 = window_.get();
+ auto* window3 = another_window.get();
+
+ // Make sure windows are not "active".
+ auto empty_state = MakeStateArray({});
+ SendConfigureEvent(xdg_surface_, 0, 0, ++serial, empty_state.get());
+ auto* xdg_surface_window =
+ server_
+ .GetObject<wl::MockSurface>(window->root_surface()->GetSurfaceId())
+ ->xdg_surface();
+ SendConfigureEvent(xdg_surface_window, 0, 0, ++serial, empty_state.get());
+ auto* xdg_surface_another_window =
+ server_
+ .GetObject<wl::MockSurface>(
+ another_window->root_surface()->GetSurfaceId())
+ ->xdg_surface();
+ SendConfigureEvent(xdg_surface_another_window, 0, 0, ++serial,
+ empty_state.get());
+
+ Sync();
+
+ // Case 1: provided parent window's widget..
+ MockPlatformWindowDelegate menu_window_delegate;
+ std::unique_ptr<WaylandWindow> menu_window = CreateWaylandWindowWithParams(
+ PlatformWindowType::kMenu, window1->GetWidget(),
+ gfx::Rect(10, 10, 10, 10), &menu_window_delegate);
+
+ EXPECT_TRUE(menu_window->parent_window() == window1);
+
+ // Case 2: didn't provide parent window's widget - must use current focused.
+ //
+ // Subcase 1: pointer focus.
+ window2->SetPointerFocus(true);
+ menu_window = CreateWaylandWindowWithParams(
+ PlatformWindowType::kMenu, gfx::kNullAcceleratedWidget,
+ gfx::Rect(10, 10, 10, 10), &menu_window_delegate);
+
+ EXPECT_TRUE(menu_window->parent_window() == window2);
+ EXPECT_TRUE(wl::IsMenuType(menu_window->type()));
+
+ // Subcase 2: keyboard focus.
+ window2->SetPointerFocus(false);
+ window2->set_keyboard_focus(true);
+ menu_window = CreateWaylandWindowWithParams(
+ PlatformWindowType::kMenu, gfx::kNullAcceleratedWidget,
+ gfx::Rect(10, 10, 10, 10), &menu_window_delegate);
+
+ // Mustn't be able to create a menu window, but rather creates a toplevel
+ // window as we must provide at least something.
+ EXPECT_TRUE(menu_window);
+ // Make it create xdg objects.
+ menu_window->Show(false);
+
+ Sync();
+
+ auto* menu_window_xdg =
+ server_
+ .GetObject<wl::MockSurface>(
+ another_window->root_surface()->GetSurfaceId())
+ ->xdg_surface();
+ EXPECT_TRUE(menu_window_xdg);
+ EXPECT_TRUE(menu_window_xdg->xdg_toplevel());
+ EXPECT_FALSE(menu_window_xdg->xdg_popup());
+
+ // Subcase 3: touch focus.
+ window2->set_keyboard_focus(false);
+ window2->set_touch_focus(true);
+ menu_window = CreateWaylandWindowWithParams(
+ PlatformWindowType::kMenu, gfx::kNullAcceleratedWidget,
+ gfx::Rect(10, 10, 10, 10), &menu_window_delegate);
+
+ EXPECT_TRUE(menu_window->parent_window() == window2);
+ EXPECT_TRUE(wl::IsMenuType(menu_window->type()));
+
+ // Case 3: neither of the windows are focused. However, there is one that is
+ // active. Must use that then.
+ window2->set_touch_focus(false);
+
+ auto active = InitializeWlArrayWithActivatedState();
+ SendConfigureEvent(xdg_surface_another_window, 0, 0, ++serial, active.get());
+ Sync();
+
+ menu_window = CreateWaylandWindowWithParams(
+ PlatformWindowType::kMenu, gfx::kNullAcceleratedWidget,
+ gfx::Rect(10, 10, 10, 10), &menu_window_delegate);
+
+ EXPECT_TRUE(menu_window->parent_window() == window3);
+ EXPECT_TRUE(wl::IsMenuType(menu_window->type()));
+}
+
INSTANTIATE_TEST_SUITE_P(XdgVersionStableTest,
WaylandWindowTest,
::testing::Values(kXdgShellStable));
diff --git a/chromium/ui/ozone/platform/wayland/host/wayland_zwp_linux_dmabuf.cc b/chromium/ui/ozone/platform/wayland/host/wayland_zwp_linux_dmabuf.cc
index 991ae63fc1c..d82674b3137 100644
--- a/chromium/ui/ozone/platform/wayland/host/wayland_zwp_linux_dmabuf.cc
+++ b/chromium/ui/ozone/platform/wayland/host/wayland_zwp_linux_dmabuf.cc
@@ -12,10 +12,6 @@
namespace ui {
-namespace {
-constexpr uint32_t kImmedVerstion = 3;
-}
-
WaylandZwpLinuxDmabuf::WaylandZwpLinuxDmabuf(
zwp_linux_dmabuf_v1* zwp_linux_dmabuf,
WaylandConnection* connection)
@@ -56,9 +52,9 @@ void WaylandZwpLinuxDmabuf::CreateBuffer(base::ScopedFD fd,
}
// It's possible to avoid waiting until the buffer is created and have it
- // immediately. This method is only available since the protocol version 3.
- if (zwp_linux_dmabuf_v1_get_version(zwp_linux_dmabuf_.get()) >=
- kImmedVerstion) {
+ // immediately. This method is only available since the protocol version 2.
+ if (wl::get_version_of_object(zwp_linux_dmabuf_.get()) >=
+ ZWP_LINUX_BUFFER_PARAMS_V1_CREATE_IMMED_SINCE_VERSION) {
wl::Object<wl_buffer> buffer(zwp_linux_buffer_params_v1_create_immed(
params, size.width(), size.height(), format, 0));
std::move(callback).Run(std::move(buffer));
diff --git a/chromium/ui/ozone/platform/wayland/host/xdg_foreign_wrapper.cc b/chromium/ui/ozone/platform/wayland/host/xdg_foreign_wrapper.cc
new file mode 100644
index 00000000000..511ad9e4ffb
--- /dev/null
+++ b/chromium/ui/ozone/platform/wayland/host/xdg_foreign_wrapper.cc
@@ -0,0 +1,128 @@
+// Copyright 2020 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 "ui/ozone/platform/wayland/host/xdg_foreign_wrapper.h"
+
+#include <xdg-foreign-unstable-v1-client-protocol.h>
+
+#include "ui/ozone/platform/wayland/host/wayland_connection.h"
+#include "ui/ozone/platform/wayland/host/wayland_window.h"
+#include "ui/platform_window/platform_window_init_properties.h"
+
+namespace ui {
+
+struct XdgForeignWrapper::ExportedSurface {
+ ExportedSurface(wl_surface* surface, OnHandleExported cb);
+ ExportedSurface(ExportedSurface&& buffer);
+ ExportedSurface& operator=(ExportedSurface&& buffer);
+ ~ExportedSurface();
+
+ // Surface that is exported.
+ wl_surface* surface_for_export = nullptr;
+
+ // Exported |surface|.
+ wl::Object<zxdg_exported_v1> exported;
+
+ // Handle of the exported |surface|.
+ std::string exported_handle;
+
+ // The cb that will be executed when |handle| is exported.
+ std::vector<OnHandleExported> callbacks;
+};
+
+XdgForeignWrapper::ExportedSurface::ExportedSurface(wl_surface* surface,
+ OnHandleExported cb)
+ : surface_for_export(surface) {
+ callbacks.emplace_back((std::move(cb)));
+}
+
+XdgForeignWrapper::ExportedSurface::ExportedSurface(ExportedSurface&& buffer) =
+ default;
+
+XdgForeignWrapper::ExportedSurface&
+XdgForeignWrapper::ExportedSurface::operator=(ExportedSurface&& buffer) =
+ default;
+
+XdgForeignWrapper::ExportedSurface::~ExportedSurface() = default;
+
+XdgForeignWrapper::XdgForeignWrapper(WaylandConnection* connection,
+ wl::Object<zxdg_exporter_v1> exporter_v1)
+ : connection_(connection), exporter_v1_(std::move(exporter_v1)) {}
+
+XdgForeignWrapper::~XdgForeignWrapper() = default;
+
+void XdgForeignWrapper::ExportSurfaceToForeign(WaylandWindow* window,
+ OnHandleExported cb) {
+ DCHECK_EQ(window->type(), PlatformWindowType::kWindow);
+ auto* surface = window->root_surface()->surface();
+ auto* exported_surface = GetExportedSurface(surface);
+ if (!exported_surface) {
+ // The |surface| has never been exported. Export it and return the handle
+ // via the |cb|.
+ ExportSurfaceInternal(surface, std::move(cb));
+ } else if (exported_surface->exported_handle.empty()) {
+ // The |surface| has already been exported, but its handle hasn't been
+ // received yet. Store the |cb| and execute when the handle is obtained.
+ exported_surface->callbacks.emplace_back(std::move(cb));
+ } else {
+ // The |surface| has already been exported and its handle has been received.
+ // Execute the |cb| and send the handle.
+ DCHECK(!exported_surface->exported_handle.empty());
+ std::move(cb).Run(exported_surface->exported_handle);
+ }
+}
+
+XdgForeignWrapper::ExportedSurface* XdgForeignWrapper::GetExportedSurface(
+ wl_surface* surface) {
+ for (auto& item : exported_surfaces_) {
+ if (item.surface_for_export == surface)
+ return &item;
+ }
+ return nullptr;
+}
+
+void XdgForeignWrapper::ExportSurfaceInternal(wl_surface* surface,
+ OnHandleExported cb) {
+ static const struct zxdg_exported_v1_listener kExportedListener = {
+ &XdgForeignWrapper::OnExported};
+
+ ExportedSurface exported_surface(surface, std::move(cb));
+ exported_surface.exported.reset(
+ zxdg_exporter_v1_export(exporter_v1_.get(), surface));
+ zxdg_exported_v1_add_listener(exported_surface.exported.get(),
+ &kExportedListener, this);
+ exported_surfaces_.emplace_back(std::move(exported_surface));
+ connection_->ScheduleFlush();
+}
+
+void XdgForeignWrapper::OnWindowRemoved(WaylandWindow* window) {
+ auto it = std::find_if(exported_surfaces_.begin(), exported_surfaces_.end(),
+ [window](const auto& surface) {
+ return window->root_surface()->surface() ==
+ surface.surface_for_export;
+ });
+ if (it != exported_surfaces_.end())
+ exported_surfaces_.erase(it);
+}
+
+// static
+void XdgForeignWrapper::OnExported(void* data,
+ zxdg_exported_v1* exported,
+ const char* handle) {
+ auto* self = static_cast<XdgForeignWrapper*>(data);
+ DCHECK(self);
+
+ auto exported_surface_it = std::find_if(
+ self->exported_surfaces_.begin(), self->exported_surfaces_.end(),
+ [exported](const auto& item) { return item.exported.get() == exported; });
+ DCHECK(exported_surface_it != self->exported_surfaces_.end());
+ exported_surface_it->exported_handle = handle;
+
+ for (auto& cb : exported_surface_it->callbacks)
+ std::move(cb).Run(exported_surface_it->exported_handle);
+
+ exported_surface_it->callbacks.clear();
+}
+
+} // namespace ui
diff --git a/chromium/ui/ozone/platform/wayland/host/xdg_foreign_wrapper.h b/chromium/ui/ozone/platform/wayland/host/xdg_foreign_wrapper.h
new file mode 100644
index 00000000000..50bb4f978db
--- /dev/null
+++ b/chromium/ui/ozone/platform/wayland/host/xdg_foreign_wrapper.h
@@ -0,0 +1,63 @@
+// Copyright 2020 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.
+
+#ifndef UI_OZONE_PLATFORM_WAYLAND_HOST_XDG_FOREIGN_WRAPPER_H_
+#define UI_OZONE_PLATFORM_WAYLAND_HOST_XDG_FOREIGN_WRAPPER_H_
+
+#include <string>
+
+#include "base/callback.h"
+#include "ui/ozone/platform/wayland/common/wayland_object.h"
+#include "ui/ozone/platform/wayland/host/wayland_connection.h"
+#include "ui/ozone/platform/wayland/host/wayland_window_observer.h"
+
+namespace ui {
+
+class WaylandConnection;
+
+// A wrapper for xdg foreign objects. Exports surfaces that have xdg_surface
+// roles and asynchronously returns handles for them. Only xdg_surface surfaces
+// may be exported. Currently supports only exporting surfaces.
+//
+// TODO(1126817): consider supporting xdg-foreign-v2.
+class XdgForeignWrapper : public WaylandWindowObserver {
+ public:
+ using OnHandleExported = base::OnceCallback<void(const std::string&)>;
+
+ XdgForeignWrapper(WaylandConnection* connection,
+ wl::Object<zxdg_exporter_v1> exporter_v1);
+ XdgForeignWrapper(const XdgForeignWrapper&) = delete;
+ XdgForeignWrapper& operator=(const XdgForeignWrapper&) = delete;
+ ~XdgForeignWrapper() override;
+
+ // Exports |window|'s wl_surface and asynchronously returns a handle for that
+ // via the |cb|. Please note that wl_surface that has xdg_surface role can be
+ // exported.
+ void ExportSurfaceToForeign(WaylandWindow* window, OnHandleExported cb);
+
+ private:
+ struct ExportedSurface;
+
+ ExportedSurface* GetExportedSurface(wl_surface* surface);
+
+ void ExportSurfaceInternal(wl_surface* surface, OnHandleExported cb);
+
+ // WaylandWindowObserver:
+ void OnWindowRemoved(WaylandWindow* window) override;
+
+ // zxdg_exported_v1_listener:
+ static void OnExported(void* data,
+ zxdg_exported_v1* exported,
+ const char* handle);
+
+ WaylandConnection* const connection_;
+
+ wl::Object<zxdg_exporter_v1> exporter_v1_;
+
+ std::vector<ExportedSurface> exported_surfaces_;
+};
+
+} // namespace ui
+
+#endif // UI_OZONE_PLATFORM_WAYLAND_HOST_XDG_FOREIGN_WRAPPER_H_
diff --git a/chromium/ui/ozone/platform/wayland/host/xdg_popup_wrapper_impl.cc b/chromium/ui/ozone/platform/wayland/host/xdg_popup_wrapper_impl.cc
index 99eb2e7012a..cee4e46e6c1 100644
--- a/chromium/ui/ozone/platform/wayland/host/xdg_popup_wrapper_impl.cc
+++ b/chromium/ui/ozone/platform/wayland/host/xdg_popup_wrapper_impl.cc
@@ -11,7 +11,9 @@
#include "base/environment.h"
#include "base/nix/xdg_util.h"
+#include "ui/events/event.h"
#include "ui/events/event_constants.h"
+#include "ui/events/types/event_type.h"
#include "ui/gfx/geometry/rect.h"
#include "ui/ozone/platform/wayland/common/wayland_util.h"
#include "ui/ozone/platform/wayland/host/wayland_connection.h"
@@ -295,10 +297,17 @@ bool XDGPopupWrapperImpl::Initialize(WaylandConnection* connection,
if (!xdg_surface_ || !parent_xdg_surface)
return false;
+ auto new_bounds = bounds;
+ // Wayland doesn't allow empty bounds. If a zero or negative size is set, the
+ // invalid_input error is raised. Thus, use the least possible one.
+ // WaylandPopup will update its bounds upon the following configure event.
+ if (new_bounds.IsEmpty())
+ new_bounds.set_size({1, 1});
+
if (connection->shell())
- return InitializeStable(connection, bounds, parent_xdg_surface);
+ return InitializeStable(connection, new_bounds, parent_xdg_surface);
else if (connection->shell_v6())
- return InitializeV6(connection, bounds, parent_xdg_surface);
+ return InitializeV6(connection, new_bounds, parent_xdg_surface);
return false;
}
@@ -456,34 +465,13 @@ bool XDGPopupWrapperImpl::CanGrabPopup(WaylandConnection* connection) const {
if (connection->IsDragInProgress() || !connection->seat())
return false;
- // According to the spec, the grab call can only be done on a key press, mouse
- // press or touch down. However, there is a problem with popup windows and
- // touch events so long as Chromium creates them only on consequent touch up
- // events. That results in Wayland compositors dismissing popups. To fix the
- // issue, do not use grab with touch events. Please note that explicit grab
- // means that a Wayland compositor dismisses a popup whenever the user clicks
- // outside the created surfaces. If the explicit grab is not used, the popups
- // are not dismissed in such cases. What is more, current non-ozone X11
- // implementation does the same. This means there is no functionality changes
- // and we do things right.
- //
- // We cannot know what was the last event. Instead, we can check if the window
- // has pointer or keyboard focus. If so, the popup will be explicitly grabbed.
- //
- // There is a bug in the gnome/mutter - if explicit grab is not used,
- // unmapping of a wl_surface (aka destroying xdg_popup and surface) to hide a
- // window results in weird behaviour. That is, a popup continues to be visible
- // on a display and it results in a crash of the entire session. Thus, just
- // continue to use grab here and avoid showing popups for touch events on
- // gnome/mutter. That is better than crashing the entire system. Otherwise,
- // Chromium has to change the way how it reacts on touch events - instead of
- // creating a menu on touch up, it must do it on touch down events.
- // https://gitlab.gnome.org/GNOME/mutter/issues/698#note_562601.
- std::unique_ptr<base::Environment> env(base::Environment::Create());
- return (base::nix::GetDesktopEnvironment(env.get()) ==
- base::nix::DESKTOP_ENVIRONMENT_GNOME) ||
- (wayland_window_->parent_window()->has_pointer_focus() ||
- wayland_window_->parent_window()->has_keyboard_focus());
+ // According to the definition of the xdg protocol, the grab request must be
+ // used in response to some sort of user action like a button press, key
+ // press, or touch down event.
+ EventType last_event_type = connection->event_serial().event_type;
+ return last_event_type == ET_TOUCH_PRESSED ||
+ last_event_type == ET_KEY_PRESSED ||
+ last_event_type == ET_MOUSE_PRESSED;
}
void XDGPopupWrapperImpl::Configure(void* data,
diff --git a/chromium/ui/ozone/platform/wayland/host/xdg_surface_wrapper_impl.cc b/chromium/ui/ozone/platform/wayland/host/xdg_surface_wrapper_impl.cc
index f1a03831363..6ee18c65b7e 100644
--- a/chromium/ui/ozone/platform/wayland/host/xdg_surface_wrapper_impl.cc
+++ b/chromium/ui/ozone/platform/wayland/host/xdg_surface_wrapper_impl.cc
@@ -4,7 +4,7 @@
#include "ui/ozone/platform/wayland/host/xdg_surface_wrapper_impl.h"
-#include <aura-shell-client-protocol.h>
+#include <xdg-decoration-unstable-v1-client-protocol.h>
#include <xdg-shell-client-protocol.h>
#include <xdg-shell-unstable-v6-client-protocol.h>
@@ -204,6 +204,16 @@ void XDGSurfaceWrapperImpl::CloseTopLevelStable(
surface->wayland_window_->OnCloseRequest();
}
+void XDGSurfaceWrapperImpl::SetTopLevelDecorationMode(
+ zxdg_toplevel_decoration_v1_mode requested_mode) {
+ if (requested_mode == decoration_mode_)
+ return;
+
+ decoration_mode_ = requested_mode;
+ zxdg_toplevel_decoration_v1_set_mode(zxdg_toplevel_decoration_.get(),
+ requested_mode);
+}
+
// static
void XDGSurfaceWrapperImpl::ConfigureV6(void* data,
struct zxdg_surface_v6* zxdg_surface_v6,
@@ -255,6 +265,17 @@ xdg_surface* XDGSurfaceWrapperImpl::xdg_surface() const {
return xdg_surface_.get();
}
+// static
+void XDGSurfaceWrapperImpl::ConfigureDecoration(
+ void* data,
+ struct zxdg_toplevel_decoration_v1* decoration,
+ uint32_t mode) {
+ auto* surface = static_cast<XDGSurfaceWrapperImpl*>(data);
+ DCHECK(surface);
+ surface->SetTopLevelDecorationMode(
+ static_cast<zxdg_toplevel_decoration_v1_mode>(mode));
+}
+
bool XDGSurfaceWrapperImpl::InitializeStable(bool with_toplevel) {
static const xdg_surface_listener xdg_surface_listener = {
&XDGSurfaceWrapperImpl::ConfigureStable,
@@ -287,7 +308,11 @@ bool XDGSurfaceWrapperImpl::InitializeStable(bool with_toplevel) {
LOG(ERROR) << "Failed to create xdg_toplevel";
return false;
}
+
xdg_toplevel_add_listener(xdg_toplevel_.get(), &xdg_toplevel_listener, this);
+
+ InitializeXdgDecoration();
+
wayland_window_->root_surface()->Commit();
connection_->ScheduleFlush();
return true;
@@ -329,16 +354,23 @@ bool XDGSurfaceWrapperImpl::InitializeV6(bool with_toplevel) {
zxdg_toplevel_v6_add_listener(zxdg_toplevel_v6_.get(),
&zxdg_toplevel_v6_listener, this);
- if (connection_->aura_shell()) {
- aura_surface_.reset(zaura_shell_get_aura_surface(
- connection_->aura_shell(), wayland_window_->root_surface()->surface()));
- zaura_surface_set_fullscreen_mode(aura_surface_.get(),
- ZAURA_SURFACE_FULLSCREEN_MODE_IMMERSIVE);
- }
-
wayland_window_->root_surface()->Commit();
connection_->ScheduleFlush();
return true;
}
+void XDGSurfaceWrapperImpl::InitializeXdgDecoration() {
+ if (connection_->xdg_decoration_manager_v1()) {
+ DCHECK(!zxdg_toplevel_decoration_);
+ static const zxdg_toplevel_decoration_v1_listener decoration_listener = {
+ &XDGSurfaceWrapperImpl::ConfigureDecoration,
+ };
+ zxdg_toplevel_decoration_.reset(
+ zxdg_decoration_manager_v1_get_toplevel_decoration(
+ connection_->xdg_decoration_manager_v1(), xdg_toplevel_.get()));
+ zxdg_toplevel_decoration_v1_add_listener(zxdg_toplevel_decoration_.get(),
+ &decoration_listener, this);
+ }
+}
+
} // namespace ui
diff --git a/chromium/ui/ozone/platform/wayland/host/xdg_surface_wrapper_impl.h b/chromium/ui/ozone/platform/wayland/host/xdg_surface_wrapper_impl.h
index 2381aecfd9c..da945779a76 100644
--- a/chromium/ui/ozone/platform/wayland/host/xdg_surface_wrapper_impl.h
+++ b/chromium/ui/ozone/platform/wayland/host/xdg_surface_wrapper_impl.h
@@ -7,7 +7,11 @@
#include "ui/ozone/platform/wayland/host/shell_surface_wrapper.h"
-#include "base/macros.h"
+#include <xdg-decoration-unstable-v1-client-protocol.h>
+
+#include <cstdint>
+#include <string>
+
#include "base/strings/string16.h"
#include "ui/ozone/platform/wayland/common/wayland_object.h"
@@ -25,6 +29,8 @@ class XDGSurfaceWrapperImpl : public ShellSurfaceWrapper {
public:
XDGSurfaceWrapperImpl(WaylandWindow* wayland_window,
WaylandConnection* connection);
+ XDGSurfaceWrapperImpl(const XDGSurfaceWrapperImpl&) = delete;
+ XDGSurfaceWrapperImpl& operator=(const XDGSurfaceWrapperImpl&) = delete;
~XDGSurfaceWrapperImpl() override;
// ShellSurfaceWrapper overrides:
@@ -68,6 +74,14 @@ class XDGSurfaceWrapperImpl : public ShellSurfaceWrapper {
static void CloseTopLevelV6(void* data,
struct zxdg_toplevel_v6* zxdg_toplevel_v6);
+ void SetTopLevelDecorationMode(
+ zxdg_toplevel_decoration_v1_mode requested_mode);
+ // zxdg_decoration_listener
+ static void ConfigureDecoration(
+ void* data,
+ struct zxdg_toplevel_decoration_v1* decoration,
+ uint32_t mode);
+
struct xdg_surface* xdg_surface() const;
zxdg_surface_v6* zxdg_surface() const;
@@ -77,6 +91,9 @@ class XDGSurfaceWrapperImpl : public ShellSurfaceWrapper {
// Initializes using XDG Shell V6 protocol.
bool InitializeV6(bool with_toplevel);
+ // Initializes the xdg-decoration protocol extension, if available.
+ void InitializeXdgDecoration();
+
// Non-owing WaylandWindow that uses this surface wrapper.
WaylandWindow* const wayland_window_;
WaylandConnection* const connection_;
@@ -87,11 +104,14 @@ class XDGSurfaceWrapperImpl : public ShellSurfaceWrapper {
wl::Object<zxdg_toplevel_v6> zxdg_toplevel_v6_;
wl::Object<struct xdg_surface> xdg_surface_;
wl::Object<xdg_toplevel> xdg_toplevel_;
- wl::Object<zaura_surface> aura_surface_;
+ wl::Object<zxdg_toplevel_decoration_v1> zxdg_toplevel_decoration_;
bool surface_for_popup_ = false;
- DISALLOW_COPY_AND_ASSIGN(XDGSurfaceWrapperImpl);
+ // Keeps track of the decoration mode currently in use if xdg-decoration
+ // protocol extension is available, otherwise CLIENT_SIDE is assumed.
+ enum zxdg_toplevel_decoration_v1_mode decoration_mode_ =
+ ZXDG_TOPLEVEL_DECORATION_V1_MODE_CLIENT_SIDE;
};
} // namespace ui
diff --git a/chromium/ui/ozone/platform/wayland/ozone_platform_wayland.cc b/chromium/ui/ozone/platform/wayland/ozone_platform_wayland.cc
index 8de40eb6896..e4968f1bc42 100644
--- a/chromium/ui/ozone/platform/wayland/ozone_platform_wayland.cc
+++ b/chromium/ui/ozone/platform/wayland/ozone_platform_wayland.cc
@@ -12,6 +12,7 @@
#include "base/bind.h"
#include "base/memory/ptr_util.h"
#include "base/message_loop/message_pump_type.h"
+#include "base/no_destructor.h"
#include "base/threading/sequenced_task_runner_handle.h"
#include "ui/base/buildflags.h"
#include "ui/base/cursor/cursor_factory.h"
@@ -63,23 +64,6 @@ namespace ui {
namespace {
-constexpr OzonePlatform::PlatformProperties kWaylandPlatformProperties = {
- // Supporting server-side decorations requires a support of
- // xdg-decorations. But this protocol has been accepted into the upstream
- // recently, and it will take time before it is taken by compositors. For
- // now, always use custom frames and disallow switching to server-side
- // frames.
- // https://github.com/wayland-project/wayland-protocols/commit/76d1ae8c65739eff3434ef219c58a913ad34e988
- .custom_frame_pref_default = true,
-
- // Wayland doesn't provide clients with global screen coordinates. Instead,
- // it forces clients to position windows relative to their top level windows
- // if the have child-parent relationship. In case of toplevel windows,
- // clients simply don't know their position on screens and always assume
- // they are located at some arbitrary position.
- .ignore_screen_bounds_for_menus = true,
-};
-
constexpr OzonePlatform::InitializedHostProperties
kWaylandInitializedHostProperties = {
/*supports_overlays=*/false,
@@ -232,7 +216,29 @@ class OzonePlatformWayland : public OzonePlatform {
}
const PlatformProperties& GetPlatformProperties() override {
- return kWaylandPlatformProperties;
+ static base::NoDestructor<OzonePlatform::PlatformProperties> properties;
+ static bool initialised = false;
+ if (!initialised) {
+ // Supporting server-side decorations requires a support of
+ // xdg-decorations. But this protocol has been accepted into the upstream
+ // recently, and it will take time before it is taken by compositors. For
+ // now, always use custom frames and disallow switching to server-side
+ // frames.
+ // https://github.com/wayland-project/wayland-protocols/commit/76d1ae8c65739eff3434ef219c58a913ad34e988
+ properties->custom_frame_pref_default = true;
+
+ // Wayland doesn't provide clients with global screen coordinates.
+ // Instead, it forces clients to position windows relative to their top
+ // level windows if the have child-parent relationship. In case of
+ // toplevel windows, clients simply don't know their position on screens
+ // and always assume they are located at some arbitrary position.
+ properties->ignore_screen_bounds_for_menus = true;
+ properties->app_modal_dialogs_use_event_blocker = true;
+
+ initialised = true;
+ }
+
+ return *properties;
}
const InitializedHostProperties& GetInitializedHostProperties() override {
@@ -252,6 +258,12 @@ class OzonePlatformWayland : public OzonePlatform {
buffer_manager_->AddBindingWaylandBufferManagerGpu(std::move(receiver));
}
+ void PostMainMessageLoopStart(
+ base::OnceCallback<void()> shutdown_cb) override {
+ DCHECK(connection_);
+ connection_->SetShutdownCb(std::move(shutdown_cb));
+ }
+
private:
#if BUILDFLAG(USE_XKBCOMMON)
XkbEvdevCodes xkb_evdev_code_converter_;
diff --git a/chromium/ui/ozone/platform/wayland/test/mock_surface.cc b/chromium/ui/ozone/platform/wayland/test/mock_surface.cc
index 524b4f45bc3..d7ec1ec227b 100644
--- a/chromium/ui/ozone/platform/wayland/test/mock_surface.cc
+++ b/chromium/ui/ozone/platform/wayland/test/mock_surface.cc
@@ -87,6 +87,10 @@ MockSurface::MockSurface(wl_resource* resource) : ServerObject(resource) {}
MockSurface::~MockSurface() {
if (xdg_surface_ && xdg_surface_->resource())
wl_resource_destroy(xdg_surface_->resource());
+ if (sub_surface_ && sub_surface_->resource())
+ wl_resource_destroy(sub_surface_->resource());
+ if (viewport_ && viewport_->resource())
+ wl_resource_destroy(viewport_->resource());
}
MockSurface* MockSurface::FromResource(wl_resource* resource) {
diff --git a/chromium/ui/ozone/platform/wayland/test/mock_surface.h b/chromium/ui/ozone/platform/wayland/test/mock_surface.h
index e562a20b144..5c4e5cfb795 100644
--- a/chromium/ui/ozone/platform/wayland/test/mock_surface.h
+++ b/chromium/ui/ozone/platform/wayland/test/mock_surface.h
@@ -15,6 +15,7 @@
#include "ui/ozone/platform/wayland/test/mock_xdg_surface.h"
#include "ui/ozone/platform/wayland/test/server_object.h"
#include "ui/ozone/platform/wayland/test/test_subsurface.h"
+#include "ui/ozone/platform/wayland/test/test_viewport.h"
#include "ui/ozone/platform/wayland/test/test_xdg_popup.h"
struct wl_resource;
@@ -52,6 +53,9 @@ class MockSurface : public ServerObject {
}
TestSubSurface* sub_surface() const { return sub_surface_; }
+ void set_viewport(TestViewport* viewport) { viewport_ = viewport; }
+ TestViewport* viewport() { return viewport_; }
+
void set_frame_callback(wl_resource* callback_resource) {
DCHECK(!frame_callback_);
frame_callback_ = callback_resource;
@@ -70,6 +74,7 @@ class MockSurface : public ServerObject {
private:
MockXdgSurface* xdg_surface_ = nullptr;
TestSubSurface* sub_surface_ = nullptr;
+ TestViewport* viewport_ = nullptr;
wl_resource* frame_callback_ = nullptr;
diff --git a/chromium/ui/ozone/platform/wayland/test/test_viewport.cc b/chromium/ui/ozone/platform/wayland/test/test_viewport.cc
new file mode 100644
index 00000000000..b82e86fd2fe
--- /dev/null
+++ b/chromium/ui/ozone/platform/wayland/test/test_viewport.cc
@@ -0,0 +1,49 @@
+// Copyright 2020 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 "ui/ozone/platform/wayland/test/test_viewport.h"
+
+#include "base/notreached.h"
+#include "ui/ozone/platform/wayland/test/mock_surface.h"
+
+namespace wl {
+
+namespace {
+
+void SetSource(wl_client* client,
+ wl_resource* resource,
+ wl_fixed_t x,
+ wl_fixed_t y,
+ wl_fixed_t width,
+ wl_fixed_t height) {
+ NOTIMPLEMENTED_LOG_ONCE();
+}
+
+void SetDestination(wl_client* client,
+ wl_resource* resource,
+ int32_t x,
+ int32_t y) {
+ NOTIMPLEMENTED_LOG_ONCE();
+}
+
+} // namespace
+
+const struct wp_viewport_interface kTestViewportImpl = {
+ DestroyResource,
+ SetSource,
+ SetDestination,
+};
+
+TestViewport::TestViewport(wl_resource* resource, wl_resource* surface)
+ : ServerObject(resource), surface_(surface) {
+ DCHECK(surface_);
+}
+
+TestViewport::~TestViewport() {
+ auto* mock_surface = GetUserDataAs<MockSurface>(surface_);
+ if (mock_surface)
+ mock_surface->set_viewport(nullptr);
+}
+
+} // namespace wl
diff --git a/chromium/ui/ozone/platform/wayland/test/test_viewport.h b/chromium/ui/ozone/platform/wayland/test/test_viewport.h
new file mode 100644
index 00000000000..0cea33c68e5
--- /dev/null
+++ b/chromium/ui/ozone/platform/wayland/test/test_viewport.h
@@ -0,0 +1,32 @@
+// Copyright 2020 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.
+
+#ifndef UI_OZONE_PLATFORM_WAYLAND_TEST_TEST_VIEWPORT_H_
+#define UI_OZONE_PLATFORM_WAYLAND_TEST_TEST_VIEWPORT_H_
+
+#include <viewporter-server-protocol.h>
+
+#include "ui/ozone/platform/wayland/test/server_object.h"
+
+struct wl_resource;
+
+namespace wl {
+
+extern const struct wp_viewport_interface kTestViewportImpl;
+
+class TestViewport : public ServerObject {
+ public:
+ explicit TestViewport(wl_resource* resource, wl_resource* surface);
+ ~TestViewport() override;
+ TestViewport(const TestViewport& rhs) = delete;
+ TestViewport& operator=(const TestViewport& rhs) = delete;
+
+ private:
+ // Surface resource that is the ground for this Viewport.
+ wl_resource* surface_ = nullptr;
+};
+
+} // namespace wl
+
+#endif // UI_OZONE_PLATFORM_WAYLAND_TEST_TEST_VIEWPORT_H_
diff --git a/chromium/ui/ozone/platform/wayland/test/test_viewporter.cc b/chromium/ui/ozone/platform/wayland/test/test_viewporter.cc
new file mode 100644
index 00000000000..1b44f81105e
--- /dev/null
+++ b/chromium/ui/ozone/platform/wayland/test/test_viewporter.cc
@@ -0,0 +1,53 @@
+// Copyright 2020 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 "ui/ozone/platform/wayland/test/test_viewporter.h"
+
+#include <viewporter-server-protocol.h>
+#include <wayland-server-core.h>
+
+#include "base/check.h"
+#include "ui/ozone/platform/wayland/test/mock_surface.h"
+#include "ui/ozone/platform/wayland/test/test_viewport.h"
+
+namespace wl {
+
+namespace {
+
+constexpr uint32_t kViewporterVersion = 1;
+
+void GetViewport(struct wl_client* client,
+ struct wl_resource* resource,
+ uint32_t id,
+ struct wl_resource* surface) {
+ auto* mock_surface = GetUserDataAs<MockSurface>(surface);
+ if (mock_surface->viewport()) {
+ wl_resource_post_error(resource, WP_VIEWPORTER_ERROR_VIEWPORT_EXISTS,
+ "viewport exists");
+ return;
+ }
+
+ wl_resource* viewport_resource =
+ CreateResourceWithImpl<::testing::NiceMock<TestViewport>>(
+ client, &wp_viewport_interface, wl_resource_get_version(resource),
+ &kTestViewportImpl, id, surface);
+ DCHECK(viewport_resource);
+ mock_surface->set_viewport(GetUserDataAs<TestViewport>(viewport_resource));
+}
+
+} // namespace
+
+const struct wp_viewporter_interface kTestViewporterImpl = {
+ DestroyResource,
+ GetViewport,
+};
+
+TestViewporter::TestViewporter()
+ : GlobalObject(&wp_viewporter_interface,
+ &kTestViewporterImpl,
+ kViewporterVersion) {}
+
+TestViewporter::~TestViewporter() = default;
+
+} // namespace wl
diff --git a/chromium/ui/ozone/platform/wayland/test/test_viewporter.h b/chromium/ui/ozone/platform/wayland/test/test_viewporter.h
new file mode 100644
index 00000000000..6f8281a5686
--- /dev/null
+++ b/chromium/ui/ozone/platform/wayland/test/test_viewporter.h
@@ -0,0 +1,23 @@
+// Copyright 2020 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.
+
+#ifndef UI_OZONE_PLATFORM_WAYLAND_TEST_TEST_VIEWPORTER_H_
+#define UI_OZONE_PLATFORM_WAYLAND_TEST_TEST_VIEWPORTER_H_
+
+#include "ui/ozone/platform/wayland/test/global_object.h"
+
+namespace wl {
+
+// Manage wl_viewporter object.
+class TestViewporter : public GlobalObject {
+ public:
+ TestViewporter();
+ ~TestViewporter() override;
+ TestViewporter(const TestViewporter& rhs) = delete;
+ TestViewporter& operator=(const TestViewporter& rhs) = delete;
+};
+
+} // namespace wl
+
+#endif // UI_OZONE_PLATFORM_WAYLAND_TEST_TEST_VIEWPORTER_H_
diff --git a/chromium/ui/ozone/platform/wayland/test/test_wayland_server_thread.cc b/chromium/ui/ozone/platform/wayland/test/test_wayland_server_thread.cc
index c6f0fe7cabc..6cf79816b5c 100644
--- a/chromium/ui/ozone/platform/wayland/test/test_wayland_server_thread.cc
+++ b/chromium/ui/ozone/platform/wayland/test/test_wayland_server_thread.cc
@@ -58,6 +58,8 @@ bool TestWaylandServerThread::Start(uint32_t shell_version) {
return false;
if (!sub_compositor_.Initialize(display_.get()))
return false;
+ if (!viewporter_.Initialize(display_.get()))
+ return false;
if (!output_.Initialize(display_.get()))
return false;
SetupOutputs();
diff --git a/chromium/ui/ozone/platform/wayland/test/test_wayland_server_thread.h b/chromium/ui/ozone/platform/wayland/test/test_wayland_server_thread.h
index e3d4d489202..712ce602bf1 100644
--- a/chromium/ui/ozone/platform/wayland/test/test_wayland_server_thread.h
+++ b/chromium/ui/ozone/platform/wayland/test/test_wayland_server_thread.h
@@ -22,6 +22,7 @@
#include "ui/ozone/platform/wayland/test/test_output.h"
#include "ui/ozone/platform/wayland/test/test_seat.h"
#include "ui/ozone/platform/wayland/test/test_subcompositor.h"
+#include "ui/ozone/platform/wayland/test/test_viewporter.h"
#include "ui/ozone/platform/wayland/test/test_zwp_text_input_manager.h"
struct wl_client;
@@ -111,6 +112,7 @@ class TestWaylandServerThread : public base::Thread,
// Represent Wayland global objects
TestCompositor compositor_;
TestSubCompositor sub_compositor_;
+ TestViewporter viewporter_;
TestDataDeviceManager data_device_manager_;
TestOutput output_;
TestSeat seat_;
diff --git a/chromium/ui/ozone/platform/wayland/test/wayland_test.cc b/chromium/ui/ozone/platform/wayland/test/wayland_test.cc
index 4ce3ad031cd..b155af688f8 100644
--- a/chromium/ui/ozone/platform/wayland/test/wayland_test.cc
+++ b/chromium/ui/ozone/platform/wayland/test/wayland_test.cc
@@ -4,7 +4,10 @@
#include "ui/ozone/platform/wayland/test/wayland_test.h"
+#include <memory>
+
#include "base/run_loop.h"
+#include "ui/base/ui_base_features.h"
#include "ui/events/ozone/layout/keyboard_layout_engine_manager.h"
#include "ui/events/ozone/layout/scoped_keyboard_layout_engine.h"
#include "ui/ozone/platform/wayland/host/wayland_output_manager.h"
@@ -43,6 +46,15 @@ WaylandTest::WaylandTest()
WaylandTest::~WaylandTest() {}
void WaylandTest::SetUp() {
+ // TODO(1096425): remove this once Ozone is default on Linux. This is required
+ // to be able to run ozone_unittests locally without passing
+ // --enable-features=UseOzonePlatform explicitly. linux-ozone-rel bot does
+ // that automatically through changes done to "variants", which is also
+ // convenient to have locally so that we don't need to worry about that (it's
+ // the Wayland DragAndDrop that relies on the feature).
+ feature_list_.InitAndEnableFeature(features::kUseOzonePlatform);
+ ASSERT_TRUE(features::IsUsingOzonePlatform());
+
ASSERT_TRUE(server_.Start(GetParam()));
ASSERT_TRUE(connection_->Initialize());
screen_ = connection_->wayland_output_manager()->CreateWaylandScreen(
diff --git a/chromium/ui/ozone/platform/wayland/test/wayland_test.h b/chromium/ui/ozone/platform/wayland/test/wayland_test.h
index 97df3efbade..f08e25a4bc3 100644
--- a/chromium/ui/ozone/platform/wayland/test/wayland_test.h
+++ b/chromium/ui/ozone/platform/wayland/test/wayland_test.h
@@ -7,6 +7,7 @@
#include <memory>
+#include "base/test/scoped_feature_list.h"
#include "base/test/task_environment.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/base/buildflags.h"
@@ -82,6 +83,7 @@ class WaylandTest : public ::testing::TestWithParam<uint32_t> {
#endif
std::unique_ptr<KeyboardLayoutEngine> keyboard_layout_engine_;
+ base::test::ScopedFeatureList feature_list_;
DISALLOW_COPY_AND_ASSIGN(WaylandTest);
};
diff --git a/chromium/ui/ozone/platform/x11/ozone_platform_x11.cc b/chromium/ui/ozone/platform/x11/ozone_platform_x11.cc
index 4997e86af1a..3d9e737c0c9 100644
--- a/chromium/ui/ozone/platform/x11/ozone_platform_x11.cc
+++ b/chromium/ui/ozone/platform/x11/ozone_platform_x11.cc
@@ -9,12 +9,14 @@
#include "base/message_loop/message_pump_type.h"
#include "base/metrics/histogram_functions.h"
+#include "base/no_destructor.h"
#include "base/strings/utf_string_conversions.h"
#include "build/build_config.h"
#include "ui/base/buildflags.h"
#include "ui/base/cursor/cursor_factory.h"
#include "ui/base/dragdrop/os_exchange_data_provider_factory.h"
#include "ui/base/dragdrop/os_exchange_data_provider_factory_ozone.h"
+#include "ui/base/ime/linux/linux_input_method_context_factory.h"
#include "ui/base/x/x11_cursor_factory.h"
#include "ui/base/x/x11_error_handler.h"
#include "ui/base/x/x11_util.h"
@@ -43,8 +45,7 @@
#include "ui/base/dragdrop/os_exchange_data_provider_non_backed.h"
#include "ui/base/ime/chromeos/input_method_chromeos.h"
#else
-#include "ui/base/ime/linux/input_method_auralinux.h" // nogncheck
-#include "ui/base/ime/linux/linux_input_method_context_factory.h" // nogncheck
+#include "ui/base/ime/linux/input_method_auralinux.h"
#include "ui/ozone/platform/x11/x11_os_exchange_data_provider_ozone.h"
#endif
@@ -64,26 +65,13 @@ namespace ui {
namespace {
-constexpr OzonePlatform::PlatformProperties kX11PlatformProperties{
- .needs_view_token = false,
- .custom_frame_pref_default = false,
- .use_system_title_bar = true,
-
- // When the Ozone X11 backend is running, use a UI loop to grab Expose
- // events. See GLSurfaceGLX and https://crbug.com/326995.
- .message_pump_type_for_gpu = base::MessagePumpType::UI,
- // When the Ozone X11 backend is running, use a UI loop to dispatch
- // SHM completion events.
- .message_pump_type_for_viz_compositor = base::MessagePumpType::UI,
- .supports_vulkan_swap_chain = true,
- .platform_shows_drag_image = false,
- .supports_global_application_menus = true};
-
// Singleton OzonePlatform implementation for X11 platform.
class OzonePlatformX11 : public OzonePlatform,
public ui::OSExchangeDataProviderFactoryOzone {
public:
- OzonePlatformX11() { SetInstance(this); }
+ OzonePlatformX11() {
+ SetInstance(this);
+ }
~OzonePlatformX11() override {}
@@ -165,7 +153,28 @@ class OzonePlatformX11 : public OzonePlatform,
}
const PlatformProperties& GetPlatformProperties() override {
- return kX11PlatformProperties;
+ static base::NoDestructor<OzonePlatform::PlatformProperties> properties;
+ static bool initialised = false;
+ if (!initialised) {
+ properties->custom_frame_pref_default = ui::GetCustomFramePrefDefault();
+ properties->use_system_title_bar = true;
+
+ // When the Ozone X11 backend is running, use a UI loop to grab Expose
+ // events. See GLSurfaceGLX and https://crbug.com/326995.
+ properties->message_pump_type_for_gpu = base::MessagePumpType::UI;
+ // When the Ozone X11 backend is running, use a UI loop to dispatch
+ // SHM completion events.
+ properties->message_pump_type_for_viz_compositor =
+ base::MessagePumpType::UI;
+ properties->supports_vulkan_swap_chain = true;
+ properties->platform_shows_drag_image = false;
+ properties->supports_global_application_menus = true;
+ properties->app_modal_dialogs_use_event_blocker = true;
+
+ initialised = true;
+ }
+
+ return *properties;
}
void InitializeUI(const InitParams& params) override {
diff --git a/chromium/ui/ozone/platform/x11/x11_canvas_surface.cc b/chromium/ui/ozone/platform/x11/x11_canvas_surface.cc
index ce6c1d8fd1e..7ece6c9954d 100644
--- a/chromium/ui/ozone/platform/x11/x11_canvas_surface.cc
+++ b/chromium/ui/ozone/platform/x11/x11_canvas_surface.cc
@@ -8,11 +8,12 @@
#include "third_party/skia/include/core/SkCanvas.h"
#include "third_party/skia/include/core/SkImageInfo.h"
#include "ui/gfx/vsync_provider.h"
+#include "ui/gfx/x/connection.h"
namespace ui {
X11CanvasSurface::X11CanvasSurface(gfx::AcceleratedWidget widget)
- : x11_software_bitmap_presenter_(widget) {}
+ : x11_software_bitmap_presenter_(x11::Connection::Get(), widget, true) {}
X11CanvasSurface::~X11CanvasSurface() = default;
diff --git a/chromium/ui/ozone/platform/x11/x11_clipboard_ozone.cc b/chromium/ui/ozone/platform/x11/x11_clipboard_ozone.cc
index 16a04768639..9cc7e1bc245 100644
--- a/chromium/ui/ozone/platform/x11/x11_clipboard_ozone.cc
+++ b/chromium/ui/ozone/platform/x11/x11_clipboard_ozone.cc
@@ -16,6 +16,7 @@
#include "ui/gfx/x/x11_atom_cache.h"
#include "ui/gfx/x/x11_types.h"
#include "ui/gfx/x/xproto.h"
+#include "ui/gfx/x/xproto_util.h"
using base::Contains;
@@ -183,8 +184,8 @@ bool X11ClipboardOzone::OnSelectionRequest(
.target = event.target,
.property = event.property,
};
- SendEvent(selection_event, selection_event.requestor,
- x11::EventMask::NoEvent);
+ x11::SendEvent(selection_event, selection_event.requestor,
+ x11::EventMask::NoEvent);
return true;
}
diff --git a/chromium/ui/ozone/platform/x11/x11_screen_ozone.cc b/chromium/ui/ozone/platform/x11/x11_screen_ozone.cc
index 76aeb9e1c14..b98ae4ed908 100644
--- a/chromium/ui/ozone/platform/x11/x11_screen_ozone.cc
+++ b/chromium/ui/ozone/platform/x11/x11_screen_ozone.cc
@@ -10,6 +10,8 @@
#include "ui/events/platform/x11/x11_event_source.h"
#include "ui/gfx/font_render_params.h"
#include "ui/gfx/geometry/dip_util.h"
+#include "ui/gfx/geometry/point_conversions.h"
+#include "ui/gfx/geometry/rect_conversions.h"
#include "ui/gfx/native_widget_types.h"
#include "ui/platform_window/x11/x11_topmost_window_finder.h"
#include "ui/platform_window/x11/x11_window.h"
@@ -29,10 +31,6 @@ float GetDeviceScaleFactor() {
return device_scale_factor;
}
-gfx::Point PixelToDIPPoint(const gfx::Point& pixel_point) {
- return gfx::ConvertPointToDIP(GetDeviceScaleFactor(), pixel_point);
-}
-
} // namespace
X11ScreenOzone::X11ScreenOzone()
@@ -74,14 +72,20 @@ display::Display X11ScreenOzone::GetDisplayForAcceleratedWidget(
}
gfx::Point X11ScreenOzone::GetCursorScreenPoint() const {
+ base::Optional<gfx::Point> point_in_pixels;
if (ui::X11EventSource::HasInstance()) {
- base::Optional<gfx::Point> point =
- ui::X11EventSource::GetInstance()
- ->GetRootCursorLocationFromCurrentEvent();
- if (point)
- return PixelToDIPPoint(point.value());
+ point_in_pixels = ui::X11EventSource::GetInstance()
+ ->GetRootCursorLocationFromCurrentEvent();
+ }
+ if (!point_in_pixels) {
+ // This call is expensive so we explicitly only call it when
+ // |point_in_pixels| is not set. We note that base::Optional::value_or()
+ // would cause it to be called regardless.
+ point_in_pixels = GetCursorLocation();
}
- return PixelToDIPPoint(GetCursorLocation());
+ // TODO(danakj): Should this be rounded? Or kept as a floating point?
+ return gfx::ToFlooredPoint(
+ gfx::ConvertPointToDips(*point_in_pixels, GetDeviceScaleFactor()));
}
gfx::AcceleratedWidget X11ScreenOzone::GetAcceleratedWidgetAtScreenPoint(
@@ -107,14 +111,19 @@ display::Display X11ScreenOzone::GetDisplayNearestPoint(
}
display::Display X11ScreenOzone::GetDisplayMatching(
- const gfx::Rect& match_rect) const {
+ const gfx::Rect& match_rect_in_pixels) const {
+ gfx::Rect match_rect = gfx::ToEnclosingRect(
+ gfx::ConvertRectToDips(match_rect_in_pixels, GetDeviceScaleFactor()));
const display::Display* matching_display =
display::FindDisplayWithBiggestIntersection(
- x11_display_manager_->displays(),
- gfx::ConvertRectToDIP(GetDeviceScaleFactor(), match_rect));
+ x11_display_manager_->displays(), match_rect);
return matching_display ? *matching_display : GetPrimaryDisplay();
}
+void X11ScreenOzone::SetScreenSaverSuspended(bool suspend) {
+ SuspendX11ScreenSaver(suspend);
+}
+
void X11ScreenOzone::AddObserver(display::DisplayObserver* observer) {
x11_display_manager_->AddObserver(observer);
}
diff --git a/chromium/ui/ozone/platform/x11/x11_screen_ozone.h b/chromium/ui/ozone/platform/x11/x11_screen_ozone.h
index de7d392d17b..6aba14834f3 100644
--- a/chromium/ui/ozone/platform/x11/x11_screen_ozone.h
+++ b/chromium/ui/ozone/platform/x11/x11_screen_ozone.h
@@ -46,7 +46,8 @@ class X11ScreenOzone : public PlatformScreen,
display::Display GetDisplayNearestPoint(
const gfx::Point& point) const override;
display::Display GetDisplayMatching(
- const gfx::Rect& match_rect) const override;
+ const gfx::Rect& match_rect_in_pixels) const override;
+ void SetScreenSaverSuspended(bool suspend) override;
void AddObserver(display::DisplayObserver* observer) override;
void RemoveObserver(display::DisplayObserver* observer) override;
std::string GetCurrentWorkspace() override;
diff --git a/chromium/ui/ozone/platform_selection.cc b/chromium/ui/ozone/platform_selection.cc
index 1b49a08af70..eb8e85edba6 100644
--- a/chromium/ui/ozone/platform_selection.cc
+++ b/chromium/ui/ozone/platform_selection.cc
@@ -33,6 +33,9 @@ int GetOzonePlatformId() {
return g_selected_platform;
std::string platform_name = GetPlatformName();
+ // TODO(b/169115289) remove once all Tast tests use "drm".
+ if (platform_name == "gbm")
+ platform_name = "drm";
// Search for a matching platform in the list.
for (int platform_id = 0; platform_id < kPlatformCount; ++platform_id) {
diff --git a/chromium/ui/ozone/public/input_controller.cc b/chromium/ui/ozone/public/input_controller.cc
index 43a27b43952..43e5fca8d2e 100644
--- a/chromium/ui/ozone/public/input_controller.cc
+++ b/chromium/ui/ozone/public/input_controller.cc
@@ -21,6 +21,7 @@ class StubInputController : public InputController {
// InputController:
bool HasMouse() override { return false; }
+ bool HasPointingStick() override { return false; }
bool HasTouchpad() override { return false; }
bool IsCapsLockEnabled() override { return false; }
void SetCapsLockEnabled(bool enabled) override {}
diff --git a/chromium/ui/ozone/public/input_controller.h b/chromium/ui/ozone/public/input_controller.h
index cbf94825a32..27b5ad3acd8 100644
--- a/chromium/ui/ozone/public/input_controller.h
+++ b/chromium/ui/ozone/public/input_controller.h
@@ -43,6 +43,7 @@ class COMPONENT_EXPORT(OZONE_BASE) InputController {
// Functions for checking devices existence.
virtual bool HasMouse() = 0;
+ virtual bool HasPointingStick() = 0;
virtual bool HasTouchpad() = 0;
// Keyboard settings.
diff --git a/chromium/ui/ozone/public/mojom/drm_device.mojom b/chromium/ui/ozone/public/mojom/drm_device.mojom
index 6504ea5dddd..caf4a7e5a7b 100644
--- a/chromium/ui/ozone/public/mojom/drm_device.mojom
+++ b/chromium/ui/ozone/public/mojom/drm_device.mojom
@@ -57,11 +57,16 @@ interface DrmDevice {
array<display.mojom.DisplayConfigurationParams> config_requests) =>
(map<int64, bool> statuses);
- // Gets or sets high-definition content protection (HDCP) (DRM as in
+ // Gets high-definition content protection (HDCP) (DRM as in
// digital rights management) state.
GetHDCPState(int64 display_id) =>
- (int64 display_id, bool success, display.mojom.HDCPState state);
- SetHDCPState(int64 display_id, display.mojom.HDCPState state) =>
+ (int64 display_id, bool success, display.mojom.HDCPState state,
+ display.mojom.ContentProtectionMethod protection_method);
+
+ // Sets high-definition content protection (HDCP) (DRM as in
+ // digital rights management) state.
+ SetHDCPState(int64 display_id, display.mojom.HDCPState state,
+ display.mojom.ContentProtectionMethod protection_method) =>
(int64 display_id, bool success);
// Sets a 3x3 color transform matrix on the display hardware.
diff --git a/chromium/ui/ozone/public/ozone_platform.cc b/chromium/ui/ozone/public/ozone_platform.cc
index c7027b208f0..bcc577c5494 100644
--- a/chromium/ui/ozone/public/ozone_platform.cc
+++ b/chromium/ui/ozone/public/ozone_platform.cc
@@ -36,6 +36,9 @@ void EnsureInstance() {
} // namespace
+OzonePlatform::PlatformProperties::PlatformProperties() = default;
+OzonePlatform::PlatformProperties::~PlatformProperties() = default;
+
OzonePlatform::OzonePlatform() {
DCHECK(!g_instance) << "There should only be a single OzonePlatform.";
g_instance = this;
diff --git a/chromium/ui/ozone/public/ozone_platform.h b/chromium/ui/ozone/public/ozone_platform.h
index 797c79d057e..764945ed097 100644
--- a/chromium/ui/ozone/public/ozone_platform.h
+++ b/chromium/ui/ozone/public/ozone_platform.h
@@ -70,6 +70,11 @@ class COMPONENT_EXPORT(OZONE) OzonePlatform {
// Struct used to indicate platform properties.
struct PlatformProperties {
+ PlatformProperties();
+ PlatformProperties(const PlatformProperties& other) = delete;
+ PlatformProperties& operator=(const PlatformProperties& other) = delete;
+ ~PlatformProperties();
+
// Fuchsia only: set to true when the platforms requires |view_token| field
// in PlatformWindowInitProperties when creating a window.
bool needs_view_token = false;
@@ -105,6 +110,10 @@ class COMPONENT_EXPORT(OZONE) OzonePlatform {
// Linux only, but see a TODO in BrowserDesktopWindowTreeHostLinux.
// Determines whether the platform supports the global application menu.
bool supports_global_application_menus = false;
+
+ // Determines if the application modal dialogs should use the event blocker
+ // to allow the only browser window receiving UI events.
+ bool app_modal_dialogs_use_event_blocker = false;
};
// Properties available in the host process after initialization.
diff --git a/chromium/ui/ozone/public/platform_screen.cc b/chromium/ui/ozone/public/platform_screen.cc
index c2440a5b237..8b58cf95caa 100644
--- a/chromium/ui/ozone/public/platform_screen.cc
+++ b/chromium/ui/ozone/public/platform_screen.cc
@@ -23,4 +23,8 @@ std::string PlatformScreen::GetCurrentWorkspace() {
return {};
}
+void PlatformScreen::SetScreenSaverSuspended(bool suspend) {
+ NOTIMPLEMENTED_LOG_ONCE();
+}
+
} // namespace ui
diff --git a/chromium/ui/ozone/public/platform_screen.h b/chromium/ui/ozone/public/platform_screen.h
index ba20597d8c5..71cc12c195b 100644
--- a/chromium/ui/ozone/public/platform_screen.h
+++ b/chromium/ui/ozone/public/platform_screen.h
@@ -77,6 +77,9 @@ class COMPONENT_EXPORT(OZONE_BASE) PlatformScreen {
virtual display::Display GetDisplayMatching(
const gfx::Rect& match_rect) const = 0;
+ // Suspends the platform-specific screensaver, if applicable.
+ virtual void SetScreenSaverSuspended(bool suspend);
+
// Adds/Removes display observers.
virtual void AddObserver(display::DisplayObserver* observer) = 0;
virtual void RemoveObserver(display::DisplayObserver* observer) = 0;