diff options
author | Allan Sandfeld Jensen <allan.jensen@qt.io> | 2020-07-16 11:45:35 +0200 |
---|---|---|
committer | Allan Sandfeld Jensen <allan.jensen@qt.io> | 2020-07-17 08:59:23 +0000 |
commit | 552906b0f222c5d5dd11b9fd73829d510980461a (patch) | |
tree | 3a11e6ed0538a81dd83b20cf3a4783e297f26d91 /chromium/ui/ozone | |
parent | 1b05827804eaf047779b597718c03e7d38344261 (diff) | |
download | qtwebengine-chromium-552906b0f222c5d5dd11b9fd73829d510980461a.tar.gz |
BASELINE: Update Chromium to 83.0.4103.122
Change-Id: Ie3a82f5bb0076eec2a7c6a6162326b4301ee291e
Reviewed-by: Michael BrĂ¼ning <michael.bruning@qt.io>
Diffstat (limited to 'chromium/ui/ozone')
259 files changed, 5966 insertions, 4404 deletions
diff --git a/chromium/ui/ozone/BUILD.gn b/chromium/ui/ozone/BUILD.gn index bd18c574998..7e53cb2a7ac 100644 --- a/chromium/ui/ozone/BUILD.gn +++ b/chromium/ui/ozone/BUILD.gn @@ -85,6 +85,7 @@ jumbo_component("ozone_base") { "public/ozone_switches.cc", "public/ozone_switches.h", "public/platform_clipboard.h", + "public/platform_screen.cc", "public/platform_screen.h", "public/platform_window_surface.h", "public/surface_factory_ozone.cc", @@ -103,6 +104,7 @@ jumbo_component("ozone_base") { "//ipc", "//skia", "//ui/base/clipboard:clipboard_types", + "//ui/base/mojom:cursor_type", "//ui/display", "//ui/display/types", "//ui/display/util", @@ -126,6 +128,7 @@ jumbo_component("ozone_base") { # Everyone should depend on //ui/ozone instead except a handful of # things that would otherwise create a cycle. "//ui/base", + "//ui/base/cursor", "//ui/events/ozone/*", "//ui/ozone/common/*", "//ui/ozone/public/mojom", @@ -220,20 +223,15 @@ jumbo_source_set("test_support_internal") { "//testing/gtest", "//ui/gfx:test_support", "//ui/gfx/geometry", - "//ui/ozone/public/mojom:mojom_trait_unit_test", "//ui/platform_window:platform_window", ] - public_deps = [ - "//base/test:test_support", - ] + public_deps = [ "//base/test:test_support" ] } jumbo_static_library("test_support") { testonly = true - public_deps = [ - ":test_support_internal", - ] + public_deps = [ ":test_support_internal" ] } action("generate_ozone_platform_list") { @@ -258,12 +256,8 @@ action("generate_ozone_platform_list") { action("generate_constructor_list") { script = "generate_constructor_list.py" - inputs = [ - platform_list_txt_file, - ] - outputs = [ - constructor_list_cc_file, - ] + inputs = [ platform_list_txt_file ] + outputs = [ constructor_list_cc_file ] args = [ "--platform_list=" + rebase_path(platform_list_txt_file, root_build_dir), @@ -276,15 +270,11 @@ action("generate_constructor_list") { "--include=\"ui/ozone/public/ozone_platform.h\"", ] - deps = [ - ":generate_ozone_platform_list", - ] + deps = [ ":generate_ozone_platform_list" ] } test("ozone_unittests") { - deps = [ - ":test_support", - ] + deps = [ ":test_support" ] # Add tests of platform internals. deps += ozone_platform_test_deps @@ -293,18 +283,14 @@ test("ozone_unittests") { # 2nd copy of any code via the component. assert_no_deps = [ "//ui/ozone" ] - data_deps = [ - "//testing/buildbot/filters:ozone_unittests_filters", - ] + data_deps = [ "//testing/buildbot/filters:ozone_unittests_filters" ] } # X11 backend has its own test suite only built when we are using the x11 # backend. if (ozone_platform_x11) { test("ozone_x11_unittests") { - deps = [ - ":test_support", - ] + deps = [ ":test_support" ] deps += [ "platform/x11:x11_unittests" ] diff --git a/chromium/ui/ozone/common/BUILD.gn b/chromium/ui/ozone/common/BUILD.gn index 562057e9bdd..05f34b34014 100644 --- a/chromium/ui/ozone/common/BUILD.gn +++ b/chromium/ui/ozone/common/BUILD.gn @@ -24,9 +24,7 @@ source_set("common") { "stub_overlay_manager.h", ] - public_deps = [ - "//ui/ozone:ozone_base", - ] + public_deps = [ "//ui/ozone:ozone_base" ] deps = [ "//ui/gfx/ipc/color", @@ -34,9 +32,7 @@ source_set("common") { "//ui/gl:buildflags", ] - data_deps = [ - "//third_party/mesa_headers", - ] + data_deps = [ "//third_party/mesa_headers" ] visibility = [ "//ui/ozone/platform/*" ] diff --git a/chromium/ui/ozone/common/gl_ozone_egl.cc b/chromium/ui/ozone/common/gl_ozone_egl.cc index b9f6aa7213a..7c2758ca8b8 100644 --- a/chromium/ui/ozone/common/gl_ozone_egl.cc +++ b/chromium/ui/ozone/common/gl_ozone_egl.cc @@ -35,11 +35,6 @@ bool GLOzoneEGL::InitializeStaticGLBindings( return true; } -void GLOzoneEGL::InitializeLogGLBindings() { - gl::InitializeLogGLBindingsGL(); - gl::InitializeLogGLBindingsEGL(); -} - void GLOzoneEGL::SetDisabledExtensionsPlatform( const std::string& disabled_extensions) { gl::SetDisabledExtensionsEGL(disabled_extensions); diff --git a/chromium/ui/ozone/common/gl_ozone_egl.h b/chromium/ui/ozone/common/gl_ozone_egl.h index e2889bf50b9..ec8768347c3 100644 --- a/chromium/ui/ozone/common/gl_ozone_egl.h +++ b/chromium/ui/ozone/common/gl_ozone_egl.h @@ -9,6 +9,7 @@ #include "base/macros.h" #include "third_party/khronos/EGL/eglplatform.h" #include "ui/gl/gl_implementation.h" +#include "ui/gl/gl_surface_egl.h" #include "ui/ozone/public/gl_ozone.h" namespace ui { @@ -22,7 +23,6 @@ class GLOzoneEGL : public GLOzone { // GLOzone: bool InitializeGLOneOffPlatform() override; bool InitializeStaticGLBindings(gl::GLImplementation implementation) override; - void InitializeLogGLBindings() override; void SetDisabledExtensionsPlatform( const std::string& disabled_extensions) override; bool InitializeExtensionSettingsOneOffPlatform() override; @@ -42,9 +42,10 @@ class GLOzoneEGL : public GLOzone { const gfx::Size& size) override = 0; protected: - // Returns native platform display handle. This is used to obtain the EGL - // display connection for the native display. - virtual EGLNativeDisplayType GetNativeDisplay() = 0; + // Returns native platform display handle and platform type as per + // EGL platform extensions. + // This is used to obtain the EGL display connection for the native display. + virtual gl::EGLDisplayPlatform GetNativeDisplay() = 0; // Sets up GL bindings for the native surface. virtual bool LoadGLES2Bindings(gl::GLImplementation implementation) = 0; diff --git a/chromium/ui/ozone/common/gl_surface_egl_readback.cc b/chromium/ui/ozone/common/gl_surface_egl_readback.cc index fd21b8926d6..4f15ad6fb0d 100644 --- a/chromium/ui/ozone/common/gl_surface_egl_readback.cc +++ b/chromium/ui/ozone/common/gl_surface_egl_readback.cc @@ -23,7 +23,7 @@ GLSurfaceEglReadback::GLSurfaceEglReadback() bool GLSurfaceEglReadback::Resize(const gfx::Size& size, float scale_factor, - ColorSpace color_space, + const gfx::ColorSpace& color_space, bool has_alpha) { pixels_.reset(); @@ -62,8 +62,8 @@ gfx::SwapResult GLSurfaceEglReadback::SwapBuffers( return swap_result; } -bool GLSurfaceEglReadback::FlipsVertically() const { - return true; +gfx::SurfaceOrigin GLSurfaceEglReadback::GetOrigin() const { + return gfx::SurfaceOrigin::kTopLeft; } GLSurfaceEglReadback::~GLSurfaceEglReadback() { diff --git a/chromium/ui/ozone/common/gl_surface_egl_readback.h b/chromium/ui/ozone/common/gl_surface_egl_readback.h index c985eb52338..d25c12da865 100644 --- a/chromium/ui/ozone/common/gl_surface_egl_readback.h +++ b/chromium/ui/ozone/common/gl_surface_egl_readback.h @@ -28,11 +28,11 @@ class GLSurfaceEglReadback : public gl::PbufferGLSurfaceEGL { // GLSurface implementation. bool Resize(const gfx::Size& size, float scale_factor, - ColorSpace color_space, + const gfx::ColorSpace& color_space, bool has_alpha) override; bool IsOffscreen() override; gfx::SwapResult SwapBuffers(PresentationCallback callback) override; - bool FlipsVertically() const override; + gfx::SurfaceOrigin GetOrigin() const override; // TODO(kylechar): Implement SupportsPostSubBuffer() and PostSubBuffer(). diff --git a/chromium/ui/ozone/common/gpu/ozone_gpu_message_params.cc b/chromium/ui/ozone/common/gpu/ozone_gpu_message_params.cc index 72d40a9990d..48aaeefd2ca 100644 --- a/chromium/ui/ozone/common/gpu/ozone_gpu_message_params.cc +++ b/chromium/ui/ozone/common/gpu/ozone_gpu_message_params.cc @@ -7,7 +7,6 @@ #include "ui/gfx/geometry/rect_conversions.h" #include "ui/gfx/ipc/gfx_param_traits.h" #include "ui/gfx/ipc/skia/gfx_skia_param_traits.h" -#include "ui/ozone/public/overlay_surface_candidate.h" namespace ui { @@ -22,22 +21,4 @@ DisplaySnapshot_Params::DisplaySnapshot_Params( DisplaySnapshot_Params::~DisplaySnapshot_Params() {} -OverlayCheck_Params::OverlayCheck_Params() {} - -OverlayCheck_Params::OverlayCheck_Params( - const ui::OverlaySurfaceCandidate& candidate) - : buffer_size(candidate.buffer_size), - transform(candidate.transform), - format(candidate.format), - display_rect(gfx::ToNearestRect(candidate.display_rect)), - crop_rect(candidate.crop_rect), - is_opaque(candidate.is_opaque), - plane_z_order(candidate.plane_z_order), - is_overlay_candidate(candidate.overlay_handled) {} - -OverlayCheck_Params::OverlayCheck_Params(const OverlayCheck_Params& other) = - default; - -OverlayCheck_Params::~OverlayCheck_Params() {} - } // namespace ui diff --git a/chromium/ui/ozone/common/gpu/ozone_gpu_message_params.h b/chromium/ui/ozone/common/gpu/ozone_gpu_message_params.h index efd3ceb7cbc..128252e7d26 100644 --- a/chromium/ui/ozone/common/gpu/ozone_gpu_message_params.h +++ b/chromium/ui/ozone/common/gpu/ozone_gpu_message_params.h @@ -16,12 +16,8 @@ #include "ui/gfx/color_space.h" #include "ui/gfx/geometry/point.h" #include "ui/gfx/geometry/size.h" -#include "ui/gfx/overlay_transform.h" -#include "ui/ozone/public/overlay_candidates_ozone.h" -#include "ui/ozone/public/overlay_surface_candidate.h" namespace ui { -class OverlaySurfaceCandidate; struct DisplayMode_Params { DisplayMode_Params(); @@ -43,6 +39,8 @@ struct DisplaySnapshot_Params { display::DisplayConnectionType type = display::DISPLAY_CONNECTION_TYPE_NONE; bool is_aspect_preserving_scaling = false; bool has_overscan = false; + display::PrivacyScreenState privacy_screen_state = + display::PrivacyScreenState::kNotSupported; bool has_color_correction_matrix = false; bool color_correction_in_linear_space = false; gfx::ColorSpace color_space; @@ -62,31 +60,6 @@ struct DisplaySnapshot_Params { gfx::Size maximum_cursor_size; }; -struct OverlayCheck_Params { - OverlayCheck_Params(); - OverlayCheck_Params(const OverlaySurfaceCandidate& candidate); - OverlayCheck_Params(const OverlayCheck_Params& other); - ~OverlayCheck_Params(); - - gfx::Size buffer_size; - gfx::OverlayTransform transform = gfx::OVERLAY_TRANSFORM_NONE; - gfx::BufferFormat format = gfx::BufferFormat::BGRA_8888; - gfx::Rect display_rect; - gfx::RectF crop_rect; - bool is_opaque = false; - int plane_z_order = 0; - // By default we mark this configuration valid for promoting it to an overlay. - bool is_overlay_candidate = true; -}; - -struct OverlayCheckReturn_Params { - OverlayCheckReturn_Params() = default; - OverlayCheckReturn_Params(const OverlayCheckReturn_Params& other) = default; - ~OverlayCheckReturn_Params() = default; - - OverlayStatus status = OVERLAY_STATUS_PENDING; -}; - } // namespace ui #endif // UI_OZONE_COMMON_GPU_OZONE_GPU_MESSAGE_PARAMS_H_ diff --git a/chromium/ui/ozone/common/gpu/ozone_gpu_messages.h b/chromium/ui/ozone/common/gpu/ozone_gpu_messages.h index fd9813f25c2..74caeb476cb 100644 --- a/chromium/ui/ozone/common/gpu/ozone_gpu_messages.h +++ b/chromium/ui/ozone/common/gpu/ozone_gpu_messages.h @@ -5,6 +5,7 @@ // Multiply-included message file, hence no include guard here, but see below // for a much smaller-than-usual include guard section. // no-include-guard-because-multiply-included +// NOLINT(build/header_guard) #include <stdint.h> @@ -38,9 +39,8 @@ IPC_ENUM_TRAITS_MAX_VALUE(display::HDCPState, display::HDCP_STATE_LAST) IPC_ENUM_TRAITS_MAX_VALUE(display::PanelOrientation, display::PanelOrientation::kLast) -IPC_ENUM_TRAITS_MAX_VALUE(gfx::OverlayTransform, gfx::OVERLAY_TRANSFORM_LAST) - -IPC_ENUM_TRAITS_MAX_VALUE(ui::OverlayStatus, ui::OVERLAY_STATUS_LAST) +IPC_ENUM_TRAITS_MAX_VALUE(display::PrivacyScreenState, + display::PrivacyScreenState::kPrivacyScreenStateLast) // clang-format off IPC_STRUCT_TRAITS_BEGIN(ui::DisplayMode_Params) @@ -56,6 +56,7 @@ IPC_STRUCT_TRAITS_BEGIN(ui::DisplaySnapshot_Params) IPC_STRUCT_TRAITS_MEMBER(type) IPC_STRUCT_TRAITS_MEMBER(is_aspect_preserving_scaling) IPC_STRUCT_TRAITS_MEMBER(has_overscan) + IPC_STRUCT_TRAITS_MEMBER(privacy_screen_state) IPC_STRUCT_TRAITS_MEMBER(has_color_correction_matrix) IPC_STRUCT_TRAITS_MEMBER(color_correction_in_linear_space) IPC_STRUCT_TRAITS_MEMBER(color_space) @@ -79,22 +80,6 @@ IPC_STRUCT_TRAITS_BEGIN(display::GammaRampRGBEntry) IPC_STRUCT_TRAITS_MEMBER(g) IPC_STRUCT_TRAITS_MEMBER(b) IPC_STRUCT_TRAITS_END() - -IPC_STRUCT_TRAITS_BEGIN(ui::OverlayCheck_Params) - IPC_STRUCT_TRAITS_MEMBER(buffer_size) - IPC_STRUCT_TRAITS_MEMBER(transform) - IPC_STRUCT_TRAITS_MEMBER(format) - IPC_STRUCT_TRAITS_MEMBER(display_rect) - IPC_STRUCT_TRAITS_MEMBER(crop_rect) - IPC_STRUCT_TRAITS_MEMBER(is_opaque) - IPC_STRUCT_TRAITS_MEMBER(plane_z_order) - IPC_STRUCT_TRAITS_MEMBER(is_overlay_candidate) -IPC_STRUCT_TRAITS_END() - -IPC_STRUCT_TRAITS_BEGIN(ui::OverlayCheckReturn_Params) - IPC_STRUCT_TRAITS_MEMBER(status) -IPC_STRUCT_TRAITS_END() - // clang-format on //------------------------------------------------------------------------------ @@ -170,10 +155,10 @@ IPC_MESSAGE_CONTROL3(OzoneGpuMsg_SetGammaCorrection, std::vector<display::GammaRampRGBEntry>, // Degamma lut std::vector<display::GammaRampRGBEntry>) // Gamma lut -IPC_MESSAGE_CONTROL2(OzoneGpuMsg_CheckOverlayCapabilities, - gfx::AcceleratedWidget /* widget */, - std::vector<ui::OverlayCheck_Params> /* overlays */) - +// Set the privacy screen state of the display with |display_id| +IPC_MESSAGE_CONTROL2(OzoneGpuMsg_SetPrivacyScreen, + int64_t /* display_id */, + bool /* enabled */) //------------------------------------------------------------------------------ // Browser Messages // These messages are from the GPU to the browser process. @@ -203,10 +188,3 @@ IPC_MESSAGE_CONTROL1(OzoneHostMsg_DisplayControlTaken, bool /* success */) // Response to OzoneGpuMsg_RelinquishDisplayControl. IPC_MESSAGE_CONTROL1(OzoneHostMsg_DisplayControlRelinquished, bool /* success */) - -// Response to OzoneGpuMsg_CheckOverlayCapabilities. Returns list of supported -// params. -IPC_MESSAGE_CONTROL3(OzoneHostMsg_OverlayCapabilitiesReceived, - gfx::AcceleratedWidget /* widget */, - std::vector<ui::OverlayCheck_Params> /* overlays */, - std::vector<ui::OverlayCheckReturn_Params> /* returns */) diff --git a/chromium/ui/ozone/common/linux/BUILD.gn b/chromium/ui/ozone/common/linux/BUILD.gn deleted file mode 100644 index 7628646fe97..00000000000 --- a/chromium/ui/ozone/common/linux/BUILD.gn +++ /dev/null @@ -1,42 +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. - -import("//build/config/ui.gni") -import("//ui/ozone/ozone.gni") - -assert(ozone_platform_gbm || ozone_platform_wayland) - -source_set("drm") { - sources = [ - "drm_util_linux.cc", - "drm_util_linux.h", - ] - - deps = [ - "//base:base", - "//build/config/linux/libdrm", - "//ui/gfx:buffer_types", - ] -} - -source_set("gbm") { - sources = [ - "gbm_buffer.h", - "gbm_device.h", - "gbm_wrapper.cc", - "scoped_gbm_device.cc", - "scoped_gbm_device.h", - ] - - deps = [ - ":drm", - "//base:base", - "//build/config/linux/libdrm", - "//third_party/minigbm", - "//ui/gfx:buffer_types", - "//ui/gfx:memory_buffer", - "//ui/gfx/geometry:geometry", - "//ui/ozone:ozone_base", - ] -} diff --git a/chromium/ui/ozone/common/linux/OWNERS b/chromium/ui/ozone/common/linux/OWNERS deleted file mode 100644 index d047913b027..00000000000 --- a/chromium/ui/ozone/common/linux/OWNERS +++ /dev/null @@ -1,3 +0,0 @@ -dcastagna@chromium.org -dnicoara@chromium.org -msisov@igalia.com diff --git a/chromium/ui/ozone/common/linux/drm_util_linux.cc b/chromium/ui/ozone/common/linux/drm_util_linux.cc deleted file mode 100644 index 7cb7b4ebe5d..00000000000 --- a/chromium/ui/ozone/common/linux/drm_util_linux.cc +++ /dev/null @@ -1,111 +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/common/linux/drm_util_linux.h" - -#include <drm_fourcc.h> - -#include "base/logging.h" - -#ifndef DRM_FORMAT_INVALID -// TODO(mcasas): Remove when uprevving //third_party/libdrm. -#define DRM_FORMAT_INVALID 0 -#endif - -#ifndef DRM_FORMAT_P010 -#define DRM_FORMAT_P010 fourcc_code('P', '0', '1', '0') -#endif - -namespace ui { - -int GetFourCCFormatFromBufferFormat(gfx::BufferFormat format) { - switch (format) { - case gfx::BufferFormat::R_8: - return DRM_FORMAT_R8; - case gfx::BufferFormat::R_16: - return DRM_FORMAT_R16; - case gfx::BufferFormat::RG_88: - return DRM_FORMAT_GR88; - case gfx::BufferFormat::BGR_565: - return DRM_FORMAT_RGB565; - case gfx::BufferFormat::RGBA_4444: - return DRM_FORMAT_INVALID; - case gfx::BufferFormat::RGBA_8888: - return DRM_FORMAT_ABGR8888; - case gfx::BufferFormat::RGBX_8888: - return DRM_FORMAT_XBGR8888; - case gfx::BufferFormat::BGRA_8888: - return DRM_FORMAT_ARGB8888; - case gfx::BufferFormat::BGRX_8888: - return DRM_FORMAT_XRGB8888; - case gfx::BufferFormat::BGRX_1010102: - return DRM_FORMAT_XRGB2101010; - case gfx::BufferFormat::RGBX_1010102: - return DRM_FORMAT_XBGR2101010; - case gfx::BufferFormat::RGBA_F16: - return DRM_FORMAT_INVALID; - case gfx::BufferFormat::YVU_420: - return DRM_FORMAT_YVU420; - case gfx::BufferFormat::YUV_420_BIPLANAR: - return DRM_FORMAT_NV12; - case gfx::BufferFormat::P010: - return DRM_FORMAT_P010; - } - return DRM_FORMAT_INVALID; -} - -gfx::BufferFormat GetBufferFormatFromFourCCFormat(int format) { - switch (format) { - case DRM_FORMAT_R8: - return gfx::BufferFormat::R_8; - case DRM_FORMAT_GR88: - return gfx::BufferFormat::RG_88; - case DRM_FORMAT_ABGR8888: - return gfx::BufferFormat::RGBA_8888; - case DRM_FORMAT_XBGR8888: - return gfx::BufferFormat::RGBX_8888; - case DRM_FORMAT_ARGB8888: - return gfx::BufferFormat::BGRA_8888; - case DRM_FORMAT_XRGB8888: - return gfx::BufferFormat::BGRX_8888; - case DRM_FORMAT_XRGB2101010: - return gfx::BufferFormat::BGRX_1010102; - case DRM_FORMAT_XBGR2101010: - return gfx::BufferFormat::RGBX_1010102; - case DRM_FORMAT_RGB565: - return gfx::BufferFormat::BGR_565; - case DRM_FORMAT_NV12: - return gfx::BufferFormat::YUV_420_BIPLANAR; - case DRM_FORMAT_YVU420: - return gfx::BufferFormat::YVU_420; - case DRM_FORMAT_P010: - return gfx::BufferFormat::P010; - default: - NOTREACHED(); - return gfx::BufferFormat::BGRA_8888; - } -} - -bool IsValidBufferFormat(uint32_t current_format) { - switch (current_format) { - case DRM_FORMAT_R8: - case DRM_FORMAT_GR88: - case DRM_FORMAT_ABGR8888: - case DRM_FORMAT_XBGR8888: - case DRM_FORMAT_ARGB8888: - case DRM_FORMAT_XRGB8888: - case DRM_FORMAT_XRGB2101010: - case DRM_FORMAT_XBGR2101010: - case DRM_FORMAT_RGB565: - case DRM_FORMAT_NV12: - case DRM_FORMAT_YVU420: - case DRM_FORMAT_P010: - return true; - default: - return false; - } - return false; -} - -} // namespace ui diff --git a/chromium/ui/ozone/common/linux/drm_util_linux.h b/chromium/ui/ozone/common/linux/drm_util_linux.h deleted file mode 100644 index 78705b910e7..00000000000 --- a/chromium/ui/ozone/common/linux/drm_util_linux.h +++ /dev/null @@ -1,20 +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_COMMON_LINUX_DRM_UTIL_LINUX_H_ -#define UI_OZONE_COMMON_LINUX_DRM_UTIL_LINUX_H_ - -#include "ui/gfx/buffer_types.h" - -namespace ui { - -int GetFourCCFormatFromBufferFormat(gfx::BufferFormat format); -gfx::BufferFormat GetBufferFormatFromFourCCFormat(int format); - -// Returns true if the fourcc format is known. -bool IsValidBufferFormat(uint32_t current_format); - -} // namespace ui - -#endif // UI_OZONE_COMMON_LINUX_DRM_UTIL_LINUX_H__ diff --git a/chromium/ui/ozone/common/linux/gbm_buffer.h b/chromium/ui/ozone/common/linux/gbm_buffer.h deleted file mode 100644 index 2c7d8039fb1..00000000000 --- a/chromium/ui/ozone/common/linux/gbm_buffer.h +++ /dev/null @@ -1,44 +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_COMMON_LINUX_GBM_BUFFER_H_ -#define UI_OZONE_COMMON_LINUX_GBM_BUFFER_H_ - -#include <inttypes.h> - -#include "third_party/skia/include/core/SkRefCnt.h" -#include "ui/gfx/buffer_types.h" -#include "ui/gfx/geometry/size.h" -#include "ui/gfx/native_pixmap_handle.h" - -class SkSurface; - -namespace ui { - -class GbmBuffer { - public: - virtual ~GbmBuffer() {} - - virtual uint32_t GetFormat() const = 0; - virtual uint64_t GetFormatModifier() const = 0; - virtual uint32_t GetFlags() const = 0; - // TODO(reveman): This should not be needed once crbug.com/597932 is - // fixed, as the size would be queried directly from the underlying bo. - virtual gfx::Size GetSize() const = 0; - virtual gfx::BufferFormat GetBufferFormat() const = 0; - virtual bool AreFdsValid() const = 0; - virtual size_t GetNumPlanes() const = 0; - virtual int GetPlaneFd(size_t plane) const = 0; - virtual uint32_t GetPlaneHandle(size_t plane) const = 0; - virtual uint32_t GetPlaneStride(size_t plane) const = 0; - virtual size_t GetPlaneOffset(size_t plane) const = 0; - virtual size_t GetPlaneSize(size_t plane) const = 0; - virtual uint32_t GetHandle() const = 0; - virtual gfx::NativePixmapHandle ExportHandle() const = 0; - virtual sk_sp<SkSurface> GetSurface() = 0; -}; - -} // namespace ui - -#endif // UI_OZONE_COMMON_LINUX_GBM_BUFFER_H_ diff --git a/chromium/ui/ozone/common/linux/gbm_device.h b/chromium/ui/ozone/common/linux/gbm_device.h deleted file mode 100644 index 84a43d361b9..00000000000 --- a/chromium/ui/ozone/common/linux/gbm_device.h +++ /dev/null @@ -1,40 +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_COMMON_LINUX_GBM_DEVICE_H_ -#define UI_OZONE_COMMON_LINUX_GBM_DEVICE_H_ - -#include <gbm.h> -#include <memory> - -#include "base/files/file.h" -#include "base/macros.h" -#include "ui/gfx/geometry/size.h" -#include "ui/gfx/native_pixmap_handle.h" - -namespace ui { - -class GbmBuffer; - -class GbmDevice { - public: - virtual ~GbmDevice() {} - - virtual std::unique_ptr<GbmBuffer> CreateBuffer(uint32_t format, - const gfx::Size& size, - uint32_t flags) = 0; - virtual std::unique_ptr<GbmBuffer> CreateBufferWithModifiers( - uint32_t format, - const gfx::Size& size, - uint32_t flags, - const std::vector<uint64_t>& modifiers) = 0; - virtual std::unique_ptr<GbmBuffer> CreateBufferFromHandle( - uint32_t format, - const gfx::Size& size, - gfx::NativePixmapHandle handle) = 0; -}; - -} // namespace ui - -#endif // UI_OZONE_COMMON_LINUX_GBM_DEVICE_H_ diff --git a/chromium/ui/ozone/common/linux/gbm_wrapper.cc b/chromium/ui/ozone/common/linux/gbm_wrapper.cc deleted file mode 100644 index 00970e3e3c2..00000000000 --- a/chromium/ui/ozone/common/linux/gbm_wrapper.cc +++ /dev/null @@ -1,334 +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/common/linux/gbm_wrapper.h" - -#include <gbm.h> -#include <memory> -#include <utility> - -#include "base/posix/eintr_wrapper.h" -#include "third_party/skia/include/core/SkSurface.h" -#include "ui/gfx/buffer_format_util.h" -#include "ui/ozone/common/linux/drm_util_linux.h" -#include "ui/ozone/common/linux/gbm_buffer.h" -#include "ui/ozone/common/linux/gbm_device.h" - -#if !defined(MINIGBM) -#include <fcntl.h> -#include <xf86drm.h> -#endif - -namespace gbm_wrapper { - -namespace { - -int GetPlaneFdForBo(gbm_bo* bo, size_t plane) { -#if defined(MINIGBM) - return gbm_bo_get_plane_fd(bo, plane); -#else - const int plane_count = gbm_bo_get_plane_count(bo); - DCHECK(plane_count > 0 && plane < static_cast<size_t>(plane_count)); - - // System linux gbm (or Mesa gbm) does not provide fds per plane basis. Thus, - // get plane handle and use drm ioctl to get a prime fd out of it avoid having - // two different branches for minigbm and Mesa gbm here. - gbm_device* gbm_dev = gbm_bo_get_device(bo); - int dev_fd = gbm_device_get_fd(gbm_dev); - DCHECK_GE(dev_fd, 0); - - const uint32_t plane_handle = gbm_bo_get_handle_for_plane(bo, plane).u32; - int fd = -1; - int ret; - // Use DRM_RDWR to allow the fd to be mappable in another process. - ret = drmPrimeHandleToFD(dev_fd, plane_handle, DRM_CLOEXEC | DRM_RDWR, &fd); - - // Older DRM implementations blocked DRM_RDWR, but gave a read/write mapping - // anyways - if (ret) - ret = drmPrimeHandleToFD(dev_fd, plane_handle, DRM_CLOEXEC, &fd); - - return ret ? ret : fd; -#endif -} - -size_t GetSizeOfPlane(gbm_bo* bo, - uint32_t format, - const gfx::Size& size, - size_t plane) { -#if defined(MINIGBM) - return gbm_bo_get_plane_size(bo, plane); -#else - DCHECK(!size.IsEmpty()); - - // Get row size of the plane, stride and subsampled height to finally get the - // size of a plane in bytes. - const gfx::BufferFormat buffer_format = - ui::GetBufferFormatFromFourCCFormat(format); - const base::CheckedNumeric<size_t> stride_for_plane = - gbm_bo_get_stride_for_plane(bo, plane); - const base::CheckedNumeric<size_t> subsampled_height = - size.height() / - gfx::SubsamplingFactorForBufferFormat(buffer_format, plane); - - // Apply subsampling factor to get size in bytes. - const base::CheckedNumeric<size_t> checked_plane_size = - subsampled_height * stride_for_plane; - - return checked_plane_size.ValueOrDie(); -#endif -} - -} // namespace - -class Buffer final : public ui::GbmBuffer { - public: - Buffer(struct gbm_bo* bo, - uint32_t format, - uint32_t flags, - uint64_t modifier, - const gfx::Size& size, - gfx::NativePixmapHandle handle) - : bo_(bo), - format_(format), - format_modifier_(modifier), - flags_(flags), - size_(size), - handle_(std::move(handle)) {} - - ~Buffer() override { - DCHECK(!mmap_data_); - gbm_bo_destroy(bo_); - } - - uint32_t GetFormat() const override { return format_; } - uint64_t GetFormatModifier() const override { return format_modifier_; } - uint32_t GetFlags() const override { return flags_; } - // TODO(reveman): This should not be needed once crbug.com/597932 is fixed, - // as the size would be queried directly from the underlying bo. - gfx::Size GetSize() const override { return size_; } - gfx::BufferFormat GetBufferFormat() const override { - return ui::GetBufferFormatFromFourCCFormat(format_); - } - bool AreFdsValid() const override { - if (handle_.planes.empty()) - return false; - - for (const auto& plane : handle_.planes) { - if (!plane.fd.is_valid()) - return false; - } - return true; - } - size_t GetNumPlanes() const override { return handle_.planes.size(); } - int GetPlaneFd(size_t plane) const override { - DCHECK_LT(plane, handle_.planes.size()); - return handle_.planes[plane].fd.get(); - } - uint32_t GetPlaneStride(size_t plane) const override { - DCHECK_LT(plane, handle_.planes.size()); - return handle_.planes[plane].stride; - } - size_t GetPlaneOffset(size_t plane) const override { - DCHECK_LT(plane, handle_.planes.size()); - return handle_.planes[plane].offset; - } - size_t GetPlaneSize(size_t plane) const override { - DCHECK_LT(plane, handle_.planes.size()); - return static_cast<size_t>(handle_.planes[plane].size); - } - uint32_t GetPlaneHandle(size_t plane) const override { - DCHECK_LT(plane, handle_.planes.size()); - return gbm_bo_get_handle_for_plane(bo_, plane).u32; - } - uint32_t GetHandle() const override { return gbm_bo_get_handle(bo_).u32; } - gfx::NativePixmapHandle ExportHandle() const override { - return CloneHandleForIPC(handle_); - } - - sk_sp<SkSurface> GetSurface() override { - DCHECK(!mmap_data_); - uint32_t stride; - void* addr; - addr = -#if defined(MINIGBM) - gbm_bo_map(bo_, 0, 0, gbm_bo_get_width(bo_), gbm_bo_get_height(bo_), - GBM_BO_TRANSFER_READ_WRITE, &stride, &mmap_data_, 0); -#else - gbm_bo_map(bo_, 0, 0, gbm_bo_get_width(bo_), gbm_bo_get_height(bo_), - GBM_BO_TRANSFER_READ_WRITE, &stride, &mmap_data_); -#endif - - if (!addr) - return nullptr; - SkImageInfo info = - SkImageInfo::MakeN32Premul(size_.width(), size_.height()); - return SkSurface::MakeRasterDirectReleaseProc(info, addr, stride, - &Buffer::UnmapGbmBo, this); - } - - private: - static void UnmapGbmBo(void* pixels, void* context) { - Buffer* buffer = static_cast<Buffer*>(context); - gbm_bo_unmap(buffer->bo_, buffer->mmap_data_); - buffer->mmap_data_ = nullptr; - } - - gbm_bo* const bo_; - void* mmap_data_ = nullptr; - - const uint32_t format_; - const uint64_t format_modifier_; - const uint32_t flags_; - - const gfx::Size size_; - - const gfx::NativePixmapHandle handle_; - - DISALLOW_COPY_AND_ASSIGN(Buffer); -}; - -std::unique_ptr<Buffer> CreateBufferForBO(struct gbm_bo* bo, - uint32_t format, - const gfx::Size& size, - uint32_t flags) { - DCHECK(bo); - gfx::NativePixmapHandle handle; - - const uint64_t modifier = gbm_bo_get_modifier(bo); - const int plane_count = gbm_bo_get_plane_count(bo); - // The Mesa's gbm implementation explicitly checks whether plane count <= and - // returns 1 if the condition is true. Nevertheless, use a DCHECK here to make - // sure the condition is not broken there. - DCHECK_GT(plane_count, 0); - // Ensure there are no differences in integer signs by casting any possible - // values to size_t. - for (size_t i = 0; i < static_cast<size_t>(plane_count); ++i) { - // The fd returned by gbm_bo_get_fd is not ref-counted and need to be - // kept open for the lifetime of the buffer. - base::ScopedFD fd(GetPlaneFdForBo(bo, i)); - - if (!fd.is_valid()) { - PLOG(ERROR) << "Failed to export buffer to dma_buf"; - gbm_bo_destroy(bo); - return nullptr; - } - - handle.planes.emplace_back( - gbm_bo_get_stride_for_plane(bo, i), gbm_bo_get_offset(bo, i), - GetSizeOfPlane(bo, format, size, i), std::move(fd)); - } - - handle.modifier = modifier; - return std::make_unique<Buffer>(bo, format, flags, modifier, size, - std::move(handle)); -} - -class Device final : public ui::GbmDevice { - public: - Device(gbm_device* device) : device_(device) {} - ~Device() override { gbm_device_destroy(device_); } - - std::unique_ptr<ui::GbmBuffer> CreateBuffer(uint32_t format, - const gfx::Size& size, - uint32_t flags) override { - struct gbm_bo* bo = - gbm_bo_create(device_, size.width(), size.height(), format, flags); - if (!bo) { -#if DCHECK_IS_ON() - const char fourcc_as_string[5] = {format & 0xFF, format >> 8 & 0xFF, - format >> 16 & 0xFF, - format >> 24 & 0xFF, 0}; - - LOG(WARNING) << "Failed to create GBM BO, " << fourcc_as_string << ", " - << size.ToString() << ", flags: 0x" << std::hex << flags - << "; gbm_device_is_format_supported() = " - << gbm_device_is_format_supported(device_, format, flags); -#endif - return nullptr; - } - - return CreateBufferForBO(bo, format, size, flags); - } - - std::unique_ptr<ui::GbmBuffer> CreateBufferWithModifiers( - uint32_t format, - const gfx::Size& size, - uint32_t flags, - const std::vector<uint64_t>& modifiers) override { - if (modifiers.empty()) - return CreateBuffer(format, size, flags); - struct gbm_bo* bo = gbm_bo_create_with_modifiers( - device_, size.width(), size.height(), format, modifiers.data(), - modifiers.size()); - if (!bo) - return nullptr; - - return CreateBufferForBO(bo, format, size, flags); - } - - std::unique_ptr<ui::GbmBuffer> CreateBufferFromHandle( - uint32_t format, - const gfx::Size& size, - gfx::NativePixmapHandle handle) override { - DCHECK_EQ(handle.planes[0].offset, 0u); - - // Try to use scanout if supported. - int gbm_flags = GBM_BO_USE_SCANOUT; -#if defined(MINIGBM) - gbm_flags |= GBM_BO_USE_TEXTURING; -#endif - if (!gbm_device_is_format_supported(device_, format, gbm_flags)) - gbm_flags &= ~GBM_BO_USE_SCANOUT; - - struct gbm_bo* bo = nullptr; - if (!gbm_device_is_format_supported(device_, format, gbm_flags)) { - LOG(ERROR) << "gbm format not supported: " << format; - return nullptr; - } - - struct gbm_import_fd_modifier_data fd_data; - fd_data.width = size.width(); - fd_data.height = size.height(); - fd_data.format = format; - fd_data.num_fds = handle.planes.size(); - fd_data.modifier = handle.modifier; - - DCHECK_LE(handle.planes.size(), 3u); - for (size_t i = 0; i < handle.planes.size(); ++i) { - fd_data.fds[i] = handle.planes[i < handle.planes.size() ? i : 0].fd.get(); - fd_data.strides[i] = handle.planes[i].stride; - fd_data.offsets[i] = handle.planes[i].offset; - } - - // The fd passed to gbm_bo_import is not ref-counted and need to be - // kept open for the lifetime of the buffer. - bo = gbm_bo_import(device_, GBM_BO_IMPORT_FD_MODIFIER, &fd_data, gbm_flags); - if (!bo) { - LOG(ERROR) << "nullptr returned from gbm_bo_import"; - return nullptr; - } - - return std::make_unique<Buffer>(bo, format, gbm_flags, handle.modifier, - size, std::move(handle)); - } - - private: - gbm_device* const device_; - - DISALLOW_COPY_AND_ASSIGN(Device); -}; - -} // namespace gbm_wrapper - -namespace ui { - -std::unique_ptr<GbmDevice> CreateGbmDevice(int fd) { - gbm_device* device = gbm_create_device(fd); - if (!device) - return nullptr; - return std::make_unique<gbm_wrapper::Device>(device); -} - -} // namespace ui diff --git a/chromium/ui/ozone/common/linux/gbm_wrapper.h b/chromium/ui/ozone/common/linux/gbm_wrapper.h deleted file mode 100644 index 926549d6edf..00000000000 --- a/chromium/ui/ozone/common/linux/gbm_wrapper.h +++ /dev/null @@ -1,18 +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_COMMON_LINUX_GBM_WRAPPER_H_ -#define UI_OZONE_COMMON_LINUX_GBM_WRAPPER_H_ - -#include <memory> - -#include "ui/ozone/common/linux/gbm_device.h" - -namespace ui { - -std::unique_ptr<ui::GbmDevice> CreateGbmDevice(int fd); - -} // namespace ui - -#endif // UI_OZONE_COMMON_LINUX_GBM_WRAPPER_H_ diff --git a/chromium/ui/ozone/common/linux/scoped_gbm_device.cc b/chromium/ui/ozone/common/linux/scoped_gbm_device.cc deleted file mode 100644 index 21f00b93bd0..00000000000 --- a/chromium/ui/ozone/common/linux/scoped_gbm_device.cc +++ /dev/null @@ -1,14 +0,0 @@ -// Copyright 2019 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/common/linux/scoped_gbm_device.h" - -namespace ui { - -void GbmDeviceDeleter::operator()(gbm_device* device) { - if (device) - gbm_device_destroy(device); -} - -} // namespace ui diff --git a/chromium/ui/ozone/common/linux/scoped_gbm_device.h b/chromium/ui/ozone/common/linux/scoped_gbm_device.h deleted file mode 100644 index 94c97c83b11..00000000000 --- a/chromium/ui/ozone/common/linux/scoped_gbm_device.h +++ /dev/null @@ -1,22 +0,0 @@ -// Copyright 2019 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_COMMON_LINUX_SCOPED_GBM_DEVICE_H_ -#define UI_OZONE_COMMON_LINUX_SCOPED_GBM_DEVICE_H_ - -#include <gbm.h> - -#include <memory> - -namespace ui { - -struct GbmDeviceDeleter { - void operator()(gbm_device* device); -}; - -using ScopedGbmDevice = std::unique_ptr<gbm_device, GbmDeviceDeleter>; - -} // namespace ui - -#endif // UI_OZONE_COMMON_LINUX_SCOPED_GBM_DEVICE_H_ diff --git a/chromium/ui/ozone/demo/BUILD.gn b/chromium/ui/ozone/demo/BUILD.gn index a77245ced52..9524c025b80 100644 --- a/chromium/ui/ozone/demo/BUILD.gn +++ b/chromium/ui/ozone/demo/BUILD.gn @@ -39,7 +39,7 @@ source_set("ozone_demo_lib") { ] if (is_fuchsia) { - deps += [ "//third_party/fuchsia-sdk/sdk:fuchsia-ui-policy" ] + deps += [ "//third_party/fuchsia-sdk/sdk/fidl/fuchsia.ui.policy" ] } } @@ -102,10 +102,11 @@ executable("skia_demo") { } if (is_fuchsia) { - fuchsia_package("ozone_demo_pkg") { + cr_fuchsia_package("ozone_demo_pkg") { testonly = true binary = ":ozone_demo" package_name_override = "ozone_demo" + manifest = "//build/config/fuchsia/gfx_tests.cmx" } fuchsia_package_runner("ozone_demo_fuchsia") { diff --git a/chromium/ui/ozone/demo/gl_renderer.cc b/chromium/ui/ozone/demo/gl_renderer.cc index 35a51c5efe4..8c266b61096 100644 --- a/chromium/ui/ozone/demo/gl_renderer.cc +++ b/chromium/ui/ozone/demo/gl_renderer.cc @@ -38,7 +38,7 @@ bool GlRenderer::Initialize() { return false; } - gl_surface_->Resize(size_, 1.f, gl::GLSurface::ColorSpace::UNSPECIFIED, true); + gl_surface_->Resize(size_, 1.f, gfx::ColorSpace(), true); if (!context_->MakeCurrent(gl_surface_.get())) { LOG(ERROR) << "Failed to make GL context current"; diff --git a/chromium/ui/ozone/demo/skia/skia_gl_renderer.cc b/chromium/ui/ozone/demo/skia/skia_gl_renderer.cc index 6d2dd5d5cf6..a4ed2416df4 100644 --- a/chromium/ui/ozone/demo/skia/skia_gl_renderer.cc +++ b/chromium/ui/ozone/demo/skia/skia_gl_renderer.cc @@ -30,12 +30,6 @@ namespace ui { namespace { -const GrGLInterface* GrGLCreateNativeInterface() { - return GrGLAssembleInterface(nullptr, [](void* ctx, const char name[]) { - return gl::GetGLProcAddress(name); - }); -} - const char kUseDDL[] = "use-ddl"; } // namespace @@ -64,15 +58,16 @@ bool SkiaGlRenderer::Initialize() { return false; } - gl_surface_->Resize(size_, 1.f, gl::GLSurface::ColorSpace::UNSPECIFIED, true); + gl_surface_->Resize(size_, 1.f, gfx::ColorSpace(), true); if (!gl_context_->MakeCurrent(gl_surface_.get())) { LOG(FATAL) << "Failed to make GL context current"; return false; } - auto native_interface = - sk_sp<const GrGLInterface>(GrGLCreateNativeInterface()); + sk_sp<const GrGLInterface> native_interface = GrGLMakeAssembledInterface( + nullptr, + [](void* ctx, const char name[]) { return gl::GetGLProcAddress(name); }); DCHECK(native_interface); GrContextOptions options; // TODO(csmartdalton): enable internal multisampling after the related Skia diff --git a/chromium/ui/ozone/demo/software_renderer.cc b/chromium/ui/ozone/demo/software_renderer.cc index 90f1bee0a7e..3214fa4b3e9 100644 --- a/chromium/ui/ozone/demo/software_renderer.cc +++ b/chromium/ui/ozone/demo/software_renderer.cc @@ -57,12 +57,12 @@ void SoftwareRenderer::RenderFrame() { float fraction = NextFraction(); - sk_sp<SkSurface> surface = software_surface_->GetSurface(); + SkCanvas* canvas = software_surface_->GetCanvas(); SkColor color = SkColorSetARGB(0xff, 0, 0xff * fraction, 0xff * (1 - fraction)); - surface->getCanvas()->clear(color); + canvas->clear(color); software_surface_->PresentCanvas(gfx::Rect(size_)); diff --git a/chromium/ui/ozone/demo/surfaceless_gl_renderer.cc b/chromium/ui/ozone/demo/surfaceless_gl_renderer.cc index bda8d2106e9..6117ac4f0f3 100644 --- a/chromium/ui/ozone/demo/surfaceless_gl_renderer.cc +++ b/chromium/ui/ozone/demo/surfaceless_gl_renderer.cc @@ -151,7 +151,7 @@ bool SurfacelessGlRenderer::Initialize() { return false; } - gl_surface_->Resize(size_, 1.f, gl::GLSurface::ColorSpace::UNSPECIFIED, true); + gl_surface_->Resize(size_, 1.f, gfx::ColorSpace(), true); if (!context_->MakeCurrent(gl_surface_.get())) { LOG(ERROR) << "Failed to make GL context current"; diff --git a/chromium/ui/ozone/demo/vulkan_renderer.cc b/chromium/ui/ozone/demo/vulkan_renderer.cc index cb174ac6c7d..6d778ce8e98 100644 --- a/chromium/ui/ozone/demo/vulkan_renderer.cc +++ b/chromium/ui/ozone/demo/vulkan_renderer.cc @@ -222,9 +222,10 @@ void VulkanRenderer::RenderFrame() { /* .color = */ {/* .float32 = */ {.5f, 1.f - NextFraction(), .5f, 1.f}}}; gpu::VulkanSwapChain* vulkan_swap_chain = vulkan_surface_->swap_chain(); - gpu::VulkanSwapChain::ScopedWrite scoped_write(vulkan_swap_chain); - const uint32_t image = scoped_write.image_index(); { + gpu::VulkanSwapChain::ScopedWrite scoped_write(vulkan_swap_chain); + const uint32_t image = scoped_write.image_index(); + auto& framebuffer = framebuffers_[image]; if (!framebuffer) { framebuffer = Framebuffer::Create( @@ -293,14 +294,8 @@ void VulkanRenderer::RenderFrame() { vkCmdEndRenderPass(recorder.handle()); } VkSemaphore begin_semaphore = scoped_write.TakeBeginSemaphore(); - VkSemaphoreCreateInfo vk_semaphore_create_info = { - VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO}; - VkSemaphore end_semaphore; - CHECK(vkCreateSemaphore(device_queue_->GetVulkanDevice(), - &vk_semaphore_create_info, nullptr /* pAllocator */, - &end_semaphore) == VK_SUCCESS); + VkSemaphore end_semaphore = scoped_write.GetEndSemaphore(); CHECK(command_buffer.Submit(1, &begin_semaphore, 1, &end_semaphore)); - scoped_write.SetEndSemaphore(end_semaphore); device_queue_->GetFenceHelper()->EnqueueSemaphoreCleanupForSubmittedWork( begin_semaphore); } diff --git a/chromium/ui/ozone/demo/window_manager.cc b/chromium/ui/ozone/demo/window_manager.cc index ffea5853158..ed4f66c8df4 100644 --- a/chromium/ui/ozone/demo/window_manager.cc +++ b/chromium/ui/ozone/demo/window_manager.cc @@ -69,8 +69,8 @@ void WindowManager::OnConfigurationChanged() { } is_configuring_ = true; - delegate_->GetDisplays(base::BindRepeating(&WindowManager::OnDisplaysAquired, - base::Unretained(this))); + delegate_->GetDisplays(base::BindOnce(&WindowManager::OnDisplaysAquired, + base::Unretained(this))); } void WindowManager::OnDisplaySnapshotsInvalidated() {} diff --git a/chromium/ui/ozone/gl/BUILD.gn b/chromium/ui/ozone/gl/BUILD.gn index 8c7b4f40fb5..812955e9566 100644 --- a/chromium/ui/ozone/gl/BUILD.gn +++ b/chromium/ui/ozone/gl/BUILD.gn @@ -5,9 +5,7 @@ import("//testing/test.gni") test("ozone_gl_unittests") { - sources = [ - "gl_image_ozone_native_pixmap_unittest.cc", - ] + sources = [ "gl_image_ozone_native_pixmap_unittest.cc" ] deps = [ "//base/test:test_support", @@ -18,7 +16,5 @@ test("ozone_gl_unittests") { "//ui/ozone", ] - data_deps = [ - "//third_party/mesa_headers", - ] + data_deps = [ "//third_party/mesa_headers" ] } diff --git a/chromium/ui/ozone/gl/gl_image_ozone_native_pixmap_unittest.cc b/chromium/ui/ozone/gl/gl_image_ozone_native_pixmap_unittest.cc index 349b6106e22..229b15167bb 100644 --- a/chromium/ui/ozone/gl/gl_image_ozone_native_pixmap_unittest.cc +++ b/chromium/ui/ozone/gl/gl_image_ozone_native_pixmap_unittest.cc @@ -91,11 +91,13 @@ INSTANTIATE_TYPED_TEST_SUITE_P(GLImageNativePixmapScanoutBGRA, using GLImageScanoutTypeDisabled = testing::Types< GLImageNativePixmapTestDelegate<gfx::BufferUsage::SCANOUT, - gfx::BufferFormat::RGBX_1010102>>; + gfx::BufferFormat::RGBA_1010102>, + GLImageNativePixmapTestDelegate<gfx::BufferUsage::SCANOUT, + gfx::BufferFormat::BGRA_1010102>>; -// This test is disabled since we need mesa support for XR30/XB30 that is not +// This test is disabled since we need mesa support for AB30 that is not // available on many boards yet. -INSTANTIATE_TYPED_TEST_SUITE_P(DISABLED_GLImageNativePixmapScanoutRGBX, +INSTANTIATE_TYPED_TEST_SUITE_P(DISABLED_GLImageNativePixmapScanoutRGBA, GLImageTest, GLImageScanoutTypeDisabled); @@ -111,7 +113,7 @@ using GLImageBindTestTypes = testing::Types< GLImageNativePixmapTestDelegate<gfx::BufferUsage::GPU_READ_CPU_READ_WRITE, gfx::BufferFormat::BGRA_8888>, GLImageNativePixmapTestDelegate<gfx::BufferUsage::GPU_READ_CPU_READ_WRITE, - gfx::BufferFormat::RGBX_1010102>, + gfx::BufferFormat::RGBA_1010102>, GLImageNativePixmapTestDelegate<gfx::BufferUsage::GPU_READ_CPU_READ_WRITE, gfx::BufferFormat::R_8>, GLImageNativePixmapTestDelegate<gfx::BufferUsage::GPU_READ_CPU_READ_WRITE, diff --git a/chromium/ui/ozone/platform/cast/gl_ozone_egl_cast.cc b/chromium/ui/ozone/platform/cast/gl_ozone_egl_cast.cc index 446afea24fc..36ae5fac4d5 100644 --- a/chromium/ui/ozone/platform/cast/gl_ozone_egl_cast.cc +++ b/chromium/ui/ozone/platform/cast/gl_ozone_egl_cast.cc @@ -79,7 +79,7 @@ void GLOzoneEglCast::TerminateDisplay() { DCHECK(get_display); DCHECK(terminate); - EGLDisplay display = get_display(GetNativeDisplay()); + EGLDisplay display = get_display(GetNativeDisplay().GetDisplay()); DCHECK_NE(display, EGL_NO_DISPLAY); EGLBoolean terminate_result = terminate(display); @@ -100,9 +100,10 @@ scoped_refptr<gl::GLSurface> GLOzoneEglCast::CreateOffscreenGLSurface( return gl::InitializeGLSurface(new gl::PbufferGLSurfaceEGL(size)); } -intptr_t GLOzoneEglCast::GetNativeDisplay() { +gl::EGLDisplayPlatform GLOzoneEglCast::GetNativeDisplay() { CreateDisplayTypeAndWindowIfNeeded(); - return reinterpret_cast<intptr_t>(display_type_); + return gl::EGLDisplayPlatform( + reinterpret_cast<EGLNativeDisplayType>(display_type_)); } void GLOzoneEglCast::CreateDisplayTypeAndWindowIfNeeded() { diff --git a/chromium/ui/ozone/platform/cast/gl_ozone_egl_cast.h b/chromium/ui/ozone/platform/cast/gl_ozone_egl_cast.h index ace0cbc94ab..79bcfd833ca 100644 --- a/chromium/ui/ozone/platform/cast/gl_ozone_egl_cast.h +++ b/chromium/ui/ozone/platform/cast/gl_ozone_egl_cast.h @@ -32,7 +32,7 @@ class GLOzoneEglCast : public GLOzoneEGL { gfx::AcceleratedWidget widget) override; scoped_refptr<gl::GLSurface> CreateOffscreenGLSurface( const gfx::Size& size) override; - intptr_t GetNativeDisplay() override; + gl::EGLDisplayPlatform GetNativeDisplay() override; bool LoadGLES2Bindings(gl::GLImplementation implementation) override; intptr_t GetNativeWindow(); diff --git a/chromium/ui/ozone/platform/cast/gl_surface_cast.cc b/chromium/ui/ozone/platform/cast/gl_surface_cast.cc index d76bfacb1f8..9d62e734016 100644 --- a/chromium/ui/ozone/platform/cast/gl_surface_cast.cc +++ b/chromium/ui/ozone/platform/cast/gl_surface_cast.cc @@ -83,7 +83,7 @@ gfx::SwapResult GLSurfaceCast::SwapBuffersWithBounds( bool GLSurfaceCast::Resize(const gfx::Size& size, float scale_factor, - ColorSpace color_space, + const gfx::ColorSpace& color_space, bool has_alpha) { return parent_->ResizeDisplay(size) && NativeViewGLSurfaceEGL::Resize(size, scale_factor, color_space, diff --git a/chromium/ui/ozone/platform/cast/gl_surface_cast.h b/chromium/ui/ozone/platform/cast/gl_surface_cast.h index e294802478f..30f19d5ab05 100644 --- a/chromium/ui/ozone/platform/cast/gl_surface_cast.h +++ b/chromium/ui/ozone/platform/cast/gl_surface_cast.h @@ -30,7 +30,7 @@ class GLSurfaceCast : public gl::NativeViewGLSurfaceEGL { PresentationCallback callback) override; bool Resize(const gfx::Size& size, float scale_factor, - ColorSpace color_space, + const gfx::ColorSpace& color_space, bool has_alpha) override; bool ScheduleOverlayPlane(int z_order, gfx::OverlayTransform transform, diff --git a/chromium/ui/ozone/platform/cast/ozone_platform_cast.cc b/chromium/ui/ozone/platform/cast/ozone_platform_cast.cc index b2e3baa77fd..a2ce0266582 100644 --- a/chromium/ui/ozone/platform/cast/ozone_platform_cast.cc +++ b/chromium/ui/ozone/platform/cast/ozone_platform_cast.cc @@ -20,6 +20,7 @@ #include "ui/events/ozone/evdev/event_factory_evdev.h" #include "ui/events/ozone/layout/keyboard_layout_engine_manager.h" #include "ui/events/ozone/layout/stub/stub_keyboard_layout_engine.h" +#include "ui/gfx/native_widget_types.h" #include "ui/ozone/platform/cast/overlay_manager_cast.h" #include "ui/ozone/platform/cast/platform_window_cast.h" #include "ui/ozone/platform/cast/surface_factory_cast.h" @@ -109,7 +110,8 @@ class OzonePlatformCast : public OzonePlatform { return nullptr; } std::unique_ptr<InputMethod> CreateInputMethod( - internal::InputMethodDelegate* delegate) override { + internal::InputMethodDelegate* delegate, + gfx::AcceleratedWidget) override { return std::make_unique<InputMethodMinimal>(delegate); } @@ -124,9 +126,6 @@ class OzonePlatformCast : public OzonePlatform { cursor_factory_ = std::make_unique<CursorFactoryOzone>(); gpu_platform_support_host_.reset(CreateStubGpuPlatformSupportHost()); - if (!params.viz_display_compositor) - overlay_manager_ = std::make_unique<OverlayManagerCast>(); - // Enable dummy software rendering support if GPU process disabled // or if we're an audio-only build. // Note: switch is kDisableGpu from content/public/common/content_switches.h @@ -148,9 +147,7 @@ class OzonePlatformCast : public OzonePlatform { surface_factory_ = std::make_unique<SurfaceFactoryCast>(); } void InitializeGPU(const InitParams& params) override { - if (params.viz_display_compositor) { - overlay_manager_ = std::make_unique<OverlayManagerCast>(); - } + overlay_manager_ = std::make_unique<OverlayManagerCast>(); surface_factory_ = std::make_unique<SurfaceFactoryCast>(std::move(egl_platform_)); } diff --git a/chromium/ui/ozone/platform/cast/surface_factory_cast.cc b/chromium/ui/ozone/platform/cast/surface_factory_cast.cc index 562e60e12e2..46928b82e97 100644 --- a/chromium/ui/ozone/platform/cast/surface_factory_cast.cc +++ b/chromium/ui/ozone/platform/cast/surface_factory_cast.cc @@ -26,7 +26,7 @@ class DummySurface : public SurfaceOzoneCanvas { ~DummySurface() override {} // SurfaceOzoneCanvas implementation: - sk_sp<SkSurface> GetSurface() override { return surface_; } + SkCanvas* GetCanvas() override { return surface_->getCanvas(); } void ResizeCanvas(const gfx::Size& viewport_size) override { surface_ = @@ -114,7 +114,7 @@ GLOzone* SurfaceFactoryCast::GetGLOzone(gl::GLImplementation implementation) { std::unique_ptr<SurfaceOzoneCanvas> SurfaceFactoryCast::CreateCanvasForWidget( gfx::AcceleratedWidget widget, - base::TaskRunner* task_runner) { + scoped_refptr<base::SequencedTaskRunner> task_runner) { // Software canvas support only in headless mode if (egl_implementation_) return nullptr; @@ -126,7 +126,9 @@ scoped_refptr<gfx::NativePixmap> SurfaceFactoryCast::CreateNativePixmap( VkDevice vk_device, gfx::Size size, gfx::BufferFormat format, - gfx::BufferUsage usage) { + gfx::BufferUsage usage, + base::Optional<gfx::Size> framebuffer_size) { + DCHECK(!framebuffer_size || framebuffer_size == size); return base::MakeRefCounted<CastPixmap>(); } diff --git a/chromium/ui/ozone/platform/cast/surface_factory_cast.h b/chromium/ui/ozone/platform/cast/surface_factory_cast.h index fd1e30a73db..a7d0ef9b151 100644 --- a/chromium/ui/ozone/platform/cast/surface_factory_cast.h +++ b/chromium/ui/ozone/platform/cast/surface_factory_cast.h @@ -33,13 +33,14 @@ class SurfaceFactoryCast : public SurfaceFactoryOzone { GLOzone* GetGLOzone(gl::GLImplementation implementation) override; std::unique_ptr<SurfaceOzoneCanvas> CreateCanvasForWidget( gfx::AcceleratedWidget widget, - base::TaskRunner* task_runner) override; + scoped_refptr<base::SequencedTaskRunner> task_runner) override; scoped_refptr<gfx::NativePixmap> CreateNativePixmap( gfx::AcceleratedWidget widget, VkDevice vk_device, gfx::Size size, gfx::BufferFormat format, - gfx::BufferUsage usage) override; + gfx::BufferUsage usage, + base::Optional<gfx::Size> framebuffer_size = base::nullopt) override; private: std::unique_ptr<GLOzoneEglCast> egl_implementation_; diff --git a/chromium/ui/ozone/platform/drm/BUILD.gn b/chromium/ui/ozone/platform/drm/BUILD.gn index 3319865a62a..d820eee6a6f 100644 --- a/chromium/ui/ozone/platform/drm/BUILD.gn +++ b/chromium/ui/ozone/platform/drm/BUILD.gn @@ -20,10 +20,6 @@ source_set("gbm") { "client_native_pixmap_factory_gbm.cc", "client_native_pixmap_factory_gbm.h", "common/display_types.h", - "common/drm_overlay_candidates.cc", - "common/drm_overlay_candidates.h", - "common/drm_overlay_manager.cc", - "common/drm_overlay_manager.h", "common/drm_util.cc", "common/drm_util.h", "common/scoped_drm_types.cc", @@ -46,6 +42,10 @@ source_set("gbm") { "gpu/drm_gpu_display_manager.h", "gpu/drm_gpu_util.cc", "gpu/drm_gpu_util.h", + "gpu/drm_overlay_candidates.cc", + "gpu/drm_overlay_candidates.h", + "gpu/drm_overlay_manager.cc", + "gpu/drm_overlay_manager.h", "gpu/drm_overlay_manager_gpu.cc", "gpu/drm_overlay_manager_gpu.h", "gpu/drm_overlay_plane.cc", @@ -106,8 +106,6 @@ source_set("gbm") { "host/drm_gpu_platform_support_host.h", "host/drm_native_display_delegate.cc", "host/drm_native_display_delegate.h", - "host/drm_overlay_manager_host.cc", - "host/drm_overlay_manager_host.h", "host/drm_window_host.cc", "host/drm_window_host.h", "host/drm_window_host_manager.cc", @@ -145,11 +143,11 @@ source_set("gbm") { "//ui/events/platform", "//ui/gfx", "//ui/gfx/geometry", + "//ui/gfx/linux:drm", + "//ui/gfx/linux:gbm", "//ui/gl", "//ui/ozone:ozone_base", "//ui/ozone/common", - "//ui/ozone/common/linux:drm", - "//ui/ozone/common/linux:gbm", "//ui/ozone/public/mojom", "//ui/platform_window", ] @@ -178,8 +176,8 @@ source_set("gbm") { source_set("gbm_unittests") { testonly = true sources = [ - "common/drm_overlay_manager_unittest.cc", "common/drm_util_unittest.cc", + "gpu/drm_overlay_manager_unittest.cc", "gpu/drm_overlay_validator_unittest.cc", "gpu/drm_thread_unittest.cc", "gpu/drm_window_unittest.cc", @@ -187,8 +185,6 @@ source_set("gbm_unittests") { "gpu/hardware_display_plane_manager_unittest.cc", "gpu/mock_drm_device.cc", "gpu/mock_drm_device.h", - "gpu/mock_gbm_device.cc", - "gpu/mock_gbm_device.h", "gpu/proxy_helpers_unittest.cc", "gpu/screen_manager_unittest.cc", ] @@ -201,10 +197,11 @@ source_set("gbm_unittests") { "//testing/gtest", "//ui/base/ime", "//ui/gfx", + "//ui/gfx/linux:drm", + "//ui/gfx/linux:gbm", + "//ui/gfx/linux:test_support", "//ui/ozone:platform", "//ui/ozone/common", - "//ui/ozone/common/linux:drm", - "//ui/ozone/common/linux:gbm", ] if (drm_commit_properties_on_page_flip) { diff --git a/chromium/ui/ozone/platform/drm/OWNERS b/chromium/ui/ozone/platform/drm/OWNERS index 363a93a5f95..5392283e6fe 100644 --- a/chromium/ui/ozone/platform/drm/OWNERS +++ b/chromium/ui/ozone/platform/drm/OWNERS @@ -1,2 +1,4 @@ dcastagna@chromium.org dnicoara@chromium.org + +# COMPONENT: OS>Systems>Display diff --git a/chromium/ui/ozone/platform/drm/common/drm_util.cc b/chromium/ui/ozone/platform/drm/common/drm_util.cc index c222c05e479..06a9c37cd2c 100644 --- a/chromium/ui/ozone/platform/drm/common/drm_util.cc +++ b/chromium/ui/ozone/platform/drm/common/drm_util.cc @@ -108,6 +108,28 @@ float GetRefreshRate(const drmModeModeInfo& mode) { return (clock * 1000.0f) / (htotal * vtotal); } +display::DisplayConnectionType GetDisplayType(drmModeConnector* connector) { + switch (connector->connector_type) { + case DRM_MODE_CONNECTOR_VGA: + return display::DISPLAY_CONNECTION_TYPE_VGA; + case DRM_MODE_CONNECTOR_DVII: + case DRM_MODE_CONNECTOR_DVID: + case DRM_MODE_CONNECTOR_DVIA: + return display::DISPLAY_CONNECTION_TYPE_DVI; + case DRM_MODE_CONNECTOR_LVDS: + case DRM_MODE_CONNECTOR_eDP: + case DRM_MODE_CONNECTOR_DSI: + return display::DISPLAY_CONNECTION_TYPE_INTERNAL; + case DRM_MODE_CONNECTOR_DisplayPort: + return display::DISPLAY_CONNECTION_TYPE_DISPLAYPORT; + case DRM_MODE_CONNECTOR_HDMIA: + case DRM_MODE_CONNECTOR_HDMIB: + return display::DISPLAY_CONNECTION_TYPE_HDMI; + default: + return display::DISPLAY_CONNECTION_TYPE_UNKNOWN; + } +} + int GetDrmProperty(int fd, drmModeConnector* connector, const std::string& name, @@ -151,6 +173,26 @@ ScopedDrmPropertyBlobPtr GetDrmPropertyBlob(int fd, return nullptr; } +display::PrivacyScreenState GetPrivacyScreenState(int fd, + drmModeConnector* connector) { + ScopedDrmPropertyPtr property; + int index = GetDrmProperty(fd, connector, "privacy-screen", &property); + if (index < 0) + return display::PrivacyScreenState::kNotSupported; + + DCHECK_LT(connector->prop_values[index], + display::PrivacyScreenState::kPrivacyScreenStateLast); + if (connector->prop_values[index] >= + display::PrivacyScreenState::kPrivacyScreenStateLast) { + LOG(ERROR) << "Invalid privacy-screen property value: Expected < " + << display::PrivacyScreenState::kPrivacyScreenStateLast + << ", but got: " << connector->prop_values[index]; + } + + return static_cast<display::PrivacyScreenState>( + connector->prop_values[index]); +} + bool IsAspectPreserving(int fd, drmModeConnector* connector) { ScopedDrmPropertyPtr property; int index = GetDrmProperty(fd, connector, "scaling mode", &property); @@ -403,29 +445,6 @@ display::DisplaySnapshot::DisplayModeList ExtractDisplayModes( return modes; } -display::DisplayConnectionType GetDisplayType( - const drmModeConnector* connector) { - switch (connector->connector_type) { - case DRM_MODE_CONNECTOR_VGA: - return display::DISPLAY_CONNECTION_TYPE_VGA; - case DRM_MODE_CONNECTOR_DVII: - case DRM_MODE_CONNECTOR_DVID: - case DRM_MODE_CONNECTOR_DVIA: - return display::DISPLAY_CONNECTION_TYPE_DVI; - case DRM_MODE_CONNECTOR_LVDS: - case DRM_MODE_CONNECTOR_eDP: - case DRM_MODE_CONNECTOR_DSI: - return display::DISPLAY_CONNECTION_TYPE_INTERNAL; - case DRM_MODE_CONNECTOR_DisplayPort: - return display::DISPLAY_CONNECTION_TYPE_DISPLAYPORT; - case DRM_MODE_CONNECTOR_HDMIA: - case DRM_MODE_CONNECTOR_HDMIB: - return display::DISPLAY_CONNECTION_TYPE_HDMI; - default: - return display::DISPLAY_CONNECTION_TYPE_UNKNOWN; - } -} - std::unique_ptr<display::DisplaySnapshot> CreateDisplaySnapshot( HardwareDisplayControllerInfo* info, int fd, @@ -440,6 +459,8 @@ std::unique_ptr<display::DisplaySnapshot> CreateDisplaySnapshot( IsAspectPreserving(fd, info->connector()); const display::PanelOrientation panel_orientation = GetPanelOrientation(fd, info->connector()); + const display::PrivacyScreenState privacy_screen_state = + GetPrivacyScreenState(fd, info->connector()); const bool has_color_correction_matrix = HasColorCorrectionMatrix(fd, info->crtc()) || HasPerPlaneColorCorrectionMatrix(fd, info->crtc()); @@ -495,7 +516,7 @@ std::unique_ptr<display::DisplaySnapshot> CreateDisplaySnapshot( return std::make_unique<display::DisplaySnapshot>( display_id, origin, physical_size, type, is_aspect_preserving_scaling, - has_overscan, has_color_correction_matrix, + has_overscan, privacy_screen_state, has_color_correction_matrix, color_correction_in_linear_space, display_color_space, bits_per_channel, display_name, sys_path, std::move(modes), panel_orientation, edid, current_mode, native_mode, product_code, year_of_manufacture, @@ -515,6 +536,7 @@ std::vector<DisplaySnapshot_Params> CreateDisplaySnapshotParams( p.type = d->type(); p.is_aspect_preserving_scaling = d->is_aspect_preserving_scaling(); p.has_overscan = d->has_overscan(); + p.privacy_screen_state = d->privacy_screen_state(); p.has_color_correction_matrix = d->has_color_correction_matrix(); p.color_correction_in_linear_space = d->color_correction_in_linear_space(); p.color_space = d->color_space(); @@ -563,7 +585,7 @@ std::unique_ptr<display::DisplaySnapshot> CreateDisplaySnapshot( return std::make_unique<display::DisplaySnapshot>( params.display_id, params.origin, params.physical_size, params.type, params.is_aspect_preserving_scaling, params.has_overscan, - params.has_color_correction_matrix, + params.privacy_screen_state, params.has_color_correction_matrix, params.color_correction_in_linear_space, params.color_space, params.bits_per_channel, params.display_name, params.sys_path, std::move(modes), params.panel_orientation, params.edid, current_mode, @@ -582,9 +604,9 @@ int GetFourCCFormatForOpaqueFramebuffer(gfx::BufferFormat format) { case gfx::BufferFormat::BGRA_8888: case gfx::BufferFormat::BGRX_8888: return DRM_FORMAT_XRGB8888; - case gfx::BufferFormat::BGRX_1010102: + case gfx::BufferFormat::BGRA_1010102: return DRM_FORMAT_XRGB2101010; - case gfx::BufferFormat::RGBX_1010102: + case gfx::BufferFormat::RGBA_1010102: return DRM_FORMAT_XBGR2101010; case gfx::BufferFormat::BGR_565: return DRM_FORMAT_RGB565; @@ -598,54 +620,4 @@ int GetFourCCFormatForOpaqueFramebuffer(gfx::BufferFormat format) { } } -OverlaySurfaceCandidateList CreateOverlaySurfaceCandidateListFrom( - const std::vector<OverlayCheck_Params>& params) { - OverlaySurfaceCandidateList candidates; - for (auto& p : params) { - OverlaySurfaceCandidate osc; - osc.transform = p.transform; - osc.buffer_size = p.buffer_size; - osc.format = p.format; - osc.display_rect = gfx::RectF(p.display_rect); - osc.crop_rect = p.crop_rect; - osc.is_opaque = p.is_opaque; - osc.plane_z_order = p.plane_z_order; - osc.overlay_handled = p.is_overlay_candidate; - candidates.push_back(osc); - } - - return candidates; -} - -std::vector<OverlayCheck_Params> CreateParamsFromOverlaySurfaceCandidate( - const OverlaySurfaceCandidateList& candidates) { - std::vector<OverlayCheck_Params> overlay_params; - for (auto& candidate : candidates) { - overlay_params.push_back(OverlayCheck_Params(candidate)); - } - - return overlay_params; -} - -OverlayStatusList CreateOverlayStatusListFrom( - const std::vector<OverlayCheckReturn_Params>& params) { - OverlayStatusList returns; - for (auto& p : params) { - returns.push_back(p.status); - } - - return returns; -} - -std::vector<OverlayCheckReturn_Params> CreateParamsFromOverlayStatusList( - const OverlayStatusList& returns) { - std::vector<OverlayCheckReturn_Params> params; - for (auto& s : returns) { - OverlayCheckReturn_Params p; - p.status = s; - params.push_back(p); - } - return params; -} - } // namespace ui diff --git a/chromium/ui/ozone/platform/drm/common/drm_util.h b/chromium/ui/ozone/platform/drm/common/drm_util.h index 71fb0e0ee54..74001bcb0d1 100644 --- a/chromium/ui/ozone/platform/drm/common/drm_util.h +++ b/chromium/ui/ozone/platform/drm/common/drm_util.h @@ -71,9 +71,6 @@ display::DisplaySnapshot::DisplayModeList ExtractDisplayModes( const display::DisplayMode** out_current_mode, const display::DisplayMode** out_native_mode); -display::DisplayConnectionType GetDisplayType( - const drmModeConnector* connector); - // |info| provides the DRM information related to the display, |fd| is the // connection to the DRM device. std::unique_ptr<display::DisplaySnapshot> CreateDisplaySnapshot( @@ -114,18 +111,6 @@ float ModeRefreshRate(const drmModeModeInfo& mode); bool ModeIsInterlaced(const drmModeModeInfo& mode); -OverlaySurfaceCandidateList CreateOverlaySurfaceCandidateListFrom( - const std::vector<OverlayCheck_Params>& params); - -std::vector<OverlayCheck_Params> CreateParamsFromOverlaySurfaceCandidate( - const OverlaySurfaceCandidateList& candidates); - -OverlayStatusList CreateOverlayStatusListFrom( - const std::vector<OverlayCheckReturn_Params>& params); - -std::vector<OverlayCheckReturn_Params> CreateParamsFromOverlayStatusList( - const OverlayStatusList& returns); - } // namespace ui #endif // UI_OZONE_PLATFORM_DRM_COMMON_DRM_UTIL_H_ diff --git a/chromium/ui/ozone/platform/drm/common/drm_util_unittest.cc b/chromium/ui/ozone/platform/drm/common/drm_util_unittest.cc index c0e59bbbe83..b81f31f265e 100644 --- a/chromium/ui/ozone/platform/drm/common/drm_util_unittest.cc +++ b/chromium/ui/ozone/platform/drm/common/drm_util_unittest.cc @@ -180,48 +180,6 @@ TEST_F(DrmUtilTest, RoundTripDisplaySnapshot) { EXPECT_EQ(ep, roundtrip_params[2]); } -TEST_F(DrmUtilTest, OverlaySurfaceCandidate) { - OverlaySurfaceCandidateList input; - - OverlaySurfaceCandidate input_osc; - input_osc.transform = gfx::OVERLAY_TRANSFORM_FLIP_VERTICAL; - input_osc.format = gfx::BufferFormat::YUV_420_BIPLANAR; - input_osc.buffer_size = gfx::Size(100, 50); - input_osc.display_rect = gfx::RectF(1., 2., 3., 4.); - input_osc.crop_rect = gfx::RectF(10., 20., 30., 40.); - input_osc.clip_rect = gfx::Rect(10, 20, 30, 40); - input_osc.is_clipped = true; - input_osc.plane_z_order = 42; - input_osc.overlay_handled = true; - - input.push_back(input_osc); - - // Roundtrip the conversions. - auto output = CreateOverlaySurfaceCandidateListFrom( - CreateParamsFromOverlaySurfaceCandidate(input)); - - EXPECT_EQ(input.size(), output.size()); - OverlaySurfaceCandidate output_osc = output[0]; - - EXPECT_EQ(input_osc.transform, output_osc.transform); - EXPECT_EQ(input_osc.format, output_osc.format); - EXPECT_EQ(input_osc.buffer_size, output_osc.buffer_size); - EXPECT_EQ(input_osc.display_rect, output_osc.display_rect); - EXPECT_EQ(input_osc.crop_rect, output_osc.crop_rect); - EXPECT_EQ(input_osc.plane_z_order, output_osc.plane_z_order); - EXPECT_EQ(input_osc.overlay_handled, output_osc.overlay_handled); - - EXPECT_FALSE(input < output); - EXPECT_FALSE(output < input); - - std::map<OverlaySurfaceCandidateList, int> map; - map[input] = 42; - const auto& iter = map.find(output); - - EXPECT_NE(map.end(), iter); - EXPECT_EQ(42, iter->second); -} - TEST_F(DrmUtilTest, TestDisplayModesExtraction) { // Initialize a list of display modes. constexpr size_t kNumModes = 5; diff --git a/chromium/ui/ozone/platform/drm/common/scoped_drm_types.cc b/chromium/ui/ozone/platform/drm/common/scoped_drm_types.cc index e8b79412ff7..ef229418e3f 100644 --- a/chromium/ui/ozone/platform/drm/common/scoped_drm_types.cc +++ b/chromium/ui/ozone/platform/drm/common/scoped_drm_types.cc @@ -5,6 +5,7 @@ #include "ui/ozone/platform/drm/common/scoped_drm_types.h" #include <stdint.h> // required by xf86drmMode.h +#include <xf86drm.h> #include <xf86drmMode.h> namespace ui { @@ -55,4 +56,8 @@ void DrmFramebufferDeleter::operator()(drmModeFB* framebuffer) const { drmModeFreeFB(framebuffer); } +void DrmVersionDeleter::operator()(drmVersion* version) const { + drmFreeVersion(version); +} + } // namespace ui diff --git a/chromium/ui/ozone/platform/drm/common/scoped_drm_types.h b/chromium/ui/ozone/platform/drm/common/scoped_drm_types.h index 32f9dc92db3..22345a8545c 100644 --- a/chromium/ui/ozone/platform/drm/common/scoped_drm_types.h +++ b/chromium/ui/ozone/platform/drm/common/scoped_drm_types.h @@ -20,6 +20,7 @@ typedef struct _drmModeProperty drmModePropertyRes; typedef struct _drmModeAtomicReq drmModeAtomicReq; typedef struct _drmModePropertyBlob drmModePropertyBlobRes; typedef struct _drmModeRes drmModeRes; +typedef struct _drmVersion drmVersion; typedef struct drm_color_lut drm_color_lut; typedef struct drm_color_ctm drm_color_ctm; @@ -58,6 +59,9 @@ struct DrmPropertyBlobDeleter { struct DrmFramebufferDeleter { void operator()(drmModeFB* framebuffer) const; }; +struct DrmVersionDeleter { + void operator()(drmVersion* version) const; +}; typedef std::unique_ptr<drmModeRes, DrmResourcesDeleter> ScopedDrmResourcesPtr; typedef std::unique_ptr<drmModeConnector, DrmConnectorDeleter> @@ -77,6 +81,7 @@ typedef std::unique_ptr<drmModePropertyBlobRes, DrmPropertyBlobDeleter> ScopedDrmPropertyBlobPtr; typedef std::unique_ptr<drmModeFB, DrmFramebufferDeleter> ScopedDrmFramebufferPtr; +typedef std::unique_ptr<drmVersion, DrmVersionDeleter> ScopedDrmVersionPtr; typedef std::unique_ptr<drm_color_lut, base::FreeDeleter> ScopedDrmColorLutPtr; typedef std::unique_ptr<drm_color_ctm, base::FreeDeleter> ScopedDrmColorCtmPtr; diff --git a/chromium/ui/ozone/platform/drm/gpu/crtc_controller.cc b/chromium/ui/ozone/platform/drm/gpu/crtc_controller.cc index 6f3690ddaaa..adf1285bb7b 100644 --- a/chromium/ui/ozone/platform/drm/gpu/crtc_controller.cc +++ b/chromium/ui/ozone/platform/drm/gpu/crtc_controller.cc @@ -8,9 +8,7 @@ #include "base/logging.h" #include "base/time/time.h" -#include "ui/display/types/display_constants.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" @@ -24,9 +22,7 @@ CrtcController::CrtcController(const scoped_refptr<DrmDevice>& drm, uint32_t connector) : drm_(drm), crtc_(crtc), - connector_(connector), - internal_diplay_only_modifiers_( - {I915_FORMAT_MOD_Y_TILED_CCS, I915_FORMAT_MOD_Yf_TILED_CCS}) {} + connector_(connector) {} CrtcController::~CrtcController() { if (!is_disabled_) { @@ -40,14 +36,16 @@ CrtcController::~CrtcController() { } DisableCursor(); - drm_->DisableCrtc(crtc_); + drm_->plane_manager()->DisableModeset(crtc_, connector_); } } bool CrtcController::Modeset(const DrmOverlayPlane& plane, - drmModeModeInfo mode) { - if (!drm_->SetCrtc(crtc_, plane.buffer->opaque_framebuffer_id(), - std::vector<uint32_t>(1, connector_), &mode)) { + 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() @@ -74,12 +72,15 @@ bool CrtcController::Disable() { is_disabled_ = true; DisableCursor(); - return drm_->DisableCrtc(crtc_); + 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_)) { @@ -90,8 +91,8 @@ bool CrtcController::AssignOverlayPlanes(HardwareDisplayPlaneList* plane_list, return true; } - if (!drm_->plane_manager()->AssignOverlayPlanes(plane_list, overlays, crtc_, - this)) { + if (!drm_->plane_manager()->AssignOverlayPlanes(plane_list, overlays, + crtc_)) { PLOG(ERROR) << "Failed to assign overlay planes for crtc " << crtc_; return false; } @@ -100,21 +101,7 @@ bool CrtcController::AssignOverlayPlanes(HardwareDisplayPlaneList* plane_list, } std::vector<uint64_t> CrtcController::GetFormatModifiers(uint32_t format) { - std::vector<uint64_t> modifiers = - drm_->plane_manager()->GetFormatModifiers(crtc_, format); - - display::DisplayConnectionType display_type = - ui::GetDisplayType(drm_->GetConnector(connector_).get()); - // If this is an external display, remove the modifiers applicable to internal - // displays only. - if (display_type != display::DISPLAY_CONNECTION_TYPE_INTERNAL) { - for (auto modifier : internal_diplay_only_modifiers_) { - modifiers.erase(std::remove(modifiers.begin(), modifiers.end(), modifier), - modifiers.end()); - } - } - - return modifiers; + return drm_->plane_manager()->GetFormatModifiers(crtc_, format); } void CrtcController::SetCursor(uint32_t handle, const gfx::Size& size) { diff --git a/chromium/ui/ozone/platform/drm/gpu/crtc_controller.h b/chromium/ui/ozone/platform/drm/gpu/crtc_controller.h index 0e3d59a5317..258093f28fc 100644 --- a/chromium/ui/ozone/platform/drm/gpu/crtc_controller.h +++ b/chromium/ui/ozone/platform/drm/gpu/crtc_controller.h @@ -40,15 +40,19 @@ class CrtcController { const scoped_refptr<DrmDevice>& drm() const { return drm_; } bool is_disabled() const { return is_disabled_; } - // 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, drmModeModeInfo mode); + // 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 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 @@ -75,8 +79,6 @@ class CrtcController { // TODO(dnicoara) Add support for hardware mirroring (multiple connectors). const uint32_t connector_; - const std::vector<uint64_t> internal_diplay_only_modifiers_; - drmModeModeInfo mode_ = {}; scoped_refptr<DrmFramebuffer> modeset_framebuffer_; diff --git a/chromium/ui/ozone/platform/drm/gpu/drm_device.cc b/chromium/ui/ozone/platform/drm/gpu/drm_device.cc index 9e049a84b3f..943816dddf9 100644 --- a/chromium/ui/ozone/platform/drm/gpu/drm_device.cc +++ b/chromium/ui/ozone/platform/drm/gpu/drm_device.cc @@ -146,7 +146,7 @@ DrmPropertyBlobMetadata::~DrmPropertyBlobMetadata() { class DrmDevice::PageFlipManager { public: PageFlipManager() : next_id_(0) {} - ~PageFlipManager() {} + ~PageFlipManager() = default; void OnPageFlip(uint32_t frame, base::TimeTicks timestamp, uint64_t id) { auto it = @@ -248,7 +248,7 @@ DrmDevice::DrmDevice(const base::FilePath& device_path, is_primary_device_(is_primary_device), gbm_(std::move(gbm)) {} -DrmDevice::~DrmDevice() {} +DrmDevice::~DrmDevice() = default; bool DrmDevice::Initialize() { // Ignore devices that cannot perform modesetting. @@ -302,36 +302,22 @@ ScopedDrmCrtcPtr DrmDevice::GetCrtc(uint32_t crtc_id) { bool DrmDevice::SetCrtc(uint32_t crtc_id, uint32_t framebuffer, std::vector<uint32_t> connectors, - drmModeModeInfo* mode) { + const drmModeModeInfo& mode) { DCHECK(file_.IsValid()); DCHECK(!connectors.empty()); - DCHECK(mode); TRACE_EVENT2("drm", "DrmDevice::SetCrtc", "crtc", crtc_id, "size", - gfx::Size(mode->hdisplay, mode->vdisplay).ToString()); + gfx::Size(mode.hdisplay, mode.vdisplay).ToString()); return !drmModeSetCrtc(file_.GetPlatformFile(), crtc_id, framebuffer, 0, 0, - connectors.data(), connectors.size(), mode); -} - -bool DrmDevice::SetCrtc(drmModeCrtc* crtc, std::vector<uint32_t> connectors) { - DCHECK(file_.IsValid()); - // If there's no buffer then the CRTC was disabled. - if (!crtc->buffer_id) - return DisableCrtc(crtc->crtc_id); - - DCHECK(!connectors.empty()); - - TRACE_EVENT1("drm", "DrmDevice::RestoreCrtc", "crtc", crtc->crtc_id); - return !drmModeSetCrtc(file_.GetPlatformFile(), crtc->crtc_id, - crtc->buffer_id, crtc->x, crtc->y, connectors.data(), - connectors.size(), &crtc->mode); + connectors.data(), connectors.size(), + const_cast<drmModeModeInfo*>(&mode)); } bool DrmDevice::DisableCrtc(uint32_t crtc_id) { DCHECK(file_.IsValid()); TRACE_EVENT1("drm", "DrmDevice::DisableCrtc", "crtc", crtc_id); - return !drmModeSetCrtc(file_.GetPlatformFile(), crtc_id, 0, 0, 0, NULL, 0, - NULL); + return !drmModeSetCrtc(file_.GetPlatformFile(), crtc_id, 0, 0, 0, nullptr, 0, + nullptr); } ScopedDrmConnectorPtr DrmDevice::GetConnector(uint32_t connector_id) { @@ -432,7 +418,8 @@ bool DrmDevice::SetProperty(uint32_t connector_id, property_id, value); } -ScopedDrmPropertyBlob DrmDevice::CreatePropertyBlob(void* blob, size_t size) { +ScopedDrmPropertyBlob DrmDevice::CreatePropertyBlob(const void* blob, + size_t size) { uint32_t id = 0; int ret = drmModeCreatePropertyBlob(file_.GetPlatformFile(), blob, size, &id); DCHECK(!ret && id); @@ -526,7 +513,7 @@ bool DrmDevice::MapDumbBuffer(uint32_t handle, size_t size, void** pixels) { return false; } - *pixels = mmap(0, size, PROT_READ | PROT_WRITE, MAP_SHARED, + *pixels = mmap(nullptr, size, PROT_READ | PROT_WRITE, MAP_SHARED, file_.GetPlatformFile(), map_request.offset); if (*pixels == MAP_FAILED) { PLOG(ERROR) << "Cannot mmap dumb buffer"; diff --git a/chromium/ui/ozone/platform/drm/gpu/drm_device.h b/chromium/ui/ozone/platform/drm/gpu/drm_device.h index d5ef13b1b6f..0cbcca2fe96 100644 --- a/chromium/ui/ozone/platform/drm/gpu/drm_device.h +++ b/chromium/ui/ozone/platform/drm/gpu/drm_device.h @@ -18,8 +18,8 @@ #include "base/time/time.h" #include "ui/gfx/geometry/rect.h" #include "ui/gfx/geometry/rect_f.h" +#include "ui/gfx/linux/gbm_device.h" #include "ui/gfx/overlay_transform.h" -#include "ui/ozone/common/linux/gbm_device.h" #include "ui/ozone/platform/drm/common/scoped_drm_types.h" #include "ui/ozone/platform/drm/gpu/page_flip_request.h" @@ -106,12 +106,7 @@ class DrmDevice : public base::RefCountedThreadSafe<DrmDevice> { virtual bool SetCrtc(uint32_t crtc_id, uint32_t framebuffer, std::vector<uint32_t> connectors, - drmModeModeInfo* mode); - - // Used to set a specific configuration to the CRTC. Normally this function - // would be called with a CRTC saved state (from |GetCrtc|) to restore it to - // its original configuration. - virtual bool SetCrtc(drmModeCrtc* crtc, std::vector<uint32_t> connectors); + const drmModeModeInfo& mode); virtual bool DisableCrtc(uint32_t crtc_id); @@ -168,7 +163,8 @@ class DrmDevice : public base::RefCountedThreadSafe<DrmDevice> { uint64_t value); // Creates a property blob with data |blob| of size |size|. - virtual ScopedDrmPropertyBlob CreatePropertyBlob(void* blob, size_t size); + virtual ScopedDrmPropertyBlob CreatePropertyBlob(const void* blob, + size_t size); virtual void DestroyPropertyBlob(uint32_t id); diff --git a/chromium/ui/ozone/platform/drm/gpu/drm_display.cc b/chromium/ui/ozone/platform/drm/gpu/drm_display.cc index 6cf5be1105d..89b9ea98bb4 100644 --- a/chromium/ui/ozone/platform/drm/gpu/drm_display.cc +++ b/chromium/ui/ozone/platform/drm/gpu/drm_display.cc @@ -8,6 +8,7 @@ #include <memory> #include "base/stl_util.h" +#include "base/trace_event/trace_event.h" #include "ui/display/types/display_snapshot.h" #include "ui/display/types/gamma_ramp_rgb_entry.h" #include "ui/ozone/platform/drm/common/drm_util.h" @@ -20,6 +21,8 @@ namespace { const char kContentProtection[] = "Content Protection"; +const char kPrivacyScreen[] = "privacy-screen"; + struct ContentProtectionMapping { const char* name; display::HDCPState state; @@ -49,15 +52,16 @@ uint32_t GetContentProtectionValue(drmModePropertyRes* property, return 0; } -std::string GetEnumNameForProperty(drmModeConnector* connector, +std::string GetEnumNameForProperty(drmModeObjectProperties* property_values, drmModePropertyRes* property) { - for (int prop_idx = 0; prop_idx < connector->count_props; ++prop_idx) { - if (connector->props[prop_idx] != property->prop_id) + for (uint32_t prop_idx = 0; prop_idx < property_values->count_props; + ++prop_idx) { + if (property_values->props[prop_idx] != property->prop_id) continue; for (int enum_idx = 0; enum_idx < property->count_enums; ++enum_idx) { const drm_mode_property_enum& property_enum = property->enums[enum_idx]; - if (property_enum.value == connector->prop_values[prop_idx]) + if (property_enum.value == property_values->prop_values[prop_idx]) return property_enum.name; } } @@ -114,7 +118,7 @@ std::unique_ptr<display::DisplaySnapshot> DrmDisplay::Update( bool DrmDisplay::Configure(const drmModeModeInfo* mode, const gfx::Point& origin) { VLOG(1) << "DRM configuring: device=" << drm_->device_path().value() - << " crtc=" << crtc_ << " connector=" << connector_ + << " crtc=" << crtc_ << " connector=" << connector_->connector_id << " origin=" << origin.ToString() << " size=" << (mode ? GetDrmModeSize(*mode).ToString() : "0x0") << " refresh_rate=" << (mode ? mode->vrefresh : 0) << "Hz"; @@ -123,7 +127,7 @@ bool DrmDisplay::Configure(const drmModeModeInfo* 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_; + << " crtc=" << crtc_ << " connector=" << connector_->connector_id; return false; } } else { @@ -142,6 +146,8 @@ bool DrmDisplay::GetHDCPState(display::HDCPState* state) { if (!connector_) return false; + TRACE_EVENT1("drm", "DrmDisplay::GetHDCPState", "connector", + connector_->connector_id); ScopedDrmPropertyPtr hdcp_property( drm_->GetProperty(connector_.get(), kContentProtection)); if (!hdcp_property) { @@ -149,8 +155,10 @@ bool DrmDisplay::GetHDCPState(display::HDCPState* state) { return false; } + ScopedDrmObjectPropertyPtr property_values(drm_->GetObjectProperties( + connector_->connector_id, DRM_MODE_OBJECT_CONNECTOR)); std::string name = - GetEnumNameForProperty(connector_.get(), hdcp_property.get()); + GetEnumNameForProperty(property_values.get(), hdcp_property.get()); for (size_t i = 0; i < base::size(kContentProtectionStates); ++i) { if (name == kContentProtectionStates[i].name) { *state = kContentProtectionStates[i].state; @@ -200,4 +208,25 @@ void DrmDisplay::SetGammaCorrection( } } +// TODO(gildekel): consider reformatting this to use the new DRM API or cache +// |privacy_screen_property| after crrev.com/c/1715751 lands. +void DrmDisplay::SetPrivacyScreen(bool enabled) { + if (!connector_) + return; + + ScopedDrmPropertyPtr privacy_screen_property( + drm_->GetProperty(connector_.get(), kPrivacyScreen)); + + if (!privacy_screen_property) { + LOG(ERROR) << "'" << kPrivacyScreen << "' property doesn't exist."; + return; + } + + if (!drm_->SetProperty(connector_->connector_id, + privacy_screen_property->prop_id, enabled)) { + LOG(ERROR) << (enabled ? "Enabling" : "Disabling") << " property '" + << kPrivacyScreen << "' failed!"; + } +} + } // namespace ui diff --git a/chromium/ui/ozone/platform/drm/gpu/drm_display.h b/chromium/ui/ozone/platform/drm/gpu/drm_display.h index c2516cb4d8f..b6a1d08f9b2 100644 --- a/chromium/ui/ozone/platform/drm/gpu/drm_display.h +++ b/chromium/ui/ozone/platform/drm/gpu/drm_display.h @@ -54,6 +54,7 @@ class DrmDisplay { void SetGammaCorrection( const std::vector<display::GammaRampRGBEntry>& degamma_lut, const std::vector<display::GammaRampRGBEntry>& gamma_lut); + void SetPrivacyScreen(bool enabled); private: ScreenManager* screen_manager_; // Not owned. diff --git a/chromium/ui/ozone/platform/drm/gpu/drm_framebuffer.cc b/chromium/ui/ozone/platform/drm/gpu/drm_framebuffer.cc index 9b855fdda03..772786b42ed 100644 --- a/chromium/ui/ozone/platform/drm/gpu/drm_framebuffer.cc +++ b/chromium/ui/ozone/platform/drm/gpu/drm_framebuffer.cc @@ -6,8 +6,9 @@ #include <utility> -#include "ui/ozone/common/linux/drm_util_linux.h" -#include "ui/ozone/common/linux/gbm_buffer.h" +#include "ui/gfx/buffer_format_util.h" +#include "ui/gfx/linux/drm_util_linux.h" +#include "ui/gfx/linux/gbm_buffer.h" #include "ui/ozone/platform/drm/common/drm_util.h" #include "ui/ozone/platform/drm/gpu/drm_device.h" @@ -28,8 +29,18 @@ scoped_refptr<DrmFramebuffer> DrmFramebuffer::AddFramebuffer( modifiers[i] = params.modifier; } + const auto fourcc_format = GetBufferFormatFromFourCCFormat(params.format); + const uint32_t opaque_format = + GetFourCCFormatForOpaqueFramebuffer(fourcc_format); + // Intel Display Controller won't support AR/B30 framebuffers, only XR/B30, + // but that doesn't matter because anyway those two bits of alpha are useless; + // use the opaque directly in this case. + const bool force_opaque = AlphaBitsForBufferFormat(fourcc_format) == 2; + + const auto drm_format = force_opaque ? opaque_format : params.format; + uint32_t framebuffer_id = 0; - if (!drm_device->AddFramebuffer2(params.width, params.height, params.format, + if (!drm_device->AddFramebuffer2(params.width, params.height, drm_format, params.handles, params.strides, params.offsets, modifiers, &framebuffer_id, params.flags)) { @@ -37,10 +48,8 @@ scoped_refptr<DrmFramebuffer> DrmFramebuffer::AddFramebuffer( return nullptr; } - uint32_t opaque_format = GetFourCCFormatForOpaqueFramebuffer( - GetBufferFormatFromFourCCFormat(params.format)); uint32_t opaque_framebuffer_id = 0; - if (opaque_format != params.format && + if (opaque_format != drm_format && !drm_device->AddFramebuffer2(params.width, params.height, opaque_format, params.handles, params.strides, params.offsets, modifiers, @@ -51,22 +60,23 @@ scoped_refptr<DrmFramebuffer> DrmFramebuffer::AddFramebuffer( } return base::MakeRefCounted<DrmFramebuffer>( - std::move(drm_device), framebuffer_id, params.format, - opaque_framebuffer_id, opaque_format, params.modifier, - params.preferred_modifiers, gfx::Size(params.width, params.height)); + std::move(drm_device), framebuffer_id, drm_format, opaque_framebuffer_id, + opaque_format, params.modifier, params.preferred_modifiers, + gfx::Size(params.width, params.height)); } // static scoped_refptr<DrmFramebuffer> DrmFramebuffer::AddFramebuffer( scoped_refptr<DrmDevice> drm, const GbmBuffer* buffer, + const gfx::Size& framebuffer_size, std::vector<uint64_t> preferred_modifiers) { - gfx::Size size = buffer->GetSize(); + DCHECK(gfx::Rect(buffer->GetSize()).Contains(gfx::Rect(framebuffer_size))); AddFramebufferParams params; params.format = buffer->GetFormat(); params.modifier = buffer->GetFormatModifier(); - params.width = size.width(); - params.height = size.height(); + params.width = framebuffer_size.width(); + params.height = framebuffer_size.height(); params.num_planes = buffer->GetNumPlanes(); params.preferred_modifiers = preferred_modifiers; for (size_t i = 0; i < params.num_planes; ++i) { diff --git a/chromium/ui/ozone/platform/drm/gpu/drm_framebuffer.h b/chromium/ui/ozone/platform/drm/gpu/drm_framebuffer.h index 9c3991e6b7c..079297ac1a7 100644 --- a/chromium/ui/ozone/platform/drm/gpu/drm_framebuffer.h +++ b/chromium/ui/ozone/platform/drm/gpu/drm_framebuffer.h @@ -45,6 +45,7 @@ class DrmFramebuffer : public base::RefCountedThreadSafe<DrmFramebuffer> { static scoped_refptr<DrmFramebuffer> AddFramebuffer( scoped_refptr<DrmDevice> drm_device, const GbmBuffer* buffer, + const gfx::Size& framebuffer_size, std::vector<uint64_t> preferred_modifiers = std::vector<uint64_t>()); DrmFramebuffer(scoped_refptr<DrmDevice> drm_device, 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 e1c2075e66a..74a5f19d91c 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 @@ -11,7 +11,7 @@ #include "ui/display/types/display_mode.h" #include "ui/display/types/display_snapshot.h" #include "ui/display/types/gamma_ramp_rgb_entry.h" -#include "ui/ozone/common/linux/drm_util_linux.h" +#include "ui/gfx/linux/drm_util_linux.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_device_manager.h" @@ -68,11 +68,10 @@ bool FindMatchingMode(const std::vector<drmModeModeInfo> modes, DrmGpuDisplayManager::DrmGpuDisplayManager(ScreenManager* screen_manager, DrmDeviceManager* drm_device_manager) - : screen_manager_(screen_manager), drm_device_manager_(drm_device_manager) { -} + : screen_manager_(screen_manager), + drm_device_manager_(drm_device_manager) {} -DrmGpuDisplayManager::~DrmGpuDisplayManager() { -} +DrmGpuDisplayManager::~DrmGpuDisplayManager() = default; void DrmGpuDisplayManager::SetClearOverlayCacheCallback( base::RepeatingClosure callback) { @@ -87,6 +86,9 @@ MovableDisplaySnapshots DrmGpuDisplayManager::GetDisplays() { const DrmDeviceVector& devices = drm_device_manager_->GetDrmDevices(); size_t device_index = 0; for (const auto& drm : devices) { + // Receiving a signal that DRM state was updated. Need to reset the plane + // manager's resource cache since IDs may have changed. + drm->plane_manager()->ResetConnectorsCache(drm->GetResources()); auto display_infos = GetAvailableDisplayControllerInfos(drm->get_fd()); for (const auto& display_info : display_infos) { auto it = std::find_if( @@ -215,9 +217,8 @@ void DrmGpuDisplayManager::SetColorMatrix( display->SetColorMatrix(color_matrix); } -void DrmGpuDisplayManager::SetBackgroundColor( - int64_t display_id, - const uint64_t background_color) { +void DrmGpuDisplayManager::SetBackgroundColor(int64_t display_id, + const uint64_t background_color) { DrmDisplay* display = FindDisplay(display_id); if (!display) { LOG(ERROR) << "There is no display with ID" << display_id; @@ -239,6 +240,16 @@ void DrmGpuDisplayManager::SetGammaCorrection( display->SetGammaCorrection(degamma_lut, gamma_lut); } +void DrmGpuDisplayManager::SetPrivacyScreen(int64_t display_id, bool enabled) { + DrmDisplay* display = FindDisplay(display_id); + if (!display) { + LOG(ERROR) << "There is no display with ID " << display_id; + return; + } + + display->SetPrivacyScreen(enabled); +} + DrmDisplay* DrmGpuDisplayManager::FindDisplay(int64_t display_id) { for (const auto& display : displays_) { if (display->display_id() == display_id) 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 e2af38c90f0..885732aaaaf 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 @@ -58,6 +58,7 @@ class DrmGpuDisplayManager { int64_t display_id, const std::vector<display::GammaRampRGBEntry>& degamma_lut, const std::vector<display::GammaRampRGBEntry>& gamma_lut); + void SetPrivacyScreen(int64_t display_id, bool enabled); private: DrmDisplay* FindDisplay(int64_t display_id); diff --git a/chromium/ui/ozone/platform/drm/gpu/drm_gpu_util.cc b/chromium/ui/ozone/platform/drm/gpu/drm_gpu_util.cc index 518916ce903..bc1ab154808 100644 --- a/chromium/ui/ozone/platform/drm/gpu/drm_gpu_util.cc +++ b/chromium/ui/ozone/platform/drm/gpu/drm_gpu_util.cc @@ -4,8 +4,11 @@ #include "ui/ozone/platform/drm/gpu/drm_gpu_util.h" +#include <fcntl.h> +#include <xf86drm.h> #include <xf86drmMode.h> +#include "base/files/scoped_file.h" #include "base/trace_event/trace_event.h" #include "ui/display/types/gamma_ramp_rgb_entry.h" #include "ui/ozone/platform/drm/gpu/drm_device.h" @@ -117,4 +120,23 @@ std::vector<display::GammaRampRGBEntry> ResampleLut( return result; } +bool IsDriverName(const char* device_file_name, const char* driver) { + base::ScopedFD fd(open(device_file_name, O_RDWR)); + if (!fd.is_valid()) { + LOG(ERROR) << "Failed to open DRM device " << device_file_name; + return false; + } + + ScopedDrmVersionPtr version(drmGetVersion(fd.get())); + if (!version) { + LOG(ERROR) << "Failed to query DRM version " << device_file_name; + return false; + } + + if (strncmp(driver, version->name, version->name_len) == 0) + return true; + + return false; +} + } // namespace ui diff --git a/chromium/ui/ozone/platform/drm/gpu/drm_gpu_util.h b/chromium/ui/ozone/platform/drm/gpu/drm_gpu_util.h index 1972bef7af4..ab04da742d3 100644 --- a/chromium/ui/ozone/platform/drm/gpu/drm_gpu_util.h +++ b/chromium/ui/ozone/platform/drm/gpu/drm_gpu_util.h @@ -36,6 +36,9 @@ std::vector<display::GammaRampRGBEntry> ResampleLut( const std::vector<display::GammaRampRGBEntry>& lut_in, size_t desired_size); +// Check DRM driver name match. +bool IsDriverName(const char* device_file_name, const char* driver); + } // namespace ui #endif // UI_OZONE_PLATFORM_DRM_GPU_DRM_GPU_UTIL_H_ diff --git a/chromium/ui/ozone/platform/drm/common/drm_overlay_candidates.cc b/chromium/ui/ozone/platform/drm/gpu/drm_overlay_candidates.cc index 97b0deedc49..24f26109b82 100644 --- a/chromium/ui/ozone/platform/drm/common/drm_overlay_candidates.cc +++ b/chromium/ui/ozone/platform/drm/gpu/drm_overlay_candidates.cc @@ -2,9 +2,9 @@ // 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/common/drm_overlay_candidates.h" +#include "ui/ozone/platform/drm/gpu/drm_overlay_candidates.h" -#include "ui/ozone/platform/drm/common/drm_overlay_manager.h" +#include "ui/ozone/platform/drm/gpu/drm_overlay_manager.h" #include "ui/ozone/public/overlay_surface_candidate.h" namespace ui { diff --git a/chromium/ui/ozone/platform/drm/common/drm_overlay_candidates.h b/chromium/ui/ozone/platform/drm/gpu/drm_overlay_candidates.h index b0b49fb6eb0..bd9577ea8e7 100644 --- a/chromium/ui/ozone/platform/drm/common/drm_overlay_candidates.h +++ b/chromium/ui/ozone/platform/drm/gpu/drm_overlay_candidates.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_COMMON_DRM_OVERLAY_CANDIDATES_H_ -#define UI_OZONE_PLATFORM_DRM_COMMON_DRM_OVERLAY_CANDIDATES_H_ +#ifndef UI_OZONE_PLATFORM_DRM_GPU_DRM_OVERLAY_CANDIDATES_H_ +#define UI_OZONE_PLATFORM_DRM_GPU_DRM_OVERLAY_CANDIDATES_H_ #include <vector> @@ -36,4 +36,4 @@ class DrmOverlayCandidates : public OverlayCandidatesOzone { } // namespace ui -#endif // UI_OZONE_PLATFORM_DRM_COMMON_DRM_OVERLAY_CANDIDATES_H_ +#endif // UI_OZONE_PLATFORM_DRM_GPU_DRM_OVERLAY_CANDIDATES_H_ diff --git a/chromium/ui/ozone/platform/drm/common/drm_overlay_manager.cc b/chromium/ui/ozone/platform/drm/gpu/drm_overlay_manager.cc index 2c53f4adbc6..686e6633801 100644 --- a/chromium/ui/ozone/platform/drm/common/drm_overlay_manager.cc +++ b/chromium/ui/ozone/platform/drm/gpu/drm_overlay_manager.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/common/drm_overlay_manager.h" +#include "ui/ozone/platform/drm/gpu/drm_overlay_manager.h" #include <algorithm> #include <memory> @@ -10,21 +10,34 @@ #include "base/metrics/histogram_macros.h" #include "base/trace_event/trace_event.h" +#include "ui/base/ui_base_features.h" #include "ui/gfx/geometry/rect_conversions.h" -#include "ui/ozone/platform/drm/common/drm_overlay_candidates.h" +#include "ui/ozone/platform/drm/gpu/drm_overlay_candidates.h" #include "ui/ozone/public/overlay_surface_candidate.h" namespace ui { namespace { // Maximum number of overlay configurations to keep in MRU cache. -constexpr size_t kMaxCacheSize = 10; +constexpr size_t kMaxCacheSize = 100; // How many times an overlay configuration needs to be requested before sending // a query to display controller to see if the request will work. The overlay // configuration will be rejected until a query is sent and response received. constexpr int kThrottleRequestSize = 3; +// Returns |candidates| but with all NativePixmap pointers removed in order to +// avoid keeping them alive. +std::vector<OverlaySurfaceCandidate> ToCacheKey( + const std::vector<OverlaySurfaceCandidate>& candidates) { + std::vector<OverlaySurfaceCandidate> result = candidates; + for (auto& candidate : result) { + // Make sure the cache entry does not keep the NativePixmap alive. + candidate.native_pixmap = nullptr; + } + return result; +} + } // namespace DrmOverlayManager::DrmOverlayManager() { @@ -66,13 +79,28 @@ void DrmOverlayManager::CheckOverlaySupport( result_candidates.back().overlay_handled = can_handle; } + if (features::IsSynchronousPageFlipTestingEnabled()) { + std::vector<OverlayStatus> status = + SendOverlayValidationRequestSync(result_candidates, widget); + size_t size = candidates->size(); + DCHECK_EQ(size, status.size()); + for (size_t i = 0; i < size; i++) { + DCHECK(status[i] == OVERLAY_STATUS_ABLE || + status[i] == OVERLAY_STATUS_NOT); + candidates->at(i).overlay_handled = status[i] == OVERLAY_STATUS_ABLE; + } + return; + } + auto widget_cache_map_it = widget_cache_map_.find(widget); if (widget_cache_map_it == widget_cache_map_.end()) { widget_cache_map_it = widget_cache_map_.emplace(widget, kMaxCacheSize).first; } OverlayCandidatesListCache& cache = widget_cache_map_it->second; - auto iter = cache.Get(result_candidates); + std::vector<OverlaySurfaceCandidate> cache_key = + ToCacheKey(result_candidates); + auto iter = cache.Get(cache_key); if (iter == cache.end()) { // We can skip GPU side validation in case all candidates are invalid. bool needs_gpu_validation = std::any_of( @@ -82,7 +110,7 @@ void DrmOverlayManager::CheckOverlaySupport( value.status.resize(result_candidates.size(), needs_gpu_validation ? OVERLAY_STATUS_PENDING : OVERLAY_STATUS_NOT); - iter = cache.Put(result_candidates, std::move(value)); + iter = cache.Put(cache_key, std::move(value)); } bool cache_hit = false; @@ -104,7 +132,8 @@ void DrmOverlayManager::CheckOverlaySupport( candidates->at(i).overlay_handled = status[i] == OVERLAY_STATUS_ABLE; } } - UMA_HISTOGRAM_BOOLEAN("DrmOverlayManager.CacheHit", cache_hit); + UMA_HISTOGRAM_BOOLEAN("Compositing.Display.DrmOverlayManager.CacheHit", + cache_hit); } bool DrmOverlayManager::CanHandleCandidate( @@ -139,7 +168,7 @@ void DrmOverlayManager::UpdateCacheForOverlayCandidates( return; OverlayCandidatesListCache& cache = widget_cache_map_it->second; - auto iter = cache.Peek(candidates); + auto iter = cache.Peek(ToCacheKey(candidates)); if (iter != cache.end()) iter->second.status = status; } diff --git a/chromium/ui/ozone/platform/drm/common/drm_overlay_manager.h b/chromium/ui/ozone/platform/drm/gpu/drm_overlay_manager.h index f748fe4fa41..87173fa824a 100644 --- a/chromium/ui/ozone/platform/drm/common/drm_overlay_manager.h +++ b/chromium/ui/ozone/platform/drm/gpu/drm_overlay_manager.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_COMMON_DRM_OVERLAY_MANAGER_H_ -#define UI_OZONE_PLATFORM_DRM_COMMON_DRM_OVERLAY_MANAGER_H_ +#ifndef UI_OZONE_PLATFORM_DRM_GPU_DRM_OVERLAY_MANAGER_H_ +#define UI_OZONE_PLATFORM_DRM_GPU_DRM_OVERLAY_MANAGER_H_ #include <memory> #include <vector> @@ -46,9 +46,15 @@ class DrmOverlayManager : public OverlayManagerOzone { const std::vector<OverlaySurfaceCandidate>& candidates, gfx::AcceleratedWidget widget) = 0; + // Similar to SendOverlayValidationRequest() but instead of calling + // UpdateCacheForOverlayCandidates(), returns the result synchronously. + virtual std::vector<OverlayStatus> SendOverlayValidationRequestSync( + const std::vector<OverlaySurfaceCandidate>& candidates, + gfx::AcceleratedWidget widget) = 0; + // Perform basic validation to see if |candidate| is a valid request. - virtual bool CanHandleCandidate(const OverlaySurfaceCandidate& candidate, - gfx::AcceleratedWidget widget) const; + bool CanHandleCandidate(const OverlaySurfaceCandidate& candidate, + gfx::AcceleratedWidget widget) const; // Updates the MRU cache for overlay configuration |candidates| with |status|. void UpdateCacheForOverlayCandidates( @@ -86,4 +92,4 @@ class DrmOverlayManager : public OverlayManagerOzone { } // namespace ui -#endif // UI_OZONE_PLATFORM_DRM_COMMON_DRM_OVERLAY_MANAGER_H_ +#endif // UI_OZONE_PLATFORM_DRM_GPU_DRM_OVERLAY_MANAGER_H_ diff --git a/chromium/ui/ozone/platform/drm/gpu/drm_overlay_manager_gpu.cc b/chromium/ui/ozone/platform/drm/gpu/drm_overlay_manager_gpu.cc index ecadeb3c81d..2137523fbd8 100644 --- a/chromium/ui/ozone/platform/drm/gpu/drm_overlay_manager_gpu.cc +++ b/chromium/ui/ozone/platform/drm/gpu/drm_overlay_manager_gpu.cc @@ -23,7 +23,25 @@ void DrmOverlayManagerGpu::SendOverlayValidationRequest( gfx::AcceleratedWidget widget) { TRACE_EVENT_ASYNC_BEGIN0( "hwoverlays", "DrmOverlayManagerGpu::SendOverlayValidationRequest", this); + SetClearCacheCallbackIfNecessary(); + drm_thread_proxy_->CheckOverlayCapabilities( + widget, candidates, + base::BindOnce(&DrmOverlayManagerGpu::ReceiveOverlayValidationResponse, + weak_ptr_factory_.GetWeakPtr())); +} +std::vector<OverlayStatus> +DrmOverlayManagerGpu::SendOverlayValidationRequestSync( + const std::vector<OverlaySurfaceCandidate>& candidates, + gfx::AcceleratedWidget widget) { + TRACE_EVENT_ASYNC_BEGIN0( + "hwoverlays", "DrmOverlayManagerGpu::SendOverlayValidationRequestSync", + this); + SetClearCacheCallbackIfNecessary(); + return drm_thread_proxy_->CheckOverlayCapabilitiesSync(widget, candidates); +} + +void DrmOverlayManagerGpu::SetClearCacheCallbackIfNecessary() { // Adds a callback for the DRM thread to let us know when display // configuration has changed and to reset cache of valid overlay // configurations. This happens in SendOverlayValidationRequest() because the @@ -35,11 +53,6 @@ void DrmOverlayManagerGpu::SendOverlayValidationRequest( drm_thread_proxy_->SetClearOverlayCacheCallback(base::BindRepeating( &DrmOverlayManagerGpu::ResetCache, weak_ptr_factory_.GetWeakPtr())); } - - drm_thread_proxy_->CheckOverlayCapabilities( - widget, candidates, - base::BindOnce(&DrmOverlayManagerGpu::ReceiveOverlayValidationResponse, - weak_ptr_factory_.GetWeakPtr())); } void DrmOverlayManagerGpu::ReceiveOverlayValidationResponse( diff --git a/chromium/ui/ozone/platform/drm/gpu/drm_overlay_manager_gpu.h b/chromium/ui/ozone/platform/drm/gpu/drm_overlay_manager_gpu.h index da66930887f..3931e02dac5 100644 --- a/chromium/ui/ozone/platform/drm/gpu/drm_overlay_manager_gpu.h +++ b/chromium/ui/ozone/platform/drm/gpu/drm_overlay_manager_gpu.h @@ -9,7 +9,7 @@ #include "base/macros.h" #include "base/memory/weak_ptr.h" -#include "ui/ozone/platform/drm/common/drm_overlay_manager.h" +#include "ui/ozone/platform/drm/gpu/drm_overlay_manager.h" namespace ui { class DrmThreadProxy; @@ -26,6 +26,11 @@ class DrmOverlayManagerGpu : public DrmOverlayManager { void SendOverlayValidationRequest( const std::vector<OverlaySurfaceCandidate>& candidates, gfx::AcceleratedWidget widget) override; + std::vector<OverlayStatus> SendOverlayValidationRequestSync( + const std::vector<OverlaySurfaceCandidate>& candidates, + gfx::AcceleratedWidget widget) override; + + void SetClearCacheCallbackIfNecessary(); void ReceiveOverlayValidationResponse( gfx::AcceleratedWidget widget, diff --git a/chromium/ui/ozone/platform/drm/common/drm_overlay_manager_unittest.cc b/chromium/ui/ozone/platform/drm/gpu/drm_overlay_manager_unittest.cc index 6d13aae57e1..a668e215095 100644 --- a/chromium/ui/ozone/platform/drm/common/drm_overlay_manager_unittest.cc +++ b/chromium/ui/ozone/platform/drm/gpu/drm_overlay_manager_unittest.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/common/drm_overlay_manager.h" +#include "ui/ozone/platform/drm/gpu/drm_overlay_manager.h" #include "base/bind.h" #include "base/callback.h" @@ -33,6 +33,11 @@ class TestDrmOverlayManager : public DrmOverlayManager { gfx::AcceleratedWidget widget) override { requests_.push_back(candidates); } + std::vector<OverlayStatus> SendOverlayValidationRequestSync( + const std::vector<OverlaySurfaceCandidate>& candidates, + gfx::AcceleratedWidget widget) override { + return {}; + } private: std::vector<std::vector<OverlaySurfaceCandidate>> requests_; diff --git a/chromium/ui/ozone/platform/drm/gpu/drm_overlay_validator.cc b/chromium/ui/ozone/platform/drm/gpu/drm_overlay_validator.cc index 27ce37a0be7..4c496547411 100644 --- a/chromium/ui/ozone/platform/drm/gpu/drm_overlay_validator.cc +++ b/chromium/ui/ozone/platform/drm/gpu/drm_overlay_validator.cc @@ -9,15 +9,17 @@ #include <vector> #include "base/files/platform_file.h" +#include "base/metrics/histogram_macros.h" #include "ui/gfx/geometry/rect_conversions.h" #include "ui/gfx/geometry/size_conversions.h" #include "ui/gfx/gpu_fence.h" -#include "ui/ozone/common/linux/drm_util_linux.h" -#include "ui/ozone/common/linux/gbm_buffer.h" +#include "ui/gfx/linux/drm_util_linux.h" +#include "ui/gfx/linux/gbm_buffer.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_framebuffer.h" #include "ui/ozone/platform/drm/gpu/drm_window.h" +#include "ui/ozone/platform/drm/gpu/gbm_pixmap.h" #include "ui/ozone/platform/drm/gpu/hardware_display_controller.h" namespace ui { @@ -27,7 +29,12 @@ namespace { scoped_refptr<DrmFramebuffer> GetBufferForPageFlipTest( const DrmWindow* drm_window, const OverlaySurfaceCandidate& overlay_surface, - std::vector<scoped_refptr<DrmFramebuffer>>* reusable_buffers) { + std::vector<scoped_refptr<DrmFramebuffer>>* reusable_buffers, + size_t* total_allocated_memory_size) { + if (overlay_surface.native_pixmap) { + return static_cast<GbmPixmap*>(overlay_surface.native_pixmap.get()) + ->framebuffer(); + } uint32_t fourcc_format = overlay_surface.is_opaque ? GetFourCCFormatForOpaqueFramebuffer(overlay_surface.format) @@ -58,11 +65,16 @@ scoped_refptr<DrmFramebuffer> GetBufferForPageFlipTest( fourcc_format, size, GBM_BO_USE_SCANOUT, modifiers) : drm_device->gbm_device()->CreateBuffer(fourcc_format, size, GBM_BO_USE_SCANOUT); + if (!buffer) return nullptr; + for (size_t i = 0; i < buffer->GetNumPlanes(); ++i) + *total_allocated_memory_size += buffer->GetPlaneSize(i); + scoped_refptr<DrmFramebuffer> drm_framebuffer = - DrmFramebuffer::AddFramebuffer(drm_device, buffer.get(), modifiers); + DrmFramebuffer::AddFramebuffer(drm_device, buffer.get(), + buffer->GetSize(), modifiers); if (!drm_framebuffer) return nullptr; @@ -96,14 +108,16 @@ OverlayStatusList DrmOverlayValidator::TestPageFlip( for (const auto& plane : last_used_planes) reusable_buffers.push_back(plane.buffer); + size_t total_allocated_memory_size = 0; + for (size_t i = 0; i < params.size(); ++i) { if (!params[i].overlay_handled) { returns[i] = OVERLAY_STATUS_NOT; continue; } - scoped_refptr<DrmFramebuffer> buffer = - GetBufferForPageFlipTest(window_, params[i], &reusable_buffers); + scoped_refptr<DrmFramebuffer> buffer = GetBufferForPageFlipTest( + window_, params[i], &reusable_buffers, &total_allocated_memory_size); DrmOverlayPlane plane(buffer, params[i].plane_z_order, params[i].transform, gfx::ToNearestRect(params[i].display_rect), @@ -125,6 +139,10 @@ OverlayStatusList DrmOverlayValidator::TestPageFlip( } } + UMA_HISTOGRAM_MEMORY_KB( + "Compositing.Display.DrmOverlayManager.TotalTestBufferMemorySize", + total_allocated_memory_size / 1024); + return returns; } 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 e6517340906..cc86756bdf3 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 @@ -14,9 +14,10 @@ #include "testing/gtest/include/gtest/gtest.h" #include "ui/gfx/geometry/rect_conversions.h" #include "ui/gfx/gpu_fence.h" +#include "ui/gfx/linux/drm_util_linux.h" +#include "ui/gfx/linux/gbm_buffer.h" +#include "ui/gfx/linux/test/mock_gbm_device.h" #include "ui/ozone/common/gpu/ozone_gpu_message_params.h" -#include "ui/ozone/common/linux/drm_util_linux.h" -#include "ui/ozone/common/linux/gbm_buffer.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" @@ -25,7 +26,6 @@ #include "ui/ozone/platform/drm/gpu/drm_window.h" #include "ui/ozone/platform/drm/gpu/hardware_display_controller.h" #include "ui/ozone/platform/drm/gpu/mock_drm_device.h" -#include "ui/ozone/platform/drm/gpu/mock_gbm_device.h" #include "ui/ozone/platform/drm/gpu/screen_manager.h" namespace { @@ -40,14 +40,14 @@ constexpr uint32_t kConnectorIdBase = 100; constexpr uint32_t kPlaneIdBase = 200; constexpr uint32_t kInFormatsBlobPropIdBase = 400; -constexpr uint32_t kTypePropId = 300; -constexpr uint32_t kInFormatsPropId = 301; +constexpr uint32_t kTypePropId = 3010; +constexpr uint32_t kInFormatsPropId = 3011; } // namespace class DrmOverlayValidatorTest : public testing::Test { public: - DrmOverlayValidatorTest() {} + DrmOverlayValidatorTest() = default; void SetUp() override; void TearDown() override; @@ -67,14 +67,15 @@ class DrmOverlayValidatorTest : public testing::Test { scoped_refptr<ui::DrmFramebuffer> CreateBuffer() { auto gbm_buffer = drm_->gbm_device()->CreateBuffer( DRM_FORMAT_XRGB8888, primary_rect_.size(), GBM_BO_USE_SCANOUT); - return ui::DrmFramebuffer::AddFramebuffer(drm_, gbm_buffer.get()); + return ui::DrmFramebuffer::AddFramebuffer(drm_, gbm_buffer.get(), + primary_rect_.size()); } scoped_refptr<ui::DrmFramebuffer> CreateOverlayBuffer(uint32_t format, const gfx::Size& size) { auto gbm_buffer = drm_->gbm_device()->CreateBuffer(format, size, GBM_BO_USE_SCANOUT); - return ui::DrmFramebuffer::AddFramebuffer(drm_, gbm_buffer.get()); + return ui::DrmFramebuffer::AddFramebuffer(drm_, gbm_buffer.get(), size); } protected: @@ -86,7 +87,7 @@ class DrmOverlayValidatorTest : public testing::Test { std::vector<PlaneState> planes; }; - void InitializeDrmState(const std::vector<CrtcState>& crtc_states); + void InitDrmStatesAndControllers(const std::vector<CrtcState>& crtc_states); base::test::SingleThreadTaskEnvironment task_environment_{ base::test::SingleThreadTaskEnvironment::MainThreadType::UI}; @@ -105,6 +106,8 @@ class DrmOverlayValidatorTest : public testing::Test { gfx::Rect primary_rect_; private: + void SetupControllers(); + DISALLOW_COPY_AND_ASSIGN(DrmOverlayValidatorTest); }; @@ -115,70 +118,42 @@ void DrmOverlayValidatorTest::SetUp() { auto gbm = std::make_unique<ui::MockGbmDevice>(); gbm_ = gbm.get(); drm_ = new ui::MockDrmDevice(std::move(gbm)); - - CrtcState crtc_state = {/* .planes = */ { - {/* .formats = */ {DRM_FORMAT_XRGB8888}}, - }}; - InitializeDrmState({crtc_state}); - - screen_manager_ = std::make_unique<ui::ScreenManager>(); - screen_manager_->AddDisplayController(drm_, kCrtcIdBase, kConnectorIdBase); - screen_manager_->ConfigureDisplayController( - drm_, kCrtcIdBase, kConnectorIdBase, gfx::Point(), kDefaultMode); - - drm_device_manager_ = std::make_unique<ui::DrmDeviceManager>(nullptr); - - std::unique_ptr<ui::DrmWindow> window(new ui::DrmWindow( - kDefaultWidgetHandle, drm_device_manager_.get(), screen_manager_.get())); - window->Initialize(); - window->SetBounds( - gfx::Rect(gfx::Size(kDefaultMode.hdisplay, kDefaultMode.vdisplay))); - screen_manager_->AddWindow(kDefaultWidgetHandle, std::move(window)); - window_ = screen_manager_->GetWindow(kDefaultWidgetHandle); - overlay_validator_ = std::make_unique<ui::DrmOverlayValidator>(window_); - - overlay_rect_ = - gfx::Rect(0, 0, kDefaultMode.hdisplay / 2, kDefaultMode.vdisplay / 2); - - primary_rect_ = gfx::Rect(0, 0, kDefaultMode.hdisplay, kDefaultMode.vdisplay); - - ui::OverlaySurfaceCandidate primary_candidate; - primary_candidate.buffer_size = primary_rect_.size(); - primary_candidate.display_rect = gfx::RectF(primary_rect_); - primary_candidate.is_opaque = true; - primary_candidate.format = gfx::BufferFormat::BGRX_8888; - primary_candidate.overlay_handled = true; - overlay_params_.push_back(primary_candidate); - AddPlane(primary_candidate); - - ui::OverlaySurfaceCandidate overlay_candidate; - overlay_candidate.buffer_size = overlay_rect_.size(); - overlay_candidate.display_rect = gfx::RectF(overlay_rect_); - overlay_candidate.plane_z_order = 1; - primary_candidate.is_opaque = true; - overlay_candidate.format = gfx::BufferFormat::BGRX_8888; - overlay_candidate.overlay_handled = true; - overlay_params_.push_back(overlay_candidate); - AddPlane(overlay_candidate); } -void DrmOverlayValidatorTest::InitializeDrmState( +void DrmOverlayValidatorTest::InitDrmStatesAndControllers( const std::vector<CrtcState>& crtc_states) { 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(2); + 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 = kConnectorIdBase + 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> property_names = { + std::map<uint32_t, std::string> plane_property_names = { // Add all required properties. - {1000, "CRTC_ID"}, - {1001, "CRTC_X"}, - {1002, "CRTC_Y"}, - {1003, "CRTC_W"}, - {1004, "CRTC_H"}, - {1005, "FB_ID"}, - {1006, "SRC_X"}, - {1007, "SRC_Y"}, - {1008, "SRC_W"}, - {1009, "SRC_H"}, + {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"}, @@ -189,6 +164,10 @@ void DrmOverlayValidatorTest::InitializeDrmState( for (size_t crtc_idx = 0; crtc_idx < crtc_states.size(); ++crtc_idx) { crtc_properties[crtc_idx].id = kCrtcIdBase + 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()); @@ -197,7 +176,7 @@ void DrmOverlayValidatorTest::InitializeDrmState( crtc_plane_properties[plane_idx].id = plane_id++; crtc_plane_properties[plane_idx].crtc_mask = 1 << crtc_idx; - for (const auto& pair : property_names) { + for (const auto& pair : plane_property_names) { uint64_t value = 0; if (pair.first == kTypePropId) { value = @@ -219,8 +198,59 @@ void DrmOverlayValidatorTest::InitializeDrmState( crtc_plane_properties.end()); } - drm_->InitializeState(crtc_properties, plane_properties, property_names, + 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, /* use_atomic= */ true); + + SetupControllers(); +} + +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); + + drm_device_manager_ = std::make_unique<ui::DrmDeviceManager>(nullptr); + + std::unique_ptr<ui::DrmWindow> window(new ui::DrmWindow( + kDefaultWidgetHandle, drm_device_manager_.get(), screen_manager_.get())); + window->Initialize(); + window->SetBounds( + gfx::Rect(gfx::Size(kDefaultMode.hdisplay, kDefaultMode.vdisplay))); + screen_manager_->AddWindow(kDefaultWidgetHandle, std::move(window)); + window_ = screen_manager_->GetWindow(kDefaultWidgetHandle); + overlay_validator_ = std::make_unique<ui::DrmOverlayValidator>(window_); + + overlay_rect_ = + gfx::Rect(0, 0, kDefaultMode.hdisplay / 2, kDefaultMode.vdisplay / 2); + + primary_rect_ = gfx::Rect(0, 0, kDefaultMode.hdisplay, kDefaultMode.vdisplay); + + ui::OverlaySurfaceCandidate primary_candidate; + primary_candidate.buffer_size = primary_rect_.size(); + primary_candidate.display_rect = gfx::RectF(primary_rect_); + primary_candidate.is_opaque = true; + primary_candidate.format = gfx::BufferFormat::BGRX_8888; + primary_candidate.overlay_handled = true; + overlay_params_.push_back(primary_candidate); + AddPlane(primary_candidate); + + ui::OverlaySurfaceCandidate overlay_candidate; + overlay_candidate.buffer_size = overlay_rect_.size(); + overlay_candidate.display_rect = gfx::RectF(overlay_rect_); + overlay_candidate.plane_z_order = 1; + primary_candidate.is_opaque = true; + overlay_candidate.format = gfx::BufferFormat::BGRX_8888; + overlay_candidate.overlay_handled = true; + overlay_params_.push_back(overlay_candidate); + AddPlane(overlay_candidate); } void DrmOverlayValidatorTest::AddPlane( @@ -242,6 +272,11 @@ void DrmOverlayValidatorTest::TearDown() { } TEST_F(DrmOverlayValidatorTest, WindowWithNoController) { + CrtcState crtc_state = {/* .planes = */ { + {/* .formats = */ {DRM_FORMAT_XRGB8888}}, + }}; + InitDrmStatesAndControllers({crtc_state}); + // We should never promote layers to overlay when controller is not // present. ui::HardwareDisplayController* controller = window_->GetController(); @@ -254,6 +289,11 @@ TEST_F(DrmOverlayValidatorTest, WindowWithNoController) { } TEST_F(DrmOverlayValidatorTest, DontPromoteMoreLayersThanAvailablePlanes) { + CrtcState crtc_state = {/* .planes = */ { + {/* .formats = */ {DRM_FORMAT_XRGB8888}}, + }}; + InitDrmStatesAndControllers({crtc_state}); + std::vector<ui::OverlayStatus> returns = overlay_validator_->TestPageFlip( overlay_params_, ui::DrmOverlayPlaneList()); EXPECT_EQ(returns.front(), ui::OVERLAY_STATUS_ABLE); @@ -261,6 +301,11 @@ TEST_F(DrmOverlayValidatorTest, DontPromoteMoreLayersThanAvailablePlanes) { } TEST_F(DrmOverlayValidatorTest, DontCollapseOverlayToPrimaryInFullScreen) { + CrtcState crtc_state = {/* .planes = */ { + {/* .formats = */ {DRM_FORMAT_XRGB8888}}, + }}; + InitDrmStatesAndControllers({crtc_state}); + // Overlay Validator should not collapse planes during validation. overlay_params_.back().buffer_size = primary_rect_.size(); overlay_params_.back().display_rect = gfx::RectF(primary_rect_); @@ -277,10 +322,6 @@ TEST_F(DrmOverlayValidatorTest, DontCollapseOverlayToPrimaryInFullScreen) { TEST_F(DrmOverlayValidatorTest, OverlayFormat_XRGB) { // This test checks for optimal format in case of non full screen video case. // This should be XRGB when overlay doesn't support YUV. - overlay_params_.back().buffer_size = overlay_rect_.size(); - overlay_params_.back().display_rect = gfx::RectF(overlay_rect_); - plane_list_.back().display_bounds = overlay_rect_; - CrtcState state = { /* .planes = */ { @@ -288,7 +329,11 @@ TEST_F(DrmOverlayValidatorTest, OverlayFormat_XRGB) { {/* .formats = */ {DRM_FORMAT_XRGB8888}}, }, }; - InitializeDrmState(std::vector<CrtcState>(1, state)); + InitDrmStatesAndControllers(std::vector<CrtcState>(1, state)); + + overlay_params_.back().buffer_size = overlay_rect_.size(); + overlay_params_.back().display_rect = gfx::RectF(overlay_rect_); + plane_list_.back().display_bounds = overlay_rect_; std::vector<ui::OverlayStatus> returns = overlay_validator_->TestPageFlip( overlay_params_, ui::DrmOverlayPlaneList()); @@ -301,6 +346,15 @@ TEST_F(DrmOverlayValidatorTest, OverlayFormat_YUV) { // This test checks for optimal format in case of non full screen video case. // Prefer YUV as optimal format when Overlay supports it and scaling is // needed. + CrtcState state = { + /* .planes = */ + { + {/* .formats = */ {DRM_FORMAT_XRGB8888}}, + {/* .formats = */ {DRM_FORMAT_XRGB8888, DRM_FORMAT_NV12}}, + }, + }; + InitDrmStatesAndControllers(std::vector<CrtcState>(1, state)); + gfx::RectF crop_rect = gfx::RectF(0, 0, 0.5, 0.5); overlay_params_.back().buffer_size = overlay_rect_.size(); overlay_params_.back().display_rect = gfx::RectF(overlay_rect_); @@ -310,15 +364,6 @@ TEST_F(DrmOverlayValidatorTest, OverlayFormat_YUV) { plane_list_.pop_back(); AddPlane(overlay_params_.back()); - CrtcState state = { - /* .planes = */ - { - {/* .formats = */ {DRM_FORMAT_XRGB8888}}, - {/* .formats = */ {DRM_FORMAT_XRGB8888, DRM_FORMAT_NV12}}, - }, - }; - InitializeDrmState(std::vector<CrtcState>(1, state)); - std::vector<ui::OverlayStatus> returns = overlay_validator_->TestPageFlip( overlay_params_, ui::DrmOverlayPlaneList()); EXPECT_EQ(2u, returns.size()); @@ -329,12 +374,6 @@ TEST_F(DrmOverlayValidatorTest, OverlayFormat_YUV) { TEST_F(DrmOverlayValidatorTest, RejectYUVBuffersIfNotSupported) { // Check case where buffer storage format is already YUV 420 but planes don't // support it. - overlay_params_.back().buffer_size = overlay_rect_.size(); - overlay_params_.back().display_rect = gfx::RectF(overlay_rect_); - overlay_params_.back().format = gfx::BufferFormat::YUV_420_BIPLANAR; - plane_list_.pop_back(); - AddPlane(overlay_params_.back()); - CrtcState state = { /* .planes = */ { @@ -342,7 +381,13 @@ TEST_F(DrmOverlayValidatorTest, RejectYUVBuffersIfNotSupported) { {/* .formats = */ {DRM_FORMAT_XRGB8888}}, }, }; - InitializeDrmState(std::vector<CrtcState>(1, state)); + InitDrmStatesAndControllers(std::vector<CrtcState>(1, state)); + + overlay_params_.back().buffer_size = overlay_rect_.size(); + overlay_params_.back().display_rect = gfx::RectF(overlay_rect_); + overlay_params_.back().format = gfx::BufferFormat::YUV_420_BIPLANAR; + plane_list_.pop_back(); + AddPlane(overlay_params_.back()); std::vector<ui::OverlaySurfaceCandidate> validated_params = overlay_params_; std::vector<ui::OverlayStatus> returns = overlay_validator_->TestPageFlip( @@ -369,7 +414,7 @@ TEST_F(DrmOverlayValidatorTest, }, }, }; - InitializeDrmState(crtc_states); + InitDrmStatesAndControllers(crtc_states); ui::HardwareDisplayController* controller = window_->GetController(); controller->AddCrtc( @@ -392,30 +437,96 @@ TEST_F(DrmOverlayValidatorTest, validated_params, ui::DrmOverlayPlaneList()); EXPECT_EQ(2u, returns.size()); EXPECT_EQ(returns.back(), ui::OVERLAY_STATUS_ABLE); +} +TEST_F(DrmOverlayValidatorTest, + RejectYUVBuffersIfNotSupported_NoPackedFormatsInMirroredCrtc) { // This configuration should not be promoted to Overlay when either of the // controllers don't support YUV 420 format. - // Check case where we dont have support for packed formats in Mirrored CRTC. - crtc_states[1].planes[1].formats = {DRM_FORMAT_XRGB8888}; - InitializeDrmState(crtc_states); + 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}}, + }, + }, + }; + InitDrmStatesAndControllers(crtc_states); - returns = overlay_validator_->TestPageFlip(validated_params, - ui::DrmOverlayPlaneList()); + ui::HardwareDisplayController* controller = window_->GetController(); + controller->AddCrtc( + std::unique_ptr<ui::CrtcController>(new ui::CrtcController( + drm_.get(), kCrtcIdBase + 1, kConnectorIdBase + 1))); + ui::DrmOverlayPlane plane1(CreateBuffer(), nullptr); + + EXPECT_TRUE(controller->Modeset(plane1, kDefaultMode)); + + gfx::RectF crop_rect = gfx::RectF(0, 0, 0.5, 0.5); + overlay_params_.back().buffer_size = overlay_rect_.size(); + overlay_params_.back().display_rect = gfx::RectF(overlay_rect_); + overlay_params_.back().crop_rect = crop_rect; + plane_list_.back().display_bounds = overlay_rect_; + plane_list_.back().crop_rect = crop_rect; + + std::vector<ui::OverlaySurfaceCandidate> validated_params = overlay_params_; + validated_params.back().format = gfx::BufferFormat::YUV_420_BIPLANAR; + std::vector<ui::OverlayStatus> returns = overlay_validator_->TestPageFlip( + validated_params, ui::DrmOverlayPlaneList()); EXPECT_EQ(2u, returns.size()); EXPECT_EQ(returns.back(), ui::OVERLAY_STATUS_NOT); +} - // Check case where we dont have support for packed formats in primary - // display. - crtc_states[0].planes[1].formats = {DRM_FORMAT_XRGB8888}; - crtc_states[1].planes[1].formats = {DRM_FORMAT_XRGB8888, DRM_FORMAT_NV12}; - InitializeDrmState(crtc_states); +TEST_F(DrmOverlayValidatorTest, + RejectYUVBuffersIfNotSupported_NoPackedFormatsInPrimaryDisplay) { + std::vector<CrtcState> crtc_states = { + { + /* .planes = */ + { + {/* .formats = */ {DRM_FORMAT_XRGB8888}}, + {/* .formats = */ {DRM_FORMAT_XRGB8888}}, + }, + }, + { + /* .planes = */ + { + {/* .formats = */ {DRM_FORMAT_XRGB8888}}, + {/* .formats = */ {DRM_FORMAT_XRGB8888, DRM_FORMAT_NV12}}, + }, + }, + }; + InitDrmStatesAndControllers(crtc_states); + + ui::HardwareDisplayController* controller = window_->GetController(); + controller->AddCrtc( + std::unique_ptr<ui::CrtcController>(new ui::CrtcController( + drm_.get(), kCrtcIdBase + 1, kConnectorIdBase + 1))); + ui::DrmOverlayPlane plane1(CreateBuffer(), nullptr); + + EXPECT_TRUE(controller->Modeset(plane1, kDefaultMode)); + + gfx::RectF crop_rect = gfx::RectF(0, 0, 0.5, 0.5); + overlay_params_.back().buffer_size = overlay_rect_.size(); + overlay_params_.back().display_rect = gfx::RectF(overlay_rect_); + overlay_params_.back().crop_rect = crop_rect; + plane_list_.back().display_bounds = overlay_rect_; + plane_list_.back().crop_rect = crop_rect; + + std::vector<ui::OverlaySurfaceCandidate> validated_params = overlay_params_; + validated_params.back().format = gfx::BufferFormat::YUV_420_BIPLANAR; - returns = overlay_validator_->TestPageFlip(validated_params, - ui::DrmOverlayPlaneList()); + std::vector<ui::OverlayStatus> returns = overlay_validator_->TestPageFlip( + validated_params, ui::DrmOverlayPlaneList()); EXPECT_EQ(2u, returns.size()); EXPECT_EQ(returns.back(), ui::OVERLAY_STATUS_NOT); - controller->RemoveCrtc(drm_, kCrtcIdBase + 1); } TEST_F(DrmOverlayValidatorTest, OptimalFormatXRGB_MirroredControllers) { @@ -435,7 +546,7 @@ TEST_F(DrmOverlayValidatorTest, OptimalFormatXRGB_MirroredControllers) { }, }, }; - InitializeDrmState(crtc_states); + InitDrmStatesAndControllers(crtc_states); ui::HardwareDisplayController* controller = window_->GetController(); controller->AddCrtc( @@ -452,30 +563,87 @@ TEST_F(DrmOverlayValidatorTest, OptimalFormatXRGB_MirroredControllers) { overlay_params_, ui::DrmOverlayPlaneList()); EXPECT_EQ(2u, returns.size()); EXPECT_EQ(returns.back(), ui::OVERLAY_STATUS_ABLE); +} - // Check case where we dont have support for packed formats in Mirrored CRTC. - crtc_states[1].planes[1].formats = {DRM_FORMAT_XRGB8888}; - InitializeDrmState(crtc_states); +TEST_F(DrmOverlayValidatorTest, + OptimalFormatXRGB_NoPackedFormatInMirroredCrtc) { + 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}}, + }, + }, + }; + InitDrmStatesAndControllers(crtc_states); + + ui::HardwareDisplayController* controller = window_->GetController(); + controller->AddCrtc( + std::unique_ptr<ui::CrtcController>(new ui::CrtcController( + drm_.get(), kCrtcIdBase + 1, kConnectorIdBase + 1))); + ui::DrmOverlayPlane plane1(CreateBuffer(), nullptr); + EXPECT_TRUE(controller->Modeset(plane1, kDefaultMode)); + + overlay_params_.back().buffer_size = overlay_rect_.size(); + overlay_params_.back().display_rect = gfx::RectF(overlay_rect_); + plane_list_.back().display_bounds = overlay_rect_; - returns = overlay_validator_->TestPageFlip(overlay_params_, - ui::DrmOverlayPlaneList()); + std::vector<ui::OverlayStatus> returns = overlay_validator_->TestPageFlip( + overlay_params_, ui::DrmOverlayPlaneList()); EXPECT_EQ(returns.back(), ui::OVERLAY_STATUS_ABLE); +} + +TEST_F(DrmOverlayValidatorTest, + OptimalFormatXRGB_NoPackedFormatInPrimaryDisplay) { + std::vector<CrtcState> crtc_states = { + { + /* .planes = */ + { + {/* .formats = */ {DRM_FORMAT_XRGB8888}}, + {/* .formats = */ {DRM_FORMAT_XRGB8888}}, + }, + }, + { + /* .planes = */ + { + {/* .formats = */ {DRM_FORMAT_XRGB8888}}, + {/* .formats = */ {DRM_FORMAT_XRGB8888, DRM_FORMAT_NV12}}, + }, + }, + }; + InitDrmStatesAndControllers(crtc_states); + + ui::HardwareDisplayController* controller = window_->GetController(); + controller->AddCrtc( + std::unique_ptr<ui::CrtcController>(new ui::CrtcController( + drm_.get(), kCrtcIdBase + 1, kConnectorIdBase + 1))); + ui::DrmOverlayPlane plane1(CreateBuffer(), nullptr); + EXPECT_TRUE(controller->Modeset(plane1, kDefaultMode)); - // Check case where we dont have support for packed formats in primary - // display. - crtc_states[0].planes[1].formats = {DRM_FORMAT_XRGB8888}; - crtc_states[1].planes[1].formats = {DRM_FORMAT_XRGB8888, DRM_FORMAT_NV12}; - InitializeDrmState(crtc_states); + overlay_params_.back().buffer_size = overlay_rect_.size(); + overlay_params_.back().display_rect = gfx::RectF(overlay_rect_); + plane_list_.back().display_bounds = overlay_rect_; - returns = overlay_validator_->TestPageFlip(overlay_params_, - ui::DrmOverlayPlaneList()); + std::vector<ui::OverlayStatus> returns = overlay_validator_->TestPageFlip( + overlay_params_, ui::DrmOverlayPlaneList()); EXPECT_EQ(2u, returns.size()); EXPECT_EQ(returns.back(), ui::OVERLAY_STATUS_ABLE); - - controller->RemoveCrtc(drm_, kCrtcIdBase + 1); } TEST_F(DrmOverlayValidatorTest, RejectBufferAllocationFail) { + CrtcState crtc_state = {/* .planes = */ { + {/* .formats = */ {DRM_FORMAT_XRGB8888}}, + }}; + InitDrmStatesAndControllers({crtc_state}); + // Buffer allocation for scanout might fail. // In that case we should reject the overlay candidate. gbm_->set_allocation_failure(true); @@ -490,9 +658,6 @@ TEST_F(DrmOverlayValidatorTest, RejectBufferAllocationFail) { // candidates purely on the basis of having non-integer bounds. Instead, they // should be rounded to the nearest integer. TEST_F(DrmOverlayValidatorTest, NonIntegerDisplayRect) { - overlay_params_.back().display_rect.Inset(0.005f, 0.005f); - plane_list_.pop_back(); - AddPlane(overlay_params_.back()); CrtcState state = { /* .planes = */ { @@ -500,7 +665,11 @@ TEST_F(DrmOverlayValidatorTest, NonIntegerDisplayRect) { {/* .formats = */ {DRM_FORMAT_XRGB8888, DRM_FORMAT_NV12}}, }, }; - InitializeDrmState(std::vector<CrtcState>(1, state)); + InitDrmStatesAndControllers(std::vector<CrtcState>(1, state)); + + overlay_params_.back().display_rect.Inset(0.005f, 0.005f); + plane_list_.pop_back(); + AddPlane(overlay_params_.back()); std::vector<ui::OverlayStatus> returns = overlay_validator_->TestPageFlip( overlay_params_, ui::DrmOverlayPlaneList()); diff --git a/chromium/ui/ozone/platform/drm/gpu/drm_thread.cc b/chromium/ui/ozone/platform/drm/gpu/drm_thread.cc index 6a1a23c8343..33e3370b983 100644 --- a/chromium/ui/ozone/platform/drm/gpu/drm_thread.cc +++ b/chromium/ui/ozone/platform/drm/gpu/drm_thread.cc @@ -16,9 +16,11 @@ #include "base/trace_event/trace_event.h" #include "ui/display/types/display_mode.h" #include "ui/display/types/display_snapshot.h" +#include "ui/gfx/linux/drm_util_linux.h" +#include "ui/gfx/linux/gbm_defines.h" +#include "ui/gfx/linux/gbm_device.h" +#include "ui/gfx/linux/gbm_util.h" #include "ui/gfx/presentation_feedback.h" -#include "ui/ozone/common/linux/drm_util_linux.h" -#include "ui/ozone/common/linux/gbm_device.h" #include "ui/ozone/platform/drm/common/drm_util.h" #include "ui/ozone/platform/drm/gpu/drm_device_generator.h" #include "ui/ozone/platform/drm/gpu/drm_device_manager.h" @@ -36,32 +38,10 @@ namespace ui { namespace { -uint32_t BufferUsageToGbmFlags(gfx::BufferUsage usage) { - switch (usage) { - case gfx::BufferUsage::GPU_READ: - return GBM_BO_USE_TEXTURING; - case gfx::BufferUsage::SCANOUT: - return GBM_BO_USE_RENDERING | GBM_BO_USE_SCANOUT | GBM_BO_USE_TEXTURING; - case gfx::BufferUsage::SCANOUT_CAMERA_READ_WRITE: - return GBM_BO_USE_LINEAR | GBM_BO_USE_CAMERA_WRITE | GBM_BO_USE_SCANOUT | - GBM_BO_USE_TEXTURING; - case gfx::BufferUsage::CAMERA_AND_CPU_READ_WRITE: - return GBM_BO_USE_LINEAR | GBM_BO_USE_CAMERA_WRITE; - case gfx::BufferUsage::SCANOUT_CPU_READ_WRITE: - return GBM_BO_USE_LINEAR | GBM_BO_USE_SCANOUT | GBM_BO_USE_TEXTURING; - case gfx::BufferUsage::SCANOUT_VDA_WRITE: - return GBM_BO_USE_SCANOUT | GBM_BO_USE_TEXTURING | - GBM_BO_USE_HW_VIDEO_DECODER; - case gfx::BufferUsage::GPU_READ_CPU_READ_WRITE: - return GBM_BO_USE_LINEAR | GBM_BO_USE_TEXTURING; - case gfx::BufferUsage::SCANOUT_VEA_READ_CAMERA_AND_CPU_READ_WRITE: - return GBM_BO_USE_TEXTURING | GBM_BO_USE_HW_VIDEO_ENCODER; - } -} - void CreateBufferWithGbmFlags(const scoped_refptr<DrmDevice>& drm, uint32_t fourcc_format, const gfx::Size& size, + const gfx::Size& framebuffer_size, uint32_t flags, const std::vector<uint64_t>& modifiers, std::unique_ptr<GbmBuffer>* out_buffer, @@ -74,7 +54,8 @@ void CreateBufferWithGbmFlags(const scoped_refptr<DrmDevice>& drm, scoped_refptr<DrmFramebuffer> framebuffer; if (flags & GBM_BO_USE_SCANOUT) { - framebuffer = DrmFramebuffer::AddFramebuffer(drm, buffer.get(), modifiers); + framebuffer = DrmFramebuffer::AddFramebuffer(drm, buffer.get(), + framebuffer_size, modifiers); if (!framebuffer) return; } @@ -125,6 +106,7 @@ void DrmThread::RunTaskAfterWindowReady(gfx::AcceleratedWidget window, } void DrmThread::Init() { + TRACE_EVENT0("drm", "DrmThread::Init"); device_manager_ = std::make_unique<DrmDeviceManager>(std::move(device_generator_)); screen_manager_ = std::make_unique<ScreenManager>(); @@ -141,16 +123,18 @@ void DrmThread::Init() { void DrmThread::CreateBuffer(gfx::AcceleratedWidget widget, const gfx::Size& size, + const gfx::Size& framebuffer_size, gfx::BufferFormat format, gfx::BufferUsage usage, uint32_t client_flags, std::unique_ptr<GbmBuffer>* buffer, scoped_refptr<DrmFramebuffer>* framebuffer) { + TRACE_EVENT0("drm", "DrmThread::CreateBuffer"); scoped_refptr<ui::DrmDevice> drm = device_manager_->GetDrmDevice(widget); CHECK(drm) << "No devices available for buffer allocation."; DrmWindow* window = screen_manager_->GetWindow(widget); - uint32_t flags = BufferUsageToGbmFlags(usage); + uint32_t flags = ui::BufferUsageToGbmFlags(usage); uint32_t fourcc_format = ui::GetFourCCFormatFromBufferFormat(format); // TODO(hoegsberg): We shouldn't really get here without a window, @@ -161,8 +145,8 @@ void DrmThread::CreateBuffer(gfx::AcceleratedWidget widget, modifiers = window->GetController()->GetFormatModifiers(fourcc_format); } - CreateBufferWithGbmFlags(drm, fourcc_format, size, flags, modifiers, buffer, - framebuffer); + CreateBufferWithGbmFlags(drm, fourcc_format, size, framebuffer_size, flags, + modifiers, buffer, framebuffer); // NOTE: BufferUsage::SCANOUT is used to create buffers that will be // explicitly set via kms on a CRTC (e.g: BufferQueue buffers), therefore @@ -170,8 +154,8 @@ void DrmThread::CreateBuffer(gfx::AcceleratedWidget widget, // buffer in that case. if (!*buffer && usage != gfx::BufferUsage::SCANOUT) { flags &= ~GBM_BO_USE_SCANOUT; - CreateBufferWithGbmFlags(drm, fourcc_format, size, flags, modifiers, buffer, - framebuffer); + CreateBufferWithGbmFlags(drm, fourcc_format, size, framebuffer_size, flags, + modifiers, buffer, framebuffer); } } @@ -181,10 +165,11 @@ void DrmThread::CreateBufferAsync(gfx::AcceleratedWidget widget, gfx::BufferUsage usage, uint32_t client_flags, CreateBufferAsyncCallback callback) { + TRACE_EVENT0("drm", "DrmThread::CreateBufferAsync"); std::unique_ptr<GbmBuffer> buffer; scoped_refptr<DrmFramebuffer> framebuffer; - CreateBuffer(widget, size, format, usage, client_flags, &buffer, - &framebuffer); + CreateBuffer(widget, size, /*framebuffer_size=*/size, format, usage, + client_flags, &buffer, &framebuffer); std::move(callback).Run(std::move(buffer), std::move(framebuffer)); } @@ -195,6 +180,7 @@ void DrmThread::CreateBufferFromHandle( gfx::NativePixmapHandle handle, std::unique_ptr<GbmBuffer>* out_buffer, scoped_refptr<DrmFramebuffer>* out_framebuffer) { + TRACE_EVENT0("drm", "DrmThread::CreateBufferFromHandle"); scoped_refptr<ui::DrmDevice> drm = device_manager_->GetDrmDevice(widget); DCHECK(drm); @@ -207,7 +193,8 @@ void DrmThread::CreateBufferFromHandle( if (buffer->GetFlags() & GBM_BO_USE_SCANOUT) { // NB: This is not required to succeed; framebuffers are added for // imported buffers on a best effort basis. - framebuffer = DrmFramebuffer::AddFramebuffer(drm, buffer.get()); + framebuffer = + DrmFramebuffer::AddFramebuffer(drm, buffer.get(), buffer->GetSize()); } *out_buffer = std::move(buffer); @@ -223,6 +210,7 @@ void DrmThread::SchedulePageFlip( std::vector<DrmOverlayPlane> planes, SwapCompletionOnceCallback submission_callback, PresentationOnceCallback presentation_callback) { + TRACE_EVENT0("drm", "DrmThread::SchedulePageFlip"); scoped_refptr<ui::DrmDevice> drm_device = device_manager_->GetDrmDevice(widget); @@ -238,6 +226,7 @@ void DrmThread::OnPlanesReadyForPageFlip( SwapCompletionOnceCallback submission_callback, PresentationOnceCallback presentation_callback, std::vector<DrmOverlayPlane> planes) { + TRACE_EVENT0("drm", "DrmThread::OnPlanesReadyForPageFlip"); DrmWindow* window = screen_manager_->GetWindow(widget); if (window) { window->SchedulePageFlip(std::move(planes), std::move(submission_callback), @@ -249,6 +238,7 @@ void DrmThread::OnPlanesReadyForPageFlip( } void DrmThread::IsDeviceAtomic(gfx::AcceleratedWidget widget, bool* is_atomic) { + TRACE_EVENT0("drm", "DrmThread::IsDeviceAtomic"); scoped_refptr<ui::DrmDevice> drm_device = device_manager_->GetDrmDevice(widget); @@ -257,6 +247,7 @@ void DrmThread::IsDeviceAtomic(gfx::AcceleratedWidget widget, bool* is_atomic) { void DrmThread::CreateWindow(gfx::AcceleratedWidget widget, const gfx::Rect& initial_bounds) { + TRACE_EVENT0("drm", "DrmThread::CreateWindow"); DCHECK_GT(widget, last_created_window_); last_created_window_ = widget; @@ -271,12 +262,14 @@ void DrmThread::CreateWindow(gfx::AcceleratedWidget widget, } void DrmThread::DestroyWindow(gfx::AcceleratedWidget widget) { + TRACE_EVENT0("drm", "DrmThread::DestroyWindow"); std::unique_ptr<DrmWindow> window = screen_manager_->RemoveWindow(widget); window->Shutdown(); } void DrmThread::SetWindowBounds(gfx::AcceleratedWidget widget, const gfx::Rect& bounds) { + TRACE_EVENT0("drm", "DrmThread::SetWindowBounds"); screen_manager_->GetWindow(widget)->SetBounds(bounds); } @@ -284,26 +277,41 @@ void DrmThread::SetCursor(gfx::AcceleratedWidget widget, const std::vector<SkBitmap>& bitmaps, const gfx::Point& location, int32_t frame_delay_ms) { + TRACE_EVENT0("drm", "DrmThread::SetCursor"); screen_manager_->GetWindow(widget) ->SetCursor(bitmaps, location, frame_delay_ms); } void DrmThread::MoveCursor(gfx::AcceleratedWidget widget, const gfx::Point& location) { + TRACE_EVENT0("drm", "DrmThread::MoveCursor"); screen_manager_->GetWindow(widget)->MoveCursor(location); } void DrmThread::CheckOverlayCapabilities( gfx::AcceleratedWidget widget, const OverlaySurfaceCandidateList& overlays, - base::OnceCallback<void(gfx::AcceleratedWidget, - const OverlaySurfaceCandidateList&, - const OverlayStatusList&)> callback) { + OverlayCapabilitiesCallback callback) { TRACE_EVENT0("drm,hwoverlays", "DrmThread::CheckOverlayCapabilities"); - std::move(callback).Run( - widget, overlays, - screen_manager_->GetWindow(widget)->TestPageFlip(overlays)); + std::vector<OverlayStatus> result; + CheckOverlayCapabilitiesSync(widget, overlays, &result); + std::move(callback).Run(widget, overlays, std::move(result)); +} + +void DrmThread::CheckOverlayCapabilitiesSync( + gfx::AcceleratedWidget widget, + const OverlaySurfaceCandidateList& overlays, + std::vector<OverlayStatus>* result) { + TRACE_EVENT0("drm,hwoverlays", "DrmThread::CheckOverlayCapabilitiesSync"); + + DrmWindow* window = screen_manager_->GetWindow(widget); + if (!window) { + result->clear(); + result->insert(result->end(), overlays.size(), OVERLAY_STATUS_NOT); + return; + } + *result = window->TestPageFlip(overlays); } void DrmThread::GetDeviceCursor( @@ -313,6 +321,7 @@ void DrmThread::GetDeviceCursor( void DrmThread::RefreshNativeDisplays( base::OnceCallback<void(MovableDisplaySnapshots)> callback) { + TRACE_EVENT0("drm", "DrmThread::RefreshNativeDisplays"); std::move(callback).Run(display_manager_->GetDisplays()); } @@ -321,6 +330,7 @@ void DrmThread::ConfigureNativeDisplay( std::unique_ptr<display::DisplayMode> mode, const gfx::Point& origin, base::OnceCallback<void(int64_t, bool)> callback) { + TRACE_EVENT0("drm", "DrmThread::ConfigureNativeDisplay"); std::move(callback).Run( id, display_manager_->ConfigureDisplay(id, *mode, origin)); } @@ -328,20 +338,24 @@ void DrmThread::ConfigureNativeDisplay( void DrmThread::DisableNativeDisplay( int64_t id, base::OnceCallback<void(int64_t, bool)> callback) { + TRACE_EVENT0("drm", "DrmThread::DisableNativeDisplay"); std::move(callback).Run(id, display_manager_->DisableDisplay(id)); } void DrmThread::TakeDisplayControl(base::OnceCallback<void(bool)> callback) { + TRACE_EVENT0("drm", "DrmThread::TakeDisplayControl"); std::move(callback).Run(display_manager_->TakeDisplayControl()); } void DrmThread::RelinquishDisplayControl( base::OnceCallback<void(bool)> callback) { + TRACE_EVENT0("drm", "DrmThread::RelinquishDisplayControl"); display_manager_->RelinquishDisplayControl(); std::move(callback).Run(true); } void DrmThread::AddGraphicsDevice(const base::FilePath& path, base::File file) { + TRACE_EVENT0("drm", "DrmThread::AddGraphicsDevice"); device_manager_->AddDrmDevice(path, std::move(file)); // There might be tasks that were blocked on a DrmDevice becoming available. @@ -349,12 +363,14 @@ void DrmThread::AddGraphicsDevice(const base::FilePath& path, base::File file) { } void DrmThread::RemoveGraphicsDevice(const base::FilePath& path) { + TRACE_EVENT0("drm", "DrmThread::RemoveGraphicsDevice"); device_manager_->RemoveDrmDevice(path); } void DrmThread::GetHDCPState( int64_t display_id, base::OnceCallback<void(int64_t, bool, display::HDCPState)> 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); @@ -363,12 +379,14 @@ void DrmThread::GetHDCPState( void DrmThread::SetHDCPState(int64_t display_id, display::HDCPState state, base::OnceCallback<void(int64_t, bool)> callback) { + TRACE_EVENT0("drm", "DrmThread::SetHDCPState"); std::move(callback).Run(display_id, display_manager_->SetHDCPState(display_id, state)); } void DrmThread::SetColorMatrix(int64_t display_id, const std::vector<float>& color_matrix) { + TRACE_EVENT0("drm", "DrmThread::SetColorMatrix"); display_manager_->SetColorMatrix(display_id, color_matrix); } @@ -376,9 +394,14 @@ void DrmThread::SetGammaCorrection( int64_t display_id, const std::vector<display::GammaRampRGBEntry>& degamma_lut, const std::vector<display::GammaRampRGBEntry>& gamma_lut) { + TRACE_EVENT0("drm", "DrmThread::SetGammaCorrection"); display_manager_->SetGammaCorrection(display_id, degamma_lut, gamma_lut); } +void DrmThread::SetPrivacyScreen(int64_t display_id, bool enabled) { + display_manager_->SetPrivacyScreen(display_id, enabled); +} + void DrmThread::AddDrmDeviceReceiver( mojo::PendingReceiver<ozone::mojom::DrmDevice> receiver) { TRACE_EVENT0("drm", "DrmThread::AddDrmDeviceReceiver"); diff --git a/chromium/ui/ozone/platform/drm/gpu/drm_thread.h b/chromium/ui/ozone/platform/drm/gpu/drm_thread.h index cb4268aaf50..69586599c7d 100644 --- a/chromium/ui/ozone/platform/drm/gpu/drm_thread.h +++ b/chromium/ui/ozone/platform/drm/gpu/drm_thread.h @@ -25,6 +25,7 @@ #include "ui/ozone/platform/drm/gpu/drm_device_generator.h" #include "ui/ozone/public/mojom/device_cursor.mojom.h" #include "ui/ozone/public/mojom/drm_device.mojom.h" +#include "ui/ozone/public/overlay_surface_candidate.h" #include "ui/ozone/public/swap_completion_callback.h" namespace base { @@ -62,6 +63,11 @@ class DrmThread : public base::Thread, public ozone::mojom::DeviceCursor, public ozone::mojom::DrmDevice { public: + using OverlayCapabilitiesCallback = + base::OnceCallback<void(gfx::AcceleratedWidget, + const std::vector<OverlaySurfaceCandidate>&, + const std::vector<OverlayStatus>&)>; + DrmThread(); ~DrmThread() override; @@ -78,6 +84,7 @@ class DrmThread : public base::Thread, // DrmThreadProxy (on GPU)thread) is the client for these methods. void CreateBuffer(gfx::AcceleratedWidget widget, const gfx::Size& size, + const gfx::Size& framebuffer_size, gfx::BufferFormat format, gfx::BufferUsage usage, uint32_t flags, @@ -102,6 +109,21 @@ class DrmThread : public base::Thread, void AddDrmDeviceReceiver( mojo::PendingReceiver<ozone::mojom::DrmDevice> receiver); + // Verifies if the display controller can successfully scanout the given set + // of OverlaySurfaceCandidates and return the status associated with each + // candidate. + void CheckOverlayCapabilities( + gfx::AcceleratedWidget widget, + const std::vector<OverlaySurfaceCandidate>& candidates, + OverlayCapabilitiesCallback callback); + + // Similar to CheckOverlayCapabilities() but stores the result in |result| + // instead of running a callback. + void CheckOverlayCapabilitiesSync( + gfx::AcceleratedWidget widget, + const std::vector<OverlaySurfaceCandidate>& candidates, + std::vector<OverlayStatus>* result); + // DrmWindowProxy (on GPU thread) is the client for these methods. void SchedulePageFlip(gfx::AcceleratedWidget widget, std::vector<DrmOverlayPlane> planes, @@ -143,12 +165,7 @@ class DrmThread : public base::Thread, int64_t display_id, const std::vector<display::GammaRampRGBEntry>& degamma_lut, const std::vector<display::GammaRampRGBEntry>& gamma_lut) override; - void CheckOverlayCapabilities( - gfx::AcceleratedWidget widget, - const OverlaySurfaceCandidateList& overlays, - base::OnceCallback<void(gfx::AcceleratedWidget, - const OverlaySurfaceCandidateList&, - const OverlayStatusList&)> callback) override; + void SetPrivacyScreen(int64_t display_id, bool enabled) override; void GetDeviceCursor( mojo::PendingAssociatedReceiver<ozone::mojom::DeviceCursor> receiver) override; diff --git a/chromium/ui/ozone/platform/drm/gpu/drm_thread_message_proxy.cc b/chromium/ui/ozone/platform/drm/gpu/drm_thread_message_proxy.cc index d55cab5a79b..f7072c320e1 100644 --- a/chromium/ui/ozone/platform/drm/gpu/drm_thread_message_proxy.cc +++ b/chromium/ui/ozone/platform/drm/gpu/drm_thread_message_proxy.cc @@ -58,8 +58,7 @@ bool DrmThreadMessageProxy::OnMessageReceived(const IPC::Message& message) { IPC_MESSAGE_HANDLER(OzoneGpuMsg_SetHDCPState, OnSetHDCPState) IPC_MESSAGE_HANDLER(OzoneGpuMsg_SetColorMatrix, OnSetColorMatrix) IPC_MESSAGE_HANDLER(OzoneGpuMsg_SetGammaCorrection, OnSetGammaCorrection) - IPC_MESSAGE_HANDLER(OzoneGpuMsg_CheckOverlayCapabilities, - OnCheckOverlayCapabilities) + IPC_MESSAGE_HANDLER(OzoneGpuMsg_SetPrivacyScreen, OnSetPrivacyScreen) IPC_MESSAGE_UNHANDLED(handled = false) IPC_END_MESSAGE_MAP() @@ -110,22 +109,6 @@ void DrmThreadMessageProxy::OnCursorMove(gfx::AcceleratedWidget widget, widget, location)); } -void DrmThreadMessageProxy::OnCheckOverlayCapabilities( - gfx::AcceleratedWidget widget, - const std::vector<OverlayCheck_Params>& param_overlays) { - DCHECK(drm_thread_->IsRunning()); - auto overlays = CreateOverlaySurfaceCandidateListFrom(param_overlays); - auto callback = - base::BindOnce(&DrmThreadMessageProxy::OnCheckOverlayCapabilitiesCallback, - weak_ptr_factory_.GetWeakPtr()); - - auto safe_callback = CreateSafeOnceCallback(std::move(callback)); - drm_thread_->task_runner()->PostTask( - FROM_HERE, base::BindOnce(&DrmThread::CheckOverlayCapabilities, - base::Unretained(drm_thread_), widget, overlays, - std::move(safe_callback))); -} - void DrmThreadMessageProxy::OnRefreshNativeDisplays() { DCHECK(drm_thread_->IsRunning()); auto callback = @@ -253,14 +236,13 @@ void DrmThreadMessageProxy::OnSetGammaCorrection( degamma_lut, gamma_lut)); } -void DrmThreadMessageProxy::OnCheckOverlayCapabilitiesCallback( - gfx::AcceleratedWidget widget, - const OverlaySurfaceCandidateList& candidates, - const OverlayStatusList& returns) const { - auto param_overlays = CreateParamsFromOverlaySurfaceCandidate(candidates); - auto param_returns = CreateParamsFromOverlayStatusList(returns); - sender_->Send(new OzoneHostMsg_OverlayCapabilitiesReceived( - widget, param_overlays, param_returns)); +void DrmThreadMessageProxy::OnSetPrivacyScreen(int64_t display_id, + bool enabled) { + DCHECK(drm_thread_->IsRunning()); + drm_thread_->task_runner()->PostTask( + FROM_HERE, + base::BindOnce(&DrmThread::SetPrivacyScreen, + base::Unretained(drm_thread_), display_id, enabled)); } void DrmThreadMessageProxy::OnRefreshNativeDisplaysCallback( diff --git a/chromium/ui/ozone/platform/drm/gpu/drm_thread_message_proxy.h b/chromium/ui/ozone/platform/drm/gpu/drm_thread_message_proxy.h index b1bdf683eaf..55407d6d44f 100644 --- a/chromium/ui/ozone/platform/drm/gpu/drm_thread_message_proxy.h +++ b/chromium/ui/ozone/platform/drm/gpu/drm_thread_message_proxy.h @@ -15,7 +15,6 @@ #include "ui/gfx/native_widget_types.h" #include "ui/ozone/platform/drm/common/display_types.h" #include "ui/ozone/platform/drm/gpu/inter_thread_messaging_proxy.h" -#include "ui/ozone/public/overlay_surface_candidate.h" namespace base { struct FileDescriptor; @@ -30,7 +29,6 @@ class Rect; namespace ui { class DrmThread; struct DisplayMode_Params; -struct OverlayCheck_Params; class DrmThreadMessageProxy : public IPC::MessageFilter, public InterThreadMessagingProxy { @@ -57,9 +55,6 @@ class DrmThreadMessageProxy : public IPC::MessageFilter, const gfx::Point& location, int frame_delay_ms); void OnCursorMove(gfx::AcceleratedWidget widget, const gfx::Point& location); - void OnCheckOverlayCapabilities( - gfx::AcceleratedWidget widget, - const std::vector<OverlayCheck_Params>& overlays); // Display related IPC handlers. void OnRefreshNativeDisplays(); @@ -80,11 +75,7 @@ class DrmThreadMessageProxy : public IPC::MessageFilter, int64_t display_id, const std::vector<display::GammaRampRGBEntry>& degamma_lut, const std::vector<display::GammaRampRGBEntry>& gamma_lut); - - void OnCheckOverlayCapabilitiesCallback( - gfx::AcceleratedWidget widget, - const OverlaySurfaceCandidateList& overlays, - const OverlayStatusList& returns) const; + void OnSetPrivacyScreen(int64_t display_id, bool enabled); void OnRefreshNativeDisplaysCallback(MovableDisplaySnapshots displays) const; void OnConfigureNativeDisplayCallback(int64_t display_id, bool success) const; void OnDisableNativeDisplayCallback(int64_t display_id, bool success) const; diff --git a/chromium/ui/ozone/platform/drm/gpu/drm_thread_proxy.cc b/chromium/ui/ozone/platform/drm/gpu/drm_thread_proxy.cc index 745b3974f89..8a0178c20e9 100644 --- a/chromium/ui/ozone/platform/drm/gpu/drm_thread_proxy.cc +++ b/chromium/ui/ozone/platform/drm/gpu/drm_thread_proxy.cc @@ -8,7 +8,7 @@ #include <utility> #include "base/bind.h" -#include "ui/ozone/common/linux/gbm_wrapper.h" +#include "ui/gfx/linux/gbm_wrapper.h" #include "ui/ozone/platform/drm/gpu/drm_device.h" #include "ui/ozone/platform/drm/gpu/drm_device_generator.h" #include "ui/ozone/platform/drm/gpu/drm_thread_message_proxy.h" @@ -80,16 +80,19 @@ std::unique_ptr<DrmWindowProxy> DrmThreadProxy::CreateDrmWindowProxy( void DrmThreadProxy::CreateBuffer(gfx::AcceleratedWidget widget, const gfx::Size& size, + const gfx::Size& framebuffer_size, gfx::BufferFormat format, gfx::BufferUsage usage, uint32_t flags, std::unique_ptr<GbmBuffer>* buffer, scoped_refptr<DrmFramebuffer>* framebuffer) { + TRACE_EVENT0("drm", "DrmThreadProxy::CreateBuffer"); DCHECK(drm_thread_.task_runner()) << "no task runner! in DrmThreadProxy::CreateBuffer"; - base::OnceClosure task = - base::BindOnce(&DrmThread::CreateBuffer, base::Unretained(&drm_thread_), - widget, size, format, usage, flags, buffer, framebuffer); + base::ScopedAllowBaseSyncPrimitivesOutsideBlockingScope allow_wait; + base::OnceClosure task = base::BindOnce( + &DrmThread::CreateBuffer, base::Unretained(&drm_thread_), widget, size, + framebuffer_size, format, usage, flags, buffer, framebuffer); PostSyncTask( drm_thread_.task_runner(), base::BindOnce(&DrmThread::RunTaskAfterWindowReady, @@ -127,6 +130,8 @@ void DrmThreadProxy::CreateBufferFromHandle( gfx::NativePixmapHandle handle, std::unique_ptr<GbmBuffer>* buffer, scoped_refptr<DrmFramebuffer>* framebuffer) { + TRACE_EVENT0("drm", "DrmThreadProxy::CreateBufferFromHandle"); + base::ScopedAllowBaseSyncPrimitivesOutsideBlockingScope allow_wait; base::OnceClosure task = base::BindOnce( &DrmThread::CreateBufferFromHandle, base::Unretained(&drm_thread_), widget, size, format, std::move(handle), buffer, framebuffer); @@ -150,7 +155,7 @@ void DrmThreadProxy::SetClearOverlayCacheCallback( void DrmThreadProxy::CheckOverlayCapabilities( gfx::AcceleratedWidget widget, const std::vector<OverlaySurfaceCandidate>& candidates, - OverlayCapabilitiesCallback callback) { + DrmThread::OverlayCapabilitiesCallback callback) { DCHECK(drm_thread_.task_runner()); base::OnceClosure task = base::BindOnce( &DrmThread::CheckOverlayCapabilities, base::Unretained(&drm_thread_), @@ -162,6 +167,23 @@ void DrmThreadProxy::CheckOverlayCapabilities( std::move(task), nullptr)); } +std::vector<OverlayStatus> DrmThreadProxy::CheckOverlayCapabilitiesSync( + gfx::AcceleratedWidget widget, + const std::vector<OverlaySurfaceCandidate>& candidates) { + TRACE_EVENT0("drm", "DrmThreadProxy::CheckOverlayCapabilitiesSync"); + DCHECK(drm_thread_.task_runner()); + base::ScopedAllowBaseSyncPrimitivesOutsideBlockingScope allow_wait; + std::vector<OverlayStatus> result; + base::OnceClosure task = base::BindOnce( + &DrmThread::CheckOverlayCapabilitiesSync, base::Unretained(&drm_thread_), + widget, candidates, &result); + PostSyncTask( + drm_thread_.task_runner(), + base::BindOnce(&DrmThread::RunTaskAfterWindowReady, + base::Unretained(&drm_thread_), widget, std::move(task))); + return result; +} + void DrmThreadProxy::AddDrmDeviceReceiver( mojo::PendingReceiver<ozone::mojom::DrmDevice> receiver) { DCHECK(drm_thread_.task_runner()) << "DrmThreadProxy::AddDrmDeviceReceiver " diff --git a/chromium/ui/ozone/platform/drm/gpu/drm_thread_proxy.h b/chromium/ui/ozone/platform/drm/gpu/drm_thread_proxy.h index 1327102e343..303a7eb9cbe 100644 --- a/chromium/ui/ozone/platform/drm/gpu/drm_thread_proxy.h +++ b/chromium/ui/ozone/platform/drm/gpu/drm_thread_proxy.h @@ -26,11 +26,6 @@ class InterThreadMessagingProxy; // proxy objects then deal with safely posting the messages to the DRM thread. class DrmThreadProxy { public: - using OverlayCapabilitiesCallback = - base::OnceCallback<void(gfx::AcceleratedWidget, - const std::vector<OverlaySurfaceCandidate>&, - const std::vector<OverlayStatus>&)>; - DrmThreadProxy(); ~DrmThreadProxy(); @@ -43,6 +38,7 @@ class DrmThreadProxy { void CreateBuffer(gfx::AcceleratedWidget widget, const gfx::Size& size, + const gfx::Size& framebuffer_size, gfx::BufferFormat format, gfx::BufferUsage usage, uint32_t flags, @@ -77,7 +73,12 @@ class DrmThreadProxy { void CheckOverlayCapabilities( gfx::AcceleratedWidget widget, const std::vector<OverlaySurfaceCandidate>& candidates, - OverlayCapabilitiesCallback callback); + DrmThread::OverlayCapabilitiesCallback callback); + + // Similar to CheckOverlayCapabilities() but returns the result synchronously. + std::vector<OverlayStatus> CheckOverlayCapabilitiesSync( + gfx::AcceleratedWidget widget, + const std::vector<OverlaySurfaceCandidate>& candidates); void AddDrmDeviceReceiver( mojo::PendingReceiver<ozone::mojom::DrmDevice> receiver); diff --git a/chromium/ui/ozone/platform/drm/gpu/drm_thread_unittest.cc b/chromium/ui/ozone/platform/drm/gpu/drm_thread_unittest.cc index 5f576a8f6d7..fdd7a2e3785 100644 --- a/chromium/ui/ozone/platform/drm/gpu/drm_thread_unittest.cc +++ b/chromium/ui/ozone/platform/drm/gpu/drm_thread_unittest.cc @@ -11,9 +11,9 @@ #include "base/test/task_environment.h" #include "mojo/public/cpp/bindings/remote.h" #include "testing/gtest/include/gtest/gtest.h" +#include "ui/gfx/linux/test/mock_gbm_device.h" #include "ui/ozone/platform/drm/gpu/drm_device_generator.h" #include "ui/ozone/platform/drm/gpu/mock_drm_device.h" -#include "ui/ozone/platform/drm/gpu/mock_gbm_device.h" namespace ui { @@ -167,4 +167,27 @@ TEST_F(DrmThreadTest, RunTaskAfterWindowReady) { drm_thread_.FlushForTesting(); } +// Verifies that we gracefully handle the case where CheckOverlayCapabilities() +// is called on a destroyed window. +TEST_F(DrmThreadTest, CheckOverlayCapabilitiesDestroyedWindow) { + gfx::AcceleratedWidget widget = 5; + constexpr gfx::Rect bounds(10, 10); + constexpr size_t candidates_size = 9; + std::vector<OverlaySurfaceCandidate> candidates(candidates_size); + std::vector<OverlayStatus> result; + AddGraphicsDevice(); + drm_device_->CreateWindow(widget, bounds); + drm_device_->DestroyWindow(widget); + drm_device_.FlushForTesting(); + drm_thread_.task_runner()->PostTask( + FROM_HERE, base::BindOnce(&DrmThread::CheckOverlayCapabilitiesSync, + base::Unretained(&drm_thread_), widget, + candidates, &result)); + drm_thread_.FlushForTesting(); + EXPECT_EQ(candidates_size, result.size()); + for (const auto& status : result) { + EXPECT_EQ(OVERLAY_STATUS_NOT, status); + } +} + } // namespace ui 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 f3240ed685c..824992ab157 100644 --- a/chromium/ui/ozone/platform/drm/gpu/drm_window_unittest.cc +++ b/chromium/ui/ozone/platform/drm/gpu/drm_window_unittest.cc @@ -20,14 +20,14 @@ #include "third_party/skia/include/core/SkImageInfo.h" #include "third_party/skia/include/core/SkSurface.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/gfx/presentation_feedback.h" -#include "ui/ozone/common/linux/gbm_buffer.h" #include "ui/ozone/platform/drm/gpu/drm_device_generator.h" #include "ui/ozone/platform/drm/gpu/drm_device_manager.h" #include "ui/ozone/platform/drm/gpu/drm_framebuffer.h" #include "ui/ozone/platform/drm/gpu/hardware_display_controller.h" #include "ui/ozone/platform/drm/gpu/mock_drm_device.h" -#include "ui/ozone/platform/drm/gpu/mock_gbm_device.h" #include "ui/ozone/platform/drm/gpu/screen_manager.h" #include "ui/ozone/public/surface_ozone_canvas.h" @@ -182,8 +182,9 @@ TEST_F(DrmWindowTest, CheckDeathOnFailedSwap) { std::unique_ptr<ui::GbmBuffer> buffer = drm_->gbm_device()->CreateBuffer( DRM_FORMAT_XRGB8888, window_size, GBM_BO_USE_SCANOUT); + ASSERT_TRUE(buffer); scoped_refptr<ui::DrmFramebuffer> framebuffer = - ui::DrmFramebuffer::AddFramebuffer(drm_, buffer.get()); + ui::DrmFramebuffer::AddFramebuffer(drm_, buffer.get(), window_size); ui::DrmOverlayPlane plane(framebuffer, nullptr); drm_->set_page_flip_expectation(false); diff --git a/chromium/ui/ozone/platform/drm/gpu/gbm_pixmap.h b/chromium/ui/ozone/platform/drm/gpu/gbm_pixmap.h index 17e1de67075..1c4d9aeb58f 100644 --- a/chromium/ui/ozone/platform/drm/gpu/gbm_pixmap.h +++ b/chromium/ui/ozone/platform/drm/gpu/gbm_pixmap.h @@ -8,8 +8,8 @@ #include <memory> #include <vector> +#include "ui/gfx/linux/gbm_buffer.h" #include "ui/gfx/native_pixmap.h" -#include "ui/ozone/common/linux/gbm_buffer.h" #include "ui/ozone/platform/drm/gpu/drm_framebuffer.h" namespace ui { 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 d015577ba1b..fcb45780025 100644 --- a/chromium/ui/ozone/platform/drm/gpu/gbm_surface_factory.cc +++ b/chromium/ui/ozone/platform/drm/gpu/gbm_surface_factory.cc @@ -5,6 +5,7 @@ #include "ui/ozone/platform/drm/gpu/gbm_surface_factory.h" #include <gbm.h> +#include <xf86drm.h> #include <memory> #include <utility> @@ -14,13 +15,16 @@ #include "build/build_config.h" #include "third_party/khronos/EGL/egl.h" #include "ui/gfx/buffer_format_util.h" +#include "ui/gfx/extension_set.h" +#include "ui/gfx/linux/drm_util_linux.h" +#include "ui/gfx/linux/gbm_defines.h" +#include "ui/gfx/linux/scoped_gbm_device.h" #include "ui/gfx/native_pixmap.h" #include "ui/gl/gl_surface_egl.h" #include "ui/ozone/common/egl_util.h" #include "ui/ozone/common/gl_ozone_egl.h" -#include "ui/ozone/common/linux/drm_util_linux.h" -#include "ui/ozone/common/linux/scoped_gbm_device.h" #include "ui/ozone/platform/drm/common/drm_util.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" #include "ui/ozone/platform/drm/gpu/gbm_overlay_surface.h" @@ -83,7 +87,68 @@ class GLOzoneEGLGbm : public GLOzoneEGL { } protected: - intptr_t GetNativeDisplay() override { return EGL_DEFAULT_DISPLAY; } + gl::EGLDisplayPlatform GetNativeDisplay() override { + if (native_display_.Valid()) + return native_display_; + + // Default to null platform + native_display_ = gl::EGLDisplayPlatform(EGL_DEFAULT_DISPLAY); + + gl::g_driver_egl.InitializeClientExtensionBindings(); + + const char* client_extensions_string = + eglQueryString(EGL_NO_DISPLAY, EGL_EXTENSIONS); + + gfx::ExtensionSet client_extensions = + client_extensions_string + ? gfx::MakeExtensionSet(client_extensions_string) + : gfx::ExtensionSet(); + + if (gfx::HasExtension(client_extensions, "EGL_MESA_platform_surfaceless")) { + native_display_ = gl::EGLDisplayPlatform(EGL_DEFAULT_DISPLAY, + EGL_PLATFORM_SURFACELESS_MESA); + } + + if (!(gfx::HasExtension(client_extensions, "EGL_EXT_device_query") && + gfx::HasExtension(client_extensions, "EGL_EXT_platform_device") && + gfx::HasExtension(client_extensions, "EGL_EXT_device_enumeration"))) { + LOG(WARNING) << "Platform device extensions not found."; + return native_display_; + } + + std::vector<EGLDeviceEXT> devices(DRM_MAX_MINOR, EGL_NO_DEVICE_EXT); + EGLDeviceEXT amdgpu_device = EGL_NO_DEVICE_EXT; + EGLDeviceEXT i915_device = EGL_NO_DEVICE_EXT; + EGLint num_devices = 0; + + eglQueryDevicesEXT(DRM_MAX_MINOR, devices.data(), &num_devices); + devices.resize(num_devices); + for (EGLDeviceEXT device : devices) { + const char* filename = + eglQueryDeviceStringEXT(device, EGL_DRM_DEVICE_FILE_EXT); + if (!filename) // Not a DRM device. + continue; + if (IsDriverName(filename, "amdgpu")) + amdgpu_device = device; + if (IsDriverName(filename, "i915")) + i915_device = device; + } + + if (amdgpu_device != EGL_NO_DEVICE_EXT) { + native_display_ = gl::EGLDisplayPlatform( + reinterpret_cast<EGLNativeDisplayType>(amdgpu_device), + EGL_PLATFORM_DEVICE_EXT); + } + + // If we also have Intel integrated, use it instead. + if (i915_device != EGL_NO_DEVICE_EXT) { + native_display_ = gl::EGLDisplayPlatform( + reinterpret_cast<EGLNativeDisplayType>(i915_device), + EGL_PLATFORM_DEVICE_EXT); + } + + return native_display_; + } bool LoadGLES2Bindings(gl::GLImplementation impl) override { return LoadDefaultEGLGLES2Bindings(impl); @@ -92,6 +157,7 @@ class GLOzoneEGLGbm : public GLOzoneEGL { private: GbmSurfaceFactory* surface_factory_; DrmThreadProxy* drm_thread_proxy_; + gl::EGLDisplayPlatform native_display_; DISALLOW_COPY_AND_ASSIGN(GLOzoneEGLGbm); }; @@ -213,9 +279,9 @@ scoped_refptr<gfx::NativePixmap> GbmSurfaceFactory::CreateNativePixmapForVulkan( std::unique_ptr<GbmBuffer> buffer; scoped_refptr<DrmFramebuffer> framebuffer; - drm_thread_proxy_->CreateBuffer(widget, size, format, usage, - GbmPixmap::kFlagNoModifiers, &buffer, - &framebuffer); + drm_thread_proxy_->CreateBuffer(widget, size, /*framebuffer_size=*/size, + format, usage, GbmPixmap::kFlagNoModifiers, + &buffer, &framebuffer); if (!buffer) return nullptr; @@ -274,7 +340,7 @@ std::unique_ptr<OverlaySurface> GbmSurfaceFactory::CreateOverlaySurface( std::unique_ptr<SurfaceOzoneCanvas> GbmSurfaceFactory::CreateCanvasForWidget( gfx::AcceleratedWidget widget, - base::TaskRunner* task_runner) { + scoped_refptr<base::SequencedTaskRunner> task_runner) { DCHECK(thread_checker_.CalledOnValidThread()); LOG(ERROR) << "Software rendering mode is not supported with GBM platform"; return nullptr; @@ -285,11 +351,17 @@ scoped_refptr<gfx::NativePixmap> GbmSurfaceFactory::CreateNativePixmap( VkDevice vk_device, gfx::Size size, gfx::BufferFormat format, - gfx::BufferUsage usage) { + gfx::BufferUsage usage, + base::Optional<gfx::Size> framebuffer_size) { + if (framebuffer_size && + !gfx::Rect(size).Contains(gfx::Rect(*framebuffer_size))) { + return nullptr; + } std::unique_ptr<GbmBuffer> buffer; scoped_refptr<DrmFramebuffer> framebuffer; - drm_thread_proxy_->CreateBuffer(widget, size, format, usage, 0 /* flags */, - &buffer, &framebuffer); + drm_thread_proxy_->CreateBuffer( + widget, size, framebuffer_size ? *framebuffer_size : size, format, usage, + 0 /* flags */, &buffer, &framebuffer); if (!buffer) return nullptr; return base::MakeRefCounted<GbmPixmap>(this, std::move(buffer), diff --git a/chromium/ui/ozone/platform/drm/gpu/gbm_surface_factory.h b/chromium/ui/ozone/platform/drm/gpu/gbm_surface_factory.h index 679848c3d31..ab3089b7242 100644 --- a/chromium/ui/ozone/platform/drm/gpu/gbm_surface_factory.h +++ b/chromium/ui/ozone/platform/drm/gpu/gbm_surface_factory.h @@ -55,13 +55,14 @@ class GbmSurfaceFactory : public SurfaceFactoryOzone { gfx::AcceleratedWidget window) override; std::unique_ptr<SurfaceOzoneCanvas> CreateCanvasForWidget( gfx::AcceleratedWidget widget, - base::TaskRunner* task_runner) override; + scoped_refptr<base::SequencedTaskRunner> task_runner) override; scoped_refptr<gfx::NativePixmap> CreateNativePixmap( gfx::AcceleratedWidget widget, VkDevice vk_device, gfx::Size size, gfx::BufferFormat format, - gfx::BufferUsage usage) override; + gfx::BufferUsage usage, + base::Optional<gfx::Size> framebuffer_size = base::nullopt) override; void CreateNativePixmapAsync(gfx::AcceleratedWidget widget, VkDevice vk_device, gfx::Size size, diff --git a/chromium/ui/ozone/platform/drm/gpu/gbm_surfaceless.cc b/chromium/ui/ozone/platform/drm/gpu/gbm_surfaceless.cc index 62cac1b7bb2..ae654f1dbf8 100644 --- a/chromium/ui/ozone/platform/drm/gpu/gbm_surfaceless.cc +++ b/chromium/ui/ozone/platform/drm/gpu/gbm_surfaceless.cc @@ -10,6 +10,7 @@ #include "base/bind.h" #include "base/logging.h" #include "base/task/post_task.h" +#include "base/task/thread_pool.h" #include "base/trace_event/trace_event.h" #include "ui/gfx/gpu_fence.h" #include "ui/gfx/presentation_feedback.h" @@ -154,11 +155,10 @@ void GbmSurfaceless::SwapBuffersAsync( base::OnceClosure fence_retired_callback = base::BindOnce( &GbmSurfaceless::FenceRetired, weak_factory_.GetWeakPtr(), frame); - base::PostTaskAndReply(FROM_HERE, - {base::ThreadPool(), base::MayBlock(), - base::TaskShutdownBehavior::CONTINUE_ON_SHUTDOWN}, - std::move(fence_wait_task), - std::move(fence_retired_callback)); + base::ThreadPool::PostTaskAndReply( + FROM_HERE, + {base::MayBlock(), base::TaskShutdownBehavior::CONTINUE_ON_SHUTDOWN}, + std::move(fence_wait_task), std::move(fence_retired_callback)); } void GbmSurfaceless::PostSubBufferAsync( 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 b8b8b4229a3..6f240331ab6 100644 --- a/chromium/ui/ozone/platform/drm/gpu/hardware_display_controller.cc +++ b/chromium/ui/ozone/platform/drm/gpu/hardware_display_controller.cc @@ -29,6 +29,12 @@ #include "ui/ozone/platform/drm/gpu/hardware_display_plane.h" #include "ui/ozone/platform/drm/gpu/page_flip_request.h" +// Vendor ID for downstream, interim ChromeOS specific modifiers. +#define DRM_FORMAT_MOD_VENDOR_CHROMEOS 0xf0 +// TODO(gurchetansingh) Remove once DRM_FORMAT_MOD_ARM_AFBC is used by all +// kernels and allocators. +#define DRM_FORMAT_MOD_CHROMEOS_ROCKCHIP_AFBC fourcc_mod_code(CHROMEOS, 1) + namespace ui { namespace { @@ -52,7 +58,7 @@ void DrawCursor(DrmDumbBuffer* cursor, const SkBitmap& image) { // Clear to transparent in case |image| is smaller than the canvas. SkCanvas* canvas = cursor->GetCanvas(); canvas->clear(SK_ColorTRANSPARENT); - canvas->drawBitmapRect(image, damage, NULL); + canvas->drawBitmapRect(image, damage, nullptr); } } // namespace @@ -65,29 +71,39 @@ HardwareDisplayController::HardwareDisplayController( AllocateCursorBuffers(); } -HardwareDisplayController::~HardwareDisplayController() { -} +HardwareDisplayController::~HardwareDisplayController() = default; bool HardwareDisplayController::Modeset(const DrmOverlayPlane& primary, - drmModeModeInfo mode) { + const drmModeModeInfo& mode) { TRACE_EVENT0("drm", "HDC::Modeset"); - DCHECK(primary.buffer.get()); - bool status = true; - for (const auto& controller : crtc_controllers_) - status &= controller->Modeset(primary, mode); - - is_disabled_ = false; - ResetCursor(); - OnModesetComplete(primary); - return status; + return ModesetCrtc(primary, /*use_current_crtc_mode=*/false, mode); } bool HardwareDisplayController::Enable(const DrmOverlayPlane& primary) { TRACE_EVENT0("drm", "HDC::Enable"); + drmModeModeInfo empty_mode = {}; + return ModesetCrtc(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, controller->mode()); + + GetDrmDevice()->plane_manager()->BeginFrame(&owned_hardware_planes_); + DrmOverlayPlaneList plane_list; + plane_list.push_back(primary.Clone()); + + for (const auto& controller : crtc_controllers_) { + status &= + controller->AssignOverlayPlanes(&owned_hardware_planes_, plane_list, + /*is_modesetting=*/true); + + status &= controller->Modeset( + primary, use_current_crtc_mode ? controller->mode() : mode, + owned_hardware_planes_); + } is_disabled_ = false; ResetCursor(); @@ -99,6 +115,10 @@ void HardwareDisplayController::Disable() { TRACE_EVENT0("drm", "HDC::Disable"); 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(); bool ret = GetDrmDevice()->plane_manager()->DisableOverlayPlanes( @@ -166,12 +186,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; } @@ -347,6 +368,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 264e25005da..6fb71b24860 100644 --- a/chromium/ui/ozone/platform/drm/gpu/hardware_display_controller.h +++ b/chromium/ui/ozone/platform/drm/gpu/hardware_display_controller.h @@ -95,7 +95,7 @@ class HardwareDisplayController { // Performs the initial CRTC configuration. If successful, it will display the // framebuffer for |primary| with |mode|. - bool Modeset(const DrmOverlayPlane& primary, drmModeModeInfo 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); @@ -169,6 +169,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); 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 2f5ceca4c53..80118d38fdc 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 @@ -13,29 +13,35 @@ #include "testing/gtest/include/gtest/gtest.h" #include "third_party/skia/include/core/SkCanvas.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/gfx/native_pixmap.h" #include "ui/gfx/presentation_feedback.h" -#include "ui/ozone/common/linux/gbm_buffer.h" #include "ui/ozone/platform/drm/gpu/crtc_controller.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_controller.h" #include "ui/ozone/platform/drm/gpu/hardware_display_plane.h" #include "ui/ozone/platform/drm/gpu/mock_drm_device.h" -#include "ui/ozone/platform/drm/gpu/mock_gbm_device.h" namespace { // Create a basic mode for a 6x4 screen. -const drmModeModeInfo kDefaultMode = - {0, 6, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, {'\0'}}; +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 kPrimaryConnector = 10; -constexpr uint32_t kSecondaryConnector = 11; -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 kTypePropId = 3010; +constexpr uint32_t kInFormatsPropId = 3011; const gfx::Size kDefaultModeSize(kDefaultMode.hdisplay, kDefaultMode.vdisplay); const gfx::Size kOverlaySize(kDefaultMode.hdisplay / 2, @@ -63,13 +69,14 @@ class HardwareDisplayControllerTest : public testing::Test { scoped_refptr<ui::DrmFramebuffer> CreateBuffer() { std::unique_ptr<ui::GbmBuffer> buffer = drm_->gbm_device()->CreateBuffer( DRM_FORMAT_XRGB8888, kDefaultModeSize, GBM_BO_USE_SCANOUT); - return ui::DrmFramebuffer::AddFramebuffer(drm_, buffer.get()); + return ui::DrmFramebuffer::AddFramebuffer(drm_, buffer.get(), + kDefaultModeSize); } scoped_refptr<ui::DrmFramebuffer> CreateOverlayBuffer() { std::unique_ptr<ui::GbmBuffer> buffer = drm_->gbm_device()->CreateBuffer( DRM_FORMAT_XRGB8888, kOverlaySize, GBM_BO_USE_SCANOUT); - return ui::DrmFramebuffer::AddFramebuffer(drm_, buffer.get()); + return ui::DrmFramebuffer::AddFramebuffer(drm_, buffer.get(), kOverlaySize); } protected: @@ -94,7 +101,7 @@ void HardwareDisplayControllerTest::SetUp() { controller_ = std::make_unique<ui::HardwareDisplayController>( std::make_unique<ui::CrtcController>(drm_.get(), kPrimaryCrtc, - kPrimaryConnector), + kConnectorIdBase), gfx::Point()); } @@ -104,24 +111,37 @@ void HardwareDisplayControllerTest::TearDown() { } void HardwareDisplayControllerTest::InitializeDrmDevice(bool use_atomic) { - constexpr uint32_t kTypePropId = 300; - constexpr uint32_t kInFormatsPropId = 301; - constexpr uint32_t kInFormatsBlobPropId = 400; - std::vector<ui::MockDrmDevice::CrtcProperties> crtc_properties(2); + std::map<uint32_t, std::string> crtc_property_names = { + {1000, "ACTIVE"}, + {1001, "MODE_ID"}, + }; + + std::vector<ui::MockDrmDevice::ConnectorProperties> connector_properties(2); + std::map<uint32_t, std::string> connector_property_names = { + {kCrtcIdPropId, "CRTC_ID"}, + }; + for (size_t i = 0; i < connector_properties.size(); ++i) { + connector_properties[i].id = kConnectorIdBase + 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> property_names = { + std::map<uint32_t, std::string> plane_property_names = { // Add all required properties. - {200, "CRTC_ID"}, - {201, "CRTC_X"}, - {202, "CRTC_Y"}, - {203, "CRTC_W"}, - {204, "CRTC_H"}, - {205, "FB_ID"}, - {206, "SRC_X"}, - {207, "SRC_Y"}, - {208, "SRC_W"}, - {209, "SRC_H"}, + {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"}, // Add some optional properties we use for convenience. {kTypePropId, "type"}, {kInFormatsPropId, "IN_FORMATS"}, @@ -129,6 +149,10 @@ void HardwareDisplayControllerTest::InitializeDrmDevice(bool use_atomic) { for (size_t i = 0; i < crtc_properties.size(); ++i) { crtc_properties[i].id = kCrtcIdBase + i; + for (const auto& pair : crtc_property_names) { + crtc_properties[i].properties.push_back( + {/* .id = */ pair.first, /* .value = */ 0}); + } for (size_t j = 0; j < 2; ++j) { const uint32_t offset = plane_properties.size(); @@ -136,7 +160,7 @@ void HardwareDisplayControllerTest::InitializeDrmDevice(bool use_atomic) { ui::MockDrmDevice::PlaneProperties plane; plane.id = kPlaneOffset + offset; plane.crtc_mask = 1 << i; - for (const auto& pair : property_names) { + for (const auto& pair : plane_property_names) { uint32_t value = 0; if (pair.first == kTypePropId) value = j == 0 ? DRM_PLANE_TYPE_PRIMARY : DRM_PLANE_TYPE_OVERLAY; @@ -147,24 +171,21 @@ void HardwareDisplayControllerTest::InitializeDrmDevice(bool use_atomic) { {/* .id = */ pair.first, /*.value = */ value}); }; - drm_format_modifier y_css = {.formats = 1UL, - .modifier = I915_FORMAT_MOD_Y_TILED_CCS}; - drm_format_modifier yf_css = {.formats = 1UL, - .modifier = I915_FORMAT_MOD_Yf_TILED_CCS}; - drm_format_modifier x = {.formats = 1UL, - .modifier = I915_FORMAT_MOD_X_TILED}; - drm_format_modifier linear = {.formats = 1UL, - .modifier = DRM_FORMAT_MOD_LINEAR}; drm_->SetPropertyBlob(ui::MockDrmDevice::AllocateInFormatsBlob( - kInFormatsBlobPropId, {DRM_FORMAT_XRGB8888}, - {y_css, yf_css, x, linear})); + kInFormatsBlobPropId, {DRM_FORMAT_XRGB8888}, {})); plane_properties.emplace_back(std::move(plane)); } } - drm_->InitializeState(crtc_properties, plane_properties, property_names, - use_atomic); + 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, use_atomic); } void HardwareDisplayControllerTest::SchedulePageFlip( @@ -207,56 +228,78 @@ TEST_F(HardwareDisplayControllerTest, CheckModesettingResult) { EXPECT_FALSE(plane.buffer->HasOneRef()); } -TEST_F(HardwareDisplayControllerTest, ModifiersWithConnectorType) { - ui::DrmOverlayPlane plane(CreateBuffer(), nullptr); +TEST_F(HardwareDisplayControllerTest, CheckModesettingSetsProps) { + 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()); - // With internal displays, all modifiers including compressed (css) should be - // there. - drm_->set_connector_type(DRM_MODE_CONNECTOR_eDP); - - std::vector<uint64_t> internal_modifiers = - controller_->GetFormatModifiers(DRM_FORMAT_XRGB8888); - ASSERT_FALSE(internal_modifiers.empty()); - - EXPECT_NE(std::find(internal_modifiers.begin(), internal_modifiers.end(), - I915_FORMAT_MOD_Y_TILED_CCS), - internal_modifiers.end()); - EXPECT_NE(std::find(internal_modifiers.begin(), internal_modifiers.end(), - I915_FORMAT_MOD_Yf_TILED_CCS), - internal_modifiers.end()); - EXPECT_NE(std::find(internal_modifiers.begin(), internal_modifiers.end(), - I915_FORMAT_MOD_X_TILED), - internal_modifiers.end()); - EXPECT_NE(std::find(internal_modifiers.begin(), internal_modifiers.end(), - DRM_FORMAT_MOD_LINEAR), - internal_modifiers.end()); - - // With external displays, *_CSS modifiers (2 of them) should not exist. - drm_->set_connector_type(DRM_MODE_CONNECTOR_DisplayPort); - - std::vector<uint64_t> external_modifiers = - controller_->GetFormatModifiers(DRM_FORMAT_XRGB8888); - ASSERT_FALSE(external_modifiers.empty()); - EXPECT_EQ(external_modifiers.size(), internal_modifiers.size() - 2); - - EXPECT_EQ(std::find(external_modifiers.begin(), external_modifiers.end(), - I915_FORMAT_MOD_Y_TILED_CCS), - external_modifiers.end()); - EXPECT_EQ(std::find(external_modifiers.begin(), external_modifiers.end(), - I915_FORMAT_MOD_Yf_TILED_CCS), - external_modifiers.end()); - EXPECT_NE(std::find(internal_modifiers.begin(), internal_modifiers.end(), - I915_FORMAT_MOD_X_TILED), - internal_modifiers.end()); - EXPECT_NE(std::find(internal_modifiers.begin(), internal_modifiers.end(), - DRM_FORMAT_MOD_LINEAR), - internal_modifiers.end()); + 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); +} + +TEST_F(HardwareDisplayControllerTest, CheckDisableResetsProps) { + 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()); + + SchedulePageFlip(std::move(planes)); + + // Test props values after disabling. + controller_->Disable(); + + 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); } TEST_F(HardwareDisplayControllerTest, CheckStateAfterPageFlip) { ui::DrmOverlayPlane plane1(CreateBuffer(), nullptr); EXPECT_TRUE(controller_->Modeset(plane1, kDefaultMode)); + EXPECT_EQ(1, drm_->get_commit_count()); ui::DrmOverlayPlane plane2(CreateBuffer(), nullptr); std::vector<ui::DrmOverlayPlane> planes; @@ -270,13 +313,14 @@ 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); @@ -284,20 +328,6 @@ TEST_F(HardwareDisplayControllerTest, CheckStateIfModesetFails) { 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"); -} - TEST_F(HardwareDisplayControllerTest, CheckOverlayPresent) { ui::DrmOverlayPlane plane1(CreateBuffer(), nullptr); ui::DrmOverlayPlane plane2( @@ -305,6 +335,7 @@ TEST_F(HardwareDisplayControllerTest, CheckOverlayPresent) { gfx::Rect(kOverlaySize), gfx::RectF(kDefaultModeSizeF), true, nullptr); EXPECT_TRUE(controller_->Modeset(plane1, kDefaultMode)); + EXPECT_EQ(1, drm_->get_commit_count()); std::vector<ui::DrmOverlayPlane> planes; planes.push_back(plane1.Clone()); @@ -314,7 +345,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")); @@ -327,13 +358,14 @@ TEST_F(HardwareDisplayControllerTest, CheckOverlayTestMode) { gfx::Rect(kOverlaySize), gfx::RectF(kDefaultModeSizeF), true, nullptr); EXPECT_TRUE(controller_->Modeset(plane1, kDefaultMode)); + 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")); @@ -343,14 +375,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")); @@ -375,12 +407,13 @@ TEST_F(HardwareDisplayControllerTest, AcceptUnderlays) { } TEST_F(HardwareDisplayControllerTest, PageflipMirroredControllers) { - controller_->AddCrtc(std::unique_ptr<ui::CrtcController>( - new ui::CrtcController(drm_.get(), kSecondaryCrtc, kSecondaryConnector))); + controller_->AddCrtc( + std::unique_ptr<ui::CrtcController>(new 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_EQ(2, drm_->get_commit_count()); ui::DrmOverlayPlane plane2(CreateBuffer(), nullptr); std::vector<ui::DrmOverlayPlane> planes; @@ -389,7 +422,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(3, 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")); @@ -400,8 +433,9 @@ TEST_F(HardwareDisplayControllerTest, PageflipMirroredControllers) { } TEST_F(HardwareDisplayControllerTest, PlaneStateAfterRemoveCrtc) { - controller_->AddCrtc(std::unique_ptr<ui::CrtcController>( - new ui::CrtcController(drm_.get(), kSecondaryCrtc, kSecondaryConnector))); + controller_->AddCrtc( + std::unique_ptr<ui::CrtcController>(new ui::CrtcController( + drm_.get(), kSecondaryCrtc, kConnectorIdBase + 1))); ui::DrmOverlayPlane plane1(CreateBuffer(), nullptr); EXPECT_TRUE(controller_->Modeset(plane1, kDefaultMode)); @@ -472,8 +506,9 @@ TEST_F(HardwareDisplayControllerTest, PlaneStateAfterDestroyingCrtc) { } TEST_F(HardwareDisplayControllerTest, PlaneStateAfterAddCrtc) { - controller_->AddCrtc(std::unique_ptr<ui::CrtcController>( - new ui::CrtcController(drm_.get(), kSecondaryCrtc, kSecondaryConnector))); + controller_->AddCrtc( + std::unique_ptr<ui::CrtcController>(new ui::CrtcController( + drm_.get(), kSecondaryCrtc, kConnectorIdBase + 1))); ui::DrmOverlayPlane plane1(CreateBuffer(), nullptr); EXPECT_TRUE(controller_->Modeset(plane1, kDefaultMode)); @@ -534,10 +569,10 @@ TEST_F(HardwareDisplayControllerTest, ModesetWhilePageFlipping) { } TEST_F(HardwareDisplayControllerTest, FailPageFlipping) { - drm_->set_commit_expectation(false); - ui::DrmOverlayPlane plane1(CreateBuffer(), nullptr); EXPECT_TRUE(controller_->Modeset(plane1, kDefaultMode)); + + drm_->set_commit_expectation(false); std::vector<ui::DrmOverlayPlane> planes; planes.push_back(plane1.Clone()); EXPECT_DEATH_IF_SUPPORTED(SchedulePageFlip(std::move(planes)), @@ -565,8 +600,9 @@ TEST_F(HardwareDisplayControllerTest, AddCrtcMidPageFlip) { planes.push_back(plane1.Clone()); SchedulePageFlip(std::move(planes)); - controller_->AddCrtc(std::unique_ptr<ui::CrtcController>( - new ui::CrtcController(drm_.get(), kSecondaryCrtc, kSecondaryConnector))); + controller_->AddCrtc( + std::unique_ptr<ui::CrtcController>(new ui::CrtcController( + drm_.get(), kSecondaryCrtc, kConnectorIdBase + 1))); drm_->RunCallbacks(); EXPECT_EQ(gfx::SwapResult::SWAP_ACK, last_swap_result_); 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 a118c818103..28d692268d7 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 @@ -123,6 +123,7 @@ bool HardwareDisplayPlaneAtomic::SetPlaneData( return false; } + crtc_id_ = crtc_id; return true; } 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 a28f562a468..af874abf6c7 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 @@ -18,8 +18,6 @@ class Rect; namespace ui { -class CrtcController; - class HardwareDisplayPlaneAtomic : public HardwareDisplayPlane { public: HardwareDisplayPlaneAtomic(uint32_t id); @@ -37,11 +35,10 @@ class HardwareDisplayPlaneAtomic : public HardwareDisplayPlane { bool SetPlaneCtm(drmModeAtomicReq* property_set, uint32_t ctm_blob_id); - void set_crtc(CrtcController* crtc) { crtc_ = crtc; } - CrtcController* crtc() const { return crtc_; } + uint32_t crtc_id() { return crtc_id_; } private: - CrtcController* crtc_ = nullptr; + uint32_t crtc_id_ = 0; DISALLOW_COPY_AND_ASSIGN(HardwareDisplayPlaneAtomic); }; 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 66f79d06038..0cdaaca15cf 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 @@ -28,20 +28,16 @@ HardwareDisplayPlaneList::HardwareDisplayPlaneList() { atomic_property_set.reset(drmModeAtomicAlloc()); } -HardwareDisplayPlaneList::~HardwareDisplayPlaneList() { -} +HardwareDisplayPlaneList::~HardwareDisplayPlaneList() = default; HardwareDisplayPlaneList::PageFlipInfo::PageFlipInfo(uint32_t crtc_id, - uint32_t framebuffer, - CrtcController* crtc) - : crtc_id(crtc_id), framebuffer(framebuffer), crtc(crtc) { -} + uint32_t framebuffer) + : crtc_id(crtc_id), framebuffer(framebuffer) {} HardwareDisplayPlaneList::PageFlipInfo::PageFlipInfo( const PageFlipInfo& other) = default; -HardwareDisplayPlaneList::PageFlipInfo::~PageFlipInfo() { -} +HardwareDisplayPlaneList::PageFlipInfo::~PageFlipInfo() = default; HardwareDisplayPlaneManager::CrtcState::CrtcState() = default; @@ -52,8 +48,7 @@ HardwareDisplayPlaneManager::CrtcState::CrtcState(CrtcState&&) = default; HardwareDisplayPlaneManager::HardwareDisplayPlaneManager(DrmDevice* drm) : drm_(drm) {} -HardwareDisplayPlaneManager::~HardwareDisplayPlaneManager() { -} +HardwareDisplayPlaneManager::~HardwareDisplayPlaneManager() = default; bool HardwareDisplayPlaneManager::Initialize() { // Try to get all of the planes if possible, so we don't have to try to @@ -99,9 +94,19 @@ HardwareDisplayPlane* HardwareDisplayPlaneManager::FindNextUnusedPlane( } int HardwareDisplayPlaneManager::LookupCrtcIndex(uint32_t crtc_id) const { - for (size_t i = 0; i < crtc_state_.size(); ++i) + for (size_t i = 0; i < crtc_state_.size(); ++i) { if (crtc_state_[i].properties.id == crtc_id) return i; + } + return -1; +} + +int HardwareDisplayPlaneManager::LookupConnectorIndex( + uint32_t connector_id) const { + for (size_t i = 0; i < connectors_props_.size(); ++i) { + if (connectors_props_[i].id == connector_id) + return i; + } return -1; } @@ -159,8 +164,7 @@ void HardwareDisplayPlaneManager::BeginFrame( bool HardwareDisplayPlaneManager::AssignOverlayPlanes( HardwareDisplayPlaneList* plane_list, const DrmOverlayPlaneList& overlay_list, - uint32_t crtc_id, - CrtcController* crtc) { + uint32_t crtc_id) { int crtc_index = LookupCrtcIndex(crtc_id); if (crtc_index < 0) { LOG(ERROR) << "Cannot find crtc " << crtc_id; @@ -185,16 +189,16 @@ bool HardwareDisplayPlaneManager::AssignOverlayPlanes( // 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; }; + 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())); } - if (!SetPlaneData(plane_list, hw_plane, plane, crtc_id, fixed_point_rect, - crtc)) { + if (!SetPlaneData(plane_list, hw_plane, plane, crtc_id, fixed_point_rect)) { ResetCurrentPlaneList(plane_list); return false; } @@ -226,6 +230,28 @@ std::vector<uint64_t> HardwareDisplayPlaneManager::GetFormatModifiers( return std::vector<uint64_t>(); } +void HardwareDisplayPlaneManager::ResetConnectorsCache( + const ScopedDrmResourcesPtr& resources) { + connectors_props_.clear(); + + for (int i = 0; i < resources->count_connectors; ++i) { + ConnectorProperties state_props; + state_props.id = resources->connectors[i]; + + ScopedDrmObjectPropertyPtr props(drm_->GetObjectProperties( + resources->connectors[i], DRM_MODE_OBJECT_CONNECTOR)); + if (!props) { + PLOG(ERROR) << "Failed to get Connector properties for connector=" + << state_props.id; + continue; + } + GetDrmPropertyForName(drm_, props.get(), "CRTC_ID", &state_props.crtc_id); + DCHECK(!drm_->is_atomic() || state_props.crtc_id.id); + + connectors_props_.emplace_back(std::move(state_props)); + } +} + bool HardwareDisplayPlaneManager::SetColorMatrix( uint32_t crtc_id, const std::vector<float>& color_matrix) { @@ -319,6 +345,8 @@ bool HardwareDisplayPlaneManager::InitializeCrtcState() { return false; } + ResetConnectorsCache(resources); + unsigned int num_crtcs_with_out_fence_ptr = 0; for (int i = 0; i < resources->count_crtcs; ++i) { @@ -333,6 +361,12 @@ bool HardwareDisplayPlaneManager::InitializeCrtcState() { continue; } + GetDrmPropertyForName(drm_, props.get(), "ACTIVE", + &state.properties.active); + DCHECK(!drm_->is_atomic() || state.properties.active.id); + GetDrmPropertyForName(drm_, props.get(), "MODE_ID", + &state.properties.mode_id); + DCHECK(!drm_->is_atomic() || state.properties.mode_id.id); // These properties are optional. If they don't exist we can tell by the // invalid ID. GetDrmPropertyForName(drm_, props.get(), "CTM", &state.properties.ctm); 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 6298d579e4f..b24007d6611 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 @@ -40,13 +40,12 @@ struct HardwareDisplayPlaneList { std::vector<HardwareDisplayPlane*> old_plane_list; struct PageFlipInfo { - PageFlipInfo(uint32_t crtc_id, uint32_t framebuffer, CrtcController* crtc); + PageFlipInfo(uint32_t crtc_id, uint32_t framebuffer); PageFlipInfo(const PageFlipInfo& other); ~PageFlipInfo(); uint32_t crtc_id; uint32_t framebuffer; - CrtcController* crtc; }; // In the case of non-atomic operation, this info will be used for // pageflipping. @@ -57,13 +56,22 @@ struct HardwareDisplayPlaneList { class HardwareDisplayPlaneManager { public: - HardwareDisplayPlaneManager(DrmDevice* drm); + explicit HardwareDisplayPlaneManager(DrmDevice* drm); virtual ~HardwareDisplayPlaneManager(); // This parses information from the drm driver, adding any new planes // 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; + // Clears old frame state out. Must be called before any AssignOverlayPlanes // calls. void BeginFrame(HardwareDisplayPlaneList* plane_list); @@ -86,11 +94,10 @@ class HardwareDisplayPlaneManager { // |crtc_id| will be used. |overlay_list| must be sorted bottom-to-top. virtual bool AssignOverlayPlanes(HardwareDisplayPlaneList* plane_list, const DrmOverlayPlaneList& overlay_list, - uint32_t crtc_id, - CrtcController* crtc); + 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 @@ -98,6 +105,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; @@ -134,11 +142,21 @@ class HardwareDisplayPlaneManager { std::vector<uint64_t> GetFormatModifiers(uint32_t crtc_id, uint32_t format) const; + // Cache the most updated connectors found in DRM resources. This needs to be + // called whenever a DRM hotplug event is received via UDEV. + void ResetConnectorsCache(const ScopedDrmResourcesPtr& resources); + 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; @@ -173,8 +191,7 @@ class HardwareDisplayPlaneManager { HardwareDisplayPlane* hw_plane, const DrmOverlayPlane& overlay, uint32_t crtc_id, - const gfx::Rect& src_rect, - CrtcController* crtc) = 0; + const gfx::Rect& src_rect) = 0; virtual std::unique_ptr<HardwareDisplayPlane> CreatePlane(uint32_t plane_id); @@ -185,8 +202,10 @@ class HardwareDisplayPlaneManager { uint32_t crtc_index, const DrmOverlayPlane& overlay) const; - // Convert |crtc_id| into an index, returning -1 if the ID couldn't be found. + // Convert |crtc/connector_id| into an index, returning -1 if the ID couldn't + // be found. int LookupCrtcIndex(uint32_t crtc_id) const; + int LookupConnectorIndex(uint32_t connector_idx) const; // Returns true if |plane| can support |overlay| and compatible with // |crtc_index|. @@ -211,6 +230,7 @@ class HardwareDisplayPlaneManager { std::vector<std::unique_ptr<HardwareDisplayPlane>> planes_; std::vector<CrtcState> crtc_state_; + std::vector<ConnectorProperties> connectors_props_; std::vector<uint32_t> supported_formats_; DISALLOW_COPY_AND_ASSIGN(HardwareDisplayPlaneManager); 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 869c4414763..5f4a4101c2c 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 @@ -57,17 +57,81 @@ HardwareDisplayPlaneManagerAtomic::HardwareDisplayPlaneManagerAtomic( DrmDevice* drm) : HardwareDisplayPlaneManager(drm) {} -HardwareDisplayPlaneManagerAtomic::~HardwareDisplayPlaneManagerAtomic() { +HardwareDisplayPlaneManagerAtomic::~HardwareDisplayPlaneManagerAtomic() = + default; + +bool HardwareDisplayPlaneManagerAtomic::Modeset( + uint32_t crtc_id, + uint32_t framebuffer_id, + uint32_t connector_id, + const drmModeModeInfo& mode, + const HardwareDisplayPlaneList& plane_list) { + const int connector_idx = LookupConnectorIndex(connector_id); + DCHECK_GE(connector_idx, 0); + connectors_props_[connector_idx].crtc_id.value = crtc_id; + bool res = + AddPropertyIfValid(plane_list.atomic_property_set.get(), connector_id, + 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 = 1UL; + ScopedDrmPropertyBlob mode_blob = + drm_->CreatePropertyBlob(&mode, sizeof(mode)); + crtc_state_[crtc_idx].properties.mode_id.value = + mode_blob ? mode_blob->id() : 0; + + res &= AddPropertyIfValid(plane_list.atomic_property_set.get(), crtc_id, + crtc_state_[crtc_idx].properties.active); + res &= AddPropertyIfValid(plane_list.atomic_property_set.get(), crtc_id, + crtc_state_[crtc_idx].properties.mode_id); + + DCHECK(res); + return Commit(const_cast<HardwareDisplayPlaneList*>(&plane_list), + /*should_modeset=*/true, + /*page_flip_request=*/nullptr, + /*out_fence=*/nullptr); +} + +bool HardwareDisplayPlaneManagerAtomic::DisableModeset(uint32_t crtc_id, + uint32_t connector) { + ScopedDrmAtomicReqPtr property_set(drmModeAtomicAlloc()); + + 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); } 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 = !page_flip_request; + bool test_only = !should_modeset && !page_flip_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); @@ -77,31 +141,29 @@ bool HardwareDisplayPlaneManagerAtomic::Commit( } } - std::vector<CrtcController*> crtcs; + 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()) - crtcs.push_back(atomic_plane->crtc()); + 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 (auto* const crtc : crtcs) { - int idx = LookupCrtcIndex(crtc->crtc()); + for (uint32_t crtc : crtcs) { + int idx = LookupCrtcIndex(crtc); #if defined(COMMIT_PROPERTIES_ON_PAGE_FLIP) // Apply all CRTC properties in the page-flip so we don't block the // 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(), - crtc_state_[idx].properties.degamma_lut); - AddPropertyIfValid(request, crtc->crtc(), - crtc_state_[idx].properties.gamma_lut); - AddPropertyIfValid(request, crtc->crtc(), crtc_state_[idx].properties.ctm); + 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); #endif - AddPropertyIfValid(request, crtc->crtc(), + AddPropertyIfValid(request, crtc, crtc_state_[idx].properties.background_color); } @@ -114,11 +176,10 @@ bool HardwareDisplayPlaneManagerAtomic::Commit( } uint32_t flags = 0; - if (test_only) { - flags = DRM_MODE_ATOMIC_TEST_ONLY; - } else { - flags = DRM_MODE_ATOMIC_NONBLOCK; - } + if (should_modeset) + flags = DRM_MODE_ATOMIC_ALLOW_MODESET; + else + flags = test_only ? DRM_MODE_ATOMIC_TEST_ONLY : DRM_MODE_ATOMIC_NONBLOCK; // 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 @@ -230,8 +291,7 @@ bool HardwareDisplayPlaneManagerAtomic::SetPlaneData( HardwareDisplayPlane* hw_plane, const DrmOverlayPlane& overlay, uint32_t crtc_id, - const gfx::Rect& src_rect, - CrtcController* crtc) { + const gfx::Rect& src_rect) { HardwareDisplayPlaneAtomic* atomic_plane = static_cast<HardwareDisplayPlaneAtomic*>(hw_plane); uint32_t framebuffer_id = overlay.enable_blend @@ -256,7 +316,6 @@ bool HardwareDisplayPlaneManagerAtomic::SetPlaneData( LOG(ERROR) << "Failed to set plane properties"; return false; } - atomic_plane->set_crtc(crtc); return true; } @@ -346,7 +405,7 @@ bool HardwareDisplayPlaneManagerAtomic::CommitGammaCorrection( bool HardwareDisplayPlaneManagerAtomic::AddOutFencePtrProperties( drmModeAtomicReqPtr property_set, - const std::vector<CrtcController*>& crtcs, + const std::vector<uint32_t>& crtcs, std::vector<base::ScopedFD>* out_fence_fds, std::vector<base::ScopedFD::Receiver>* out_fence_fd_receivers) { // Reserve space in vector to ensure no reallocation will take place @@ -356,8 +415,8 @@ bool HardwareDisplayPlaneManagerAtomic::AddOutFencePtrProperties( out_fence_fds->reserve(crtcs.size()); out_fence_fd_receivers->reserve(crtcs.size()); - for (auto* crtc : crtcs) { - const auto crtc_index = LookupCrtcIndex(crtc->crtc()); + for (uint32_t crtc : crtcs) { + const auto crtc_index = LookupCrtcIndex(crtc); DCHECK_GE(crtc_index, 0); const auto out_fence_ptr_id = crtc_state_[crtc_index].properties.out_fence_ptr.id; @@ -371,11 +430,11 @@ bool HardwareDisplayPlaneManagerAtomic::AddOutFencePtrProperties( // commit, so we need to ensure that the pointer remains valid // until then. int ret = drmModeAtomicAddProperty( - property_set, crtc->crtc(), out_fence_ptr_id, + property_set, crtc, out_fence_ptr_id, reinterpret_cast<uint64_t>(out_fence_fd_receivers->back().get())); if (ret < 0) { - LOG(ERROR) << "Failed to set OUT_FENCE_PTR property for crtc=" - << crtc->crtc() << " error=" << -ret; + LOG(ERROR) << "Failed to set OUT_FENCE_PTR property for crtc=" << crtc + << " error=" << -ret; out_fence_fd_receivers->pop_back(); out_fence_fds->pop_back(); return false; 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 c259643ef5a..2aa11b73071 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 @@ -15,11 +15,18 @@ namespace ui { class HardwareDisplayPlaneManagerAtomic : public HardwareDisplayPlaneManager { public: - HardwareDisplayPlaneManagerAtomic(DrmDevice* drm); + explicit HardwareDisplayPlaneManagerAtomic(DrmDevice* drm); ~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(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; @@ -38,8 +45,7 @@ class HardwareDisplayPlaneManagerAtomic : public HardwareDisplayPlaneManager { HardwareDisplayPlane* hw_plane, const DrmOverlayPlane& overlay, uint32_t crtc_id, - const gfx::Rect& src_rect, - CrtcController* crtc) override; + const gfx::Rect& src_rect) override; private: bool InitializePlanes() override; @@ -48,7 +54,7 @@ class HardwareDisplayPlaneManagerAtomic : public HardwareDisplayPlaneManager { bool CommitGammaCorrection(const CrtcProperties& crtc_props) override; bool AddOutFencePtrProperties( drmModeAtomicReqPtr property_set, - const std::vector<CrtcController*>& crtcs, + 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 11b6c8de1da..a09037cf0df 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 @@ -12,6 +12,7 @@ #include "base/bind.h" #include "base/posix/eintr_wrapper.h" #include "base/task/post_task.h" +#include "base/task/thread_pool.h" #include "ui/gfx/gpu_fence.h" #include "ui/gfx/presentation_feedback.h" #include "ui/ozone/platform/drm/gpu/crtc_controller.h" @@ -42,13 +43,31 @@ HardwareDisplayPlaneManagerLegacy::HardwareDisplayPlaneManagerLegacy( DrmDevice* drm) : HardwareDisplayPlaneManager(drm) {} -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::DisableModeset(uint32_t crtc_id, + uint32_t connector) { + return drm_->DisableCrtc(crtc_id); } bool HardwareDisplayPlaneManagerLegacy::Commit( HardwareDisplayPlaneList* plane_list, + bool should_modeset, scoped_refptr<PageFlipRequest> page_flip_request, std::unique_ptr<gfx::GpuFence>* out_fence) { + DCHECK(!should_modeset); + bool test_only = !page_flip_request; if (test_only) { for (HardwareDisplayPlane* plane : plane_list->plane_list) { @@ -121,10 +140,9 @@ bool HardwareDisplayPlaneManagerLegacy::ValidatePrimarySize( void HardwareDisplayPlaneManagerLegacy::RequestPlanesReadyCallback( DrmOverlayPlaneList planes, base::OnceCallback<void(DrmOverlayPlaneList planes)> callback) { - base::PostTaskAndReplyWithResult( + base::ThreadPool::PostTaskAndReplyWithResult( FROM_HERE, - {base::ThreadPool(), base::MayBlock(), - base::TaskShutdownBehavior::CONTINUE_ON_SHUTDOWN}, + {base::MayBlock(), base::TaskShutdownBehavior::CONTINUE_ON_SHUTDOWN}, base::BindOnce(&WaitForPlaneFences, std::move(planes)), std::move(callback)); } @@ -178,8 +196,7 @@ bool HardwareDisplayPlaneManagerLegacy::SetPlaneData( HardwareDisplayPlane* hw_plane, const DrmOverlayPlane& overlay, uint32_t crtc_id, - const gfx::Rect& src_rect, - CrtcController* crtc) { + const gfx::Rect& src_rect) { // Legacy modesetting rejects transforms. if (overlay.plane_transform != gfx::OVERLAY_TRANSFORM_NONE) return false; @@ -188,7 +205,7 @@ bool HardwareDisplayPlaneManagerLegacy::SetPlaneData( 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(), crtc)); + crtc_id, overlay.buffer->opaque_framebuffer_id())); } else { 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 3843560218e..668ffde7258 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 @@ -15,11 +15,18 @@ namespace ui { class HardwareDisplayPlaneManagerLegacy : public HardwareDisplayPlaneManager { public: - HardwareDisplayPlaneManagerLegacy(DrmDevice* device); + explicit HardwareDisplayPlaneManagerLegacy(DrmDevice* device); ~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(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; @@ -41,8 +48,7 @@ class HardwareDisplayPlaneManagerLegacy : public HardwareDisplayPlaneManager { HardwareDisplayPlane* hw_plane, const DrmOverlayPlane& overlay, uint32_t crtc_id, - const gfx::Rect& src_rect, - CrtcController* crtc) override; + const gfx::Rect& src_rect) override; bool IsCompatible(HardwareDisplayPlane* plane, const DrmOverlayPlane& overlay, uint32_t crtc_index) const 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 3450da8065e..5acf29f9eb8 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 @@ -18,7 +18,10 @@ #include "ui/display/types/gamma_ramp_rgb_entry.h" #include "ui/gfx/gpu_fence.h" #include "ui/gfx/gpu_fence_handle.h" -#include "ui/ozone/common/linux/gbm_buffer.h" +#include "ui/gfx/linux/drm_util_linux.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_framebuffer.h" #include "ui/ozone/platform/drm/gpu/drm_gpu_util.h" @@ -26,30 +29,40 @@ #include "ui/ozone/platform/drm/gpu/hardware_display_plane_manager_atomic.h" #include "ui/ozone/platform/drm/gpu/hardware_display_plane_manager_legacy.h" #include "ui/ozone/platform/drm/gpu/mock_drm_device.h" -#include "ui/ozone/platform/drm/gpu/mock_gbm_device.h" namespace { constexpr uint32_t kPlaneOffset = 100; -constexpr uint32_t kTypePropId = 300; -constexpr uint32_t kInFormatsPropId = 301; -constexpr uint32_t kPlaneCtmId = 302; -constexpr uint32_t kCtmPropId = 303; -constexpr uint32_t kGammaLutPropId = 304; -constexpr uint32_t kGammaLutSizePropId = 305; -constexpr uint32_t kDegammaLutPropId = 306; -constexpr uint32_t kDegammaLutSizePropId = 307; -constexpr uint32_t kOutFencePtrPropId = 308; +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; +constexpr uint32_t kGammaLutSizePropId = 1005; +constexpr uint32_t kDegammaLutPropId = 1006; +constexpr uint32_t kDegammaLutSizePropId = 1007; +constexpr uint32_t kOutFencePtrPropId = 1008; + +constexpr uint32_t kCrtcIdPropId = 2000; +constexpr uint32_t kTypePropId = 3010; +constexpr uint32_t kInFormatsPropId = 3011; +constexpr uint32_t kPlaneCtmId = 3012; + constexpr uint32_t kInFormatsBlobPropId = 400; -constexpr uint32_t kBackgroundColorPropId = 401; const gfx::Size kDefaultBufferSize(2, 2); +// Create a basic mode for a 6x4 screen. +drmModeModeInfo kDefaultMode = {0, 6, 0, 0, 0, 0, 4, 0, + 0, 0, 0, 0, 0, 0, {'\0'}}; class HardwareDisplayPlaneManagerTest : public testing::Test, public testing::WithParamInterface<bool> { public: - HardwareDisplayPlaneManagerTest() {} + HardwareDisplayPlaneManagerTest() = default; void InitializeDrmState(size_t crtc_count, size_t planes_per_crtc); @@ -74,7 +87,7 @@ class HardwareDisplayPlaneManagerTest uint32_t format) { std::unique_ptr<ui::GbmBuffer> buffer = fake_drm_->gbm_device()->CreateBuffer(format, size, GBM_BO_USE_SCANOUT); - return ui::DrmFramebuffer::AddFramebuffer(fake_drm_, buffer.get()); + return ui::DrmFramebuffer::AddFramebuffer(fake_drm_, buffer.get(), size); } protected: @@ -83,6 +96,7 @@ class HardwareDisplayPlaneManagerTest scoped_refptr<ui::MockDrmDevice> fake_drm_; std::vector<ui::MockDrmDevice::CrtcProperties> crtc_properties_; + std::vector<ui::MockDrmDevice::ConnectorProperties> connector_properties_; std::vector<ui::MockDrmDevice::PlaneProperties> plane_properties_; std::map<uint32_t, std::string> property_names_; @@ -106,35 +120,60 @@ void HardwareDisplayPlaneManagerTest::SetUp() { void HardwareDisplayPlaneManagerTest::InitializeDrmState( size_t crtc_count, size_t planes_per_crtc) { - property_names_ = { + std::map<uint32_t, std::string> crtc_property_names = { + {kActivePropId, "ACTIVE"}, + {kModePropId, "MODE_ID"}, + }; + + std::vector<ui::MockDrmDevice::ConnectorProperties> connector_properties(1); + std::map<uint32_t, std::string> connector_property_names = { + {kCrtcIdPropId, "CRTC_ID"}, + }; + for (size_t i = 0; i < connector_properties.size(); ++i) { + connector_properties[i].id = kConnectorIdBase + i; + for (const auto& pair : connector_property_names) { + connector_properties[i].properties.push_back( + {/* .id = */ pair.first, /* .value = */ 0}); + } + } + connector_properties_ = connector_properties; + + std::vector<ui::MockDrmDevice::PlaneProperties> plane_properties( + planes_per_crtc * crtc_count); + std::map<uint32_t, std::string> plane_property_names = { // Add all required properties. - {200, "CRTC_ID"}, - {201, "CRTC_X"}, - {202, "CRTC_Y"}, - {203, "CRTC_W"}, - {204, "CRTC_H"}, - {205, "FB_ID"}, - {206, "SRC_X"}, - {207, "SRC_Y"}, - {208, "SRC_W"}, - {209, "SRC_H"}, + {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"}, }; + // Always add an additional cursor plane. ++planes_per_crtc; for (size_t i = 0; i < crtc_count; ++i) { ui::MockDrmDevice::CrtcProperties crtc_prop; // Start ID at 1 cause 0 is an invalid ID. - crtc_prop.id = i + 1; + crtc_prop.id = kCrtcIdBase + i; + for (const auto& pair : crtc_property_names) { + crtc_prop.properties.push_back( + {/* .id = */ pair.first, /* .value = */ 0}); + } crtc_properties_.emplace_back(std::move(crtc_prop)); for (size_t j = 0; j < planes_per_crtc; ++j) { ui::MockDrmDevice::PlaneProperties plane_prop; plane_prop.id = kPlaneOffset + i * planes_per_crtc + j; plane_prop.crtc_mask = 1 << i; - for (const auto& pair : property_names_) { + for (const auto& pair : plane_property_names) { uint32_t value = 0; if (pair.first == kTypePropId) { if (j == 0) @@ -154,36 +193,42 @@ void HardwareDisplayPlaneManagerTest::InitializeDrmState( } } + 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()); + // Separately add optional properties that will be used in some tests, but the // tests will append the property to the planes on a case-by-case basis. // // Plane properties: property_names_.insert({kPlaneCtmId, "PLANE_CTM"}); // CRTC properties: + property_names_.insert({kBackgroundColorPropId, "BACKGROUND_COLOR"}); property_names_.insert({kCtmPropId, "CTM"}); property_names_.insert({kGammaLutPropId, "GAMMA_LUT"}); property_names_.insert({kGammaLutSizePropId, "GAMMA_LUT_SIZE"}); property_names_.insert({kDegammaLutPropId, "DEGAMMA_LUT"}); property_names_.insert({kDegammaLutSizePropId, "DEGAMMA_LUT_SIZE"}); property_names_.insert({kOutFencePtrPropId, "OUT_FENCE_PTR"}); - property_names_.insert({kBackgroundColorPropId, "BACKGROUND_COLOR"}); } void HardwareDisplayPlaneManagerTest::PerformPageFlip( size_t crtc_idx, ui::HardwareDisplayPlaneList* state) { ui::DrmOverlayPlaneList assigns; - ui::CrtcController crtc(fake_drm_, crtc_properties_[crtc_idx].id, 0); scoped_refptr<ui::DrmFramebuffer> xrgb_buffer = CreateBuffer(kDefaultBufferSize); assigns.push_back(ui::DrmOverlayPlane(xrgb_buffer, nullptr)); fake_drm_->plane_manager()->BeginFrame(state); ASSERT_TRUE(fake_drm_->plane_manager()->AssignOverlayPlanes( - state, assigns, crtc_properties_[crtc_idx].id, &crtc)); + 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( @@ -213,16 +258,86 @@ uint64_t HardwareDisplayPlaneManagerTest::GetPlanePropertyValue( using HardwareDisplayPlaneManagerLegacyTest = HardwareDisplayPlaneManagerTest; using HardwareDisplayPlaneManagerAtomicTest = HardwareDisplayPlaneManagerTest; +TEST_P(HardwareDisplayPlaneManagerTest, ResettingConnectorCache) { + const int connector_and_crtc_count = 3; + InitializeDrmState(/*crtc_count=*/connector_and_crtc_count, + /*planes_per_crtc=*/1); + + // Create 3 connectors, kConnectorIdBase + 0/1/2 + std::vector<ui::MockDrmDevice::ConnectorProperties> connector_properties( + connector_and_crtc_count); + for (size_t i = 0; i < connector_and_crtc_count; ++i) { + connector_properties[i].id = kConnectorIdBase + i; + connector_properties[i].properties.push_back( + {/* .id = */ kCrtcIdPropId, /* .value = */ 0}); + } + + fake_drm_->InitializeState(crtc_properties_, connector_properties, + 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)); + } + + // Replace last connector and update state. + connector_properties[connector_and_crtc_count - 1].id = kConnectorIdBase + 3; + fake_drm_->UpdateState(crtc_properties_, connector_properties, + 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)); + EXPECT_TRUE(fake_drm_->plane_manager()->Modeset( + crtc_properties_[2].id, kFrameBuffer, kConnectorIdBase + 3, kDefaultMode, + state)); +} + +TEST_P(HardwareDisplayPlaneManagerLegacyTest, Modeset) { + InitializeDrmState(/*crtc_count=*/1, /*planes_per_crtc=*/1); + fake_drm_->InitializeState(crtc_properties_, connector_properties_, + plane_properties_, property_names_, + /*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()); + EXPECT_EQ(1, fake_drm_->get_set_crtc_call_count()); +} + +TEST_P(HardwareDisplayPlaneManagerLegacyTest, DisableModeset) { + InitializeDrmState(/*crtc_count=*/1, /*planes_per_crtc=*/1); + fake_drm_->InitializeState(crtc_properties_, connector_properties_, + plane_properties_, property_names_, + /*use_atomic*/ false); + + EXPECT_TRUE( + fake_drm_->plane_manager()->DisableModeset(crtc_properties_[0].id, 0)); +} + TEST_P(HardwareDisplayPlaneManagerLegacyTest, SinglePlaneAssignment) { ui::DrmOverlayPlaneList assigns; assigns.push_back(ui::DrmOverlayPlane(fake_buffer_, nullptr)); InitializeDrmState(/*crtc_count=*/2, /*planes_per_crtc=*/1); - fake_drm_->InitializeState(crtc_properties_, plane_properties_, - property_names_, use_atomic_); + fake_drm_->InitializeState(crtc_properties_, connector_properties_, + plane_properties_, property_names_, use_atomic_); EXPECT_TRUE(fake_drm_->plane_manager()->AssignOverlayPlanes( - &state_, assigns, crtc_properties_[0].id, nullptr)); + &state_, assigns, crtc_properties_[0].id)); EXPECT_EQ(1u, state_.plane_list.size()); } @@ -231,8 +346,8 @@ TEST_P(HardwareDisplayPlaneManagerLegacyTest, AddCursor) { assigns.push_back(ui::DrmOverlayPlane(fake_buffer_, nullptr)); InitializeDrmState(/*crtc_count=*/2, /*planes_per_crtc=*/1); - fake_drm_->InitializeState(crtc_properties_, plane_properties_, - property_names_, use_atomic_); + fake_drm_->InitializeState(crtc_properties_, connector_properties_, + plane_properties_, property_names_, use_atomic_); bool cursor_found = false; for (const auto& plane : fake_drm_->plane_manager()->planes()) { @@ -249,11 +364,11 @@ TEST_P(HardwareDisplayPlaneManagerLegacyTest, BadCrtc) { assigns.push_back(ui::DrmOverlayPlane(fake_buffer_, nullptr)); InitializeDrmState(/*crtc_count=*/2, /*planes_per_crtc=*/1); - fake_drm_->InitializeState(crtc_properties_, plane_properties_, - property_names_, use_atomic_); + fake_drm_->InitializeState(crtc_properties_, connector_properties_, + plane_properties_, property_names_, use_atomic_); - EXPECT_FALSE(fake_drm_->plane_manager()->AssignOverlayPlanes(&state_, assigns, - 0, nullptr)); + EXPECT_FALSE( + fake_drm_->plane_manager()->AssignOverlayPlanes(&state_, assigns, 0)); } TEST_P(HardwareDisplayPlaneManagerLegacyTest, NotEnoughPlanes) { @@ -262,11 +377,11 @@ TEST_P(HardwareDisplayPlaneManagerLegacyTest, NotEnoughPlanes) { assigns.push_back(ui::DrmOverlayPlane(fake_buffer_, nullptr)); InitializeDrmState(/*crtc_count=*/2, /*planes_per_crtc=*/1); - fake_drm_->InitializeState(crtc_properties_, plane_properties_, - property_names_, use_atomic_); + fake_drm_->InitializeState(crtc_properties_, connector_properties_, + plane_properties_, property_names_, use_atomic_); EXPECT_FALSE(fake_drm_->plane_manager()->AssignOverlayPlanes( - &state_, assigns, crtc_properties_[0].id, nullptr)); + &state_, assigns, crtc_properties_[0].id)); } TEST_P(HardwareDisplayPlaneManagerLegacyTest, MultipleCrtcs) { @@ -274,13 +389,13 @@ TEST_P(HardwareDisplayPlaneManagerLegacyTest, MultipleCrtcs) { assigns.push_back(ui::DrmOverlayPlane(fake_buffer_, nullptr)); InitializeDrmState(/*crtc_count=*/2, /*planes_per_crtc=*/1); - fake_drm_->InitializeState(crtc_properties_, plane_properties_, - property_names_, use_atomic_); + fake_drm_->InitializeState(crtc_properties_, connector_properties_, + plane_properties_, property_names_, use_atomic_); EXPECT_TRUE(fake_drm_->plane_manager()->AssignOverlayPlanes( - &state_, assigns, crtc_properties_[0].id, nullptr)); + &state_, assigns, crtc_properties_[0].id)); EXPECT_TRUE(fake_drm_->plane_manager()->AssignOverlayPlanes( - &state_, assigns, crtc_properties_[1].id, nullptr)); + &state_, assigns, crtc_properties_[1].id)); EXPECT_EQ(2u, state_.plane_list.size()); } @@ -290,13 +405,13 @@ TEST_P(HardwareDisplayPlaneManagerLegacyTest, MultiplePlanesAndCrtcs) { assigns.push_back(ui::DrmOverlayPlane(fake_buffer_, nullptr)); InitializeDrmState(/*crtc_count=*/2, /*planes_per_crtc=*/2); - fake_drm_->InitializeState(crtc_properties_, plane_properties_, - property_names_, use_atomic_); + fake_drm_->InitializeState(crtc_properties_, connector_properties_, + plane_properties_, property_names_, use_atomic_); EXPECT_FALSE(fake_drm_->plane_manager()->AssignOverlayPlanes( - &state_, assigns, crtc_properties_[0].id, nullptr)); + &state_, assigns, crtc_properties_[0].id)); EXPECT_FALSE(fake_drm_->plane_manager()->AssignOverlayPlanes( - &state_, assigns, crtc_properties_[1].id, nullptr)); + &state_, assigns, crtc_properties_[1].id)); EXPECT_EQ(0u, state_.plane_list.size()); } @@ -307,24 +422,109 @@ TEST_P(HardwareDisplayPlaneManagerLegacyTest, CheckFramebufferFormatMatch) { assigns.push_back(ui::DrmOverlayPlane(buffer, nullptr)); InitializeDrmState(/*crtc_count=*/2, /*planes_per_crtc=*/1); - fake_drm_->InitializeState(crtc_properties_, plane_properties_, - property_names_, use_atomic_); + fake_drm_->InitializeState(crtc_properties_, connector_properties_, + plane_properties_, property_names_, use_atomic_); fake_drm_->plane_manager()->BeginFrame(&state_); // This should return false as plane manager creates planes which support // DRM_FORMAT_XRGB8888 while buffer returns kDummyFormat as its pixelFormat. EXPECT_FALSE(fake_drm_->plane_manager()->AssignOverlayPlanes( - &state_, assigns, crtc_properties_[0].id, nullptr)); + &state_, assigns, crtc_properties_[0].id)); assigns.clear(); scoped_refptr<ui::DrmFramebuffer> xrgb_buffer = CreateBuffer(kDefaultBufferSize); assigns.push_back(ui::DrmOverlayPlane(xrgb_buffer, nullptr)); fake_drm_->plane_manager()->BeginFrame(&state_); EXPECT_TRUE(fake_drm_->plane_manager()->AssignOverlayPlanes( - &state_, assigns, crtc_properties_[0].id, nullptr)); + &state_, assigns, crtc_properties_[0].id)); fake_drm_->plane_manager()->BeginFrame(&state_); EXPECT_FALSE(fake_drm_->plane_manager()->AssignOverlayPlanes( - &state_, assigns, crtc_properties_[0].id, nullptr)); + &state_, assigns, crtc_properties_[0].id)); +} + +TEST_P(HardwareDisplayPlaneManagerAtomicTest, Modeset) { + InitializeDrmState(/*crtc_count=*/1, /*planes_per_crtc=*/1); + fake_drm_->InitializeState(crtc_properties_, connector_properties_, + 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)); + + EXPECT_EQ(1, fake_drm_->get_commit_count()); +} + +TEST_P(HardwareDisplayPlaneManagerAtomicTest, DisableModeset) { + InitializeDrmState(/*crtc_count=*/1, /*planes_per_crtc=*/1); + fake_drm_->InitializeState(crtc_properties_, connector_properties_, + 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()); +} + +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); + + 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)); + + // 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) { + InitializeDrmState(/*crtc_count=*/1, /*planes_per_crtc=*/1); + fake_drm_->InitializeState(crtc_properties_, connector_properties_, + 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)); + + // Test props values after disabling. + EXPECT_TRUE(fake_drm_->plane_manager()->DisableModeset( + crtc_properties_[0].id, connector_properties_[0].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(0U, crtc_prop_for_name.value); } TEST_P(HardwareDisplayPlaneManagerAtomicTest, MultiplePlaneAssignment) { @@ -333,11 +533,11 @@ TEST_P(HardwareDisplayPlaneManagerAtomicTest, MultiplePlaneAssignment) { assigns.push_back(ui::DrmOverlayPlane(fake_buffer_, nullptr)); InitializeDrmState(/*crtc_count=*/2, /*planes_per_crtc=*/2); - fake_drm_->InitializeState(crtc_properties_, plane_properties_, - property_names_, use_atomic_); + fake_drm_->InitializeState(crtc_properties_, connector_properties_, + plane_properties_, property_names_, use_atomic_); EXPECT_TRUE(fake_drm_->plane_manager()->AssignOverlayPlanes( - &state_, assigns, crtc_properties_[0].id, nullptr)); + &state_, assigns, crtc_properties_[0].id)); EXPECT_EQ(2u, state_.plane_list.size()); } @@ -347,13 +547,13 @@ TEST_P(HardwareDisplayPlaneManagerAtomicTest, MultiplePlanesAndCrtcs) { assigns.push_back(ui::DrmOverlayPlane(fake_buffer_, nullptr)); InitializeDrmState(/*crtc_count=*/2, /*planes_per_crtc=*/2); - fake_drm_->InitializeState(crtc_properties_, plane_properties_, - property_names_, use_atomic_); + fake_drm_->InitializeState(crtc_properties_, connector_properties_, + plane_properties_, property_names_, use_atomic_); EXPECT_TRUE(fake_drm_->plane_manager()->AssignOverlayPlanes( - &state_, assigns, crtc_properties_[0].id, nullptr)); + &state_, assigns, crtc_properties_[0].id)); EXPECT_TRUE(fake_drm_->plane_manager()->AssignOverlayPlanes( - &state_, assigns, crtc_properties_[1].id, nullptr)); + &state_, assigns, crtc_properties_[1].id)); EXPECT_EQ(4u, state_.plane_list.size()); } @@ -373,21 +573,21 @@ TEST_P(HardwareDisplayPlaneManagerAtomicTest, SharedPlanes) { {/* .id = */ kInFormatsPropId, /* .value = */ kInFormatsBlobPropId}, }; plane_properties_.emplace_back(std::move(plane_prop)); - fake_drm_->InitializeState(crtc_properties_, plane_properties_, - property_names_, use_atomic_); + fake_drm_->InitializeState(crtc_properties_, connector_properties_, + plane_properties_, property_names_, use_atomic_); EXPECT_TRUE(fake_drm_->plane_manager()->AssignOverlayPlanes( - &state_, assigns, crtc_properties_[1].id, nullptr)); + &state_, assigns, crtc_properties_[1].id)); EXPECT_EQ(2u, state_.plane_list.size()); // The shared plane is now unavailable for use by the other CRTC. EXPECT_FALSE(fake_drm_->plane_manager()->AssignOverlayPlanes( - &state_, assigns, crtc_properties_[0].id, nullptr)); + &state_, assigns, crtc_properties_[0].id)); } TEST_P(HardwareDisplayPlaneManagerAtomicTest, UnusedPlanesAreReleased) { InitializeDrmState(/*crtc_count=*/2, /*planes_per_crtc=*/2); - fake_drm_->InitializeState(crtc_properties_, plane_properties_, - property_names_, use_atomic_); + fake_drm_->InitializeState(crtc_properties_, connector_properties_, + plane_properties_, property_names_, use_atomic_); ui::DrmOverlayPlaneList assigns; scoped_refptr<ui::DrmFramebuffer> primary_buffer = @@ -397,25 +597,24 @@ TEST_P(HardwareDisplayPlaneManagerAtomicTest, UnusedPlanesAreReleased) { assigns.push_back(ui::DrmOverlayPlane(primary_buffer, nullptr)); assigns.push_back(ui::DrmOverlayPlane(overlay_buffer, nullptr)); ui::HardwareDisplayPlaneList hdpl; - ui::CrtcController crtc(fake_drm_, crtc_properties_[0].id, 0); 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, &crtc)); - EXPECT_TRUE( - fake_drm_->plane_manager()->Commit(&hdpl, page_flip_request, nullptr)); + &hdpl, assigns, crtc_properties_[0].id)); + 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); EXPECT_TRUE(fake_drm_->plane_manager()->AssignOverlayPlanes( - &hdpl, assigns, crtc_properties_[0].id, &crtc)); + &hdpl, assigns, crtc_properties_[0].id)); 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")); } @@ -425,11 +624,11 @@ TEST_P(HardwareDisplayPlaneManagerAtomicTest, MultipleFrames) { assigns.push_back(ui::DrmOverlayPlane(fake_buffer_, nullptr)); InitializeDrmState(/*crtc_count=*/2, /*planes_per_crtc=*/2); - fake_drm_->InitializeState(crtc_properties_, plane_properties_, - property_names_, use_atomic_); + fake_drm_->InitializeState(crtc_properties_, connector_properties_, + plane_properties_, property_names_, use_atomic_); EXPECT_TRUE(fake_drm_->plane_manager()->AssignOverlayPlanes( - &state_, assigns, crtc_properties_[0].id, nullptr)); + &state_, assigns, crtc_properties_[0].id)); EXPECT_EQ(1u, state_.plane_list.size()); // Pretend we committed the frame. state_.plane_list.swap(state_.old_plane_list); @@ -437,7 +636,7 @@ TEST_P(HardwareDisplayPlaneManagerAtomicTest, MultipleFrames) { ui::HardwareDisplayPlane* old_plane = state_.old_plane_list[0]; // The same plane should be used. EXPECT_TRUE(fake_drm_->plane_manager()->AssignOverlayPlanes( - &state_, assigns, crtc_properties_[0].id, nullptr)); + &state_, assigns, crtc_properties_[0].id)); EXPECT_EQ(1u, state_.plane_list.size()); EXPECT_EQ(state_.plane_list[0], old_plane); } @@ -447,15 +646,15 @@ TEST_P(HardwareDisplayPlaneManagerAtomicTest, MultipleFramesDifferentPlanes) { assigns.push_back(ui::DrmOverlayPlane(fake_buffer_, nullptr)); InitializeDrmState(/*crtc_count=*/2, /*planes_per_crtc=*/2); - fake_drm_->InitializeState(crtc_properties_, plane_properties_, - property_names_, use_atomic_); + fake_drm_->InitializeState(crtc_properties_, connector_properties_, + plane_properties_, property_names_, use_atomic_); EXPECT_TRUE(fake_drm_->plane_manager()->AssignOverlayPlanes( - &state_, assigns, crtc_properties_[0].id, nullptr)); + &state_, assigns, crtc_properties_[0].id)); EXPECT_EQ(1u, state_.plane_list.size()); // The other plane should be used. EXPECT_TRUE(fake_drm_->plane_manager()->AssignOverlayPlanes( - &state_, assigns, crtc_properties_[0].id, nullptr)); + &state_, assigns, crtc_properties_[0].id)); EXPECT_EQ(2u, state_.plane_list.size()); EXPECT_NE(state_.plane_list[0], state_.plane_list[1]); } @@ -467,8 +666,8 @@ TEST_P(HardwareDisplayPlaneManagerAtomicTest, {/* .id = */ kPlaneCtmId, /* .value = */ 0}); plane_properties_[1].properties.push_back( {/* .id = */ kPlaneCtmId, /* .value = */ 0}); - fake_drm_->InitializeState(crtc_properties_, plane_properties_, - property_names_, use_atomic_); + fake_drm_->InitializeState(crtc_properties_, connector_properties_, + plane_properties_, property_names_, use_atomic_); ui::ScopedDrmColorCtmPtr ctm_blob(ui::CreateCTMBlob(std::vector<float>(9))); EXPECT_TRUE(fake_drm_->plane_manager()->SetColorCorrectionOnAllCrtcPlanes( @@ -479,8 +678,8 @@ TEST_P(HardwareDisplayPlaneManagerAtomicTest, TEST_P(HardwareDisplayPlaneManagerAtomicTest, SetColorCorrectionOnAllCrtcPlanes_NoPlaneCtmProperty) { InitializeDrmState(/*crtc_count=*/1, /*planes_per_crtc=*/1); - fake_drm_->InitializeState(crtc_properties_, plane_properties_, - property_names_, use_atomic_); + fake_drm_->InitializeState(crtc_properties_, connector_properties_, + plane_properties_, property_names_, use_atomic_); ui::ScopedDrmColorCtmPtr ctm_blob(ui::CreateCTMBlob(std::vector<float>(9))); EXPECT_FALSE(fake_drm_->plane_manager()->SetColorCorrectionOnAllCrtcPlanes( @@ -493,8 +692,8 @@ TEST_P(HardwareDisplayPlaneManagerAtomicTest, InitializeDrmState(/*crtc_count=*/1, /*planes_per_crtc=*/2); plane_properties_[0].properties.push_back( {/* .id = */ kPlaneCtmId, /* .value = */ 0}); - fake_drm_->InitializeState(crtc_properties_, plane_properties_, - property_names_, use_atomic_); + fake_drm_->InitializeState(crtc_properties_, connector_properties_, + plane_properties_, property_names_, use_atomic_); ui::ScopedDrmColorCtmPtr ctm_blob(ui::CreateCTMBlob(std::vector<float>(9))); EXPECT_FALSE(fake_drm_->plane_manager()->SetColorCorrectionOnAllCrtcPlanes( @@ -506,8 +705,8 @@ TEST_P(HardwareDisplayPlaneManagerTest, SetColorMatrix_Success) { InitializeDrmState(/*crtc_count=*/1, /*planes_per_crtc=*/1); crtc_properties_[0].properties.push_back( {/* .id = */ kCtmPropId, /* .value = */ 0}); - fake_drm_->InitializeState(crtc_properties_, plane_properties_, - property_names_, use_atomic_); + fake_drm_->InitializeState(crtc_properties_, connector_properties_, + plane_properties_, property_names_, use_atomic_); EXPECT_TRUE(fake_drm_->plane_manager()->SetColorMatrix( crtc_properties_[0].id, std::vector<float>(9))); @@ -529,8 +728,8 @@ TEST_P(HardwareDisplayPlaneManagerTest, SetColorMatrix_ErrorEmptyCtm) { InitializeDrmState(/*crtc_count=*/1, /*planes_per_crtc=*/1); crtc_properties_[0].properties.push_back( {/* .id = */ kCtmPropId, /* .value = */ 0}); - fake_drm_->InitializeState(crtc_properties_, plane_properties_, - property_names_, use_atomic_); + fake_drm_->InitializeState(crtc_properties_, connector_properties_, + plane_properties_, property_names_, use_atomic_); EXPECT_FALSE( fake_drm_->plane_manager()->SetColorMatrix(crtc_properties_[0].id, {})); @@ -548,8 +747,8 @@ TEST_P(HardwareDisplayPlaneManagerTest, SetGammaCorrection_MissingDegamma) { InitializeDrmState(/*crtc_count=*/1, /*planes_per_crtc=*/1); crtc_properties_[0].properties.push_back( {/* .id = */ kCtmPropId, /* .value = */ 0}); - fake_drm_->InitializeState(crtc_properties_, plane_properties_, - property_names_, use_atomic_); + fake_drm_->InitializeState(crtc_properties_, connector_properties_, + plane_properties_, property_names_, use_atomic_); EXPECT_FALSE(fake_drm_->plane_manager()->SetGammaCorrection( crtc_properties_[0].id, {{0, 0, 0}}, {})); @@ -564,8 +763,9 @@ TEST_P(HardwareDisplayPlaneManagerTest, SetGammaCorrection_MissingDegamma) { crtc_properties_[0].properties.push_back( {/* .id = */ kDegammaLutSizePropId, /* .value = */ 1}); - fake_drm_->InitializeState(crtc_properties_, plane_properties_, - property_names_, /*use_atomic=*/true); + fake_drm_->InitializeState(crtc_properties_, connector_properties_, + plane_properties_, property_names_, + /*use_atomic=*/true); EXPECT_FALSE(fake_drm_->plane_manager()->SetGammaCorrection( crtc_properties_[0].id, {{0, 0, 0}}, {})); @@ -583,8 +783,8 @@ TEST_P(HardwareDisplayPlaneManagerTest, SetGammaCorrection_MissingGamma) { InitializeDrmState(/*crtc_count=*/1, /*planes_per_crtc=*/1); crtc_properties_[0].properties.push_back( {/* .id = */ kCtmPropId, /* .value = */ 0}); - fake_drm_->InitializeState(crtc_properties_, plane_properties_, - property_names_, use_atomic_); + fake_drm_->InitializeState(crtc_properties_, connector_properties_, + plane_properties_, property_names_, use_atomic_); EXPECT_FALSE(fake_drm_->plane_manager()->SetGammaCorrection( crtc_properties_[0].id, {}, {{0, 0, 0}})); @@ -599,8 +799,9 @@ TEST_P(HardwareDisplayPlaneManagerTest, SetGammaCorrection_MissingGamma) { crtc_properties_[0].properties.push_back( {/* .id = */ kGammaLutSizePropId, /* .value = */ 1}); - fake_drm_->InitializeState(crtc_properties_, plane_properties_, - property_names_, /*use_atomic=*/true); + fake_drm_->InitializeState(crtc_properties_, connector_properties_, + plane_properties_, property_names_, + /*use_atomic=*/true); EXPECT_FALSE(fake_drm_->plane_manager()->SetGammaCorrection( crtc_properties_[0].id, {}, {{0, 0, 0}})); @@ -616,8 +817,8 @@ TEST_P(HardwareDisplayPlaneManagerTest, SetGammaCorrection_MissingGamma) { TEST_P(HardwareDisplayPlaneManagerTest, SetGammaCorrection_LegacyGamma) { InitializeDrmState(/*crtc_count=*/1, /*planes_per_crtc=*/1); - fake_drm_->InitializeState(crtc_properties_, plane_properties_, - property_names_, use_atomic_); + fake_drm_->InitializeState(crtc_properties_, connector_properties_, + plane_properties_, property_names_, use_atomic_); fake_drm_->set_legacy_gamma_ramp_expectation(true); EXPECT_TRUE(fake_drm_->plane_manager()->SetGammaCorrection( @@ -638,8 +839,8 @@ TEST_P(HardwareDisplayPlaneManagerTest, SetGammaCorrection_Success) { InitializeDrmState(/*crtc_count=*/1, /*planes_per_crtc=*/1); crtc_properties_[0].properties.push_back( {/* .id = */ kCtmPropId, /* .value = */ 0}); - fake_drm_->InitializeState(crtc_properties_, plane_properties_, - property_names_, use_atomic_); + fake_drm_->InitializeState(crtc_properties_, connector_properties_, + plane_properties_, property_names_, use_atomic_); EXPECT_FALSE(fake_drm_->plane_manager()->SetGammaCorrection( crtc_properties_[0].id, {{0, 0, 0}}, {})); @@ -653,8 +854,8 @@ TEST_P(HardwareDisplayPlaneManagerTest, SetGammaCorrection_Success) { {/* .id = */ kGammaLutSizePropId, /* .value = */ 1}); crtc_properties_[0].properties.push_back( {/* .id = */ kGammaLutPropId, /* .value = */ 0}); - fake_drm_->InitializeState(crtc_properties_, plane_properties_, - property_names_, use_atomic_); + fake_drm_->InitializeState(crtc_properties_, connector_properties_, + plane_properties_, property_names_, use_atomic_); ui::HardwareDisplayPlaneList state; // Check that we reset the properties correctly. @@ -693,30 +894,30 @@ TEST_P(HardwareDisplayPlaneManagerTest, SetBackgroundColor_Success) { InitializeDrmState(/*crtc_count=*/1, /*planes_per_crtc=*/1); crtc_properties_[0].properties.push_back( {/* .id = */ kBackgroundColorPropId, /* .value = */ 0}); - fake_drm_->InitializeState(crtc_properties_, plane_properties_, - property_names_, use_atomic_); + fake_drm_->InitializeState(crtc_properties_, connector_properties_, + plane_properties_, property_names_, use_atomic_); fake_drm_->plane_manager()->SetBackgroundColor(crtc_properties_[0].id, 0); if (use_atomic_) { ui::HardwareDisplayPlaneList state; PerformPageFlip(/*crtc_idx=*/0, &state); EXPECT_EQ(1, fake_drm_->get_commit_count()); - EXPECT_EQ(0u, GetCrtcPropertyValue(crtc_properties_[0].id, - "BACKGROUND_COLOR")); + EXPECT_EQ(0u, + GetCrtcPropertyValue(crtc_properties_[0].id, "BACKGROUND_COLOR")); } else { EXPECT_EQ(0, fake_drm_->get_set_object_property_count()); } crtc_properties_[0].properties.push_back( {/* .id = */ kBackgroundColorPropId, /* .value = */ 1}); - fake_drm_->InitializeState(crtc_properties_, plane_properties_, - property_names_, use_atomic_); + fake_drm_->InitializeState(crtc_properties_, connector_properties_, + plane_properties_, property_names_, use_atomic_); fake_drm_->plane_manager()->SetBackgroundColor(crtc_properties_[0].id, 1); if (use_atomic_) { ui::HardwareDisplayPlaneList state; PerformPageFlip(/*crtc_idx=*/0, &state); EXPECT_EQ(2, fake_drm_->get_commit_count()); - EXPECT_EQ(1u, GetCrtcPropertyValue(crtc_properties_[0].id, - "BACKGROUND_COLOR")); + EXPECT_EQ(1u, + GetCrtcPropertyValue(crtc_properties_[0].id, "BACKGROUND_COLOR")); } else { EXPECT_EQ(0, fake_drm_->get_set_object_property_count()); } @@ -728,11 +929,8 @@ TEST_P(HardwareDisplayPlaneManagerAtomicTest, CreateBuffer(kDefaultBufferSize); InitializeDrmState(/*crtc_count=*/2, /*planes_per_crtc=*/1); - fake_drm_->InitializeState(crtc_properties_, plane_properties_, - property_names_, use_atomic_); - - ui::CrtcController crtc1(fake_drm_, crtc_properties_[0].id, 0); - ui::CrtcController crtc2(fake_drm_, crtc_properties_[1].id, 0); + fake_drm_->InitializeState(crtc_properties_, connector_properties_, + plane_properties_, property_names_, use_atomic_); ui::DrmOverlayPlaneList assigns1; assigns1.push_back(ui::DrmOverlayPlane(fake_buffer_, nullptr)); @@ -741,16 +939,16 @@ TEST_P(HardwareDisplayPlaneManagerAtomicTest, fake_drm_->plane_manager()->BeginFrame(&state_); EXPECT_TRUE(fake_drm_->plane_manager()->AssignOverlayPlanes( - &state_, assigns1, crtc_properties_[0].id, &crtc1)); + &state_, assigns1, crtc_properties_[0].id)); EXPECT_TRUE(fake_drm_->plane_manager()->AssignOverlayPlanes( - &state_, assigns2, crtc_properties_[1].id, &crtc2)); + &state_, assigns2, crtc_properties_[1].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_, 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); } @@ -763,7 +961,8 @@ TEST_P(HardwareDisplayPlaneManagerTest, {/* .id = */ kOutFencePtrPropId, /* .value = */ 2}); EXPECT_FALSE(fake_drm_->InitializeStateWithResult( - crtc_properties_, plane_properties_, property_names_, use_atomic_)); + crtc_properties_, connector_properties_, plane_properties_, + property_names_, use_atomic_)); } TEST_P(HardwareDisplayPlaneManagerTest, @@ -777,19 +976,42 @@ TEST_P(HardwareDisplayPlaneManagerTest, {/* .id = */ kOutFencePtrPropId, /* .value = */ 3}); EXPECT_TRUE(fake_drm_->InitializeStateWithResult( - crtc_properties_, plane_properties_, property_names_, use_atomic_)); + crtc_properties_, connector_properties_, plane_properties_, + property_names_, use_atomic_)); +} + +// Verifies that formats with 2 bits of alpha decay to opaques for AddFB2(). +TEST_P(HardwareDisplayPlaneManagerTest, ForceOpaqueFormatsForAddFramebuffer) { + InitializeDrmState(/*crtc_count=*/3, /*planes_per_crtc=*/1); + + struct { + uint32_t input_fourcc; // FourCC presented to AddFramebuffer. + uint32_t used_fourcc; // FourCC expected to be used in AddFramebuffer. + } kFourCCFormats[] = { + {DRM_FORMAT_ABGR2101010, DRM_FORMAT_XBGR2101010}, + {DRM_FORMAT_ARGB2101010, DRM_FORMAT_XRGB2101010}, + }; + + for (const auto& format_pair : kFourCCFormats) { + scoped_refptr<ui::DrmFramebuffer> drm_fb = + CreateBufferWithFormat(kDefaultBufferSize, format_pair.input_fourcc); + + EXPECT_EQ(drm_fb->framebuffer_pixel_format(), format_pair.used_fourcc); + EXPECT_EQ(drm_fb->opaque_framebuffer_pixel_format(), + format_pair.used_fourcc); + } } -INSTANTIATE_TEST_SUITE_P(/* no prefix */, +INSTANTIATE_TEST_SUITE_P(All, HardwareDisplayPlaneManagerTest, testing::Values(false, true)); // TODO(dnicoara): Migrate as many tests as possible to the general list above. -INSTANTIATE_TEST_SUITE_P(/* no prefix */, +INSTANTIATE_TEST_SUITE_P(All, HardwareDisplayPlaneManagerLegacyTest, testing::Values(false)); -INSTANTIATE_TEST_SUITE_P(/* no prefix */, +INSTANTIATE_TEST_SUITE_P(All, HardwareDisplayPlaneManagerAtomicTest, testing::Values(true)); @@ -826,7 +1048,7 @@ void FakeFenceFD::Signal() const { class HardwareDisplayPlaneManagerPlanesReadyTest : public testing::Test { protected: - HardwareDisplayPlaneManagerPlanesReadyTest() {} + HardwareDisplayPlaneManagerPlanesReadyTest() = default; void SetUp() override { auto gbm_device = std::make_unique<ui::MockGbmDevice>(); @@ -844,7 +1066,7 @@ class HardwareDisplayPlaneManagerPlanesReadyTest : public testing::Test { std::unique_ptr<ui::GbmBuffer> buffer = fake_drm_->gbm_device()->CreateBuffer(DRM_FORMAT_XRGB8888, size, GBM_BO_USE_SCANOUT); - return ui::DrmFramebuffer::AddFramebuffer(fake_drm_, buffer.get()); + return ui::DrmFramebuffer::AddFramebuffer(fake_drm_, buffer.get(), size); } ui::DrmOverlayPlaneList CreatePlanesWithoutFences() { @@ -955,7 +1177,7 @@ TEST_F(HardwareDisplayPlaneManagerPlanesReadyTest, class HardwareDisplayPlaneAtomicMock : public ui::HardwareDisplayPlaneAtomic { public: HardwareDisplayPlaneAtomicMock() : ui::HardwareDisplayPlaneAtomic(1) {} - ~HardwareDisplayPlaneAtomicMock() override {} + ~HardwareDisplayPlaneAtomicMock() override = default; bool SetPlaneData(drmModeAtomicReq* property_set, uint32_t crtc_id, @@ -985,16 +1207,15 @@ TEST(HardwareDisplayPlaneManagerAtomic, EnableBlend) { drm_device->gbm_device()->CreateBuffer( DRM_FORMAT_XRGB8888, kDefaultBufferSize, GBM_BO_USE_SCANOUT); scoped_refptr<ui::DrmFramebuffer> framebuffer = - ui::DrmFramebuffer::AddFramebuffer(drm_device, buffer.get()); + ui::DrmFramebuffer::AddFramebuffer(drm_device, buffer.get(), + kDefaultBufferSize); ui::DrmOverlayPlane overlay(framebuffer, nullptr); overlay.enable_blend = true; - plane_manager->SetPlaneData(&plane_list, &hw_plane, overlay, 1, gfx::Rect(), - nullptr); + plane_manager->SetPlaneData(&plane_list, &hw_plane, overlay, 1, gfx::Rect()); EXPECT_EQ(hw_plane.framebuffer(), framebuffer->framebuffer_id()); overlay.enable_blend = false; - plane_manager->SetPlaneData(&plane_list, &hw_plane, overlay, 1, gfx::Rect(), - nullptr); + plane_manager->SetPlaneData(&plane_list, &hw_plane, overlay, 1, gfx::Rect()); EXPECT_EQ(hw_plane.framebuffer(), framebuffer->opaque_framebuffer_id()); } 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 b895557f44b..32c5052a2a0 100644 --- a/chromium/ui/ozone/platform/drm/gpu/mock_drm_device.cc +++ b/chromium/ui/ozone/platform/drm/gpu/mock_drm_device.cc @@ -70,6 +70,11 @@ MockDrmDevice::CrtcProperties::CrtcProperties() = default; MockDrmDevice::CrtcProperties::CrtcProperties(const CrtcProperties&) = default; MockDrmDevice::CrtcProperties::~CrtcProperties() = default; +MockDrmDevice::ConnectorProperties::ConnectorProperties() = default; +MockDrmDevice::ConnectorProperties::ConnectorProperties( + const ConnectorProperties&) = default; +MockDrmDevice::ConnectorProperties::~ConnectorProperties() = default; + MockDrmDevice::PlaneProperties::PlaneProperties() = default; MockDrmDevice::PlaneProperties::PlaneProperties(const PlaneProperties&) = default; @@ -82,7 +87,6 @@ MockDrmDevice::MockDrmDevice(std::unique_ptr<GbmDevice> gbm_device) std::move(gbm_device)), get_crtc_call_count_(0), set_crtc_call_count_(0), - restore_crtc_call_count_(0), add_framebuffer_call_count_(0), remove_framebuffer_call_count_(0), page_flip_call_count_(0), @@ -96,6 +100,8 @@ MockDrmDevice::MockDrmDevice(std::unique_ptr<GbmDevice> gbm_device) plane_manager_ = std::make_unique<HardwareDisplayPlaneManagerLegacy>(this); } +MockDrmDevice::~MockDrmDevice() = default; + // static ScopedDrmPropertyBlobPtr MockDrmDevice::AllocateInFormatsBlob( uint32_t id, @@ -126,21 +132,23 @@ ScopedDrmPropertyBlobPtr MockDrmDevice::AllocateInFormatsBlob( void MockDrmDevice::InitializeState( const std::vector<CrtcProperties>& crtc_properties, + const std::vector<ConnectorProperties>& connector_properties, const std::vector<PlaneProperties>& plane_properties, const std::map<uint32_t, std::string>& property_names, bool use_atomic) { - CHECK(InitializeStateWithResult(crtc_properties, plane_properties, - property_names, use_atomic)); + CHECK(InitializeStateWithResult(crtc_properties, connector_properties, + plane_properties, property_names, + use_atomic)); } bool MockDrmDevice::InitializeStateWithResult( const std::vector<CrtcProperties>& crtc_properties, + const std::vector<ConnectorProperties>& connector_properties, const std::vector<PlaneProperties>& plane_properties, const std::map<uint32_t, std::string>& property_names, bool use_atomic) { - crtc_properties_ = crtc_properties; - plane_properties_ = plane_properties; - property_names_ = property_names; + UpdateState(crtc_properties, connector_properties, plane_properties, + property_names); if (use_atomic) { plane_manager_ = std::make_unique<HardwareDisplayPlaneManagerAtomic>(this); } else { @@ -150,7 +158,16 @@ bool MockDrmDevice::InitializeStateWithResult( return plane_manager_->Initialize(); } -MockDrmDevice::~MockDrmDevice() {} +void MockDrmDevice::UpdateState( + const std::vector<CrtcProperties>& crtc_properties, + const std::vector<ConnectorProperties>& connector_properties, + const std::vector<PlaneProperties>& plane_properties, + const std::map<uint32_t, std::string>& property_names) { + crtc_properties_ = crtc_properties; + connector_properties_ = connector_properties; + plane_properties_ = plane_properties; + property_names_ = property_names; +} ScopedDrmResourcesPtr MockDrmDevice::GetResources() { ScopedDrmResourcesPtr resources(DrmAllocator<drmModeRes>()); @@ -160,6 +177,12 @@ ScopedDrmResourcesPtr MockDrmDevice::GetResources() { for (size_t i = 0; i < crtc_properties_.size(); ++i) resources->crtcs[i] = crtc_properties_[i].id; + resources->count_connectors = connector_properties_.size(); + resources->connectors = static_cast<uint32_t*>( + drmMalloc(sizeof(uint32_t) * resources->count_connectors)); + for (size_t i = 0; i < connector_properties_.size(); ++i) + resources->connectors[i] = connector_properties_[i].id; + return resources; } @@ -185,6 +208,11 @@ ScopedDrmObjectPropertyPtr MockDrmDevice::GetObjectProperties( CrtcProperties* properties = FindObjectById(object_id, crtc_properties_); if (properties) return CreatePropertyObject(properties->properties); + } else if (object_type == DRM_MODE_OBJECT_CONNECTOR) { + ConnectorProperties* properties = + FindObjectById(object_id, connector_properties_); + if (properties) + return CreatePropertyObject(properties->properties); } return nullptr; @@ -198,30 +226,20 @@ ScopedDrmCrtcPtr MockDrmDevice::GetCrtc(uint32_t crtc_id) { bool MockDrmDevice::SetCrtc(uint32_t crtc_id, uint32_t framebuffer, std::vector<uint32_t> connectors, - drmModeModeInfo* mode) { + const drmModeModeInfo& mode) { crtc_fb_[crtc_id] = framebuffer; current_framebuffer_ = framebuffer; set_crtc_call_count_++; return set_crtc_expectation_; } -bool MockDrmDevice::SetCrtc(drmModeCrtc* crtc, - std::vector<uint32_t> connectors) { - restore_crtc_call_count_++; - return true; -} - bool MockDrmDevice::DisableCrtc(uint32_t crtc_id) { current_framebuffer_ = 0; return true; } ScopedDrmConnectorPtr MockDrmDevice::GetConnector(uint32_t connector_id) { - ScopedDrmConnectorPtr connector = - ScopedDrmConnectorPtr(DrmAllocator<drmModeConnector>()); - connector->connector_id = connector_id; - connector->connector_type = connector_type_; - return connector; + return ScopedDrmConnectorPtr(DrmAllocator<drmModeConnector>()); } bool MockDrmDevice::AddFramebuffer2(uint32_t width, @@ -304,7 +322,7 @@ bool MockDrmDevice::SetProperty(uint32_t connector_id, return true; } -ScopedDrmPropertyBlob MockDrmDevice::CreatePropertyBlob(void* blob, +ScopedDrmPropertyBlob MockDrmDevice::CreatePropertyBlob(const void* blob, size_t size) { uint32_t id = ++property_id_generator_; allocated_property_blobs_.insert(id); @@ -412,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) @@ -424,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; @@ -484,6 +506,13 @@ bool MockDrmDevice::UpdateProperty(uint32_t object_id, if (crtc_properties) return UpdateProperty(property_id, value, &crtc_properties->properties); + ConnectorProperties* connector_properties = + FindObjectById(object_id, connector_properties_); + if (connector_properties) { + return UpdateProperty(property_id, value, + &connector_properties->properties); + } + return false; } diff --git a/chromium/ui/ozone/platform/drm/gpu/mock_drm_device.h b/chromium/ui/ozone/platform/drm/gpu/mock_drm_device.h index 656870049e3..7eedf4e1939 100644 --- a/chromium/ui/ozone/platform/drm/gpu/mock_drm_device.h +++ b/chromium/ui/ozone/platform/drm/gpu/mock_drm_device.h @@ -34,6 +34,16 @@ class MockDrmDevice : public DrmDevice { std::vector<DrmDevice::Property> properties; }; + struct ConnectorProperties { + ConnectorProperties(); + ConnectorProperties(const ConnectorProperties&); + ~ConnectorProperties(); + + uint32_t id; + + std::vector<DrmDevice::Property> properties; + }; + struct PlaneProperties { PlaneProperties(); PlaneProperties(const PlaneProperties&); @@ -44,7 +54,7 @@ class MockDrmDevice : public DrmDevice { std::vector<DrmDevice::Property> properties; }; - MockDrmDevice(std::unique_ptr<GbmDevice> gbm_device); + explicit MockDrmDevice(std::unique_ptr<GbmDevice> gbm_device); static ScopedDrmPropertyBlobPtr AllocateInFormatsBlob( uint32_t id, @@ -53,7 +63,6 @@ class MockDrmDevice : public DrmDevice { int get_get_crtc_call_count() const { return get_crtc_call_count_; } int get_set_crtc_call_count() const { return set_crtc_call_count_; } - int get_restore_crtc_call_count() const { return restore_crtc_call_count_; } int get_add_framebuffer_call_count() const { return add_framebuffer_call_count_; } @@ -89,18 +98,24 @@ class MockDrmDevice : public DrmDevice { return it != crtc_cursor_map_.end() ? it->second : 0; } - void set_connector_type(uint32_t type) { connector_type_ = type; } - - void InitializeState(const std::vector<CrtcProperties>& crtc_properties, - const std::vector<PlaneProperties>& plane_properties, - const std::map<uint32_t, std::string>& property_names, - bool use_atomic); + void InitializeState( + const std::vector<CrtcProperties>& crtc_properties, + const std::vector<ConnectorProperties>& connector_properties, + const std::vector<PlaneProperties>& plane_properties, + const std::map<uint32_t, std::string>& property_names, + bool use_atomic); bool InitializeStateWithResult( const std::vector<CrtcProperties>& crtc_properties, + const std::vector<ConnectorProperties>& connector_properties, const std::vector<PlaneProperties>& plane_properties, const std::map<uint32_t, std::string>& property_names, bool use_atomic); + void UpdateState(const std::vector<CrtcProperties>& crtc_properties, + const std::vector<ConnectorProperties>& connector_properties, + const std::vector<PlaneProperties>& plane_properties, + const std::map<uint32_t, std::string>& property_names); + void RunCallbacks(); void SetPropertyBlob(ScopedDrmPropertyBlobPtr blob); @@ -114,8 +129,7 @@ class MockDrmDevice : public DrmDevice { bool SetCrtc(uint32_t crtc_id, uint32_t framebuffer, std::vector<uint32_t> connectors, - drmModeModeInfo* mode) override; - bool SetCrtc(drmModeCrtc* crtc, std::vector<uint32_t> connectors) override; + const drmModeModeInfo& mode) override; bool DisableCrtc(uint32_t crtc_id) override; ScopedDrmConnectorPtr GetConnector(uint32_t connector_id) override; bool AddFramebuffer2(uint32_t width, @@ -139,7 +153,8 @@ class MockDrmDevice : public DrmDevice { bool SetProperty(uint32_t connector_id, uint32_t property_id, uint64_t value) override; - ScopedDrmPropertyBlob CreatePropertyBlob(void* blob, size_t size) override; + ScopedDrmPropertyBlob CreatePropertyBlob(const void* blob, + size_t size) override; void DestroyPropertyBlob(uint32_t id) override; bool GetCapability(uint64_t capability, uint64_t* value) override; ScopedDrmPropertyBlobPtr GetPropertyBlob(uint32_t property_id) override; @@ -183,7 +198,6 @@ class MockDrmDevice : public DrmDevice { int get_crtc_call_count_; int set_crtc_call_count_; - int restore_crtc_call_count_; int add_framebuffer_call_count_; int remove_framebuffer_call_count_; int page_flip_call_count_; @@ -214,7 +228,7 @@ class MockDrmDevice : public DrmDevice { base::queue<PageFlipCallback> callbacks_; std::vector<CrtcProperties> crtc_properties_; - + std::vector<ConnectorProperties> connector_properties_; std::vector<PlaneProperties> plane_properties_; std::map<uint32_t, std::string> property_names_; @@ -225,8 +239,6 @@ class MockDrmDevice : public DrmDevice { std::set<uint32_t> allocated_property_blobs_; - uint32_t connector_type_ = DRM_MODE_CONNECTOR_eDP; - DISALLOW_COPY_AND_ASSIGN(MockDrmDevice); }; diff --git a/chromium/ui/ozone/platform/drm/gpu/mock_gbm_device.cc b/chromium/ui/ozone/platform/drm/gpu/mock_gbm_device.cc deleted file mode 100644 index 8e22910ae5b..00000000000 --- a/chromium/ui/ozone/platform/drm/gpu/mock_gbm_device.cc +++ /dev/null @@ -1,166 +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/mock_gbm_device.h" - -#include <drm_fourcc.h> -#include <xf86drm.h> -#include <memory> -#include <utility> - -#include "base/logging.h" -#include "base/numerics/safe_math.h" -#include "testing/gtest/include/gtest/gtest.h" -#include "third_party/skia/include/core/SkSurface.h" -#include "ui/ozone/common/linux/drm_util_linux.h" -#include "ui/ozone/common/linux/gbm_buffer.h" - -namespace ui { -namespace { - -class MockGbmBuffer final : public ui::GbmBuffer { - public: - MockGbmBuffer(uint32_t format, - uint32_t flags, - uint64_t modifier, - const gfx::Size& size, - std::vector<gfx::NativePixmapPlane> planes, - std::vector<uint32_t> handles) - : format_(format), - format_modifier_(modifier), - flags_(flags), - size_(size), - planes_(std::move(planes)), - handles_(std::move(handles)) {} - - ~MockGbmBuffer() override {} - - uint32_t GetFormat() const override { return format_; } - uint64_t GetFormatModifier() const override { return format_modifier_; } - uint32_t GetFlags() const override { return flags_; } - gfx::Size GetSize() const override { return size_; } - gfx::BufferFormat GetBufferFormat() const override { - return ui::GetBufferFormatFromFourCCFormat(format_); - } - bool AreFdsValid() const override { return false; } - size_t GetNumPlanes() const override { return planes_.size(); } - int GetPlaneFd(size_t plane) const override { - NOTREACHED(); - return -1; - } - uint32_t GetPlaneStride(size_t plane) const override { - DCHECK_LT(plane, planes_.size()); - return planes_[plane].stride; - } - size_t GetPlaneOffset(size_t plane) const override { - DCHECK_LT(plane, planes_.size()); - return planes_[plane].offset; - } - size_t GetPlaneSize(size_t plane) const override { - DCHECK_LT(plane, planes_.size()); - return static_cast<size_t>(planes_[plane].size); - } - uint32_t GetPlaneHandle(size_t plane) const override { - DCHECK_LT(plane, planes_.size()); - return handles_[plane]; - } - uint32_t GetHandle() const override { return GetPlaneHandle(0); } - gfx::NativePixmapHandle ExportHandle() const override { - NOTIMPLEMENTED(); - return gfx::NativePixmapHandle(); - } - - sk_sp<SkSurface> GetSurface() override { return nullptr; } - - private: - uint32_t format_ = 0; - uint64_t format_modifier_ = 0; - uint32_t flags_ = 0; - gfx::Size size_; - std::vector<gfx::NativePixmapPlane> planes_; - std::vector<uint32_t> handles_; - - DISALLOW_COPY_AND_ASSIGN(MockGbmBuffer); -}; - -} // namespace - -MockGbmDevice::MockGbmDevice() {} - -MockGbmDevice::~MockGbmDevice() {} - -void MockGbmDevice::set_allocation_failure(bool should_fail_allocations) { - should_fail_allocations_ = should_fail_allocations; -} - -std::unique_ptr<GbmBuffer> MockGbmDevice::CreateBuffer(uint32_t format, - const gfx::Size& size, - uint32_t flags) { - if (should_fail_allocations_) - return nullptr; - - return CreateBufferWithModifiers(format, size, flags, {}); -} - -std::unique_ptr<GbmBuffer> MockGbmDevice::CreateBufferWithModifiers( - uint32_t format, - const gfx::Size& size, - uint32_t flags, - const std::vector<uint64_t>& modifiers) { - if (should_fail_allocations_) - return nullptr; - - uint32_t bytes_per_pixel; - switch (format) { - case DRM_FORMAT_XRGB8888: - case DRM_FORMAT_ARGB8888: - bytes_per_pixel = 4; - break; - case DRM_FORMAT_NV12: - bytes_per_pixel = 2; - break; - default: - NOTREACHED() << "Unsupported format: " << format; - return nullptr; - } - - if (modifiers.size() > 1) - return nullptr; - - uint64_t format_modifier = - modifiers.size() ? modifiers[0] : DRM_FORMAT_MOD_NONE; - switch (format_modifier) { - case DRM_FORMAT_MOD_NONE: - case I915_FORMAT_MOD_X_TILED: - break; - default: - NOTREACHED() << "Unsupported format modifier: " << format_modifier; - return nullptr; - } - - uint32_t width = base::checked_cast<uint32_t>(size.width()); - uint32_t height = base::checked_cast<uint32_t>(size.height()); - uint32_t plane_stride = base::CheckMul(bytes_per_pixel, width).ValueOrDie(); - uint32_t plane_size = base::CheckMul(plane_stride, height).ValueOrDie(); - uint32_t plane_offset = 0; - - std::vector<gfx::NativePixmapPlane> planes; - planes.push_back(gfx::NativePixmapPlane(plane_stride, plane_offset, - plane_size, base::ScopedFD())); - std::vector<uint32_t> handles; - handles.push_back(next_handle_++); - - return std::make_unique<MockGbmBuffer>(format, flags, format_modifier, size, - std::move(planes), std::move(handles)); -} - -std::unique_ptr<GbmBuffer> MockGbmDevice::CreateBufferFromHandle( - uint32_t format, - const gfx::Size& size, - gfx::NativePixmapHandle handle) { - NOTREACHED(); - return nullptr; -} - -} // namespace ui diff --git a/chromium/ui/ozone/platform/drm/gpu/mock_gbm_device.h b/chromium/ui/ozone/platform/drm/gpu/mock_gbm_device.h deleted file mode 100644 index 5b31b5d1af4..00000000000 --- a/chromium/ui/ozone/platform/drm/gpu/mock_gbm_device.h +++ /dev/null @@ -1,43 +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_MOCK_GBM_DEVICE_H_ -#define UI_OZONE_PLATFORM_DRM_GPU_MOCK_GBM_DEVICE_H_ - -#include "ui/ozone/common/linux/gbm_device.h" - -namespace ui { - -// The real DrmDevice makes actual DRM calls which we can't use in unit tests. -class MockGbmDevice : public GbmDevice { - public: - MockGbmDevice(); - ~MockGbmDevice() override; - - void set_allocation_failure(bool should_fail_allocations); - - // GbmDevice: - std::unique_ptr<GbmBuffer> CreateBuffer(uint32_t format, - const gfx::Size& size, - uint32_t flags) override; - std::unique_ptr<GbmBuffer> CreateBufferWithModifiers( - uint32_t format, - const gfx::Size& size, - uint32_t flags, - const std::vector<uint64_t>& modifiers) override; - std::unique_ptr<GbmBuffer> CreateBufferFromHandle( - uint32_t format, - const gfx::Size& size, - gfx::NativePixmapHandle handle) override; - - private: - uint32_t next_handle_ = 0; - bool should_fail_allocations_ = false; - - DISALLOW_COPY_AND_ASSIGN(MockGbmDevice); -}; - -} // namespace ui - -#endif // UI_OZONE_PLATFORM_DRM_GPU_MOCK_GBM_DEVICE_H_ diff --git a/chromium/ui/ozone/platform/drm/gpu/screen_manager.cc b/chromium/ui/ozone/platform/drm/gpu/screen_manager.cc index 1a347ea3b3c..42473035751 100644 --- a/chromium/ui/ozone/platform/drm/gpu/screen_manager.cc +++ b/chromium/ui/ozone/platform/drm/gpu/screen_manager.cc @@ -16,8 +16,8 @@ #include "ui/gfx/geometry/rect.h" #include "ui/gfx/geometry/size.h" #include "ui/gfx/gpu_fence.h" +#include "ui/gfx/linux/gbm_buffer.h" #include "ui/gfx/skia_util.h" -#include "ui/ozone/common/linux/gbm_buffer.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.h" @@ -392,8 +392,8 @@ DrmOverlayPlane ScreenManager::GetModesetBuffer( return DrmOverlayPlane::Error(); } - scoped_refptr<DrmFramebuffer> framebuffer = - DrmFramebuffer::AddFramebuffer(drm, buffer.get(), modifiers); + scoped_refptr<DrmFramebuffer> framebuffer = DrmFramebuffer::AddFramebuffer( + drm, buffer.get(), buffer->GetSize(), modifiers); if (!framebuffer) { LOG(ERROR) << "Failed to add framebuffer for scanout buffer"; return DrmOverlayPlane::Error(); 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 b97acb43851..fea1047c7a2 100644 --- a/chromium/ui/ozone/platform/drm/gpu/screen_manager_unittest.cc +++ b/chromium/ui/ozone/platform/drm/gpu/screen_manager_unittest.cc @@ -13,7 +13,8 @@ #include "base/macros.h" #include "testing/gtest/include/gtest/gtest.h" #include "ui/gfx/gpu_fence.h" -#include "ui/ozone/common/linux/gbm_buffer.h" +#include "ui/gfx/linux/gbm_buffer.h" +#include "ui/gfx/linux/test/mock_gbm_device.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" @@ -21,7 +22,6 @@ #include "ui/ozone/platform/drm/gpu/drm_window.h" #include "ui/ozone/platform/drm/gpu/hardware_display_controller.h" #include "ui/ozone/platform/drm/gpu/mock_drm_device.h" -#include "ui/ozone/platform/drm/gpu/mock_gbm_device.h" #include "ui/ozone/platform/drm/gpu/screen_manager.h" namespace ui { @@ -31,10 +31,18 @@ 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; +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 Mode(uint16_t hdisplay, uint16_t vdisplay) { return {0, hdisplay, 0, 0, 0, 0, vdisplay, 0, 0, 0, 0, 0, 0, 0, {'\0'}}; @@ -44,8 +52,16 @@ drmModeModeInfo Mode(uint16_t hdisplay, uint16_t vdisplay) { class ScreenManagerTest : public testing::Test { public: - ScreenManagerTest() {} - ~ScreenManagerTest() override {} + struct PlaneState { + std::vector<uint32_t> formats; + }; + + struct CrtcState { + std::vector<PlaneState> planes; + }; + + ScreenManagerTest() = default; + ~ScreenManagerTest() override = default; gfx::Rect GetPrimaryBounds() const { return gfx::Rect(0, 0, kDefaultMode.hdisplay, kDefaultMode.vdisplay); @@ -57,12 +73,102 @@ class ScreenManagerTest : public testing::Test { kDefaultMode.vdisplay); } + void InitializeDrmState(const std::vector<CrtcState>& crtc_states) { + 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(2); + 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, + /* use_atomic= */ true); + } + void SetUp() override { auto gbm = std::make_unique<ui::MockGbmDevice>(); drm_ = new ui::MockDrmDevice(std::move(gbm)); device_manager_ = std::make_unique<ui::DrmDeviceManager>(nullptr); screen_manager_ = std::make_unique<ui::ScreenManager>(); } + void TearDown() override { screen_manager_.reset(); drm_ = nullptr; @@ -82,7 +188,7 @@ class ScreenManagerTest : public testing::Test { modifiers.push_back(format_modifier); auto buffer = drm_->gbm_device()->CreateBufferWithModifiers( format, size, GBM_BO_USE_SCANOUT, modifiers); - return DrmFramebuffer::AddFramebuffer(drm_, buffer.get(), modifiers); + return DrmFramebuffer::AddFramebuffer(drm_, buffer.get(), size, modifiers); } protected: @@ -201,6 +307,24 @@ TEST_F(ScreenManagerTest, CheckForControllersInMirroredMode) { } 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(crtc_states); + screen_manager_->AddDisplayController(drm_, kPrimaryCrtc, kPrimaryConnector); screen_manager_->ConfigureDisplayController( drm_, kPrimaryCrtc, kPrimaryConnector, GetPrimaryBounds().origin(), @@ -352,6 +476,24 @@ TEST_F(ScreenManagerTest, ReuseFramebufferIfDisabledThenReEnabled) { } TEST_F(ScreenManagerTest, CheckMirrorModeAfterBeginReEnabled) { + 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(crtc_states); + screen_manager_->AddDisplayController(drm_, kPrimaryCrtc, kPrimaryConnector); screen_manager_->ConfigureDisplayController( drm_, kPrimaryCrtc, kPrimaryConnector, GetPrimaryBounds().origin(), 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 41f63b230e1..6858ff5053c 100644 --- a/chromium/ui/ozone/platform/drm/gpu/vulkan_implementation_gbm.cc +++ b/chromium/ui/ozone/platform/drm/gpu/vulkan_implementation_gbm.cc @@ -9,6 +9,7 @@ #include "base/files/file_path.h" #include "base/native_library.h" #include "gpu/vulkan/vulkan_function_pointers.h" +#include "gpu/vulkan/vulkan_image.h" #include "gpu/vulkan/vulkan_instance.h" #include "gpu/vulkan/vulkan_posix_util.h" #include "gpu/vulkan/vulkan_surface.h" @@ -28,9 +29,9 @@ bool VulkanImplementationGbm::InitializeVulkanInstance(bool using_surface) { gpu::GetVulkanFunctionPointers(); base::NativeLibraryLoadError native_library_load_error; - vulkan_function_pointers->vulkan_loader_library_ = base::LoadNativeLibrary( + vulkan_function_pointers->vulkan_loader_library = base::LoadNativeLibrary( base::FilePath("libvulkan.so.1"), &native_library_load_error); - if (!vulkan_function_pointers->vulkan_loader_library_) + if (!vulkan_function_pointers->vulkan_loader_library) return false; std::vector<const char*> required_extensions = { @@ -92,6 +93,12 @@ VulkanImplementationGbm::GetRequiredDeviceExtensions() { VK_KHR_EXTERNAL_SEMAPHORE_EXTENSION_NAME, VK_KHR_EXTERNAL_SEMAPHORE_FD_EXTENSION_NAME}; } + +std::vector<const char*> +VulkanImplementationGbm::GetOptionalDeviceExtensions() { + return {}; +} + VkFence VulkanImplementationGbm::CreateVkFenceForGpuFence(VkDevice vk_device) { VkFenceCreateInfo fence_create_info = {}; fence_create_info.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO; @@ -162,17 +169,14 @@ bool VulkanImplementationGbm::CanImportGpuMemoryBuffer( return false; } -bool VulkanImplementationGbm::CreateImageFromGpuMemoryHandle( - VkDevice vk_device, +std::unique_ptr<gpu::VulkanImage> +VulkanImplementationGbm::CreateImageFromGpuMemoryHandle( + gpu::VulkanDeviceQueue* device_queue, gfx::GpuMemoryBufferHandle gmb_handle, gfx::Size size, - VkImage* vk_image, - VkImageCreateInfo* vk_image_info, - VkDeviceMemory* vk_device_memory, - VkDeviceSize* mem_allocation_size, - base::Optional<gpu::VulkanYCbCrInfo>* ycbcr_info) { + VkFormat vk_formae) { NOTIMPLEMENTED(); - return false; + return nullptr; } } // namespace ui diff --git a/chromium/ui/ozone/platform/drm/gpu/vulkan_implementation_gbm.h b/chromium/ui/ozone/platform/drm/gpu/vulkan_implementation_gbm.h index cbbbbcc5344..66bf3750705 100644 --- a/chromium/ui/ozone/platform/drm/gpu/vulkan_implementation_gbm.h +++ b/chromium/ui/ozone/platform/drm/gpu/vulkan_implementation_gbm.h @@ -27,6 +27,7 @@ class VulkanImplementationGbm : public gpu::VulkanImplementation { const std::vector<VkQueueFamilyProperties>& queue_family_properties, uint32_t queue_family_index) override; std::vector<const char*> GetRequiredDeviceExtensions() override; + std::vector<const char*> GetOptionalDeviceExtensions() override; VkFence CreateVkFenceForGpuFence(VkDevice vk_device) override; std::unique_ptr<gfx::GpuFence> ExportVkFenceToGpuFence( VkDevice vk_device, @@ -39,15 +40,11 @@ class VulkanImplementationGbm : public gpu::VulkanImplementation { VkExternalMemoryHandleTypeFlagBits GetExternalImageHandleType() override; bool CanImportGpuMemoryBuffer( gfx::GpuMemoryBufferType memory_buffer_type) override; - bool CreateImageFromGpuMemoryHandle( - VkDevice vk_device, + std::unique_ptr<gpu::VulkanImage> CreateImageFromGpuMemoryHandle( + gpu::VulkanDeviceQueue* device_queue, gfx::GpuMemoryBufferHandle gmb_handle, gfx::Size size, - VkImage* vk_image, - VkImageCreateInfo* vk_image_info, - VkDeviceMemory* vk_device_memory, - VkDeviceSize* mem_allocation_size, - base::Optional<gpu::VulkanYCbCrInfo>* ycbcr_info) override; + VkFormat vk_formae) override; private: gpu::VulkanInstance vulkan_instance_; diff --git a/chromium/ui/ozone/platform/drm/host/drm_cursor.cc b/chromium/ui/ozone/platform/drm/host/drm_cursor.cc index 8e420a59c34..afed5c26d24 100644 --- a/chromium/ui/ozone/platform/drm/host/drm_cursor.cc +++ b/chromium/ui/ozone/platform/drm/host/drm_cursor.cc @@ -220,6 +220,7 @@ gfx::Rect DrmCursor::GetCursorConfinedBounds() { void DrmCursor::InitializeOnEvdev() { DCHECK(evdev_thread_checker_.CalledOnValidThread()); + base::AutoLock lock(lock_); proxy_->InitializeOnEvdevIfNecessary(); } diff --git a/chromium/ui/ozone/platform/drm/host/drm_device_connector.cc b/chromium/ui/ozone/platform/drm/host/drm_device_connector.cc index 47ee622e339..0b3cf4a8775 100644 --- a/chromium/ui/ozone/platform/drm/host/drm_device_connector.cc +++ b/chromium/ui/ozone/platform/drm/host/drm_device_connector.cc @@ -41,11 +41,6 @@ void DrmDeviceConnector::OnGpuServiceLaunched( scoped_refptr<base::SingleThreadTaskRunner> io_runner, GpuHostBindInterfaceCallback binder, GpuHostTerminateCallback terminate_callback) { - // We can get into this state if a new instance of GpuProcessHost is created - // before the old one is destroyed. - if (host_drm_device_->IsConnected()) - host_drm_device_->OnGpuServiceLost(); - // We need to preserve |binder| to let us bind interfaces later. binder_callback_ = std::move(binder); host_id_ = host_id; 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 a0bcdbcc06c..10f559bb623 100644 --- a/chromium/ui/ozone/platform/drm/host/drm_display_host.cc +++ b/chromium/ui/ozone/platform/drm/host/drm_display_host.cc @@ -117,6 +117,10 @@ void DrmDisplayHost::SetGammaCorrection( gamma_lut); } +void DrmDisplayHost::SetPrivacyScreen(bool enabled) { + sender_->GpuSetPrivacyScreen(snapshot_->display_id(), enabled); +} + void DrmDisplayHost::OnGpuProcessLaunched() {} void DrmDisplayHost::OnGpuThreadReady() { 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 1311e66db3d..bca23f727b9 100644 --- a/chromium/ui/ozone/platform/drm/host/drm_display_host.h +++ b/chromium/ui/ozone/platform/drm/host/drm_display_host.h @@ -40,6 +40,7 @@ class DrmDisplayHost : public GpuThreadObserver { void SetGammaCorrection( const std::vector<display::GammaRampRGBEntry>& degamma_lut, const std::vector<display::GammaRampRGBEntry>& gamma_lut); + void SetPrivacyScreen(bool enabled); // Called when the IPC from the GPU process arrives to answer the above // commands. 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 360f06cd6c6..ceb96616272 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 @@ -15,12 +15,12 @@ #include "base/files/file_util.h" #include "base/strings/stringprintf.h" #include "base/task/post_task.h" +#include "base/task/thread_pool.h" #include "base/threading/thread_restrictions.h" #include "base/threading/thread_task_runner_handle.h" #include "ui/display/types/display_snapshot.h" #include "ui/events/ozone/device/device_event.h" #include "ui/events/ozone/device/device_manager.h" -#include "ui/ozone/platform/drm/common/drm_overlay_manager.h" #include "ui/ozone/platform/drm/common/drm_util.h" #include "ui/ozone/platform/drm/host/drm_device_handle.h" #include "ui/ozone/platform/drm/host/drm_display_host.h" @@ -112,11 +112,9 @@ DrmDisplayHostManager::DrmDisplayHostManager( GpuThreadAdapter* proxy, DeviceManager* device_manager, OzonePlatform::InitializedHostProperties* host_properties, - DrmOverlayManager* overlay_manager, InputControllerEvdev* input_controller) : proxy_(proxy), device_manager_(device_manager), - overlay_manager_(overlay_manager), input_controller_(input_controller), primary_graphics_card_path_(GetPrimaryDisplayCardPath()) { { @@ -251,9 +249,9 @@ void DrmDisplayHostManager::ProcessEvent() { switch (event.action_type) { case DeviceEvent::ADD: if (drm_devices_.find(event.path) == drm_devices_.end()) { - base::PostTask( + base::ThreadPool::PostTask( FROM_HERE, - {base::ThreadPool(), base::MayBlock(), + {base::MayBlock(), base::TaskShutdownBehavior::CONTINUE_ON_SHUTDOWN}, base::BindOnce( &OpenDeviceAsync, event.path, @@ -400,9 +398,6 @@ void DrmDisplayHostManager::GpuConfiguredDisplay(int64_t display_id, DrmDisplayHost* display = GetDisplay(display_id); if (display) { display->OnDisplayConfigured(status); - - if (overlay_manager_) - overlay_manager_->ResetCache(); } 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 a126bd4b5d6..1ded8afe89e 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 @@ -28,7 +28,6 @@ class DrmDeviceHandle; class DrmDisplayHost; class DrmDisplayHostManager; class DrmNativeDisplayDelegate; -class DrmOverlayManager; class GpuThreadAdapter; struct DisplaySnapshot_Params; @@ -42,7 +41,6 @@ class DrmDisplayHostManager : public DeviceEventObserver, GpuThreadObserver { GpuThreadAdapter* proxy, DeviceManager* device_manager, OzonePlatform::InitializedHostProperties* host_properties, - DrmOverlayManager* overlay_manager, InputControllerEvdev* input_controller); ~DrmDisplayHostManager() override; @@ -102,8 +100,6 @@ class DrmDisplayHostManager : public DeviceEventObserver, GpuThreadObserver { GpuThreadAdapter* const proxy_; // Not owned. DeviceManager* const device_manager_; // Not owned. - // TODO(crbug.com/936425): Remove after VizDisplayCompositor feature launches. - DrmOverlayManager* const overlay_manager_; // Not owned. InputControllerEvdev* const input_controller_; // Not owned. DrmNativeDisplayDelegate* delegate_ = nullptr; // Not owned. diff --git a/chromium/ui/ozone/platform/drm/host/drm_gpu_platform_support_host.cc b/chromium/ui/ozone/platform/drm/host/drm_gpu_platform_support_host.cc index 5dcbf2072d4..3a435294dcd 100644 --- a/chromium/ui/ozone/platform/drm/host/drm_gpu_platform_support_host.cc +++ b/chromium/ui/ozone/platform/drm/host/drm_gpu_platform_support_host.cc @@ -14,11 +14,9 @@ #include "ui/base/ui_base_switches.h" #include "ui/ozone/common/gpu/ozone_gpu_message_params.h" #include "ui/ozone/common/gpu/ozone_gpu_messages.h" -#include "ui/ozone/platform/drm/common/drm_overlay_candidates.h" #include "ui/ozone/platform/drm/common/drm_util.h" #include "ui/ozone/platform/drm/host/drm_cursor.h" #include "ui/ozone/platform/drm/host/drm_display_host_manager.h" -#include "ui/ozone/platform/drm/host/drm_overlay_manager_host.h" #include "ui/ozone/platform/drm/host/gpu_thread_observer.h" namespace ui { @@ -167,15 +165,23 @@ void DrmGpuPlatformSupportHost::OnChannelDestroyed(int host_id) { void DrmGpuPlatformSupportHost::OnMessageReceived(const IPC::Message& message) { DCHECK(ui_runner_); - if (ui_runner_->BelongsToCurrentThread()) { - if (OnMessageReceivedForDrmDisplayHostManager(message)) - return; - OnMessageReceivedForDrmOverlayManager(message); - } else { + if (!ui_runner_->BelongsToCurrentThread()) { ui_runner_->PostTask( FROM_HERE, base::BindOnce(&DrmGpuPlatformSupportHost::OnMessageReceived, weak_ptr_, message)); + return; } + + IPC_BEGIN_MESSAGE_MAP(DrmGpuPlatformSupportHost, message) + IPC_MESSAGE_HANDLER(OzoneHostMsg_UpdateNativeDisplays, + OnUpdateNativeDisplays) + IPC_MESSAGE_HANDLER(OzoneHostMsg_DisplayConfigured, OnDisplayConfigured) + IPC_MESSAGE_HANDLER(OzoneHostMsg_HDCPStateReceived, OnHDCPStateReceived) + IPC_MESSAGE_HANDLER(OzoneHostMsg_HDCPStateUpdated, OnHDCPStateUpdated) + IPC_MESSAGE_HANDLER(OzoneHostMsg_DisplayControlTaken, OnTakeDisplayControl) + IPC_MESSAGE_HANDLER(OzoneHostMsg_DisplayControlRelinquished, + OnRelinquishDisplayControl) + IPC_END_MESSAGE_MAP() } bool DrmGpuPlatformSupportHost::Send(IPC::Message* message) { @@ -213,25 +219,6 @@ void DrmGpuPlatformSupportHost::OnChannelEstablished() { std::make_unique<CursorIPC>(send_runner_, send_callback_)); } -bool DrmGpuPlatformSupportHost::OnMessageReceivedForDrmDisplayHostManager( - const IPC::Message& message) { - bool handled = true; - - IPC_BEGIN_MESSAGE_MAP(DrmGpuPlatformSupportHost, message) - IPC_MESSAGE_HANDLER(OzoneHostMsg_UpdateNativeDisplays, - OnUpdateNativeDisplays) - IPC_MESSAGE_HANDLER(OzoneHostMsg_DisplayConfigured, OnDisplayConfigured) - IPC_MESSAGE_HANDLER(OzoneHostMsg_HDCPStateReceived, OnHDCPStateReceived) - IPC_MESSAGE_HANDLER(OzoneHostMsg_HDCPStateUpdated, OnHDCPStateUpdated) - IPC_MESSAGE_HANDLER(OzoneHostMsg_DisplayControlTaken, OnTakeDisplayControl) - IPC_MESSAGE_HANDLER(OzoneHostMsg_DisplayControlRelinquished, - OnRelinquishDisplayControl) - IPC_MESSAGE_UNHANDLED(handled = false) - IPC_END_MESSAGE_MAP() - - return handled; -} - void DrmGpuPlatformSupportHost::OnUpdateNativeDisplays( const std::vector<DisplaySnapshot_Params>& params) { display_manager_->GpuHasUpdatedNativeDisplays(params); @@ -293,44 +280,6 @@ bool DrmGpuPlatformSupportHost::GpuRemoveGraphicsDevice( return Send(new OzoneGpuMsg_RemoveGraphicsDevice(path)); } -// Overlays -void DrmGpuPlatformSupportHost::RegisterHandlerForDrmOverlayManager( - DrmOverlayManagerHost* handler) { - overlay_manager_ = handler; -} - -void DrmGpuPlatformSupportHost::UnRegisterHandlerForDrmOverlayManager() { - overlay_manager_ = nullptr; -} - -bool DrmGpuPlatformSupportHost::OnMessageReceivedForDrmOverlayManager( - const IPC::Message& message) { - bool handled = true; - IPC_BEGIN_MESSAGE_MAP(DrmGpuPlatformSupportHost, message) - IPC_MESSAGE_HANDLER(OzoneHostMsg_OverlayCapabilitiesReceived, - OnOverlayResult) - // TODO(rjk): insert the extra - IPC_MESSAGE_UNHANDLED(handled = false) - IPC_END_MESSAGE_MAP() - return handled; -} - -void DrmGpuPlatformSupportHost::OnOverlayResult( - gfx::AcceleratedWidget widget, - const std::vector<OverlayCheck_Params>& params, - const std::vector<OverlayCheckReturn_Params>& param_returns) { - auto candidates = CreateOverlaySurfaceCandidateListFrom(params); - auto returns = CreateOverlayStatusListFrom(param_returns); - overlay_manager_->GpuSentOverlayResult(widget, candidates, returns); -} - -bool DrmGpuPlatformSupportHost::GpuCheckOverlayCapabilities( - gfx::AcceleratedWidget widget, - const OverlaySurfaceCandidateList& candidates) { - auto params = CreateParamsFromOverlaySurfaceCandidate(candidates); - return Send(new OzoneGpuMsg_CheckOverlayCapabilities(widget, params)); -} - // DrmDisplayHost bool DrmGpuPlatformSupportHost::GpuConfigureNativeDisplay( int64_t display_id, @@ -372,6 +321,11 @@ bool DrmGpuPlatformSupportHost::GpuDestroyWindow( return Send(new OzoneGpuMsg_DestroyWindow(widget)); } +bool DrmGpuPlatformSupportHost::GpuSetPrivacyScreen(int64_t display_id, + bool enabled) { + return Send(new OzoneGpuMsg_SetPrivacyScreen(display_id, enabled)); +} + bool DrmGpuPlatformSupportHost::GpuCreateWindow( gfx::AcceleratedWidget widget, const gfx::Rect& initial_bounds) { diff --git a/chromium/ui/ozone/platform/drm/host/drm_gpu_platform_support_host.h b/chromium/ui/ozone/platform/drm/host/drm_gpu_platform_support_host.h index 4b07ff5ab37..0d319cc3070 100644 --- a/chromium/ui/ozone/platform/drm/host/drm_gpu_platform_support_host.h +++ b/chromium/ui/ozone/platform/drm/host/drm_gpu_platform_support_host.h @@ -24,7 +24,6 @@ namespace ui { class DrmCursor; class DrmDisplayHostMananger; -class DrmOverlayManagerHost; class GpuThreadObserver; class DrmGpuPlatformSupportHost : public GpuPlatformSupportHost, @@ -73,17 +72,6 @@ class DrmGpuPlatformSupportHost : public GpuPlatformSupportHost, base::ScopedFD fd) override; bool GpuRemoveGraphicsDevice(const base::FilePath& path) override; - // Methods needed for DrmOverlayManagerHost. - // Methods for DrmOverlayManagerHost. - void RegisterHandlerForDrmOverlayManager( - DrmOverlayManagerHost* handler) override; - void UnRegisterHandlerForDrmOverlayManager() override; - - // Services needed by DrmOverlayManagerHost - bool GpuCheckOverlayCapabilities( - gfx::AcceleratedWidget widget, - const OverlaySurfaceCandidateList& new_params) override; - // Services needed by DrmDisplayHost bool GpuConfigureNativeDisplay(int64_t display_id, const ui::DisplayMode_Params& display_mode, @@ -97,6 +85,7 @@ class DrmGpuPlatformSupportHost : public GpuPlatformSupportHost, int64_t display_id, const std::vector<display::GammaRampRGBEntry>& degamma_lut, const std::vector<display::GammaRampRGBEntry>& gamma_lut) override; + bool GpuSetPrivacyScreen(int64_t display_id, bool enabled) override; // Services needed by DrmWindowHost bool GpuDestroyWindow(gfx::AcceleratedWidget widget) override; @@ -107,7 +96,6 @@ class DrmGpuPlatformSupportHost : public GpuPlatformSupportHost, private: void OnChannelEstablished(); - bool OnMessageReceivedForDrmDisplayHostManager(const IPC::Message& message); void OnUpdateNativeDisplays( const std::vector<DisplaySnapshot_Params>& displays); void OnDisplayConfigured(int64_t display_id, bool status); @@ -118,11 +106,6 @@ class DrmGpuPlatformSupportHost : public GpuPlatformSupportHost, void OnTakeDisplayControl(bool status); void OnRelinquishDisplayControl(bool status); - bool OnMessageReceivedForDrmOverlayManager(const IPC::Message& message); - void OnOverlayResult(gfx::AcceleratedWidget widget, - const std::vector<OverlayCheck_Params>& params, - const std::vector<OverlayCheckReturn_Params>& returns); - int host_id_ = -1; bool channel_established_ = false; @@ -131,7 +114,6 @@ class DrmGpuPlatformSupportHost : public GpuPlatformSupportHost, base::RepeatingCallback<void(IPC::Message*)> send_callback_; DrmDisplayHostManager* display_manager_; // Not owned. - DrmOverlayManagerHost* overlay_manager_; // Not owned. DrmCursor* const cursor_; // Not owned. base::ObserverList<GpuThreadObserver>::Unchecked gpu_thread_observers_; 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 54ecf769e5b..c5465582fb1 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 @@ -91,6 +91,12 @@ bool DrmNativeDisplayDelegate::SetGammaCorrection( return true; } +void DrmNativeDisplayDelegate::SetPrivacyScreen(int64_t display_id, + bool enabled) { + DrmDisplayHost* display = display_manager_->GetDisplay(display_id); + display->SetPrivacyScreen(enabled); +} + void DrmNativeDisplayDelegate::AddObserver( display::NativeDisplayObserver* observer) { observers_.AddObserver(observer); 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 ce322d3c10b..249e032e73a 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 @@ -44,6 +44,7 @@ class DrmNativeDisplayDelegate : public display::NativeDisplayDelegate { int64_t display_id, const std::vector<display::GammaRampRGBEntry>& degamma_lut, const std::vector<display::GammaRampRGBEntry>& gamma_lut) override; + void SetPrivacyScreen(int64_t display_id, bool enabled) override; void AddObserver(display::NativeDisplayObserver* observer) override; void RemoveObserver(display::NativeDisplayObserver* observer) override; display::FakeDisplayController* GetFakeDisplayController() override; diff --git a/chromium/ui/ozone/platform/drm/host/drm_overlay_manager_host.cc b/chromium/ui/ozone/platform/drm/host/drm_overlay_manager_host.cc deleted file mode 100644 index b08f2c9bb39..00000000000 --- a/chromium/ui/ozone/platform/drm/host/drm_overlay_manager_host.cc +++ /dev/null @@ -1,71 +0,0 @@ -// Copyright 2016 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/host/drm_overlay_manager_host.h" - -#include <stddef.h> - -#include "base/trace_event/trace_event.h" -#include "ui/gfx/geometry/rect_conversions.h" -#include "ui/ozone/platform/drm/host/drm_window_host.h" -#include "ui/ozone/platform/drm/host/drm_window_host_manager.h" -#include "ui/ozone/public/overlay_surface_candidate.h" - -namespace ui { - -DrmOverlayManagerHost::DrmOverlayManagerHost( - GpuThreadAdapter* proxy, - DrmWindowHostManager* window_manager) - : proxy_(proxy), window_manager_(window_manager) { - proxy_->RegisterHandlerForDrmOverlayManager(this); -} - -DrmOverlayManagerHost::~DrmOverlayManagerHost() { - proxy_->UnRegisterHandlerForDrmOverlayManager(); -} - -void DrmOverlayManagerHost::GpuSentOverlayResult( - gfx::AcceleratedWidget widget, - const OverlaySurfaceCandidateList& candidates, - const OverlayStatusList& returns) { - TRACE_EVENT_ASYNC_END0("hwoverlays", - "DrmOverlayManagerHost::SendOverlayValidationRequest", - this); - UpdateCacheForOverlayCandidates(candidates, widget, returns); -} - -void DrmOverlayManagerHost::SendOverlayValidationRequest( - const OverlaySurfaceCandidateList& candidates, - gfx::AcceleratedWidget widget) { - if (!proxy_->IsConnected()) - return; - TRACE_EVENT_ASYNC_BEGIN0( - "hwoverlays", "DrmOverlayManagerHost::SendOverlayValidationRequest", - this); - proxy_->GpuCheckOverlayCapabilities(widget, candidates); -} - -bool DrmOverlayManagerHost::CanHandleCandidate( - const OverlaySurfaceCandidate& candidate, - gfx::AcceleratedWidget widget) const { - if (!DrmOverlayManager::CanHandleCandidate(candidate, widget)) - return false; - - if (candidate.plane_z_order != 0) { - // It is possible that the cc rect we get actually falls off the edge of - // the screen. Usually this is prevented via things like status bars - // blocking overlaying or cc clipping it, but in case it wasn't properly - // clipped (since GL will render this situation fine) just ignore it - // here. This should be an extremely rare occurrence. - DrmWindowHost* window = window_manager_->GetWindow(widget); - if (!window->GetBounds().Contains( - gfx::ToNearestRect(candidate.display_rect))) { - return false; - } - } - - return true; -} - -} // namespace ui diff --git a/chromium/ui/ozone/platform/drm/host/drm_overlay_manager_host.h b/chromium/ui/ozone/platform/drm/host/drm_overlay_manager_host.h deleted file mode 100644 index afc354194ea..00000000000 --- a/chromium/ui/ozone/platform/drm/host/drm_overlay_manager_host.h +++ /dev/null @@ -1,60 +0,0 @@ -// Copyright 2016 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_HOST_DRM_OVERLAY_MANAGER_HOST_H_ -#define UI_OZONE_PLATFORM_DRM_HOST_DRM_OVERLAY_MANAGER_HOST_H_ - -#include <stdint.h> - -#include <vector> - -#include "base/macros.h" -#include "ui/ozone/platform/drm/common/drm_overlay_manager.h" -#include "ui/ozone/platform/drm/host/gpu_thread_adapter.h" -#include "ui/ozone/public/overlay_candidates_ozone.h" - -namespace ui { -class DrmWindowHostManager; -class OverlaySurfaceCandidate; - -// This is an implementation of DrmOverlayManager where the driver is asked -// about overlay capabilities via IPC. We have no way of querying abstract -// capabilities, only if a particular configuration is supported or not. -// Each time we we are asked if a particular configuration is supported, if we -// have not seen that configuration before, it is IPCed to the GPU via -// OzoneGpuMsg_CheckOverlayCapabilities, a test commit is then performed and -// the result is returned in OzoneHostMsg_OverlayCapabilitiesReceived. Testing -// is asynchronous, until the reply arrives that configuration will be failed. -// -// All widgets share a single cache of tested configurations stored in the -// overlay manager. -class DrmOverlayManagerHost : public DrmOverlayManager { - public: - DrmOverlayManagerHost(GpuThreadAdapter* proxy, - DrmWindowHostManager* window_manager); - ~DrmOverlayManagerHost() override; - - // Communication-free implementations of actions performed in response to - // messages from the GPU thread. - void GpuSentOverlayResult(gfx::AcceleratedWidget widget, - const OverlaySurfaceCandidateList& params, - const OverlayStatusList& returns); - - private: - // DrmOverlayManager: - void SendOverlayValidationRequest( - const OverlaySurfaceCandidateList& candidates, - gfx::AcceleratedWidget widget) override; - bool CanHandleCandidate(const OverlaySurfaceCandidate& candidate, - gfx::AcceleratedWidget widget) const override; - - GpuThreadAdapter* const proxy_; // Not owned. - DrmWindowHostManager* const window_manager_; // Not owned. - - DISALLOW_COPY_AND_ASSIGN(DrmOverlayManagerHost); -}; - -} // namespace ui - -#endif // UI_OZONE_PLATFORM_DRM_HOST_DRM_OVERLAY_MANAGER_HOST_H_ diff --git a/chromium/ui/ozone/platform/drm/host/drm_window_host.cc b/chromium/ui/ozone/platform/drm/host/drm_window_host.cc index 735b2e41bf3..e1b181ce095 100644 --- a/chromium/ui/ozone/platform/drm/host/drm_window_host.cc +++ b/chromium/ui/ozone/platform/drm/host/drm_window_host.cc @@ -11,7 +11,6 @@ #include "ui/events/ozone/evdev/event_factory_evdev.h" #include "ui/events/ozone/events_ozone.h" #include "ui/events/platform/platform_event_source.h" -#include "ui/ozone/platform/drm/common/drm_overlay_manager.h" #include "ui/ozone/platform/drm/host/drm_cursor.h" #include "ui/ozone/platform/drm/host/drm_display_host.h" #include "ui/ozone/platform/drm/host/drm_display_host_manager.h" @@ -26,15 +25,13 @@ DrmWindowHost::DrmWindowHost(PlatformWindowDelegate* delegate, EventFactoryEvdev* event_factory, DrmCursor* cursor, DrmWindowHostManager* window_manager, - DrmDisplayHostManager* display_manager, - DrmOverlayManager* overlay_manager) + DrmDisplayHostManager* display_manager) : delegate_(delegate), sender_(sender), event_factory_(event_factory), cursor_(cursor), window_manager_(window_manager), display_manager_(display_manager), - overlay_manager_(overlay_manager), bounds_(bounds), widget_(window_manager->NextAcceleratedWidget()) { window_manager_->AddWindow(widget_, this); @@ -244,9 +241,6 @@ void DrmWindowHost::SendBoundsChange() { // window bounds when the window size shrinks. cursor_->CommitBoundsChange(widget_, bounds_, GetCursorConfinedBounds()); sender_->GpuWindowBoundsChanged(widget_, bounds_); - - if (overlay_manager_) - overlay_manager_->ResetCache(); } } // namespace ui diff --git a/chromium/ui/ozone/platform/drm/host/drm_window_host.h b/chromium/ui/ozone/platform/drm/host/drm_window_host.h index 3b70802e052..99bf436fd61 100644 --- a/chromium/ui/ozone/platform/drm/host/drm_window_host.h +++ b/chromium/ui/ozone/platform/drm/host/drm_window_host.h @@ -20,9 +20,8 @@ namespace ui { -class DrmDisplayHostManager; class DrmCursor; -class DrmOverlayManager; +class DrmDisplayHostManager; class DrmWindowHostManager; class EventFactoryEvdev; class GpuThreadAdapter; @@ -47,8 +46,7 @@ class DrmWindowHost : public PlatformWindow, EventFactoryEvdev* event_factory, DrmCursor* cursor, DrmWindowHostManager* window_manager, - DrmDisplayHostManager* display_manager, - DrmOverlayManager* overlay_manager); + DrmDisplayHostManager* display_manager); ~DrmWindowHost() override; void Initialize(); @@ -107,8 +105,6 @@ class DrmWindowHost : public PlatformWindow, DrmCursor* const cursor_; // Not owned. DrmWindowHostManager* const window_manager_; // Not owned. DrmDisplayHostManager* const display_manager_; // Not owned. - // TODO(crbug.com/936425): Remove after VizDisplayCompositor feature launches. - DrmOverlayManager* const overlay_manager_; // Not owned. gfx::Rect bounds_; const gfx::AcceleratedWidget widget_; 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 074b8260abf..5035672702e 100644 --- a/chromium/ui/ozone/platform/drm/host/gpu_thread_adapter.h +++ b/chromium/ui/ozone/platform/drm/host/gpu_thread_adapter.h @@ -8,14 +8,13 @@ #include "base/file_descriptor_posix.h" #include "ui/display/types/display_constants.h" #include "ui/display/types/gamma_ramp_rgb_entry.h" +#include "ui/gfx/geometry/rect.h" #include "ui/gfx/native_widget_types.h" #include "ui/ozone/common/gpu/ozone_gpu_message_params.h" -#include "ui/ozone/public/overlay_candidates_ozone.h" namespace ui { class DrmDisplayHostManager; -class DrmOverlayManagerHost; class GpuThreadObserver; // Provides the services that the various host components need @@ -43,16 +42,6 @@ class GpuThreadAdapter { base::ScopedFD fd) = 0; virtual bool GpuRemoveGraphicsDevice(const base::FilePath& path) = 0; - // Methods for DrmOverlayManagerHost. - virtual void RegisterHandlerForDrmOverlayManager( - DrmOverlayManagerHost* handler) = 0; - virtual void UnRegisterHandlerForDrmOverlayManager() = 0; - - // Services needed by DrmOverlayManagerHost - virtual bool GpuCheckOverlayCapabilities( - gfx::AcceleratedWidget widget, - const OverlaySurfaceCandidateList& overlays) = 0; - // Services needed by DrmDisplayHost virtual bool GpuConfigureNativeDisplay( int64_t display_id, @@ -68,6 +57,7 @@ class GpuThreadAdapter { int64_t display_id, const std::vector<display::GammaRampRGBEntry>& degamma_lut, const std::vector<display::GammaRampRGBEntry>& gamma_lut) = 0; + virtual bool GpuSetPrivacyScreen(int64_t display_id, bool enabled) = 0; // Services needed by DrmWindowHost virtual bool GpuDestroyWindow(gfx::AcceleratedWidget widget) = 0; diff --git a/chromium/ui/ozone/platform/drm/host/host_cursor_proxy.cc b/chromium/ui/ozone/platform/drm/host/host_cursor_proxy.cc index c0b9083601c..1486038b808 100644 --- a/chromium/ui/ozone/platform/drm/host/host_cursor_proxy.cc +++ b/chromium/ui/ozone/platform/drm/host/host_cursor_proxy.cc @@ -6,58 +6,64 @@ #include <utility> +#include "base/threading/thread_task_runner_handle.h" #include "services/service_manager/public/cpp/connector.h" #include "ui/ozone/public/gpu_platform_support_host.h" namespace ui { +namespace { + +void DestroyRemoteOnEvdevThread( + mojo::AssociatedRemote<ui::ozone::mojom::DeviceCursor> remote) { + // Don't do anything. |remote| will automatically get destroyed. +} + +} // namespace + // We assume that this is invoked only on the Mus/UI thread. HostCursorProxy::HostCursorProxy( mojo::PendingAssociatedRemote<ui::ozone::mojom::DeviceCursor> main_cursor, mojo::PendingAssociatedRemote<ui::ozone::mojom::DeviceCursor> evdev_cursor) : main_cursor_(std::move(main_cursor)), - evdev_cursor_(std::move(evdev_cursor)), + evdev_cursor_pending_remote_(std::move(evdev_cursor)), ui_thread_ref_(base::PlatformThread::CurrentRef()) {} -HostCursorProxy::~HostCursorProxy() {} +HostCursorProxy::~HostCursorProxy() { + if (evdev_task_runner_) { + evdev_task_runner_->PostTask( + FROM_HERE, + base::BindOnce(DestroyRemoteOnEvdevThread, std::move(evdev_cursor_))); + } +} void HostCursorProxy::CursorSet(gfx::AcceleratedWidget widget, const std::vector<SkBitmap>& bitmaps, const gfx::Point& location, int frame_delay_ms) { - InitializeOnEvdevIfNecessary(); if (ui_thread_ref_ == base::PlatformThread::CurrentRef()) { main_cursor_->SetCursor(widget, bitmaps, location, frame_delay_ms); } else { + InitializeOnEvdevIfNecessary(); evdev_cursor_->SetCursor(widget, bitmaps, location, frame_delay_ms); } } void HostCursorProxy::Move(gfx::AcceleratedWidget widget, const gfx::Point& location) { - InitializeOnEvdevIfNecessary(); if (ui_thread_ref_ == base::PlatformThread::CurrentRef()) { main_cursor_->MoveCursor(widget, location); } else { + InitializeOnEvdevIfNecessary(); evdev_cursor_->MoveCursor(widget, location); } } -// Evdev runs this method on starting. But if a HostCursorProxy is created long -// after Evdev has started (e.g. if the Viz process crashes (and the -// |HostCursorProxy| self-destructs and then a new |HostCursorProxy| is built -// when the GpuThread/DrmThread pair are once again running), we need to run it -// on cursor motions. void HostCursorProxy::InitializeOnEvdevIfNecessary() { - // TODO(rjkroege): Rebind on Viz process restart. - if (evdev_bound_) + if (evdev_cursor_.is_bound()) return; - - if (ui_thread_ref_ != base::PlatformThread::CurrentRef()) { - // Rebind the mojo pipe on the current thread. We expect this to be the - // thread running EVDEV. - evdev_cursor_.Bind(evdev_cursor_.Unbind()); - } + evdev_cursor_.Bind(std::move(evdev_cursor_pending_remote_)); + evdev_task_runner_ = base::ThreadTaskRunnerHandle::Get(); } } // namespace ui diff --git a/chromium/ui/ozone/platform/drm/host/host_cursor_proxy.h b/chromium/ui/ozone/platform/drm/host/host_cursor_proxy.h index 22c16f47081..05e6ffa05d6 100644 --- a/chromium/ui/ozone/platform/drm/host/host_cursor_proxy.h +++ b/chromium/ui/ozone/platform/drm/host/host_cursor_proxy.h @@ -5,6 +5,7 @@ #ifndef UI_OZONE_PLATFORM_DRM_HOST_HOST_CURSOR_PROXY_H_ #define UI_OZONE_PLATFORM_DRM_HOST_HOST_CURSOR_PROXY_H_ +#include "base/single_thread_task_runner.h" #include "mojo/public/cpp/bindings/associated_remote.h" #include "mojo/public/cpp/bindings/pending_associated_remote.h" #include "ui/gfx/native_widget_types.h" @@ -35,12 +36,16 @@ class HostCursorProxy : public DrmCursorProxy { void Move(gfx::AcceleratedWidget window, const gfx::Point& point) override; void InitializeOnEvdevIfNecessary() override; - // Mojo implementation of the DrmCursorProxy. + // Accessed from UI thread only. mojo::AssociatedRemote<ui::ozone::mojom::DeviceCursor> main_cursor_; + + // Accessed from evdev thread only. mojo::AssociatedRemote<ui::ozone::mojom::DeviceCursor> evdev_cursor_; + mojo::PendingAssociatedRemote<ui::ozone::mojom::DeviceCursor> + evdev_cursor_pending_remote_; base::PlatformThreadRef ui_thread_ref_; - bool evdev_bound_ = false; + scoped_refptr<base::SingleThreadTaskRunner> evdev_task_runner_; DISALLOW_COPY_AND_ASSIGN(HostCursorProxy); }; 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 aaf88ca43bc..922b895b423 100644 --- a/chromium/ui/ozone/platform/drm/host/host_drm_device.cc +++ b/chromium/ui/ozone/platform/drm/host/host_drm_device.cc @@ -19,7 +19,6 @@ #include "ui/ozone/platform/drm/common/drm_util.h" #include "ui/ozone/platform/drm/host/drm_device_connector.h" #include "ui/ozone/platform/drm/host/drm_display_host_manager.h" -#include "ui/ozone/platform/drm/host/drm_overlay_manager_host.h" #include "ui/ozone/platform/drm/host/host_cursor_proxy.h" namespace ui { @@ -51,10 +50,8 @@ void HostDrmDevice::OnDrmServiceStarted() { // DRM thread is broken. } -void HostDrmDevice::ProvideManagers(DrmDisplayHostManager* display_manager, - DrmOverlayManagerHost* overlay_manager) { +void HostDrmDevice::SetDisplayManager(DrmDisplayHostManager* display_manager) { display_manager_ = display_manager; - overlay_manager_ = overlay_manager; } void HostDrmDevice::AddGpuThreadObserver(GpuThreadObserver* observer) { @@ -119,35 +116,6 @@ bool HostDrmDevice::GpuWindowBoundsChanged(gfx::AcceleratedWidget widget, return true; } -// Services needed for DrmOverlayManagerHost. -void HostDrmDevice::RegisterHandlerForDrmOverlayManager( - DrmOverlayManagerHost* handler) { - // TODO(rjkroege): Permit overlay manager to run in Viz when the display - // compositor runs in Viz. - DCHECK_CALLED_ON_VALID_THREAD(on_ui_thread_); - overlay_manager_ = handler; -} - -void HostDrmDevice::UnRegisterHandlerForDrmOverlayManager() { - DCHECK_CALLED_ON_VALID_THREAD(on_ui_thread_); - overlay_manager_ = nullptr; -} - -bool HostDrmDevice::GpuCheckOverlayCapabilities( - gfx::AcceleratedWidget widget, - const OverlaySurfaceCandidateList& overlays) { - DCHECK_CALLED_ON_VALID_THREAD(on_ui_thread_); - if (!IsConnected()) - return false; - - auto callback = - base::BindOnce(&HostDrmDevice::GpuCheckOverlayCapabilitiesCallback, this); - - drm_device_->CheckOverlayCapabilities(widget, overlays, std::move(callback)); - - return true; -} - bool HostDrmDevice::GpuRefreshNativeDisplays() { DCHECK_CALLED_ON_VALID_THREAD(on_ui_thread_); if (!IsConnected()) @@ -289,12 +257,13 @@ bool HostDrmDevice::GpuSetGammaCorrection( return true; } -void HostDrmDevice::GpuCheckOverlayCapabilitiesCallback( - gfx::AcceleratedWidget widget, - const OverlaySurfaceCandidateList& overlays, - const OverlayStatusList& returns) const { +bool HostDrmDevice::GpuSetPrivacyScreen(int64_t display_id, bool enabled) { DCHECK_CALLED_ON_VALID_THREAD(on_ui_thread_); - overlay_manager_->GpuSentOverlayResult(widget, overlays, returns); + if (!IsConnected()) + return false; + + drm_device_->SetPrivacyScreen(display_id, enabled); + return true; } void HostDrmDevice::GpuConfigureNativeDisplayCallback(int64_t display_id, @@ -364,6 +333,11 @@ void HostDrmDevice::OnGpuServiceLaunchedOnUIThread( mojo::PendingRemote<ui::ozone::mojom::DrmDevice> drm_device) { DCHECK_CALLED_ON_VALID_THREAD(on_ui_thread_); + // We can get into this state if a new instance of GpuProcessHost is created + // before the old one is destroyed. + if (IsConnected()) + OnGpuServiceLost(); + drm_device_.Bind(std::move(drm_device)); // Create two DeviceCursor connections: one for the UI thread and one for the 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 7c8c636f586..c88343d152a 100644 --- a/chromium/ui/ozone/platform/drm/host/host_drm_device.h +++ b/chromium/ui/ozone/platform/drm/host/host_drm_device.h @@ -28,7 +28,6 @@ class DisplaySnapshot; namespace ui { class DrmDisplayHostManager; -class DrmOverlayManagerHost; class GpuThreadObserver; class DrmDeviceConnector; class HostCursorProxy; @@ -40,8 +39,7 @@ class HostDrmDevice : public base::RefCountedThreadSafe<HostDrmDevice>, public: explicit HostDrmDevice(DrmCursor* cursor); - void ProvideManagers(DrmDisplayHostManager* display_manager, - DrmOverlayManagerHost* overlay_manager); + void SetDisplayManager(DrmDisplayHostManager* display_manager); void OnGpuServiceLaunchedOnIOThread( mojo::PendingRemote<ui::ozone::mojom::DrmDevice> drm_device, @@ -69,14 +67,6 @@ class HostDrmDevice : public base::RefCountedThreadSafe<HostDrmDevice>, base::ScopedFD fd) override; bool GpuRemoveGraphicsDevice(const base::FilePath& path) override; - // Services needed for DrmOverlayManagerHost. - void RegisterHandlerForDrmOverlayManager( - DrmOverlayManagerHost* handler) override; - void UnRegisterHandlerForDrmOverlayManager() override; - bool GpuCheckOverlayCapabilities( - gfx::AcceleratedWidget widget, - const OverlaySurfaceCandidateList& new_params) override; - // Services needed by DrmDisplayHost bool GpuConfigureNativeDisplay(int64_t display_id, const ui::DisplayMode_Params& display_mode, @@ -90,6 +80,7 @@ class HostDrmDevice : public base::RefCountedThreadSafe<HostDrmDevice>, int64_t display_id, const std::vector<display::GammaRampRGBEntry>& degamma_lut, const std::vector<display::GammaRampRGBEntry>& gamma_lut) override; + bool GpuSetPrivacyScreen(int64_t display_id, bool enabled) override; // Services needed by DrmWindowHost bool GpuDestroyWindow(gfx::AcceleratedWidget widget) override; @@ -109,11 +100,6 @@ class HostDrmDevice : public base::RefCountedThreadSafe<HostDrmDevice>, // TODO(rjkroege): Get rid of the need for this method in a subsequent CL. void PollForSingleThreadReady(int previous_delay); - void GpuCheckOverlayCapabilitiesCallback( - gfx::AcceleratedWidget widget, - const OverlaySurfaceCandidateList& overlays, - const OverlayStatusList& returns) const; - void GpuConfigureNativeDisplayCallback(int64_t display_id, bool success) const; @@ -135,7 +121,6 @@ class HostDrmDevice : public base::RefCountedThreadSafe<HostDrmDevice>, mojo::Remote<ui::ozone::mojom::DrmDevice> drm_device_on_io_thread_; DrmDisplayHostManager* display_manager_; // Not owned. - DrmOverlayManagerHost* overlay_manager_; // Not owned. DrmCursor* const cursor_; // Not owned. std::unique_ptr<HostCursorProxy> cursor_proxy_; diff --git a/chromium/ui/ozone/platform/drm/ozone_platform_gbm.cc b/chromium/ui/ozone/platform/drm/ozone_platform_gbm.cc index 70a1a61a8ea..16d379a0e89 100644 --- a/chromium/ui/ozone/platform/drm/ozone_platform_gbm.cc +++ b/chromium/ui/ozone/platform/drm/ozone_platform_gbm.cc @@ -25,6 +25,7 @@ #include "ui/events/ozone/evdev/event_factory_evdev.h" #include "ui/events/ozone/layout/keyboard_layout_engine_manager.h" #include "ui/gfx/linux/client_native_pixmap_dmabuf.h" +#include "ui/gfx/native_widget_types.h" #include "ui/ozone/platform/drm/common/drm_util.h" #include "ui/ozone/platform/drm/gpu/drm_device_generator.h" #include "ui/ozone/platform/drm/gpu/drm_device_manager.h" @@ -40,7 +41,6 @@ #include "ui/ozone/platform/drm/host/drm_display_host_manager.h" #include "ui/ozone/platform/drm/host/drm_gpu_platform_support_host.h" #include "ui/ozone/platform/drm/host/drm_native_display_delegate.h" -#include "ui/ozone/platform/drm/host/drm_overlay_manager_host.h" #include "ui/ozone/platform/drm/host/drm_window_host.h" #include "ui/ozone/platform/drm/host/drm_window_host_manager.h" #include "ui/ozone/platform/drm/host/host_drm_device.h" @@ -160,8 +160,7 @@ class OzonePlatformGbm : public OzonePlatform { auto platform_window = std::make_unique<DrmWindowHost>( delegate, properties.bounds, adapter, event_factory_ozone_.get(), - cursor_.get(), window_manager_.get(), display_manager_.get(), - overlay_manager_.get()); + cursor_.get(), window_manager_.get(), display_manager_.get()); platform_window->Initialize(); return std::move(platform_window); } @@ -170,7 +169,8 @@ class OzonePlatformGbm : public OzonePlatform { return std::make_unique<DrmNativeDisplayDelegate>(display_manager_.get()); } std::unique_ptr<InputMethod> CreateInputMethod( - internal::InputMethodDelegate* delegate) override { + internal::InputMethodDelegate* delegate, + gfx::AcceleratedWidget) override { #if defined(OS_CHROMEOS) return std::make_unique<InputMethodChromeOS>(delegate); #else @@ -227,23 +227,13 @@ class OzonePlatformGbm : public OzonePlatform { adapter = gpu_platform_support_host_.get(); } - std::unique_ptr<DrmOverlayManagerHost> overlay_manager_host; - if (!args.viz_display_compositor) { - overlay_manager_host = std::make_unique<DrmOverlayManagerHost>( - adapter, window_manager_.get()); - } - display_manager_ = std::make_unique<DrmDisplayHostManager>( adapter, device_manager_.get(), &host_properties_, - overlay_manager_host.get(), event_factory_ozone_->input_controller()); + event_factory_ozone_->input_controller()); cursor_factory_ozone_ = std::make_unique<BitmapCursorFactoryOzone>(); - if (using_mojo_) { - host_drm_device_->ProvideManagers(display_manager_.get(), - overlay_manager_host.get()); - } - - overlay_manager_ = std::move(overlay_manager_host); + if (using_mojo_) + host_drm_device_->SetDisplayManager(display_manager_.get()); } void InitializeGPU(const InitParams& args) override { @@ -268,10 +258,8 @@ class OzonePlatformGbm : public OzonePlatform { drm_thread_proxy_->BindThreadIntoMessagingProxy(itmp); } - if (args.viz_display_compositor) { - overlay_manager_ = - std::make_unique<DrmOverlayManagerGpu>(drm_thread_proxy_.get()); - } + overlay_manager_ = + std::make_unique<DrmOverlayManagerGpu>(drm_thread_proxy_.get()); // If gpu is in a separate process, rest of the initialization happens after // entering the sandbox. @@ -338,6 +326,7 @@ class OzonePlatformGbm : public OzonePlatform { std::unique_ptr<GbmSurfaceFactory> surface_factory_; scoped_refptr<IPC::MessageFilter> gpu_message_filter_; scoped_refptr<base::SingleThreadTaskRunner> gpu_task_runner_; + std::unique_ptr<DrmOverlayManager> overlay_manager_; // TODO(rjkroege,sadrul): Provide a more elegant solution for this issue when // running in single process mode. @@ -351,9 +340,9 @@ class OzonePlatformGbm : public OzonePlatform { // TODO(rjkroege): Remove gpu_platform_support_host_ once ozone/drm with mojo // has reached the stable channel. // A raw pointer to either |gpu_platform_support_host_| or |host_drm_device_| - // is passed to |display_manager_| and |overlay_manager_| in IntializeUI. - // To avoid a use after free, the following two members should be declared - // before the two managers, so that they're deleted after them. + // is passed to |display_manager_| in InitializeUI(). To avoid a use after + // free, the following two members should be declared before the two managers, + // so that they're deleted after them. std::unique_ptr<DrmGpuPlatformSupportHost> gpu_platform_support_host_; // Objects in the host process. @@ -370,7 +359,6 @@ class OzonePlatformGbm : public OzonePlatform { std::unique_ptr<DrmCursor> cursor_; std::unique_ptr<EventFactoryEvdev> event_factory_ozone_; std::unique_ptr<DrmDisplayHostManager> display_manager_; - std::unique_ptr<DrmOverlayManager> overlay_manager_; InitializedHostProperties host_properties_; base::WeakPtrFactory<OzonePlatformGbm> weak_factory_{this}; diff --git a/chromium/ui/ozone/platform/headless/headless_surface_factory.cc b/chromium/ui/ozone/platform/headless/headless_surface_factory.cc index 2829df06710..fc1f019133f 100644 --- a/chromium/ui/ozone/platform/headless/headless_surface_factory.cc +++ b/chromium/ui/ozone/platform/headless/headless_surface_factory.cc @@ -12,6 +12,7 @@ #include "base/macros.h" #include "base/strings/string_number_conversions.h" #include "base/task/post_task.h" +#include "base/task/thread_pool.h" #include "build/build_config.h" #include "third_party/skia/include/core/SkCanvas.h" #include "third_party/skia/include/core/SkSurface.h" @@ -75,7 +76,7 @@ class FileSurface : public SurfaceOzoneCanvas { surface_ = SkSurface::MakeRaster(SkImageInfo::MakeN32Premul( viewport_size.width(), viewport_size.height())); } - sk_sp<SkSurface> GetSurface() override { return surface_; } + SkCanvas* GetCanvas() override { return surface_->getCanvas(); } void PresentCanvas(const gfx::Rect& damage) override { if (base_path_.empty()) return; @@ -85,10 +86,10 @@ class FileSurface : public SurfaceOzoneCanvas { // TODO(dnicoara) Use SkImage instead to potentially avoid a copy. // See crbug.com/361605 for details. if (surface_->getCanvas()->readPixels(bitmap, 0, 0)) { - base::PostTask(FROM_HERE, - {base::ThreadPool(), base::MayBlock(), - base::TaskShutdownBehavior::CONTINUE_ON_SHUTDOWN}, - base::BindOnce(&WriteDataToFile, base_path_, bitmap)); + base::ThreadPool::PostTask( + FROM_HERE, + {base::MayBlock(), base::TaskShutdownBehavior::CONTINUE_ON_SHUTDOWN}, + base::BindOnce(&WriteDataToFile, base_path_, bitmap)); } } std::unique_ptr<gfx::VSyncProvider> CreateVSyncProvider() override { @@ -122,10 +123,10 @@ class FileGLSurface : public GLSurfaceEglReadback { if (!bitmap.writePixels(pixmap)) return false; - base::PostTask(FROM_HERE, - {base::ThreadPool(), base::MayBlock(), - base::TaskShutdownBehavior::CONTINUE_ON_SHUTDOWN}, - base::BindOnce(&WriteDataToFile, location_, bitmap)); + base::ThreadPool::PostTask( + FROM_HERE, + {base::MayBlock(), base::TaskShutdownBehavior::CONTINUE_ON_SHUTDOWN}, + base::BindOnce(&WriteDataToFile, location_, bitmap)); return true; } @@ -191,7 +192,9 @@ class GLOzoneEGLHeadless : public GLOzoneEGL { protected: // GLOzoneEGL: - intptr_t GetNativeDisplay() override { return EGL_DEFAULT_DISPLAY; } + gl::EGLDisplayPlatform GetNativeDisplay() override { + return gl::EGLDisplayPlatform(EGL_DEFAULT_DISPLAY); + } bool LoadGLES2Bindings(gl::GLImplementation implementation) override { return LoadDefaultEGLGLES2Bindings(implementation); @@ -232,8 +235,9 @@ GLOzone* HeadlessSurfaceFactory::GetGLOzone( } std::unique_ptr<SurfaceOzoneCanvas> -HeadlessSurfaceFactory::CreateCanvasForWidget(gfx::AcceleratedWidget widget, - base::TaskRunner* task_runner) { +HeadlessSurfaceFactory::CreateCanvasForWidget( + gfx::AcceleratedWidget widget, + scoped_refptr<base::SequencedTaskRunner> task_runner) { return std::make_unique<FileSurface>(GetPathForWidget(base_path_, widget)); } @@ -242,7 +246,8 @@ scoped_refptr<gfx::NativePixmap> HeadlessSurfaceFactory::CreateNativePixmap( VkDevice vk_device, gfx::Size size, gfx::BufferFormat format, - gfx::BufferUsage usage) { + gfx::BufferUsage usage, + base::Optional<gfx::Size> framebuffer_size) { return new TestPixmap(format); } diff --git a/chromium/ui/ozone/platform/headless/headless_surface_factory.h b/chromium/ui/ozone/platform/headless/headless_surface_factory.h index 8270d643e78..abde7d4d8ab 100644 --- a/chromium/ui/ozone/platform/headless/headless_surface_factory.h +++ b/chromium/ui/ozone/platform/headless/headless_surface_factory.h @@ -25,13 +25,14 @@ class HeadlessSurfaceFactory : public SurfaceFactoryOzone { GLOzone* GetGLOzone(gl::GLImplementation implementation) override; std::unique_ptr<SurfaceOzoneCanvas> CreateCanvasForWidget( gfx::AcceleratedWidget widget, - base::TaskRunner* task_runner) override; + scoped_refptr<base::SequencedTaskRunner> task_runner) override; scoped_refptr<gfx::NativePixmap> CreateNativePixmap( gfx::AcceleratedWidget widget, VkDevice vk_device, gfx::Size size, gfx::BufferFormat format, - gfx::BufferUsage usage) override; + gfx::BufferUsage usage, + base::Optional<gfx::Size> framebuffer_size = base::nullopt) override; private: void CheckBasePath() const; diff --git a/chromium/ui/ozone/platform/headless/ozone_platform_headless.cc b/chromium/ui/ozone/platform/headless/ozone_platform_headless.cc index c84e960f5f5..9d356f701e3 100644 --- a/chromium/ui/ozone/platform/headless/ozone_platform_headless.cc +++ b/chromium/ui/ozone/platform/headless/ozone_platform_headless.cc @@ -89,9 +89,10 @@ class OzonePlatformHeadless : public OzonePlatform { return std::make_unique<HeadlessScreen>(); } std::unique_ptr<InputMethod> CreateInputMethod( - internal::InputMethodDelegate* delegate) override { + internal::InputMethodDelegate* delegate, + gfx::AcceleratedWidget widget) override { #if defined(OS_FUCHSIA) - return std::make_unique<InputMethodFuchsia>(delegate); + return std::make_unique<InputMethodFuchsia>(delegate, widget); #else return std::make_unique<InputMethodMinimal>(delegate); #endif diff --git a/chromium/ui/ozone/platform/scenic/BUILD.gn b/chromium/ui/ozone/platform/scenic/BUILD.gn index 472e835d73a..f927e8dda1c 100644 --- a/chromium/ui/ozone/platform/scenic/BUILD.gn +++ b/chromium/ui/ozone/platform/scenic/BUILD.gn @@ -46,13 +46,13 @@ source_set("scenic") { "//mojo/public/cpp/system", "//services/service_manager/public/cpp", "//skia", - "//third_party/fuchsia-sdk/sdk:fuchsia-images", - "//third_party/fuchsia-sdk/sdk:fuchsia-mem", - "//third_party/fuchsia-sdk/sdk:fuchsia-sysmem", - "//third_party/fuchsia-sdk/sdk:fuchsia-ui-gfx", - "//third_party/fuchsia-sdk/sdk:fuchsia-ui-scenic", - "//third_party/fuchsia-sdk/sdk:scenic_cpp", - "//third_party/fuchsia-sdk/sdk:sys_cpp", + "//third_party/fuchsia-sdk/sdk/fidl/fuchsia.images", + "//third_party/fuchsia-sdk/sdk/fidl/fuchsia.mem", + "//third_party/fuchsia-sdk/sdk/fidl/fuchsia.sysmem", + "//third_party/fuchsia-sdk/sdk/fidl/fuchsia.ui.gfx", + "//third_party/fuchsia-sdk/sdk/fidl/fuchsia.ui.scenic", + "//third_party/fuchsia-sdk/sdk/pkg/scenic_cpp", + "//third_party/fuchsia-sdk/sdk/pkg/sys_cpp", "//ui/base", "//ui/base/ime/fuchsia", "//ui/display/fake", diff --git a/chromium/ui/ozone/platform/scenic/ozone_platform_scenic.cc b/chromium/ui/ozone/platform/scenic/ozone_platform_scenic.cc index 535751d99bb..d05d7fbe1fa 100644 --- a/chromium/ui/ozone/platform/scenic/ozone_platform_scenic.cc +++ b/chromium/ui/ozone/platform/scenic/ozone_platform_scenic.cc @@ -20,6 +20,7 @@ #include "ui/events/ozone/layout/keyboard_layout_engine_manager.h" #include "ui/events/ozone/layout/stub/stub_keyboard_layout_engine.h" #include "ui/events/platform/platform_event_source.h" +#include "ui/gfx/native_widget_types.h" #include "ui/ozone/common/stub_overlay_manager.h" #include "ui/ozone/platform/scenic/scenic_gpu_host.h" #include "ui/ozone/platform/scenic/scenic_gpu_service.h" @@ -118,8 +119,9 @@ class OzonePlatformScenic } std::unique_ptr<InputMethod> CreateInputMethod( - internal::InputMethodDelegate* delegate) override { - return std::make_unique<InputMethodFuchsia>(delegate); + internal::InputMethodDelegate* delegate, + gfx::AcceleratedWidget widget) override { + return std::make_unique<InputMethodFuchsia>(delegate, widget); } void InitializeUI(const InitParams& params) override { diff --git a/chromium/ui/ozone/platform/scenic/scenic_gpu_host.cc b/chromium/ui/ozone/platform/scenic/scenic_gpu_host.cc index 348f085dd95..e596541637f 100644 --- a/chromium/ui/ozone/platform/scenic/scenic_gpu_host.cc +++ b/chromium/ui/ozone/platform/scenic/scenic_gpu_host.cc @@ -13,7 +13,6 @@ #include "base/threading/thread_task_runner_handle.h" #include "mojo/public/cpp/bindings/interface_request.h" #include "mojo/public/cpp/system/message_pipe.h" -#include "mojo/public/cpp/system/platform_handle.h" #include "ui/ozone/platform/scenic/scenic_window.h" #include "ui/ozone/platform/scenic/scenic_window_manager.h" #include "ui/ozone/public/mojom/scenic_gpu_host.mojom.h" @@ -53,15 +52,14 @@ ScenicGpuHost::CreateHostProcessSelfRemote() { void ScenicGpuHost::AttachSurfaceToWindow( int32_t window_id, - mojo::ScopedHandle surface_view_holder_token_mojo) { + mojo::PlatformHandle surface_view_holder_token_mojo) { DCHECK_CALLED_ON_VALID_THREAD(ui_thread_checker_); ScenicWindow* scenic_window = scenic_window_manager_->GetWindow(window_id); if (!scenic_window) return; fuchsia::ui::views::ViewHolderToken surface_view_holder_token; - surface_view_holder_token.value = zx::eventpair( - mojo::UnwrapPlatformHandle(std::move(surface_view_holder_token_mojo)) - .TakeHandle()); + surface_view_holder_token.value = + zx::eventpair(surface_view_holder_token_mojo.TakeHandle()); scenic_window->AttachSurfaceView(std::move(surface_view_holder_token)); } diff --git a/chromium/ui/ozone/platform/scenic/scenic_gpu_host.h b/chromium/ui/ozone/platform/scenic/scenic_gpu_host.h index b83f175da4e..25d073ba0fe 100644 --- a/chromium/ui/ozone/platform/scenic/scenic_gpu_host.h +++ b/chromium/ui/ozone/platform/scenic/scenic_gpu_host.h @@ -42,7 +42,7 @@ class ScenicGpuHost : public mojom::ScenicGpuHost, // mojom::ScenicGpuHost: void AttachSurfaceToWindow( int32_t window_id, - mojo::ScopedHandle surface_view_holder_token_mojo) override; + mojo::PlatformHandle surface_view_holder_token_mojo) override; // GpuPlatformSupportHost: void OnGpuProcessLaunched( diff --git a/chromium/ui/ozone/platform/scenic/scenic_surface.cc b/chromium/ui/ozone/platform/scenic/scenic_surface.cc index 2b744f2bc79..2d75a091190 100644 --- a/chromium/ui/ozone/platform/scenic/scenic_surface.cc +++ b/chromium/ui/ozone/platform/scenic/scenic_surface.cc @@ -8,7 +8,6 @@ #include <lib/ui/scenic/cpp/view_token_pair.h> #include <lib/zx/eventpair.h> -#include "mojo/public/cpp/system/platform_handle.h" #include "ui/ozone/platform/scenic/scenic_gpu_host.h" #include "ui/ozone/platform/scenic/scenic_surface_factory.h" @@ -53,7 +52,7 @@ void ScenicSurface::SetTextureToImage(const scenic::Image& image) { material_.SetTexture(image); } -mojo::ScopedHandle ScenicSurface::CreateView() { +mojo::PlatformHandle ScenicSurface::CreateView() { DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); // Scenic will associate the View and ViewHolder regardless of which it @@ -68,8 +67,7 @@ mojo::ScopedHandle ScenicSurface::CreateView() { /*requested_presentation_time=*/0, /*requested_prediction_span=*/0, [](fuchsia::scenic::scheduling::FuturePresentationTimes info) {}); - return mojo::WrapPlatformHandle( - mojo::PlatformHandle(std::move(tokens.view_holder_token.value))); + return mojo::PlatformHandle(std::move(tokens.view_holder_token.value)); } } // namespace ui diff --git a/chromium/ui/ozone/platform/scenic/scenic_surface.h b/chromium/ui/ozone/platform/scenic/scenic_surface.h index 4a731383594..d9b730ae611 100644 --- a/chromium/ui/ozone/platform/scenic/scenic_surface.h +++ b/chromium/ui/ozone/platform/scenic/scenic_surface.h @@ -11,7 +11,7 @@ #include "base/macros.h" #include "base/threading/thread_checker.h" -#include "mojo/public/cpp/system/handle.h" +#include "mojo/public/cpp/platform/platform_handle.h" #include "ui/gfx/native_widget_types.h" #include "ui/ozone/public/platform_window_surface.h" @@ -43,7 +43,7 @@ class ScenicSurface : public ui::PlatformWindowSurface { // Creates a View for this surface, and returns a ViewHolderToken handle // that can be used to attach it into a scene graph. - mojo::ScopedHandle CreateView(); + mojo::PlatformHandle CreateView(); void AssertBelongsToCurrentThread() { DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); diff --git a/chromium/ui/ozone/platform/scenic/scenic_surface_factory.cc b/chromium/ui/ozone/platform/scenic/scenic_surface_factory.cc index 8cdaf028b7c..14053720363 100644 --- a/chromium/ui/ozone/platform/scenic/scenic_surface_factory.cc +++ b/chromium/ui/ozone/platform/scenic/scenic_surface_factory.cc @@ -52,8 +52,8 @@ class GLOzoneEGLScenic : public GLOzoneEGL { base::MakeRefCounted<gl::PbufferGLSurfaceEGL>(size)); } - EGLNativeDisplayType GetNativeDisplay() override { - return EGL_DEFAULT_DISPLAY; + gl::EGLDisplayPlatform GetNativeDisplay() override { + return gl::EGLDisplayPlatform(EGL_DEFAULT_DISPLAY); } protected: @@ -111,7 +111,7 @@ GLOzone* ScenicSurfaceFactory::GetGLOzone(gl::GLImplementation implementation) { std::unique_ptr<PlatformWindowSurface> ScenicSurfaceFactory::CreatePlatformWindowSurface( gfx::AcceleratedWidget window) { - DCHECK(gpu_host_); + DCHECK_NE(window, gfx::kNullAcceleratedWidget); auto surface = std::make_unique<ScenicSurface>(this, window, CreateScenicSession()); main_thread_task_runner_->PostTask( @@ -123,7 +123,7 @@ ScenicSurfaceFactory::CreatePlatformWindowSurface( std::unique_ptr<SurfaceOzoneCanvas> ScenicSurfaceFactory::CreateCanvasForWidget( gfx::AcceleratedWidget widget, - base::TaskRunner* task_runner) { + scoped_refptr<base::SequencedTaskRunner> task_runner) { ScenicSurface* surface = GetSurface(widget); return std::make_unique<ScenicWindowCanvas>(surface); } @@ -133,7 +133,9 @@ scoped_refptr<gfx::NativePixmap> ScenicSurfaceFactory::CreateNativePixmap( VkDevice vk_device, gfx::Size size, gfx::BufferFormat format, - gfx::BufferUsage usage) { + gfx::BufferUsage usage, + base::Optional<gfx::Size> framebuffer_size) { + DCHECK(!framebuffer_size || framebuffer_size == size); auto collection = sysmem_buffer_manager_.CreateCollection(vk_device, size, format, usage, 1); if (!collection) @@ -158,10 +160,6 @@ std::unique_ptr<gpu::VulkanImplementation> ScenicSurfaceFactory::CreateVulkanImplementation( bool allow_protected_memory, bool enforce_protected_memory) { - DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); - if (!gpu_host_) - LOG(FATAL) << "Vulkan implementation requires InitializeForGPU"; - return std::make_unique<ui::VulkanImplementationScenic>( this, &sysmem_buffer_manager_, allow_protected_memory, enforce_protected_memory); @@ -233,7 +231,7 @@ void ScenicSurfaceFactory::CreateScenicSessionOnMainThread( void ScenicSurfaceFactory::AttachSurfaceToWindow( gfx::AcceleratedWidget window, - mojo::ScopedHandle surface_view_holder_token_mojo) { + mojo::PlatformHandle surface_view_holder_token_mojo) { DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); gpu_host_->AttachSurfaceToWindow(window, std::move(surface_view_holder_token_mojo)); diff --git a/chromium/ui/ozone/platform/scenic/scenic_surface_factory.h b/chromium/ui/ozone/platform/scenic/scenic_surface_factory.h index 2214f0ad174..a14be294357 100644 --- a/chromium/ui/ozone/platform/scenic/scenic_surface_factory.h +++ b/chromium/ui/ozone/platform/scenic/scenic_surface_factory.h @@ -41,13 +41,14 @@ class ScenicSurfaceFactory : public SurfaceFactoryOzone { gfx::AcceleratedWidget widget) override; std::unique_ptr<SurfaceOzoneCanvas> CreateCanvasForWidget( gfx::AcceleratedWidget widget, - base::TaskRunner* task_runner) override; + scoped_refptr<base::SequencedTaskRunner> task_runner) override; scoped_refptr<gfx::NativePixmap> CreateNativePixmap( gfx::AcceleratedWidget widget, VkDevice vk_device, gfx::Size size, gfx::BufferFormat format, - gfx::BufferUsage usage) override; + gfx::BufferUsage usage, + base::Optional<gfx::Size> framebuffer_size = base::nullopt) override; void CreateNativePixmapAsync(gfx::AcceleratedWidget widget, VkDevice vk_device, gfx::Size size, @@ -88,8 +89,9 @@ class ScenicSurfaceFactory : public SurfaceFactoryOzone { fidl::InterfaceHandle<fuchsia::ui::scenic::SessionListener> listener); // Links a surface to its parent window in the host process. - void AttachSurfaceToWindow(gfx::AcceleratedWidget window, - mojo::ScopedHandle surface_view_holder_token_mojo); + void AttachSurfaceToWindow( + gfx::AcceleratedWidget window, + mojo::PlatformHandle surface_view_holder_token_mojo); base::flat_map<gfx::AcceleratedWidget, ScenicSurface*> surface_map_ GUARDED_BY(surface_lock_); diff --git a/chromium/ui/ozone/platform/scenic/scenic_window.cc b/chromium/ui/ozone/platform/scenic/scenic_window.cc index 965ee62ff60..0de00de69aa 100644 --- a/chromium/ui/ozone/platform/scenic/scenic_window.cc +++ b/chromium/ui/ozone/platform/scenic/scenic_window.cc @@ -37,7 +37,8 @@ ScenicWindow::ScenicWindow(ScenicWindowManager* window_manager, "chromium window"), node_(&scenic_session_), input_node_(&scenic_session_), - render_node_(&scenic_session_) { + render_node_(&scenic_session_), + background_node_(&scenic_session_) { scenic_session_.set_error_handler( fit::bind_member(this, &ScenicWindow::OnScenicError)); scenic_session_.set_event_handler( @@ -51,9 +52,28 @@ ScenicWindow::ScenicWindow(ScenicWindowManager* window_manager, // Add input shape. node_.AddChild(input_node_); - // Add rendering subtree. + // Add rendering subtree, rooted at Z=-2 to make room for background layers in + // the Z-order (lesser values are higher in the visual ordering). + constexpr float kRenderNodeZPosition = -2.; + constexpr float kBackgroundNodeZPosition = kRenderNodeZPosition + 1.; + render_node_.SetTranslation(0., 0., kRenderNodeZPosition); node_.AddChild(render_node_); + // Initialize a black background to be just behind |render_node_|. + scenic::Material background_color(&scenic_session_); + background_color.SetColor(0, 0, 0, 255); // RGBA (0,0,0,255) = opaque black. + background_node_.SetMaterial(background_color); + scenic::Rectangle background_shape(&scenic_session_, 1., 1.); + background_node_.SetShape(background_shape); + background_node_.SetTranslation(0., 0., kBackgroundNodeZPosition); + node_.AddChild(background_node_); + + // Render the background immediately. + scenic_session_.Present2( + /*requested_presentation_time=*/0, + /*requested_prediction_span=*/0, + [](fuchsia::scenic::scheduling::FuturePresentationTimes info) {}); + delegate_->OnAcceleratedWidgetAvailable(window_id_); } @@ -223,8 +243,12 @@ void ScenicWindow::UpdateSize() { render_node_.SetScale(size_dips_.width(), size_dips_.height(), 1.f); // Resize input node to cover the whole surface. - input_node_.SetShape(scenic::Rectangle(&scenic_session_, size_dips_.width(), - size_dips_.height())); + scenic::Rectangle window_rect(&scenic_session_, size_dips_.width(), + size_dips_.height()); + input_node_.SetShape(window_rect); + + // Resize the input and background nodes to cover the whole surface. + background_node_.SetShape(window_rect); // This is necessary when using vulkan because ImagePipes are presented // separately and we need to make sure our sizes change is committed. @@ -245,14 +269,30 @@ void ScenicWindow::OnScenicEvents( std::vector<fuchsia::ui::scenic::Event> events) { for (const auto& event : events) { if (event.is_gfx()) { - if (event.gfx().is_metrics()) { - if (event.gfx().metrics().node_id != node_.id()) - continue; - OnViewMetrics(event.gfx().metrics().metrics); - } else if (event.gfx().is_view_properties_changed()) { - if (event.gfx().view_properties_changed().view_id != view_.id()) - continue; - OnViewProperties(event.gfx().view_properties_changed().properties); + switch (event.gfx().Which()) { + case fuchsia::ui::gfx::Event::kMetrics: { + if (event.gfx().metrics().node_id != node_.id()) + continue; + OnViewMetrics(event.gfx().metrics().metrics); + break; + } + case fuchsia::ui::gfx::Event::kViewPropertiesChanged: { + DCHECK(event.gfx().view_properties_changed().view_id == view_.id()); + OnViewProperties(event.gfx().view_properties_changed().properties); + break; + } + case fuchsia::ui::gfx::Event::kViewAttachedToScene: { + DCHECK(event.gfx().view_attached_to_scene().view_id == view_.id()); + OnViewAttachedChanged(true); + break; + } + case fuchsia::ui::gfx::Event::kViewDetachedFromScene: { + DCHECK(event.gfx().view_detached_from_scene().view_id == view_.id()); + OnViewAttachedChanged(false); + break; + } + default: + break; } } else if (event.is_input()) { OnInputEvent(event.input()); @@ -283,6 +323,12 @@ void ScenicWindow::OnViewProperties( UpdateSize(); } +void ScenicWindow::OnViewAttachedChanged(bool is_view_attached) { + delegate_->OnWindowStateChanged(is_view_attached + ? PlatformWindowState::kNormal + : PlatformWindowState::kMinimized); +} + void ScenicWindow::OnInputEvent(const fuchsia::ui::input::InputEvent& event) { if (event.is_focus()) { delegate_->OnActivationChanged(event.focus().focused); diff --git a/chromium/ui/ozone/platform/scenic/scenic_window.h b/chromium/ui/ozone/platform/scenic/scenic_window.h index 7a32a91d31e..d70d88b218f 100644 --- a/chromium/ui/ozone/platform/scenic/scenic_window.h +++ b/chromium/ui/ozone/platform/scenic/scenic_window.h @@ -10,6 +10,7 @@ #include <lib/ui/scenic/cpp/resources.h> #include <lib/ui/scenic/cpp/session.h> #include <lib/ui/scenic/cpp/view_ref_pair.h> +#include <memory> #include <string> #include <vector> @@ -86,6 +87,7 @@ class COMPONENT_EXPORT(OZONE) ScenicWindow // Called from OnScenicEvents() to handle view properties and metrics changes. void OnViewProperties(const fuchsia::ui::gfx::ViewProperties& properties); void OnViewMetrics(const fuchsia::ui::gfx::Metrics& metrics); + void OnViewAttachedChanged(bool is_view_attached); // Called from OnScenicEvents() to handle input events. void OnInputEvent(const fuchsia::ui::input::InputEvent& event); @@ -116,6 +118,11 @@ class COMPONENT_EXPORT(OZONE) ScenicWindow // Node in |scenic_session_| for rendering (hit testing disabled). scenic::EntityNode render_node_; + + // Node in |scenic_session_| for rendering a solid color, placed just behind + // |render_node_| in the Z order. + scenic::ShapeNode background_node_; + std::unique_ptr<scenic::ViewHolder> surface_view_holder_; // The ratio used for translating device-independent coordinates to absolute diff --git a/chromium/ui/ozone/platform/scenic/scenic_window_canvas.cc b/chromium/ui/ozone/platform/scenic/scenic_window_canvas.cc index 9d5367176b1..14ef76692c8 100644 --- a/chromium/ui/ozone/platform/scenic/scenic_window_canvas.cc +++ b/chromium/ui/ozone/platform/scenic/scenic_window_canvas.cc @@ -83,7 +83,7 @@ void ScenicWindowCanvas::ResizeCanvas(const gfx::Size& viewport_size) { } } -sk_sp<SkSurface> ScenicWindowCanvas::GetSurface() { +SkCanvas* ScenicWindowCanvas::GetCanvas() { if (viewport_size_.IsEmpty() || frames_[current_frame_].is_empty()) return nullptr; @@ -108,7 +108,7 @@ sk_sp<SkSurface> ScenicWindowCanvas::GetSurface() { } } - return frames_[current_frame_].surface; + return frames_[current_frame_].surface->getCanvas(); } void ScenicWindowCanvas::PresentCanvas(const gfx::Rect& damage) { diff --git a/chromium/ui/ozone/platform/scenic/scenic_window_canvas.h b/chromium/ui/ozone/platform/scenic/scenic_window_canvas.h index 237e621a105..858711723a2 100644 --- a/chromium/ui/ozone/platform/scenic/scenic_window_canvas.h +++ b/chromium/ui/ozone/platform/scenic/scenic_window_canvas.h @@ -17,6 +17,8 @@ #include "ui/ozone/platform/scenic/scenic_surface_factory.h" #include "ui/ozone/public/surface_ozone_canvas.h" +class SkSurface; + namespace scenic { class Session; } // namespace scenic @@ -36,7 +38,7 @@ class ScenicWindowCanvas : public SurfaceOzoneCanvas { // SurfaceOzoneCanvas implementation. void ResizeCanvas(const gfx::Size& viewport_size) override; - sk_sp<SkSurface> GetSurface() override; + SkCanvas* GetCanvas() override; void PresentCanvas(const gfx::Rect& damage) override; std::unique_ptr<gfx::VSyncProvider> CreateVSyncProvider() override; diff --git a/chromium/ui/ozone/platform/scenic/vulkan_implementation_scenic.cc b/chromium/ui/ozone/platform/scenic/vulkan_implementation_scenic.cc index 191d274a9cf..599c0cb345e 100644 --- a/chromium/ui/ozone/platform/scenic/vulkan_implementation_scenic.cc +++ b/chromium/ui/ozone/platform/scenic/vulkan_implementation_scenic.cc @@ -18,6 +18,7 @@ #include "gpu/ipc/common/vulkan_ycbcr_info.h" #include "gpu/vulkan/fuchsia/vulkan_fuchsia_ext.h" #include "gpu/vulkan/vulkan_function_pointers.h" +#include "gpu/vulkan/vulkan_image.h" #include "gpu/vulkan/vulkan_instance.h" #include "gpu/vulkan/vulkan_surface.h" #include "gpu/vulkan/vulkan_util.h" @@ -57,7 +58,7 @@ bool VulkanImplementationScenic::InitializeVulkanInstance(bool using_surface) { gpu::VulkanFunctionPointers* vulkan_function_pointers = gpu::GetVulkanFunctionPointers(); - vulkan_function_pointers->vulkan_loader_library_ = handle; + vulkan_function_pointers->vulkan_loader_library = handle; std::vector<const char*> required_extensions = { VK_KHR_SURFACE_EXTENSION_NAME, VK_FUCHSIA_IMAGEPIPE_SURFACE_EXTENSION_NAME, @@ -118,9 +119,6 @@ bool VulkanImplementationScenic::GetPhysicalDevicePresentationSupport( VkPhysicalDevice physical_device, const std::vector<VkQueueFamilyProperties>& queue_family_properties, uint32_t queue_family_index) { - // TODO(spang): vkGetPhysicalDeviceMagmaPresentationSupportKHR returns false - // here. Use it once it is fixed. - NOTIMPLEMENTED(); return true; } @@ -140,6 +138,11 @@ VulkanImplementationScenic::GetRequiredDeviceExtensions() { }; } +std::vector<const char*> +VulkanImplementationScenic::GetOptionalDeviceExtensions() { + return {}; +} + VkFence VulkanImplementationScenic::CreateVkFenceForGpuFence( VkDevice vk_device) { NOTIMPLEMENTED(); @@ -230,33 +233,52 @@ bool VulkanImplementationScenic::CanImportGpuMemoryBuffer( return memory_buffer_type == gfx::NATIVE_PIXMAP; } -bool VulkanImplementationScenic::CreateImageFromGpuMemoryHandle( - VkDevice vk_device, +std::unique_ptr<gpu::VulkanImage> +VulkanImplementationScenic::CreateImageFromGpuMemoryHandle( + gpu::VulkanDeviceQueue* device_queue, gfx::GpuMemoryBufferHandle gmb_handle, gfx::Size size, - VkImage* vk_image, - VkImageCreateInfo* vk_image_info, - VkDeviceMemory* vk_device_memory, - VkDeviceSize* mem_allocation_size, - base::Optional<gpu::VulkanYCbCrInfo>* ycbcr_info) { + VkFormat vk_format) { if (gmb_handle.type != gfx::NATIVE_PIXMAP) - return false; + return nullptr; if (!gmb_handle.native_pixmap_handle.buffer_collection_id) { DLOG(ERROR) << "NativePixmapHandle.buffer_collection_id is not set."; - return false; + return nullptr; } auto collection = sysmem_buffer_manager_->GetCollectionById( gmb_handle.native_pixmap_handle.buffer_collection_id.value()); if (!collection) { - DLOG(ERROR) << "Tried to use an unknown buffer collection ID"; - return false; + DLOG(ERROR) << "Tried to use an unknown buffer collection ID."; + return nullptr; + } + VkImage vk_image = VK_NULL_HANDLE; + VkImageCreateInfo vk_image_info = {VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO}; + VkDeviceMemory vk_device_memory = VK_NULL_HANDLE; + VkDeviceSize vk_device_size = 0; + base::Optional<gpu::VulkanYCbCrInfo> ycbcr_info; + if (!collection->CreateVkImage(gmb_handle.native_pixmap_handle.buffer_index, + device_queue->GetVulkanDevice(), size, + &vk_image, &vk_image_info, &vk_device_memory, + &vk_device_size, &ycbcr_info)) { + DLOG(ERROR) << "CreateVkImage failed."; + return nullptr; + } + + auto image = gpu::VulkanImage::Create( + device_queue, vk_image, vk_device_memory, size, vk_image_info.format, + vk_image_info.tiling, vk_device_size, 0 /* memory_type_index */, + ycbcr_info); + + if (image->format() != vk_format) { + DLOG(ERROR) << "Unexpected format " << vk_format << " vs " + << image->format(); + image->Destroy(); + return nullptr; } - return collection->CreateVkImage( - gmb_handle.native_pixmap_handle.buffer_index, vk_device, size, vk_image, - vk_image_info, vk_device_memory, mem_allocation_size, ycbcr_info); + return image; } class SysmemBufferCollectionImpl : public gpu::SysmemBufferCollection { diff --git a/chromium/ui/ozone/platform/scenic/vulkan_implementation_scenic.h b/chromium/ui/ozone/platform/scenic/vulkan_implementation_scenic.h index 8b077b836a6..6b1a1afa1f1 100644 --- a/chromium/ui/ozone/platform/scenic/vulkan_implementation_scenic.h +++ b/chromium/ui/ozone/platform/scenic/vulkan_implementation_scenic.h @@ -35,6 +35,7 @@ class VulkanImplementationScenic : public gpu::VulkanImplementation { const std::vector<VkQueueFamilyProperties>& queue_family_properties, uint32_t queue_family_index) override; std::vector<const char*> GetRequiredDeviceExtensions() override; + std::vector<const char*> GetOptionalDeviceExtensions() override; VkFence CreateVkFenceForGpuFence(VkDevice vk_device) override; std::unique_ptr<gfx::GpuFence> ExportVkFenceToGpuFence( VkDevice vk_device, @@ -47,15 +48,11 @@ class VulkanImplementationScenic : public gpu::VulkanImplementation { VkExternalMemoryHandleTypeFlagBits GetExternalImageHandleType() override; bool CanImportGpuMemoryBuffer( gfx::GpuMemoryBufferType memory_buffer_type) override; - bool CreateImageFromGpuMemoryHandle( - VkDevice vk_device, + std::unique_ptr<gpu::VulkanImage> CreateImageFromGpuMemoryHandle( + gpu::VulkanDeviceQueue* device_queue, gfx::GpuMemoryBufferHandle gmb_handle, gfx::Size size, - VkImage* vk_image, - VkImageCreateInfo* vk_image_info, - VkDeviceMemory* vk_device_memory, - VkDeviceSize* mem_allocation_size, - base::Optional<gpu::VulkanYCbCrInfo>* ycbcr_info) override; + VkFormat vk_format) override; std::unique_ptr<gpu::SysmemBufferCollection> RegisterSysmemBufferCollection( VkDevice device, gfx::SysmemBufferCollectionId id, diff --git a/chromium/ui/ozone/platform/wayland/BUILD.gn b/chromium/ui/ozone/platform/wayland/BUILD.gn index 37e7ffb5d83..cb2257c898b 100644 --- a/chromium/ui/ozone/platform/wayland/BUILD.gn +++ b/chromium/ui/ozone/platform/wayland/BUILD.gn @@ -4,6 +4,7 @@ visibility = [ "//ui/ozone/*" ] +import("//build/config/linux/gtk/gtk.gni") import("//build/config/linux/pkg_config.gni") import("//testing/libfuzzer/fuzzer_test.gni") import("//ui/ozone/platform/wayland/wayland.gni") @@ -22,6 +23,8 @@ source_set("wayland") { "common/wayland_util.h", "gpu/drm_render_node_path_finder.cc", "gpu/drm_render_node_path_finder.h", + "gpu/gl_surface_egl_readback_wayland.cc", + "gpu/gl_surface_egl_readback_wayland.h", "gpu/gl_surface_wayland.cc", "gpu/gl_surface_wayland.h", "gpu/wayland_buffer_manager_gpu.cc", @@ -45,6 +48,8 @@ source_set("wayland") { "host/internal/wayland_data_offer_base.h", "host/internal/wayland_data_source_base.cc", "host/internal/wayland_data_source_base.h", + "host/shell_object_factory.cc", + "host/shell_object_factory.h", "host/shell_popup_wrapper.cc", "host/shell_popup_wrapper.h", "host/shell_surface_wrapper.cc", @@ -83,16 +88,23 @@ source_set("wayland") { "host/wayland_output_manager.h", "host/wayland_pointer.cc", "host/wayland_pointer.h", + "host/wayland_popup.cc", + "host/wayland_popup.h", "host/wayland_screen.cc", "host/wayland_screen.h", "host/wayland_shm.cc", "host/wayland_shm.h", "host/wayland_shm_buffer.cc", "host/wayland_shm_buffer.h", + "host/wayland_subsurface.cc", + "host/wayland_subsurface.h", + "host/wayland_surface.cc", + "host/wayland_surface.h", "host/wayland_touch.cc", "host/wayland_touch.h", "host/wayland_window.cc", "host/wayland_window.h", + "host/wayland_window_factory.cc", "host/wayland_window_manager.cc", "host/wayland_window_manager.h", "host/wayland_window_observer.cc", @@ -141,9 +153,9 @@ source_set("wayland") { "//ui/gfx", "//ui/gfx:memory_buffer", "//ui/gfx/geometry", + "//ui/gfx/linux:drm", "//ui/ozone:ozone_base", "//ui/ozone/common", - "//ui/ozone/common/linux:drm", "//ui/ozone/public/mojom/wayland:wayland_mojom", "//ui/platform_window", "//ui/platform_window/platform_window_handler", @@ -153,6 +165,17 @@ source_set("wayland") { deps += [ "//ui/base/ime/linux" ] } + if (use_gtk) { + sources += [ + "host/gtk_ui_delegate_wayland.cc", + "host/gtk_ui_delegate_wayland.h", + ] + deps += [ + "//build/config/linux/gtk", + "//ui/gtk:gtk_ui_delegate", + ] + } + defines = [ "OZONE_IMPLEMENTATION" ] if (use_wayland_gbm) { @@ -169,10 +192,14 @@ source_set("wayland") { deps += [ "//third_party/minigbm", "//ui/gfx:memory_buffer", - "//ui/ozone/common/linux:gbm", + "//ui/gfx/linux:gbm", ] } + if (use_bundled_weston) { + data_deps = [ "//third_party/weston" ] + } + configs += [ ":wayland-egl", "//third_party/khronos:khronos_headers", @@ -292,10 +319,11 @@ source_set("wayland_unittests") { "//ui/base:buildflags", "//ui/base/ime/linux", "//ui/events/ozone/layout", + "//ui/gfx/linux:drm", + "//ui/gfx/linux:gbm", + "//ui/gfx/linux:test_support", "//ui/ozone:platform", "//ui/ozone:test_support", - "//ui/ozone/common/linux:drm", - "//ui/ozone/common/linux:gbm", "//ui/platform_window/platform_window_handler", ] @@ -312,9 +340,7 @@ source_set("wayland_unittests") { fuzzer_test("wayland_buffer_fuzzer") { defines = [ "WL_HIDE_DEPRECATED" ] - sources = [ - "fuzzer/wayland_buffer_fuzzer.cc", - ] + sources = [ "fuzzer/wayland_buffer_fuzzer.cc" ] deps = [ ":test_support", ":wayland", diff --git a/chromium/ui/ozone/platform/wayland/DEPS b/chromium/ui/ozone/platform/wayland/DEPS index 60eec9ee675..d61519af80c 100644 --- a/chromium/ui/ozone/platform/wayland/DEPS +++ b/chromium/ui/ozone/platform/wayland/DEPS @@ -2,10 +2,11 @@ include_rules = [ "+ui/base/buildflags.h", # Doesn't bring in all of ui/base. "+ui/base/hit_test.h", # UI hit test doesn't bring in all of ui/base. "+ui/base/ui_base_features.h", + "+ui/gtk/gtk_ui_delegate.h", "+mojo/public", "+ui/base/clipboard/clipboard_constants.h", "+ui/base/dragdrop/drag_drop_types.h", - "+ui/base/dragdrop/file_info.h", + "+ui/base/dragdrop/file_info/file_info.h", "+ui/base/dragdrop/os_exchange_data.h", "+ui/base/dragdrop/os_exchange_data_provider_aura.h", ] diff --git a/chromium/ui/ozone/platform/wayland/common/wayland_util.cc b/chromium/ui/ozone/platform/wayland/common/wayland_util.cc index 0201f689e90..14593b1c614 100644 --- a/chromium/ui/ozone/platform/wayland/common/wayland_util.cc +++ b/chromium/ui/ozone/platform/wayland/common/wayland_util.cc @@ -109,7 +109,7 @@ uint32_t IdentifyDirection(const ui::WaylandConnection& connection, bool DrawBitmap(const SkBitmap& bitmap, ui::WaylandShmBuffer* out_buffer) { DCHECK(out_buffer); DCHECK(out_buffer->GetMemory()); - DCHECK(out_buffer->size() == gfx::Size(bitmap.width(), bitmap.height())); + DCHECK_EQ(out_buffer->size(), gfx::Size(bitmap.width(), bitmap.height())); auto* mapped_memory = out_buffer->GetMemory(); auto size = out_buffer->size(); @@ -141,4 +141,23 @@ void ReadDataFromFD(base::ScopedFD fd, std::vector<uint8_t>* contents) { contents->insert(contents->end(), buffer, buffer + length); } +gfx::Rect TranslateBoundsToParentCoordinates(const gfx::Rect& child_bounds, + const gfx::Rect& parent_bounds) { + return gfx::Rect( + (child_bounds.origin() - parent_bounds.origin().OffsetFromOrigin()), + child_bounds.size()); +} + +gfx::Rect TranslateBoundsToTopLevelCoordinates(const gfx::Rect& child_bounds, + const gfx::Rect& parent_bounds) { + return gfx::Rect( + (child_bounds.origin() + parent_bounds.origin().OffsetFromOrigin()), + child_bounds.size()); +} + +bool IsMenuType(ui::PlatformWindowType type) { + return type == ui::PlatformWindowType::kMenu || + type == ui::PlatformWindowType::kPopup; +} + } // namespace wl diff --git a/chromium/ui/ozone/platform/wayland/common/wayland_util.h b/chromium/ui/ozone/platform/wayland/common/wayland_util.h index 368f3d9a942..3db36965402 100644 --- a/chromium/ui/ozone/platform/wayland/common/wayland_util.h +++ b/chromium/ui/ozone/platform/wayland/common/wayland_util.h @@ -13,7 +13,9 @@ #include "base/containers/flat_map.h" #include "base/files/scoped_file.h" #include "base/macros.h" +#include "ui/gfx/geometry/rect.h" #include "ui/ozone/platform/wayland/common/wayland_object.h" +#include "ui/platform_window/platform_window_init_properties.h" class SkBitmap; @@ -50,6 +52,16 @@ bool DrawBitmap(const SkBitmap& bitmap, ui::WaylandShmBuffer* out_buffer); // Helper function to read data from a file. void ReadDataFromFD(base::ScopedFD fd, std::vector<uint8_t>* contents); +// Translates bounds relative to top level window to specified parent. +gfx::Rect TranslateBoundsToParentCoordinates(const gfx::Rect& child_bounds, + const gfx::Rect& parent_bounds); +// Translates bounds relative to parent window to top level window. +gfx::Rect TranslateBoundsToTopLevelCoordinates(const gfx::Rect& child_bounds, + const gfx::Rect& parent_bounds); + +// Says if the type is kPopup or kMenu. +bool IsMenuType(ui::PlatformWindowType type); + } // namespace wl #endif // UI_OZONE_PLATFORM_WAYLAND_COMMON_WAYLAND_UTIL_H_ diff --git a/chromium/ui/ozone/platform/wayland/gpu/gbm_pixmap_wayland.cc b/chromium/ui/ozone/platform/wayland/gpu/gbm_pixmap_wayland.cc index f36ec10cac1..c78ca1d02aa 100644 --- a/chromium/ui/ozone/platform/wayland/gpu/gbm_pixmap_wayland.cc +++ b/chromium/ui/ozone/platform/wayland/gpu/gbm_pixmap_wayland.cc @@ -18,9 +18,10 @@ #include "ui/gfx/buffer_format_util.h" #include "ui/gfx/buffer_usage_util.h" #include "ui/gfx/geometry/size_conversions.h" +#include "ui/gfx/linux/drm_util_linux.h" +#include "ui/gfx/linux/gbm_device.h" +#include "ui/gfx/linux/gbm_util.h" #include "ui/gfx/native_pixmap_handle.h" -#include "ui/ozone/common/linux/drm_util_linux.h" -#include "ui/ozone/common/linux/gbm_device.h" #include "ui/ozone/platform/wayland/gpu/gbm_surfaceless_wayland.h" #include "ui/ozone/platform/wayland/gpu/wayland_buffer_manager_gpu.h" #include "ui/ozone/public/overlay_plane.h" @@ -29,11 +30,12 @@ namespace ui { GbmPixmapWayland::GbmPixmapWayland(WaylandBufferManagerGpu* buffer_manager) - : buffer_manager_(buffer_manager) {} + : buffer_manager_(buffer_manager), + buffer_id_(buffer_manager->AllocateBufferID()) {} GbmPixmapWayland::~GbmPixmapWayland() { if (gbm_bo_) - buffer_manager_->DestroyBuffer(widget_, GetUniqueId()); + buffer_manager_->DestroyBuffer(widget_, buffer_id_); } bool GbmPixmapWayland::InitializeBuffer(gfx::Size size, @@ -44,35 +46,14 @@ bool GbmPixmapWayland::InitializeBuffer(gfx::Size size, if (!buffer_manager_->gbm_device()) return false; - uint32_t flags = 0; - switch (usage) { - case gfx::BufferUsage::GPU_READ: - flags = GBM_BO_USE_LINEAR; - break; - case gfx::BufferUsage::SCANOUT: - flags = GBM_BO_USE_RENDERING | GBM_BO_USE_SCANOUT; - break; - case gfx::BufferUsage::SCANOUT_CAMERA_READ_WRITE: - flags = GBM_BO_USE_LINEAR | GBM_BO_USE_WRITE | GBM_BO_USE_SCANOUT; - break; - case gfx::BufferUsage::SCANOUT_CPU_READ_WRITE: - flags = GBM_BO_USE_LINEAR | GBM_BO_USE_SCANOUT; - break; - case gfx::BufferUsage::SCANOUT_VDA_WRITE: - flags = GBM_BO_USE_SCANOUT; - break; - case gfx::BufferUsage::GPU_READ_CPU_READ_WRITE: - flags = GBM_BO_USE_LINEAR; - break; - default: - NOTREACHED() << "Not supported buffer format"; - break; - } - const uint32_t fourcc_format = GetFourCCFormatFromBufferFormat(format); - auto modifiers = buffer_manager_->GetModifiersForBufferFormat(format); + auto gbm_usage = ui::BufferUsageToGbmFlags(usage); + std::vector<uint64_t> modifiers; + if (!(gbm_usage & GBM_BO_USE_LINEAR)) + modifiers = buffer_manager_->GetModifiersForBufferFormat(format); + gbm_bo_ = buffer_manager_->gbm_device()->CreateBufferWithModifiers( - fourcc_format, size, flags, modifiers); + fourcc_format, size, gbm_usage, modifiers); if (!gbm_bo_) { LOG(ERROR) << "Cannot create bo with format= " << gfx::BufferFormatToString(format) << " and usage " @@ -153,7 +134,8 @@ bool GbmPixmapWayland::ScheduleOverlayPlane( surfaceless->QueueOverlayPlane( OverlayPlane(this, std::move(gpu_fence), plane_z_order, plane_transform, - display_bounds, crop_rect, enable_blend)); + display_bounds, crop_rect, enable_blend), + buffer_id_); return true; } @@ -204,7 +186,7 @@ void GbmPixmapWayland::CreateDmabufBasedBuffer() { // Asks Wayland to create a wl_buffer based on the |file| fd. buffer_manager_->CreateDmabufBasedBuffer( std::move(fd), GetBufferSize(), strides, offsets, modifiers, - gbm_bo_->GetFormat(), plane_count, GetUniqueId()); + gbm_bo_->GetFormat(), plane_count, buffer_id_); } } // namespace ui diff --git a/chromium/ui/ozone/platform/wayland/gpu/gbm_pixmap_wayland.h b/chromium/ui/ozone/platform/wayland/gpu/gbm_pixmap_wayland.h index b84aebd2733..e344054c251 100644 --- a/chromium/ui/ozone/platform/wayland/gpu/gbm_pixmap_wayland.h +++ b/chromium/ui/ozone/platform/wayland/gpu/gbm_pixmap_wayland.h @@ -12,8 +12,8 @@ #include "base/macros.h" #include "ui/gfx/buffer_types.h" #include "ui/gfx/geometry/size.h" +#include "ui/gfx/linux/gbm_buffer.h" #include "ui/gfx/native_pixmap.h" -#include "ui/ozone/common/linux/gbm_buffer.h" namespace ui { @@ -67,6 +67,9 @@ class GbmPixmapWayland : public gfx::NativePixmap { // Represents widget this pixmap backs. gfx::AcceleratedWidget widget_ = gfx::kNullAcceleratedWidget; + // A unique ID to identify the buffer for this pixmap. + const uint32_t buffer_id_; + DISALLOW_COPY_AND_ASSIGN(GbmPixmapWayland); }; 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 24df94f3836..95c840cbf77 100644 --- a/chromium/ui/ozone/platform/wayland/gpu/gbm_surfaceless_wayland.cc +++ b/chromium/ui/ozone/platform/wayland/gpu/gbm_surfaceless_wayland.cc @@ -8,6 +8,7 @@ #include "base/bind.h" #include "base/task/post_task.h" +#include "base/task/thread_pool.h" #include "base/trace_event/trace_event.h" #include "ui/gfx/gpu_fence.h" #include "ui/ozone/common/egl_util.h" @@ -38,8 +39,9 @@ GbmSurfacelessWayland::GbmSurfacelessWayland( unsubmitted_frames_.push_back(std::make_unique<PendingFrame>()); } -void GbmSurfacelessWayland::QueueOverlayPlane(OverlayPlane plane) { - planes_.push_back(std::move(plane)); +void GbmSurfacelessWayland::QueueOverlayPlane(OverlayPlane plane, + uint32_t buffer_id) { + planes_.push_back({std::move(plane), buffer_id}); } bool GbmSurfacelessWayland::ScheduleOverlayPlane( @@ -93,7 +95,8 @@ void GbmSurfacelessWayland::SwapBuffersAsync( // TODO(dcastagna): remove glFlush since eglImageFlushExternalEXT called on // the image should be enough (https://crbug.com/720045). - glFlush(); + if (!no_gl_flush_for_tests_) + glFlush(); unsubmitted_frames_.back()->Flush(); PendingFrame* frame = unsubmitted_frames_.back().get(); @@ -118,11 +121,10 @@ void GbmSurfacelessWayland::SwapBuffersAsync( base::OnceClosure fence_retired_callback = base::BindOnce( &GbmSurfacelessWayland::FenceRetired, weak_factory_.GetWeakPtr(), frame); - base::PostTaskAndReply(FROM_HERE, - {base::ThreadPool(), base::MayBlock(), - base::TaskShutdownBehavior::CONTINUE_ON_SHUTDOWN}, - std::move(fence_wait_task), - std::move(fence_retired_callback)); + base::ThreadPool::PostTaskAndReply( + FROM_HERE, + {base::MayBlock(), base::TaskShutdownBehavior::CONTINUE_ON_SHUTDOWN}, + std::move(fence_wait_task), std::move(fence_retired_callback)); } void GbmSurfacelessWayland::PostSubBufferAsync( @@ -165,6 +167,12 @@ void GbmSurfacelessWayland::SetRelyOnImplicitSync() { use_egl_fence_sync_ = false; } +gfx::SurfaceOrigin GbmSurfacelessWayland::GetOrigin() const { + // GbmSurfacelessWayland's y-axis is flipped compare to GL - (0,0) is at top + // left corner. + return gfx::SurfaceOrigin::kTopLeft; +} + GbmSurfacelessWayland::~GbmSurfacelessWayland() { buffer_manager_->UnregisterSurface(widget_); } @@ -209,7 +217,7 @@ void GbmSurfacelessWayland::SubmitFrame() { return; } - submitted_frame_->buffer_id = planes_.back().pixmap->GetUniqueId(); + submitted_frame_->buffer_id = planes_.back().buffer_id; buffer_manager_->CommitBuffer(widget_, submitted_frame_->buffer_id, submitted_frame_->damage_region_); @@ -230,6 +238,10 @@ void GbmSurfacelessWayland::FenceRetired(PendingFrame* frame) { SubmitFrame(); } +void GbmSurfacelessWayland::SetNoGLFlushForTests() { + no_gl_flush_for_tests_ = true; +} + void GbmSurfacelessWayland::OnSubmission(uint32_t buffer_id, const gfx::SwapResult& swap_result) { submitted_frame_->overlays.clear(); 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 0f584991f60..991d1718fad 100644 --- a/chromium/ui/ozone/platform/wayland/gpu/gbm_surfaceless_wayland.h +++ b/chromium/ui/ozone/platform/wayland/gpu/gbm_surfaceless_wayland.h @@ -29,7 +29,7 @@ class GbmSurfacelessWayland : public gl::SurfacelessEGL, GbmSurfacelessWayland(WaylandBufferManagerGpu* buffer_manager, gfx::AcceleratedWidget widget); - void QueueOverlayPlane(OverlayPlane plane); + void QueueOverlayPlane(OverlayPlane plane, uint32_t buffer_id); // gl::GLSurface: bool ScheduleOverlayPlane(int z_order, @@ -57,8 +57,12 @@ class GbmSurfacelessWayland : public gl::SurfacelessEGL, PresentationCallback presentation_callback) override; EGLConfig GetConfig() override; void SetRelyOnImplicitSync() override; + gfx::SurfaceOrigin GetOrigin() const override; private: + FRIEND_TEST_ALL_PREFIXES(WaylandSurfaceFactoryTest, + GbmSurfacelessWaylandCheckOrderOfCallbacksTest); + ~GbmSurfacelessWayland() override; // WaylandSurfaceGpu overrides: @@ -88,13 +92,21 @@ class GbmSurfacelessWayland : public gl::SurfacelessEGL, PresentationCallback presentation_callback; }; + struct PlaneData { + OverlayPlane plane; + const uint32_t buffer_id; + }; + void SubmitFrame(); EGLSyncKHR InsertFence(bool implicit); void FenceRetired(PendingFrame* frame); + // Sets a flag that skips glFlush step in unittests. + void SetNoGLFlushForTests(); + WaylandBufferManagerGpu* const buffer_manager_; - std::vector<OverlayPlane> planes_; + std::vector<PlaneData> planes_; // The native surface. Deleting this is allowed to free the EGLNativeWindow. gfx::AcceleratedWidget widget_; @@ -105,6 +117,8 @@ class GbmSurfacelessWayland : public gl::SurfacelessEGL, bool last_swap_buffers_result_ = true; bool use_egl_fence_sync_ = true; + bool no_gl_flush_for_tests_ = false; + base::WeakPtrFactory<GbmSurfacelessWayland> weak_factory_; DISALLOW_COPY_AND_ASSIGN(GbmSurfacelessWayland); diff --git a/chromium/ui/ozone/platform/wayland/gpu/gl_surface_egl_readback_wayland.cc b/chromium/ui/ozone/platform/wayland/gpu/gl_surface_egl_readback_wayland.cc new file mode 100644 index 00000000000..700cb969edf --- /dev/null +++ b/chromium/ui/ozone/platform/wayland/gpu/gl_surface_egl_readback_wayland.cc @@ -0,0 +1,178 @@ +// 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/gpu/gl_surface_egl_readback_wayland.h" + +#include "base/memory/shared_memory_mapping.h" +#include "base/memory/unsafe_shared_memory_region.h" +#include "base/numerics/checked_math.h" +#include "ui/ozone/platform/wayland/gpu/wayland_buffer_manager_gpu.h" + +namespace ui { + +namespace { + +constexpr size_t kMaxBuffers = 2; + +constexpr size_t kBytesPerPixelBGRA = 4; + +} // namespace + +GLSurfaceEglReadbackWayland::PixelBuffer::PixelBuffer( + base::WritableSharedMemoryMapping shm_mapping, + uint32_t buffer_id) + : shm_mapping_(std::move(shm_mapping)), buffer_id_(buffer_id) {} + +GLSurfaceEglReadbackWayland::PixelBuffer::~PixelBuffer() = default; + +GLSurfaceEglReadbackWayland::GLSurfaceEglReadbackWayland( + gfx::AcceleratedWidget widget, + WaylandBufferManagerGpu* buffer_manager) + : PbufferGLSurfaceEGL(gfx::Size(1, 1)), + widget_(widget), + buffer_manager_(buffer_manager) { + buffer_manager_->RegisterSurface(widget_, this); +} + +void GLSurfaceEglReadbackWayland::Destroy() { + DestroyBuffers(); + buffer_manager_->UnregisterSurface(widget_); + + PbufferGLSurfaceEGL::Destroy(); +} + +bool GLSurfaceEglReadbackWayland::Resize(const gfx::Size& size, + float scale_factor, + const gfx::ColorSpace& color_space, + bool has_alpha) { + DestroyBuffers(); + + pending_frames_ = 0; + + if (!PbufferGLSurfaceEGL::Resize(size, scale_factor, color_space, has_alpha)) + return false; + + for (size_t i = 0; i < kMaxBuffers; ++i) { + base::CheckedNumeric<size_t> checked_length(size.width()); + checked_length *= size.height(); + checked_length *= kBytesPerPixelBGRA; + if (!checked_length.IsValid()) + return false; + + base::UnsafeSharedMemoryRegion shm_region = + base::UnsafeSharedMemoryRegion::Create(checked_length.ValueOrDie()); + if (!shm_region.IsValid()) + return false; + + auto shm_mapping = shm_region.Map(); + if (!shm_mapping.IsValid()) + return false; + + base::subtle::PlatformSharedMemoryRegion platform_shm = + base::UnsafeSharedMemoryRegion::TakeHandleForSerialization( + std::move(shm_region)); + base::subtle::ScopedFDPair fd_pair = platform_shm.PassPlatformHandle(); + + auto buffer_id = buffer_manager_->AllocateBufferID(); + available_buffers_.push_back( + std::make_unique<PixelBuffer>(std::move(shm_mapping), buffer_id)); + + buffer_manager_->CreateShmBasedBuffer( + std::move(fd_pair.fd), checked_length.ValueOrDie(), size, buffer_id); + } + + return true; +} + +bool GLSurfaceEglReadbackWayland::IsOffscreen() { + return false; +} + +bool GLSurfaceEglReadbackWayland::SupportsAsyncSwap() { + return true; +} + +gfx::SwapResult GLSurfaceEglReadbackWayland::SwapBuffers( + PresentationCallback callback) { + NOTREACHED(); + return gfx::SwapResult::SWAP_FAILED; +} + +void GLSurfaceEglReadbackWayland::SwapBuffersAsync( + SwapCompletionCallback completion_callback, + PresentationCallback presentation_callback) { + DCHECK(pending_frames_ < kMaxBuffers); + + // Increase pending frames number. + ++pending_frames_; + + completion_callbacks_.push_back(std::move(completion_callback)); + presentation_callbacks_.push_back(std::move(presentation_callback)); + + DCHECK(!available_buffers_.empty()); + in_flight_pixel_buffers_.push_back(std::move(available_buffers_.front())); + auto* next_buffer = in_flight_pixel_buffers_.back().get(); + available_buffers_.erase(available_buffers_.begin()); + + const gfx::Size size = GetSize(); + CHECK(next_buffer->shm_mapping_.memory()); + glReadPixels(0, 0, size.width(), size.height(), GL_BGRA, GL_UNSIGNED_BYTE, + next_buffer->shm_mapping_.memory()); + + buffer_manager_->CommitBuffer(widget_, next_buffer->buffer_id_, + {{0, 0}, size}); +} + +gfx::SurfaceOrigin GLSurfaceEglReadbackWayland::GetOrigin() const { + // GLSurfaceEglReadbackWayland's y-axis is flipped compare to GL - (0,0) is at + // top left corner. + return gfx::SurfaceOrigin::kTopLeft; +} + +GLSurfaceEglReadbackWayland::~GLSurfaceEglReadbackWayland() { + Destroy(); +} + +void GLSurfaceEglReadbackWayland::OnSubmission( + uint32_t buffer_id, + const gfx::SwapResult& swap_result) { + --pending_frames_; + + if (in_flight_pixel_buffers_.front()) { + if (displayed_buffer_) + available_buffers_.push_back(std::move(displayed_buffer_)); + displayed_buffer_ = std::move(in_flight_pixel_buffers_.front()); + DCHECK_EQ(displayed_buffer_->buffer_id_, buffer_id); + } + + in_flight_pixel_buffers_.pop_front(); + + DCHECK(!completion_callbacks_.empty()); + std::move(completion_callbacks_.front()).Run(swap_result, nullptr); + completion_callbacks_.erase(completion_callbacks_.begin()); +} + +void GLSurfaceEglReadbackWayland::OnPresentation( + uint32_t buffer_id, + const gfx::PresentationFeedback& feedback) { + DCHECK(!presentation_callbacks_.empty()); + std::move(presentation_callbacks_.front()).Run(feedback); + presentation_callbacks_.erase(presentation_callbacks_.begin()); +} + +void GLSurfaceEglReadbackWayland::DestroyBuffers() { + for (const auto& pixel_buffer : available_buffers_) + buffer_manager_->DestroyBuffer(widget_, pixel_buffer->buffer_id_); + for (const auto& pixel_buffer : in_flight_pixel_buffers_) + buffer_manager_->DestroyBuffer(widget_, pixel_buffer->buffer_id_); + + if (displayed_buffer_) + buffer_manager_->DestroyBuffer(widget_, displayed_buffer_->buffer_id_); + + available_buffers_.clear(); + in_flight_pixel_buffers_.clear(); + displayed_buffer_.reset(); +} + +} // namespace ui diff --git a/chromium/ui/ozone/platform/wayland/gpu/gl_surface_egl_readback_wayland.h b/chromium/ui/ozone/platform/wayland/gpu/gl_surface_egl_readback_wayland.h new file mode 100644 index 00000000000..de83a75b2a6 --- /dev/null +++ b/chromium/ui/ozone/platform/wayland/gpu/gl_surface_egl_readback_wayland.h @@ -0,0 +1,95 @@ +// 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_GPU_GL_SURFACE_EGL_READBACK_WAYLAND_H_ +#define UI_OZONE_PLATFORM_WAYLAND_GPU_GL_SURFACE_EGL_READBACK_WAYLAND_H_ + +#include "base/containers/circular_deque.h" +#include "base/containers/flat_map.h" +#include "base/memory/shared_memory_mapping.h" +#include "ui/ozone/common/gl_surface_egl_readback.h" +#include "ui/ozone/platform/wayland/gpu/wayland_surface_gpu.h" + +namespace ui { + +class WaylandBufferManagerGpu; + +// GLSurface implementation that copies pixels from readback to shared memory +// and let Wayland compositor to present them. +class GLSurfaceEglReadbackWayland : public gl::PbufferGLSurfaceEGL, + public WaylandSurfaceGpu { + public: + GLSurfaceEglReadbackWayland(gfx::AcceleratedWidget widget, + WaylandBufferManagerGpu* buffer_manager); + GLSurfaceEglReadbackWayland(const GLSurfaceEglReadbackWayland&) = delete; + GLSurfaceEglReadbackWayland& operator=(const GLSurfaceEglReadbackWayland&) = + delete; + + // gl::GLSurface: + void Destroy() override; + bool Resize(const gfx::Size& size, + float scale_factor, + const gfx::ColorSpace& color_space, + bool has_alpha) override; + bool IsOffscreen() override; + gfx::SwapResult SwapBuffers(PresentationCallback callback) override; + bool SupportsAsyncSwap() override; + void SwapBuffersAsync(SwapCompletionCallback completion_callback, + PresentationCallback presentation_callback) override; + gfx::SurfaceOrigin GetOrigin() const override; + + private: + struct PixelBuffer { + PixelBuffer(base::WritableSharedMemoryMapping shm_mapping, + uint32_t buffer_id); + ~PixelBuffer(); + PixelBuffer(const PixelBuffer&) = delete; + PixelBuffer& operator=(const PixelBuffer&) = delete; + + // Shared memory mapping that readback pixels are written to so that Wayland + // is able to turn them in light. + base::WritableSharedMemoryMapping shm_mapping_; + + // The buffer id that corresponds to the |wl_buffer| created on the browser + // process side. + uint32_t buffer_id_ = 0; + }; + + ~GLSurfaceEglReadbackWayland() override; + + // WaylandSurfaceGpu: + void OnSubmission(uint32_t buffer_id, + const gfx::SwapResult& swap_result) override; + void OnPresentation(uint32_t buffer_id, + const gfx::PresentationFeedback& feedback) override; + + void DestroyBuffers(); + + // Widget of the window that this readback writes pixels to. + const gfx::AcceleratedWidget widget_; + + WaylandBufferManagerGpu* const buffer_manager_; + + // Size of the buffer. + gfx::Size size_; + + // Available pixel buffers based on shared memory. + std::vector<std::unique_ptr<PixelBuffer>> available_buffers_; + + // Displayed buffer that will become available after another buffer is + // submitted. + std::unique_ptr<PixelBuffer> displayed_buffer_; + + // Submitted buffers waiting to be displayed. + base::circular_deque<std::unique_ptr<PixelBuffer>> in_flight_pixel_buffers_; + + std::vector<SwapCompletionCallback> completion_callbacks_; + std::vector<PresentationCallback> presentation_callbacks_; + + size_t pending_frames_ = 0; +}; + +} // namespace ui + +#endif // UI_OZONE_PLATFORM_WAYLAND_GPU_GL_SURFACE_EGL_READBACK_WAYLAND_H_ diff --git a/chromium/ui/ozone/platform/wayland/gpu/gl_surface_wayland.cc b/chromium/ui/ozone/platform/wayland/gpu/gl_surface_wayland.cc index 22d06a8affe..02ec5b8088e 100644 --- a/chromium/ui/ozone/platform/wayland/gpu/gl_surface_wayland.cc +++ b/chromium/ui/ozone/platform/wayland/gpu/gl_surface_wayland.cc @@ -35,7 +35,7 @@ GLSurfaceWayland::GLSurfaceWayland(WaylandEglWindowPtr egl_window) bool GLSurfaceWayland::Resize(const gfx::Size& size, float scale_factor, - ColorSpace color_space, + const gfx::ColorSpace& color_space, bool has_alpha) { if (size_ == size) return true; diff --git a/chromium/ui/ozone/platform/wayland/gpu/gl_surface_wayland.h b/chromium/ui/ozone/platform/wayland/gpu/gl_surface_wayland.h index 4b9b15ea92d..87a7da0d18b 100644 --- a/chromium/ui/ozone/platform/wayland/gpu/gl_surface_wayland.h +++ b/chromium/ui/ozone/platform/wayland/gpu/gl_surface_wayland.h @@ -34,7 +34,7 @@ class GLSurfaceWayland : public gl::NativeViewGLSurfaceEGL { // gl::GLSurface: bool Resize(const gfx::Size& size, float scale_factor, - ColorSpace color_space, + const gfx::ColorSpace& color_space, bool has_alpha) override; EGLConfig GetConfig() override; 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 86980f3d598..6adfc621532 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 @@ -9,8 +9,7 @@ #include "base/bind.h" #include "base/message_loop/message_loop_current.h" #include "base/process/process.h" -#include "mojo/public/cpp/system/platform_handle.h" -#include "ui/ozone/common/linux/drm_util_linux.h" +#include "ui/gfx/linux/drm_util_linux.h" #include "ui/ozone/platform/wayland/gpu/wayland_surface_gpu.h" namespace ui { @@ -158,6 +157,10 @@ WaylandBufferManagerGpu::GetModifiersForBufferFormat( return dummy; } +uint32_t WaylandBufferManagerGpu::AllocateBufferID() { + return ++next_buffer_id_; +} + void WaylandBufferManagerGpu::CreateDmabufBasedBufferInternal( base::ScopedFD dmabuf_fd, gfx::Size size, @@ -170,9 +173,8 @@ void WaylandBufferManagerGpu::CreateDmabufBasedBufferInternal( DCHECK(io_thread_runner_->BelongsToCurrentThread()); DCHECK(remote_host_); remote_host_->CreateDmabufBasedBuffer( - mojo::WrapPlatformHandle(mojo::PlatformHandle(std::move(dmabuf_fd))), - size, strides, offsets, modifiers, current_format, planes_count, - buffer_id); + mojo::PlatformHandle(std::move(dmabuf_fd)), size, strides, offsets, + modifiers, current_format, planes_count, buffer_id); } void WaylandBufferManagerGpu::CreateShmBasedBufferInternal( @@ -182,9 +184,8 @@ void WaylandBufferManagerGpu::CreateShmBasedBufferInternal( uint32_t buffer_id) { DCHECK(io_thread_runner_->BelongsToCurrentThread()); DCHECK(remote_host_); - remote_host_->CreateShmBasedBuffer( - mojo::WrapPlatformHandle(mojo::PlatformHandle(std::move(shm_fd))), length, - size, buffer_id); + remote_host_->CreateShmBasedBuffer(mojo::PlatformHandle(std::move(shm_fd)), + length, size, buffer_id); } void WaylandBufferManagerGpu::CommitBufferInternal( diff --git a/chromium/ui/ozone/platform/wayland/gpu/wayland_buffer_manager_gpu.h b/chromium/ui/ozone/platform/wayland/gpu/wayland_buffer_manager_gpu.h index e998717b692..819d64a9834 100644 --- a/chromium/ui/ozone/platform/wayland/gpu/wayland_buffer_manager_gpu.h +++ b/chromium/ui/ozone/platform/wayland/gpu/wayland_buffer_manager_gpu.h @@ -19,7 +19,7 @@ #include "ui/ozone/public/mojom/wayland/wayland_buffer_manager.mojom.h" #if defined(WAYLAND_GBM) -#include "ui/ozone/common/linux/gbm_device.h" // nogncheck +#include "ui/gfx/linux/gbm_device.h" // nogncheck #endif namespace gfx { @@ -123,6 +123,9 @@ class WaylandBufferManagerGpu : public ozone::mojom::WaylandBufferManagerGpu { const std::vector<uint64_t>& GetModifiersForBufferFormat( gfx::BufferFormat buffer_format) const; + // Allocates a unique buffer ID. + uint32_t AllocateBufferID(); + private: void CreateDmabufBasedBufferInternal(base::ScopedFD dmabuf_fd, gfx::Size size, @@ -193,6 +196,9 @@ class WaylandBufferManagerGpu : public ozone::mojom::WaylandBufferManagerGpu { // Protects access to |widget_to_surface_map_|. base::Lock lock_; + // Keeps track of the next unique buffer ID. + uint32_t next_buffer_id_ = 0; + DISALLOW_COPY_AND_ASSIGN(WaylandBufferManagerGpu); }; diff --git a/chromium/ui/ozone/platform/wayland/gpu/wayland_canvas_surface.cc b/chromium/ui/ozone/platform/wayland/gpu/wayland_canvas_surface.cc index fe1040e5263..09cfac561f6 100644 --- a/chromium/ui/ozone/platform/wayland/gpu/wayland_canvas_surface.cc +++ b/chromium/ui/ozone/platform/wayland/gpu/wayland_canvas_surface.cc @@ -35,10 +35,9 @@ size_t CalculateStride(int width) { class WaylandCanvasSurface::SharedMemoryBuffer { public: - SharedMemoryBuffer(uint32_t buffer_id, - gfx::AcceleratedWidget widget, + SharedMemoryBuffer(gfx::AcceleratedWidget widget, WaylandBufferManagerGpu* buffer_manager) - : buffer_id_(buffer_id), + : buffer_id_(buffer_manager->AllocateBufferID()), widget_(widget), buffer_manager_(buffer_manager) { DCHECK(buffer_manager_); @@ -51,9 +50,8 @@ class WaylandCanvasSurface::SharedMemoryBuffer { // Returns the id of the buffer. uint32_t buffer_id() const { return buffer_id_; } - // Tells if the buffer is pending to be processed. Set on - // SetPendingDamageRegion calls. - bool pending() const { return pending_; } + // Tells if the buffer is currently being used. + bool used() const { return used_; } // Initializes the shared memory and asks Wayland to import a shared memory // based wl_buffer, which can be attached to a surface and have its contents @@ -95,9 +93,14 @@ class WaylandCanvasSurface::SharedMemoryBuffer { buffer_manager_->CommitBuffer(widget_, buffer_id_, damage); } - void OnSubmissionCompleted() { - DCHECK(pending_); - pending_ = false; + void OnUse() { + DCHECK(!used_); + used_ = true; + } + + void OnRelease() { + DCHECK(used_); + used_ = false; } void UpdateDirtyRegion(const gfx::Rect& damage, SkRegion::Op op) { @@ -120,22 +123,20 @@ class WaylandCanvasSurface::SharedMemoryBuffer { dirty_region_.setEmpty(); } - void SetPendingDamageRegion(const gfx::Rect& damage) { - DCHECK(!pending_); + void set_pending_damage_region(const gfx::Rect& damage) { pending_damage_region_ = damage; - pending_ = true; } - gfx::Rect pending_damage_region() { - return std::move(pending_damage_region_); + const gfx::Rect& pending_damage_region() const { + return pending_damage_region_; } private: // The id of the buffer this surface is backed. const uint32_t buffer_id_; - // Says if the buffer is pending to be submitted. - bool pending_ = false; + // Whether this buffer is currently being used. + bool used_ = false; // The widget this buffer is created for. const gfx::AcceleratedWidget widget_; @@ -169,12 +170,12 @@ WaylandCanvasSurface::~WaylandCanvasSurface() { buffer_manager_->UnregisterSurface(widget_); } -sk_sp<SkSurface> WaylandCanvasSurface::GetSurface() { +SkCanvas* WaylandCanvasSurface::GetCanvas() { DCHECK(!pending_buffer_) << "The previous pending buffer has not been presented yet"; for (const auto& buffer : buffers_) { - if (!buffer->pending()) { + if (!buffer->used()) { pending_buffer_ = buffer.get(); break; } @@ -194,8 +195,9 @@ sk_sp<SkSurface> WaylandCanvasSurface::GetSurface() { buffers_.push_back(std::move(buffer)); } - DCHECK(pending_buffer_ && !pending_buffer_->pending()); - return pending_buffer_->sk_surface(); + DCHECK(pending_buffer_); + pending_buffer_->OnUse(); + return pending_buffer_->sk_surface()->getCanvas(); } void WaylandCanvasSurface::ResizeCanvas(const gfx::Size& viewport_size) { @@ -205,13 +207,11 @@ void WaylandCanvasSurface::ResizeCanvas(const gfx::Size& viewport_size) { // by allocating buffers rounded up to larger sizes, and then reusing them if // the new size still fits (but still reallocate if the new size is much // smaller than the old size). - if (!buffers_.empty()) { - buffers_.clear(); - current_buffer_ = nullptr; - previous_buffer_ = nullptr; - pending_buffer_ = nullptr; - unsubmitted_buffers_.clear(); - } + buffers_.clear(); + current_buffer_ = nullptr; + previous_buffer_ = nullptr; + pending_buffer_ = nullptr; + unsubmitted_buffers_.clear(); size_ = viewport_size; } @@ -219,7 +219,7 @@ void WaylandCanvasSurface::PresentCanvas(const gfx::Rect& damage) { if (!pending_buffer_) return; - pending_buffer_->SetPendingDamageRegion(damage); + pending_buffer_->set_pending_damage_region(damage); unsubmitted_buffers_.push_back(pending_buffer_); pending_buffer_ = nullptr; @@ -235,49 +235,61 @@ WaylandCanvasSurface::CreateVSyncProvider() { } void WaylandCanvasSurface::ProcessUnsubmittedBuffers() { - DCHECK(!unsubmitted_buffers_.empty()); + DCHECK(!unsubmitted_buffers_.empty() && unsubmitted_buffers_.front()->used()); - if (!current_buffer_ && unsubmitted_buffers_.front()->pending()) { - current_buffer_ = std::move(unsubmitted_buffers_.front()); - unsubmitted_buffers_.erase(unsubmitted_buffers_.begin()); + // Don't submit a new buffer if there's one already submitted being + // processed. + if (current_buffer_) + return; - gfx::Rect damage = current_buffer_->pending_damage_region(); + current_buffer_ = std::move(unsubmitted_buffers_.front()); + unsubmitted_buffers_.erase(unsubmitted_buffers_.begin()); - // The buffer has been updated. Thus, the |damage| can be subtracted - // from its dirty region. - current_buffer_->UpdateDirtyRegion(damage, SkRegion::kDifference_Op); + gfx::Rect damage = current_buffer_->pending_damage_region(); - // Make sure the buffer is up-to-date by copying the outdated region from - // the previous buffer. - if (previous_buffer_ && previous_buffer_ != current_buffer_) - current_buffer_->CopyDirtyRegionFrom(previous_buffer_); + // The buffer has been updated. Thus, the |damage| can be subtracted + // from its dirty region. + current_buffer_->UpdateDirtyRegion(damage, SkRegion::kDifference_Op); - // As long as the |current_buffer_| has been updated, add dirty region to - // other buffers to make sure their regions will be updated with up-to-date - // content. - for (auto& buffer : buffers_) { - if (buffer.get() != current_buffer_) - buffer->UpdateDirtyRegion(damage, SkRegion::kUnion_Op); - } + // Make sure the buffer is up-to-date by copying the outdated region from + // the previous buffer. + if (previous_buffer_ && previous_buffer_ != current_buffer_) + current_buffer_->CopyDirtyRegionFrom(previous_buffer_); - current_buffer_->CommitBuffer(damage); + // As long as the |current_buffer_| has been updated, add dirty region to + // other buffers to make sure their regions will be updated with up-to-date + // content. + for (auto& buffer : buffers_) { + if (buffer.get() != current_buffer_) + buffer->UpdateDirtyRegion(damage, SkRegion::kUnion_Op); } + + current_buffer_->CommitBuffer(damage); } void WaylandCanvasSurface::OnSubmission(uint32_t buffer_id, const gfx::SwapResult& swap_result) { - // Upper layer does not care about the submission result, and the buffer may - // be destroyed by this time (when the surface is resized, for example). - if (!current_buffer_) + // We may get an OnSubmission callback for a buffer that was submitted + // before a ResizeCanvas call, which clears all our buffers. Check to + // see if we still know about this buffer. If we know about this buffer + // it must be |current_buffer_| because we only submit new buffers when + // |current_buffer_| is nullptr, and it is only set to nullptr in + // |OnSubmission| and |ResizeCanvas|. In |ResizeCanvas|, |buffers_| is cleared + // so we will not know about |buffer_id|. + if (std::none_of(buffers_.begin(), buffers_.end(), + [buffer_id](const auto& buffer) { + return buffer->buffer_id() == buffer_id; + })) return; + DCHECK(current_buffer_); DCHECK_EQ(current_buffer_->buffer_id(), buffer_id); - auto* buffer = current_buffer_; - previous_buffer_ = buffer; - current_buffer_ = nullptr; + if (previous_buffer_) + previous_buffer_->OnRelease(); - buffer->OnSubmissionCompleted(); + previous_buffer_ = current_buffer_; + current_buffer_ = nullptr; if (!unsubmitted_buffers_.empty()) ProcessUnsubmittedBuffers(); @@ -294,8 +306,8 @@ std::unique_ptr<WaylandCanvasSurface::SharedMemoryBuffer> WaylandCanvasSurface::CreateSharedMemoryBuffer() { DCHECK(!size_.IsEmpty()); - auto canvas_buffer = std::make_unique<SharedMemoryBuffer>( - ++buffer_id_, widget_, buffer_manager_); + auto canvas_buffer = + std::make_unique<SharedMemoryBuffer>(widget_, buffer_manager_); return canvas_buffer->Initialize(size_) ? std::move(canvas_buffer) : nullptr; } diff --git a/chromium/ui/ozone/platform/wayland/gpu/wayland_canvas_surface.h b/chromium/ui/ozone/platform/wayland/gpu/wayland_canvas_surface.h index a7596721ddd..054e27de8f1 100644 --- a/chromium/ui/ozone/platform/wayland/gpu/wayland_canvas_surface.h +++ b/chromium/ui/ozone/platform/wayland/gpu/wayland_canvas_surface.h @@ -15,6 +15,8 @@ #include "ui/ozone/platform/wayland/gpu/wayland_surface_gpu.h" #include "ui/ozone/public/surface_ozone_canvas.h" +class SkCanvas; + namespace ui { class WaylandBufferManagerGpu; @@ -31,7 +33,7 @@ class WaylandCanvasSurface : public SurfaceOzoneCanvas, ~WaylandCanvasSurface() override; // SurfaceOzoneCanvas - sk_sp<SkSurface> GetSurface() override; + SkCanvas* GetCanvas() override; void ResizeCanvas(const gfx::Size& viewport_size) override; void PresentCanvas(const gfx::Rect& damage) override; std::unique_ptr<gfx::VSyncProvider> CreateVSyncProvider() override; @@ -73,11 +75,6 @@ class WaylandCanvasSurface : public SurfaceOzoneCanvas, // Previously used buffer. Set on OnSubmission(). SharedMemoryBuffer* previous_buffer_ = nullptr; - // The id of the current existing buffer. Even though, there can only be one - // buffer (SkSurface) at a time, the buffer manager on the browser process - // side requires buffer id to be passed. - uint32_t buffer_id_ = 0; - DISALLOW_COPY_AND_ASSIGN(WaylandCanvasSurface); }; diff --git a/chromium/ui/ozone/platform/wayland/gpu/wayland_surface_factory.cc b/chromium/ui/ozone/platform/wayland/gpu/wayland_surface_factory.cc index 99ed42401c0..b8258fda199 100644 --- a/chromium/ui/ozone/platform/wayland/gpu/wayland_surface_factory.cc +++ b/chromium/ui/ozone/platform/wayland/gpu/wayland_surface_factory.cc @@ -11,6 +11,7 @@ #include "ui/ozone/common/egl_util.h" #include "ui/ozone/common/gl_ozone_egl.h" #include "ui/ozone/platform/wayland/common/wayland_object.h" +#include "ui/ozone/platform/wayland/gpu/gl_surface_egl_readback_wayland.h" #include "ui/ozone/platform/wayland/gpu/gl_surface_wayland.h" #include "ui/ozone/platform/wayland/gpu/wayland_buffer_manager_gpu.h" #include "ui/ozone/platform/wayland/gpu/wayland_canvas_surface.h" @@ -45,7 +46,7 @@ class GLOzoneEGLWayland : public GLOzoneEGL { const gfx::Size& size) override; protected: - intptr_t GetNativeDisplay() override; + gl::EGLDisplayPlatform GetNativeDisplay() override; bool LoadGLES2Bindings(gl::GLImplementation impl) override; private: @@ -77,10 +78,11 @@ scoped_refptr<gl::GLSurface> GLOzoneEGLWayland::CreateViewGLSurface( scoped_refptr<gl::GLSurface> GLOzoneEGLWayland::CreateSurfacelessViewGLSurface( gfx::AcceleratedWidget window) { - // Only EGLGLES2 is supported with surfaceless view gl. - if (gl::GetGLImplementation() != gl::kGLImplementationEGLGLES2) - return nullptr; - + if (gl::GetGLImplementation() == gl::kGLImplementationSwiftShaderGL) { + return gl::InitializeGLSurface( + base::MakeRefCounted<GLSurfaceEglReadbackWayland>(window, + buffer_manager_)); + } else { #if defined(WAYLAND_GBM) // If there is a gbm device available, use surfaceless gl surface. if (!buffer_manager_->gbm_device()) @@ -90,6 +92,7 @@ scoped_refptr<gl::GLSurface> GLOzoneEGLWayland::CreateSurfacelessViewGLSurface( #else return nullptr; #endif + } } scoped_refptr<gl::GLSurface> GLOzoneEGLWayland::CreateOffscreenGLSurface( @@ -102,10 +105,11 @@ scoped_refptr<gl::GLSurface> GLOzoneEGLWayland::CreateOffscreenGLSurface( } } -intptr_t GLOzoneEGLWayland::GetNativeDisplay() { +gl::EGLDisplayPlatform GLOzoneEGLWayland::GetNativeDisplay() { if (connection_) - return reinterpret_cast<intptr_t>(connection_->display()); - return EGL_DEFAULT_DISPLAY; + return gl::EGLDisplayPlatform( + reinterpret_cast<EGLNativeDisplayType>(connection_->display())); + return gl::EGLDisplayPlatform(EGL_DEFAULT_DISPLAY); } bool GLOzoneEGLWayland::LoadGLES2Bindings(gl::GLImplementation impl) { @@ -128,8 +132,9 @@ WaylandSurfaceFactory::WaylandSurfaceFactory( WaylandSurfaceFactory::~WaylandSurfaceFactory() = default; std::unique_ptr<SurfaceOzoneCanvas> -WaylandSurfaceFactory::CreateCanvasForWidget(gfx::AcceleratedWidget widget, - base::TaskRunner* task_runner) { +WaylandSurfaceFactory::CreateCanvasForWidget( + gfx::AcceleratedWidget widget, + scoped_refptr<base::SequencedTaskRunner> task_runner) { return std::make_unique<WaylandCanvasSurface>(buffer_manager_, widget); } @@ -159,7 +164,9 @@ scoped_refptr<gfx::NativePixmap> WaylandSurfaceFactory::CreateNativePixmap( VkDevice vk_device, gfx::Size size, gfx::BufferFormat format, - gfx::BufferUsage usage) { + gfx::BufferUsage usage, + base::Optional<gfx::Size> framebuffer_size) { + DCHECK(!framebuffer_size || framebuffer_size == size); #if defined(WAYLAND_GBM) scoped_refptr<GbmPixmapWayland> pixmap = base::MakeRefCounted<GbmPixmapWayland>(buffer_manager_); diff --git a/chromium/ui/ozone/platform/wayland/gpu/wayland_surface_factory.h b/chromium/ui/ozone/platform/wayland/gpu/wayland_surface_factory.h index 07c132c2021..51e7f9ecf95 100644 --- a/chromium/ui/ozone/platform/wayland/gpu/wayland_surface_factory.h +++ b/chromium/ui/ozone/platform/wayland/gpu/wayland_surface_factory.h @@ -31,13 +31,14 @@ class WaylandSurfaceFactory : public SurfaceFactoryOzone { GLOzone* GetGLOzone(gl::GLImplementation implementation) override; std::unique_ptr<SurfaceOzoneCanvas> CreateCanvasForWidget( gfx::AcceleratedWidget widget, - base::TaskRunner* task_runner) override; + scoped_refptr<base::SequencedTaskRunner> task_runner) override; scoped_refptr<gfx::NativePixmap> CreateNativePixmap( gfx::AcceleratedWidget widget, VkDevice vk_device, gfx::Size size, gfx::BufferFormat format, - gfx::BufferUsage usage) override; + gfx::BufferUsage usage, + base::Optional<gfx::Size> framebuffer_size = base::nullopt) override; void CreateNativePixmapAsync(gfx::AcceleratedWidget widget, VkDevice vk_device, gfx::Size size, 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 448a4a7c476..585e5666283 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 @@ -5,17 +5,24 @@ #include <memory> #include <utility> +#include "base/memory/scoped_refptr.h" #include "base/run_loop.h" +#include "base/test/mock_callback.h" #include "testing/gtest/include/gtest/gtest.h" #include "third_party/skia/include/core/SkSurface.h" -#include "ui/ozone/common/linux/gbm_buffer.h" -#include "ui/ozone/common/linux/gbm_device.h" +#include "ui/gfx/linux/gbm_buffer.h" +#include "ui/gfx/linux/gbm_device.h" +#include "ui/gfx/linux/test/mock_gbm_device.h" +#include "ui/gfx/native_pixmap.h" +#include "ui/gl/gl_image_egl.h" +#include "ui/ozone/platform/wayland/gpu/gbm_surfaceless_wayland.h" #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_window.h" #include "ui/ozone/platform/wayland/test/mock_surface.h" #include "ui/ozone/platform/wayland/test/test_wayland_server_thread.h" +#include "ui/ozone/platform/wayland/test/test_zwp_linux_buffer_params.h" #include "ui/ozone/platform/wayland/test/wayland_test.h" #include "ui/ozone/public/surface_ozone_canvas.h" #include "ui/ozone/test/mock_platform_window_delegate.h" @@ -28,62 +35,128 @@ namespace ui { namespace { -class FakeGbmBuffer : public GbmBuffer { +// Fake GLImage that just schedules overlay plane. It must become busy when +// scheduled and be associated with the swap id to track correct order of swaps +// and releases of the image. +class FakeGLImageNativePixmap : public gl::GLImageEGL { public: - FakeGbmBuffer() = default; - ~FakeGbmBuffer() override = default; - - uint32_t GetFormat() const override { return 0; } - uint64_t GetFormatModifier() const override { return 0; } - uint32_t GetFlags() const override { return 0; } - gfx::Size GetSize() const override { return gfx::Size(); } - gfx::BufferFormat GetBufferFormat() const override { - return gfx::BufferFormat::BGRA_8888; + FakeGLImageNativePixmap(scoped_refptr<gfx::NativePixmap> pixmap, + const gfx::Size& size) + : gl::GLImageEGL(size), pixmap_(pixmap) {} + + // Associates swap id with this image. + void AssociateWithSwapId(uint32_t swap_id) { + DCHECK_NE(swap_id_, swap_id); + swap_id_ = swap_id; } - bool AreFdsValid() const override { return false; } - size_t GetNumPlanes() const override { return 0; } - int GetPlaneFd(size_t plane) const override { return -1; } - uint32_t GetPlaneHandle(size_t plane) const override { return 0; } - uint32_t GetPlaneStride(size_t plane) const override { return 0u; } - size_t GetPlaneOffset(size_t plane) const override { return 0u; } - size_t GetPlaneSize(size_t plane) const override { return 0; } - uint32_t GetHandle() const override { return 0; } - gfx::NativePixmapHandle ExportHandle() const override { - return gfx::NativePixmapHandle(); + + // Returns associated swap id with this image. + uint32_t GetAssociateWithSwapId() { return swap_id_; } + + // The image is set busy when scheduled as overlay plane for + // GbmSurfacelessWayland + void SetBusy(bool busy) { busy_ = busy; } + bool busy() const { return busy_; } + + // Sets the image as displayed. + void SetDisplayed(bool displayed) { displayed_ = displayed; } + bool displayed() const { return displayed_; } + + // Overridden from GLImage: + void Flush() override {} + bool ScheduleOverlayPlane(gfx::AcceleratedWidget widget, + int z_order, + gfx::OverlayTransform transform, + const gfx::Rect& bounds_rect, + const gfx::RectF& crop_rect, + bool enable_blend, + std::unique_ptr<gfx::GpuFence> gpu_fence) override { + // The GLImage must be set busy as it has been scheduled before when + // GbmSurfacelessWayland::ScheduleOverlayPlane was called. + DCHECK(busy_); + return pixmap_->ScheduleOverlayPlane(widget, z_order, transform, + bounds_rect, crop_rect, enable_blend, + std::move(gpu_fence)); + } + scoped_refptr<gfx::NativePixmap> GetNativePixmap() override { + return pixmap_; } - sk_sp<SkSurface> GetSurface() override { return nullptr; } + + protected: + ~FakeGLImageNativePixmap() override {} private: - DISALLOW_COPY_AND_ASSIGN(FakeGbmBuffer); + scoped_refptr<gfx::NativePixmap> pixmap_; + + // Indicated if the gl image is busy. If yes, it was scheduled as overlay + // plane for further submission and can't be reused until it's freed. + bool busy_ = false; + + bool displayed_ = false; + + uint32_t swap_id_ = std::numeric_limits<uint32_t>::max(); }; -class FakeGbmDevice : public GbmDevice { +// Helper that helps to identify the last swap id. Also sets gl image associated +// with that swap as free. +class CallbacksHelper { public: - FakeGbmDevice() = default; - ~FakeGbmDevice() override = default; + CallbacksHelper() = default; + ~CallbacksHelper() = default; + + // Returns last executed swap id that received SwapCompletionCallback. + uint32_t GetLastFinishedSwapId() const { return last_finish_swap_id_; } + + // Returns next available swap id that must be used for the next submission of + // the buffer. + uint32_t GetNextLocalSwapId() { + auto next_swap_id = local_swap_id_++; + pending_local_swap_ids_.push(next_swap_id); + return next_swap_id; + } - std::unique_ptr<GbmBuffer> CreateBuffer(uint32_t format, - const gfx::Size& size, - uint32_t flags) override { - return nullptr; + void ResetLastFinishedSwapId() { + last_finish_swap_id_ = std::numeric_limits<uint32_t>::max(); } - std::unique_ptr<GbmBuffer> CreateBufferWithModifiers( - uint32_t format, - const gfx::Size& size, - uint32_t flags, - const std::vector<uint64_t>& modifiers) override { - return nullptr; + // Finishes the submission by setting the swap id of completed buffer swap and + // sets the associated gl_image as displayed and non-busy, which indicates + // 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::SwapResult result, + std::unique_ptr<gfx::GpuFence> gpu_fence) { + 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); } - std::unique_ptr<GbmBuffer> CreateBufferFromHandle( - uint32_t format, - const gfx::Size& size, - gfx::NativePixmapHandle handle) override { - return nullptr; + + void BufferPresented(uint64_t local_swap_id, + const gfx::PresentationFeedback& feedback) { + // Make sure the presentation doesn't come earlier than than swap + // completion. We don't explicitly check if the buffer is presented as this + // DCHECK is more that enough. + DCHECK(pending_local_swap_ids_.empty() || + pending_local_swap_ids_.front() > local_swap_id); } private: - DISALLOW_COPY_AND_ASSIGN(FakeGbmDevice); + uint32_t local_swap_id_ = 0; + // Make sure that local_swap_id_ != last_finish_swap_id_. + uint32_t last_finish_swap_id_ = std::numeric_limits<uint32_t>::max(); + base::queue<uint64_t> pending_local_swap_ids_; + + // Keeps track of a displayed image. + scoped_refptr<FakeGLImageNativePixmap> displayed_image_; }; } // namespace @@ -123,12 +196,219 @@ class WaylandSurfaceFactoryTest : public WaylandTest { DISALLOW_COPY_AND_ASSIGN(WaylandSurfaceFactoryTest); }; +TEST_P(WaylandSurfaceFactoryTest, + GbmSurfacelessWaylandCheckOrderOfCallbacksTest) { + 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 3 buffers. + EXPECT_CALL(*server_.zwp_linux_dmabuf_v1(), CreateParams(_, _, _)).Times(3); + + // Create buffers and FakeGlImageNativePixmap. + std::vector<scoped_refptr<FakeGLImageNativePixmap>> fake_gl_image; + for (int i = 0; i < 3; ++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(); + } + + // Now, schedule 3 buffers for swap. + auto* mock_surface = server_.GetObject<wl::MockSurface>(widget_); + + CallbacksHelper cbs_helper; + // Submit all the available buffers. + for (const auto& gl_image : fake_gl_image) { + // 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. + gl_image->AssociateWithSwapId(swap_id); + // And set it to be busy... + gl_image->SetBusy(true); + + // Prepare overlay plane. + gl_surface->ScheduleOverlayPlane( + 0, gfx::OverlayTransform::OVERLAY_TRANSFORM_FLIP_VERTICAL, + gl_image.get(), window_->GetBounds(), {}, false, nullptr); + + // 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::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_surface, Attach(_, _, _)).Times(1); + EXPECT_CALL(*mock_surface, Frame(_)).Times(1); + EXPECT_CALL(*mock_surface, DamageBuffer(_, _, _, _)).Times(1); + EXPECT_CALL(*mock_surface, Commit()).Times(1); + + Sync(); + + testing::Mock::VerifyAndClearExpectations(&mock_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_TRUE(gl_image->busy()); + EXPECT_FALSE(gl_image->displayed()); + } + } + + // Expect buffer for swap with id=1u to be committed. + EXPECT_CALL(*mock_surface, Attach(_, _, _)).Times(1); + EXPECT_CALL(*mock_surface, Frame(_)).Times(1); + EXPECT_CALL(*mock_surface, DamageBuffer(_, _, _, _)).Times(1); + EXPECT_CALL(*mock_surface, Commit()).Times(1); + + // Send the frame callback so that pending buffer for swap id=1u is processed + // and swapped. + mock_surface->SendFrameCallback(); + + Sync(); + + // 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()); + + // This will result in Wayland server releasing previously attached buffer for + // swap id=0u and calling OnSubmission for buffer with swap id=1u. + mock_surface->ReleasePrevAttachedBuffer(); + + Sync(); + + // Give mojo the chance to pass the callbacks. + base::RunLoop().RunUntilIdle(); + + // We expect only one buffer to be released. Thus, the last swap id must be + // 0 as we waited until next buffer was attached to the surface. + EXPECT_EQ(cbs_helper.GetLastFinishedSwapId(), 1u); + + // Reset to test further swap ids. + cbs_helper.ResetLastFinishedSwapId(); + + for (const auto& gl_image : fake_gl_image) { + // The first image is not displayed and not busy, the second is displayed + // and not busy. And others are not display and busy. + if (gl_image->GetAssociateWithSwapId() == 0u) { + EXPECT_FALSE(gl_image->busy()); + EXPECT_FALSE(gl_image->displayed()); + } else if (gl_image->GetAssociateWithSwapId() == 1u) { + EXPECT_FALSE(gl_image->busy()); + EXPECT_TRUE(gl_image->displayed()); + } else { + EXPECT_TRUE(gl_image->busy()); + EXPECT_FALSE(gl_image->displayed()); + } + } + + EXPECT_CALL(*mock_surface, Attach(_, _, _)).Times(1); + EXPECT_CALL(*mock_surface, Frame(_)).Times(1); + EXPECT_CALL(*mock_surface, DamageBuffer(_, _, _, _)).Times(1); + EXPECT_CALL(*mock_surface, Commit()).Times(1); + + // Send the frame callback, so that the pending buffer with swap id=2u can + // be processed. + mock_surface->SendFrameCallback(); + + Sync(); + + // 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()); + + // This will result in Wayland server releasing previously attached buffer for + // swap id=1u and calling OnSubmission for buffer with swap id=2u. + mock_surface->ReleasePrevAttachedBuffer(); + + Sync(); + + // Give mojo the chance to pass the callbacks. + base::RunLoop().RunUntilIdle(); + + // We should receive next callbacks for the next swap id. + EXPECT_EQ(cbs_helper.GetLastFinishedSwapId(), 2u); + + cbs_helper.ResetLastFinishedSwapId(); + + // All images must be free now and the last one is displayed. + 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()); + EXPECT_FALSE(gl_image->busy()); + } + } + + // There are no buffers left. Send last frame callback and verify that. + EXPECT_CALL(*mock_surface, Attach(_, _, _)).Times(0); + EXPECT_CALL(*mock_surface, Frame(_)).Times(0); + EXPECT_CALL(*mock_surface, DamageBuffer(_, _, _, _)).Times(0); + EXPECT_CALL(*mock_surface, Commit()).Times(0); + + // Send a frame callback so that the WaylandBufferManagerHost processes the + // pending buffers if any exist. + mock_surface->SendFrameCallback(); +} + TEST_P(WaylandSurfaceFactoryTest, Canvas) { auto canvas = CreateCanvas(widget_); ASSERT_TRUE(canvas); canvas->ResizeCanvas(window_->GetBounds().size()); - canvas->GetSurface(); + auto* sk_canvas = canvas->GetCanvas(); + DCHECK(sk_canvas); canvas->PresentCanvas(gfx::Rect(5, 10, 20, 15)); // Wait until the mojo calls are done. @@ -157,9 +437,11 @@ TEST_P(WaylandSurfaceFactoryTest, CanvasResize) { ASSERT_TRUE(canvas); canvas->ResizeCanvas(window_->GetBounds().size()); - canvas->GetSurface(); + auto* sk_canvas = canvas->GetCanvas(); + DCHECK(sk_canvas); canvas->ResizeCanvas(gfx::Size(100, 50)); - canvas->GetSurface(); + sk_canvas = canvas->GetCanvas(); + DCHECK(sk_canvas); canvas->PresentCanvas(gfx::Rect(0, 0, 100, 50)); base::RunLoop().RunUntilIdle(); @@ -192,7 +474,7 @@ TEST_P(WaylandSurfaceFactoryTest, CreateSurfaceCheckGbm) { EXPECT_FALSE(gl_surface); // Now, set gbm. - buffer_manager_gpu_->set_gbm_device(std::make_unique<FakeGbmDevice>()); + buffer_manager_gpu_->set_gbm_device(std::make_unique<MockGbmDevice>()); gl_surface = gl_ozone->CreateSurfacelessViewGLSurface(widget_); EXPECT_TRUE(gl_surface); diff --git a/chromium/ui/ozone/platform/wayland/gpu/wayland_surface_gpu.h b/chromium/ui/ozone/platform/wayland/gpu/wayland_surface_gpu.h index c6e36f4e191..a33e0e1f018 100644 --- a/chromium/ui/ozone/platform/wayland/gpu/wayland_surface_gpu.h +++ b/chromium/ui/ozone/platform/wayland/gpu/wayland_surface_gpu.h @@ -23,12 +23,16 @@ class WaylandSurfaceGpu { virtual ~WaylandSurfaceGpu() {} // Tells the surface the result of the last swap of buffer with the - // |buffer_id|. + // |buffer_id|. After this callback, the previously (before |buffer_id|) + // submitted buffer may be reused. This is guaranteed to be called + // in the same order that buffers were submitted. virtual void OnSubmission(uint32_t buffer_id, const gfx::SwapResult& swap_result) = 0; // Tells the surface the result of the last presentation of buffer with the - // |buffer_id|. + // |buffer_id|. This is guaranteed to be called in the same order that + // buffers were submitted, and is guaranteed to be called after the + // corresponding call to |OnSubmission| for this buffer. virtual void OnPresentation(uint32_t buffer_id, const gfx::PresentationFeedback& feedback) = 0; }; 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 new file mode 100644 index 00000000000..fef56d4fcc8 --- /dev/null +++ b/chromium/ui/ozone/platform/wayland/host/gtk_ui_delegate_wayland.cc @@ -0,0 +1,52 @@ +// 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/gtk_ui_delegate_wayland.h" + +#include <gdk/gdkwayland.h> +#include <gtk/gtk.h> + +#include "base/logging.h" +#include "ui/gfx/native_widget_types.h" +#include "ui/ozone/platform/wayland/host/wayland_connection.h" + +namespace ui { + +GtkUiDelegateWayland::GtkUiDelegateWayland(WaylandConnection* connection) + : connection_(connection) { + DCHECK(connection_); + gdk_set_allowed_backends("wayland"); +} + +GtkUiDelegateWayland::~GtkUiDelegateWayland() = default; + +void GtkUiDelegateWayland::OnInitialized() { + // Nothing to do upon initialization for Wayland. +} + +GdkKeymap* GtkUiDelegateWayland::GetGdkKeymap() { + NOTIMPLEMENTED_LOG_ONCE(); + return nullptr; +} + +GdkWindow* GtkUiDelegateWayland::GetGdkWindow( + gfx::AcceleratedWidget window_id) { + NOTIMPLEMENTED_LOG_ONCE(); + return nullptr; +} + +bool GtkUiDelegateWayland::SetGdkWindowTransientFor( + GdkWindow* window, + gfx::AcceleratedWidget parent) { + NOTIMPLEMENTED_LOG_ONCE(); + return false; +} + +void GtkUiDelegateWayland::ShowGtkWindow(GtkWindow* window) { + // TODO(crbug.com/1008755): Check if gtk_window_present_with_time is needed + // here as well, similarly to what is done in X11 impl. + gtk_window_present(window); +} + +} // 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 new file mode 100644 index 00000000000..dd7baf93bf7 --- /dev/null +++ b/chromium/ui/ozone/platform/wayland/host/gtk_ui_delegate_wayland.h @@ -0,0 +1,36 @@ +// 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_GTK_UI_DELEGATE_WAYLAND_H_ +#define UI_OZONE_PLATFORM_WAYLAND_HOST_GTK_UI_DELEGATE_WAYLAND_H_ + +#include "ui/gfx/native_widget_types.h" +#include "ui/gtk/gtk_ui_delegate.h" + +namespace ui { + +class WaylandConnection; + +class GtkUiDelegateWayland : public GtkUiDelegate { + public: + explicit GtkUiDelegateWayland(WaylandConnection* connection); + GtkUiDelegateWayland(const GtkUiDelegateWayland&) = delete; + GtkUiDelegateWayland& operator=(const GtkUiDelegateWayland&) = delete; + ~GtkUiDelegateWayland() override; + + // GtkUiDelegate: + void OnInitialized() override; + GdkKeymap* GetGdkKeymap() override; + GdkWindow* GetGdkWindow(gfx::AcceleratedWidget window_id) override; + bool SetGdkWindowTransientFor(GdkWindow* window, + gfx::AcceleratedWidget parent) override; + void ShowGtkWindow(GtkWindow* window) override; + + private: + WaylandConnection* const connection_; +}; + +} // namespace ui + +#endif // UI_OZONE_PLATFORM_WAYLAND_HOST_GTK_UI_DELEGATE_WAYLAND_H_ diff --git a/chromium/ui/ozone/platform/wayland/host/shell_object_factory.cc b/chromium/ui/ozone/platform/wayland/host/shell_object_factory.cc new file mode 100644 index 00000000000..57383be20da --- /dev/null +++ b/chromium/ui/ozone/platform/wayland/host/shell_object_factory.cc @@ -0,0 +1,47 @@ +// Copyright 2019 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/shell_object_factory.h" + +#include "ui/ozone/platform/wayland/host/wayland_connection.h" +#include "ui/ozone/platform/wayland/host/xdg_popup_wrapper_impl.h" +#include "ui/ozone/platform/wayland/host/xdg_surface_wrapper_impl.h" + +namespace ui { + +ShellObjectFactory::ShellObjectFactory() = default; +ShellObjectFactory::~ShellObjectFactory() = default; + +std::unique_ptr<ShellSurfaceWrapper> +ShellObjectFactory::CreateShellSurfaceWrapper(WaylandConnection* connection, + WaylandWindow* wayland_window) { + if (connection->shell() || connection->shell_v6()) { + auto surface = + std::make_unique<XDGSurfaceWrapperImpl>(wayland_window, connection); + return surface->Initialize(true /* with_top_level */) ? std::move(surface) + : nullptr; + } + LOG(WARNING) << "Shell protocol is not available."; + return nullptr; +} + +std::unique_ptr<ShellPopupWrapper> ShellObjectFactory::CreateShellPopupWrapper( + WaylandConnection* connection, + WaylandWindow* wayland_window, + const gfx::Rect& bounds) { + if (connection->shell() || connection->shell_v6()) { + auto surface = + std::make_unique<XDGSurfaceWrapperImpl>(wayland_window, connection); + if (!surface->Initialize(false /* with_top_level */)) + return nullptr; + + auto popup = std::make_unique<XDGPopupWrapperImpl>(std::move(surface), + wayland_window); + return popup->Initialize(connection, bounds) ? std::move(popup) : nullptr; + } + LOG(WARNING) << "Shell protocol is not available."; + return nullptr; +} + +} // namespace ui
\ No newline at end of file diff --git a/chromium/ui/ozone/platform/wayland/host/shell_object_factory.h b/chromium/ui/ozone/platform/wayland/host/shell_object_factory.h new file mode 100644 index 00000000000..a915326c23f --- /dev/null +++ b/chromium/ui/ozone/platform/wayland/host/shell_object_factory.h @@ -0,0 +1,44 @@ +// Copyright 2019 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_SHELL_OBJECT_FACTORY_H_ +#define UI_OZONE_PLATFORM_WAYLAND_HOST_SHELL_OBJECT_FACTORY_H_ + +#include <memory> + +namespace gfx { +class Rect; +} + +namespace ui { + +class ShellSurfaceWrapper; +class ShellPopupWrapper; +class WaylandConnection; +class WaylandWindow; + +// Shell factory that creates shell objects for different protocols. Preferred +// protocols are defined in the following order: +// 1) xdg-shell-stable-protocol. +// 2) xdg-shell-v6-unstable-protocol. +class ShellObjectFactory { + public: + ShellObjectFactory(); + ~ShellObjectFactory(); + + // Creates and initializes a ShellSurfaceWrapper. + std::unique_ptr<ShellSurfaceWrapper> CreateShellSurfaceWrapper( + WaylandConnection* connection, + WaylandWindow* wayland_window); + + // Creates and intitializes a ShellPopupSurface. + std::unique_ptr<ShellPopupWrapper> CreateShellPopupWrapper( + WaylandConnection* connection, + WaylandWindow* wayland_window, + const gfx::Rect& bounds); +}; + +} // namespace ui + +#endif // UI_OZONE_PLATFORM_WAYLAND_HOST_SHELL_OBJECT_FACTORY_H_
\ No newline at end of file diff --git a/chromium/ui/ozone/platform/wayland/host/shell_popup_wrapper.h b/chromium/ui/ozone/platform/wayland/host/shell_popup_wrapper.h index 952c0a2a278..2970549dd09 100644 --- a/chromium/ui/ozone/platform/wayland/host/shell_popup_wrapper.h +++ b/chromium/ui/ozone/platform/wayland/host/shell_popup_wrapper.h @@ -10,6 +10,8 @@ namespace ui { +class WaylandConnection; + enum class MenuType { TYPE_RIGHT_CLICK, TYPE_3DOT_PARENT_MENU, @@ -67,6 +69,10 @@ inline WlConstraintAdjustment operator&(WlConstraintAdjustment a, class ShellPopupWrapper { public: virtual ~ShellPopupWrapper() {} + + // Initializes the popup surface. + virtual bool Initialize(WaylandConnection* connection, + const gfx::Rect& bounds) = 0; }; gfx::Rect GetAnchorRect(MenuType menu_type, diff --git a/chromium/ui/ozone/platform/wayland/host/shell_surface_wrapper.h b/chromium/ui/ozone/platform/wayland/host/shell_surface_wrapper.h index 49b27e4c721..c75e87a627b 100644 --- a/chromium/ui/ozone/platform/wayland/host/shell_surface_wrapper.h +++ b/chromium/ui/ozone/platform/wayland/host/shell_surface_wrapper.h @@ -21,6 +21,10 @@ class ShellSurfaceWrapper { public: virtual ~ShellSurfaceWrapper() {} + // Initializes the ShellSurface. Some protocols may require to create shell + // surface without toplevel role and assign a popup role to it later. + virtual bool Initialize(bool with_toplevel) = 0; + // Sets a native window to maximized state. virtual void SetMaximized() = 0; 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 7434e702d24..79495b21a37 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 @@ -12,8 +12,7 @@ #include "base/strings/strcat.h" #include "base/strings/utf_string_conversions.h" #include "base/trace_event/trace_event.h" -#include "mojo/public/cpp/system/platform_handle.h" -#include "ui/ozone/common/linux/drm_util_linux.h" +#include "ui/gfx/linux/drm_util_linux.h" #include "ui/ozone/platform/wayland/host/wayland_connection.h" #include "ui/ozone/platform/wayland/host/wayland_drm.h" #include "ui/ozone/platform/wayland/host/wayland_shm.h" @@ -175,7 +174,7 @@ class WaylandBufferManagerHost::Surface { void ClearState() { buffers_.clear(); wl_frame_callback_.reset(); - presentation_feedbacks_ = PresentationFeedbackQueue(); + feedback_queue_ = PresentationFeedbackQueue(); ResetSurfaceContents(); @@ -212,21 +211,38 @@ class WaylandBufferManagerHost::Surface { bool HasWindow() const { return !!window_; } private: - using PresentationFeedbackQueue = base::queue< - std::pair<uint32_t, wl::Object<struct wp_presentation_feedback>>>; + struct FeedbackInfo { + // The wayland object identifying this feedback. + wl::Object<struct wp_presentation_feedback> wp_presentation_feedback; + // The buffer that this presentation feedback is for. + uint32_t buffer_id; + // The actual presentation feedback. May be missing if the callback from the + // Wayland server has not arrived yet. + base::Optional<gfx::PresentationFeedback> feedback; + // True iff OnSubmission has been called. + bool submission_completed; + }; + + using PresentationFeedbackQueue = std::vector<FeedbackInfo>; bool CommitBufferInternal(WaylandBuffer* buffer) { DCHECK(buffer && window_); DCHECK(!pending_buffer_); - // Once the BufferRelease is called, the buffer will be released. - DCHECK(buffer->released); - buffer->released = false; - DCHECK(!submitted_buffer_); submitted_buffer_ = buffer; - AttachAndDamageBuffer(buffer); + // if the same buffer has been submitted again right after the client + // received OnSubmission for that buffer, just damage the buffer and + // commit the surface again. + if (prev_submitted_buffer_ != submitted_buffer_) { + // Once the BufferRelease is called, the buffer will be released. + DCHECK(buffer->released); + buffer->released = false; + AttachBuffer(buffer); + } + + DamageBuffer(buffer); SetupFrameCallback(); SetupPresentationFeedback(buffer->buffer_id); @@ -246,13 +262,18 @@ class WaylandBufferManagerHost::Surface { // If it was the very first frame, the surface has not had a back buffer // before, and Wayland won't release the front buffer until next buffer is // attached. Thus, notify about successful submission immediately. - if (!prev_submitted_buffer_) + // + // As said above, if the client submits the same buffer again, we must + // notify the client about the submission immediately as Wayland compositor + // is not going to send a release callback for a buffer committed more than + // once. + if (!prev_submitted_buffer_ || prev_submitted_buffer_ == submitted_buffer_) CompleteSubmission(); return true; } - void AttachAndDamageBuffer(WaylandBuffer* buffer) { + void DamageBuffer(WaylandBuffer* buffer) { DCHECK(window_); gfx::Rect pending_damage_region = std::move(buffer->damage_region); @@ -263,11 +284,41 @@ class WaylandBufferManagerHost::Surface { pending_damage_region.set_size(buffer->size); DCHECK(!pending_damage_region.size().IsEmpty()); - auto* surface = window_->surface(); - wl_surface_damage_buffer( - surface, pending_damage_region.x(), pending_damage_region.y(), - pending_damage_region.width(), pending_damage_region.height()); - wl_surface_attach(surface, buffer->wl_buffer.get(), 0, 0); + if (connection_->compositor_version() >= + WL_SURFACE_DAMAGE_BUFFER_SINCE_VERSION) { + // wl_surface_damage_buffer relies on compositor API version 4. See + // https://bit.ly/2u00lv6 for details. + // We don't need to apply any scaling because pending_damage_region is + // already in buffer coordinates. + wl_surface_damage_buffer(window_->surface(), 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. + int scale = window_->buffer_scale(); + wl_surface_damage(window_->surface(), pending_damage_region.x() / scale, + pending_damage_region.y() / scale, + pending_damage_region.width() / scale + 1, + pending_damage_region.height() / scale + 1); + } + } + + void AttachBuffer(WaylandBuffer* buffer) { + DCHECK(window_); + + // The logic in DamageBuffer currently relies on attachment coordinates of + // (0, 0). If this changes, then the calculation in DamageBuffer will also + // need to be updated. + wl_surface_attach(window_->surface(), buffer->wl_buffer.get(), 0, 0); } void CommitSurface() { @@ -295,12 +346,14 @@ class WaylandBufferManagerHost::Surface { &Surface::FeedbackSyncOutput, &Surface::FeedbackPresented, &Surface::FeedbackDiscarded}; - presentation_feedbacks_.push(std::make_pair( - buffer_id, - wl::Object<struct wp_presentation_feedback>(wp_presentation_feedback( - connection_->presentation(), window_->surface())))); + feedback_queue_.push_back( + {wl::Object<struct wp_presentation_feedback>(wp_presentation_feedback( + connection_->presentation(), window_->surface())), + buffer_id, /*feedback=*/base::nullopt, + /*submission_completed=*/false}); wp_presentation_feedback_add_listener( - presentation_feedbacks_.back().second.get(), &feedback_listener, this); + feedback_queue_.back().wp_presentation_feedback.get(), + &feedback_listener, this); } void SetupBufferReleaseListener(WaylandBuffer* buffer) { @@ -382,11 +435,6 @@ class WaylandBufferManagerHost::Surface { void CompleteSubmission() { DCHECK(submitted_buffer_); auto id = submitted_buffer_->buffer_id; - - auto feedback = std::move(submitted_buffer_->feedback); - bool needs_send_feedback = submitted_buffer_->needs_send_feedback; - submitted_buffer_->needs_send_feedback = false; - prev_submitted_buffer_ = submitted_buffer_; submitted_buffer_ = nullptr; @@ -402,30 +450,68 @@ class WaylandBufferManagerHost::Surface { // If presentation feedback is not supported, use a fake feedback. This // literally means there are no presentation feedback callbacks created. if (!connection_->presentation()) { - DCHECK(presentation_feedbacks_.empty()); - OnPresentation(id, gfx::PresentationFeedback( - base::TimeTicks::Now(), base::TimeDelta(), - GetPresentationKindFlags(0))); - } else if (needs_send_feedback) { - OnPresentation(id, std::move(feedback)); + DCHECK(feedback_queue_.empty()); + buffer_manager_->OnPresentation( + window_->GetWidget(), id, + gfx::PresentationFeedback(base::TimeTicks::Now(), base::TimeDelta(), + GetPresentationKindFlags(0))); + } else { + for (auto& info : feedback_queue_) { + if (info.buffer_id == id && !info.submission_completed) { + info.submission_completed = true; + ProcessPresentationFeedbacks(); + return; + } + } + NOTREACHED() << "Did not find matching feedback for buffer_id=" << id; } } - void OnPresentation(uint32_t buffer_id, + void OnPresentation(struct wp_presentation_feedback* wp_presentation_feedback, const gfx::PresentationFeedback& feedback) { - // The order of submission and presentation callbacks cannot be controlled. - // Some Wayland compositors may fire presentation callbacks earlier than we - // are able to send submission callbacks and this is bad. Thus, handle it - // here. - if (submitted_buffer_ && submitted_buffer_->buffer_id == buffer_id) { - submitted_buffer_->needs_send_feedback = true; - submitted_buffer_->feedback = feedback; - return; + FeedbackInfo* feedback_info = nullptr; + for (auto& info : feedback_queue_) { + if (info.wp_presentation_feedback.get() == wp_presentation_feedback) { + feedback_info = &info; + break; + } else if (!info.feedback.has_value()) { // Feedback must come in order. + info.feedback = gfx::PresentationFeedback::Failure(); + } } + DCHECK(feedback_info); + DCHECK(!feedback_info->feedback.has_value()); + feedback_info->feedback = feedback; + + ProcessPresentationFeedbacks(); + } + + // We provide the guarantee to the client that: + // 1. OnPresentation and OnSubmission will be called for each submitted buffer + // 2. OnPresentation(buffer_id) will be called after OnSubmission(buffer_id) + // 3. OnPresentation and OnSubmission will be called in the same order + // of buffer submission. + // We make the following assumptions about the server: + // 1. Presentation feedback will arrive in the same order of submission. + // 2. Presentation feedback may never arrive if the buffer is destroyed. + // 3. Presentation feedback may arrive at an arbitrary time after commit. + // For these reasons, we can't associate feedback with a specific buffer, + // as there may be more than one feedback in-flight for a single buffer. + // This function ensures that we send OnPresentation for each buffer that + // already has had OnSubmission called for it (condition #2). + void ProcessPresentationFeedbacks() { + if (!window_) + return; - if (window_) - buffer_manager_->OnPresentation(window_->GetWidget(), buffer_id, - feedback); + while (!feedback_queue_.empty()) { + const auto& info = feedback_queue_.front(); + if (!info.submission_completed || !info.feedback.has_value()) + break; + buffer_manager_->OnPresentation(window_->GetWidget(), info.buffer_id, + *info.feedback); + feedback_queue_.erase(feedback_queue_.begin()); + } + // This queue should be small - if not it's likely a bug. + DCHECK_LE(feedback_queue_.size(), 25u); } // wp_presentation_feedback_listener @@ -446,11 +532,8 @@ class WaylandBufferManagerHost::Surface { uint32_t flags) { Surface* self = static_cast<Surface*>(data); DCHECK(self); - auto presentation = std::move(self->presentation_feedbacks_.front()); - DCHECK(presentation.second.get() == wp_presentation_feedback); - self->presentation_feedbacks_.pop(); self->OnPresentation( - presentation.first, + wp_presentation_feedback, gfx::PresentationFeedback( GetPresentationFeedbackTimeStamp(tv_sec_hi, tv_sec_lo, tv_nsec), base::TimeDelta::FromNanoseconds(refresh), @@ -462,10 +545,7 @@ class WaylandBufferManagerHost::Surface { struct wp_presentation_feedback* wp_presentation_feedback) { Surface* self = static_cast<Surface*>(data); DCHECK(self); - auto presentation = std::move(self->presentation_feedbacks_.front()); - DCHECK(presentation.second.get() == wp_presentation_feedback); - self->presentation_feedbacks_.pop(); - self->OnPresentation(presentation.first, + self->OnPresentation(wp_presentation_feedback, gfx::PresentationFeedback::Failure()); } @@ -500,7 +580,7 @@ class WaylandBufferManagerHost::Surface { // A presentation feedback provided by the Wayland server once frame is // shown. - PresentationFeedbackQueue presentation_feedbacks_; + PresentationFeedbackQueue feedback_queue_; // A buffer, which is pending to be submitted (look the comment in the // CommitBuffer method). @@ -598,7 +678,7 @@ void WaylandBufferManagerHost::SetWaylandBufferManagerGpu( } void WaylandBufferManagerHost::CreateDmabufBasedBuffer( - mojo::ScopedHandle dmabuf_fd, + mojo::PlatformHandle dmabuf_fd, const gfx::Size& size, const std::vector<uint32_t>& strides, const std::vector<uint32_t>& offsets, @@ -612,7 +692,7 @@ void WaylandBufferManagerHost::CreateDmabufBasedBuffer( TRACE_EVENT2("wayland", "WaylandBufferManagerHost::CreateDmabufBasedBuffer", "Format", format, "Buffer id", buffer_id); - base::ScopedFD fd = mojo::UnwrapPlatformHandle(std::move(dmabuf_fd)).TakeFD(); + base::ScopedFD fd = dmabuf_fd.TakeFD(); // Validate data and ask surface to create a buffer associated with the // |buffer_id|. @@ -642,7 +722,7 @@ void WaylandBufferManagerHost::CreateDmabufBasedBuffer( } } -void WaylandBufferManagerHost::CreateShmBasedBuffer(mojo::ScopedHandle shm_fd, +void WaylandBufferManagerHost::CreateShmBasedBuffer(mojo::PlatformHandle shm_fd, uint64_t length, const gfx::Size& size, uint32_t buffer_id) { @@ -652,7 +732,7 @@ void WaylandBufferManagerHost::CreateShmBasedBuffer(mojo::ScopedHandle shm_fd, TRACE_EVENT1("wayland", "WaylandBufferManagerHost::CreateShmBasedBuffer", "Buffer id", buffer_id); - base::ScopedFD fd = mojo::UnwrapPlatformHandle(std::move(shm_fd)).TakeFD(); + base::ScopedFD fd = shm_fd.TakeFD(); // Validate data and create a buffer associated with the |buffer_id|. if (!ValidateDataFromGpu(fd, length, size, buffer_id) || !CreateBuffer(size, buffer_id)) { 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 1f455154f34..9049a3f5a4f 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 @@ -65,14 +65,6 @@ struct WaylandBuffer { // surface can tell the gpu about successful swap. bool released = true; - // In some cases, a presentation feedback can come earlier than we fire a - // submission callback. Thus, instead of sending it immediately to the GPU - // process, we store it and fire as soon as the submission callback is - // fired. - bool needs_send_feedback = false; - - gfx::PresentationFeedback feedback; - DISALLOW_COPY_AND_ASSIGN(WaylandBuffer); }; @@ -117,7 +109,7 @@ class WaylandBufferManagerHost : public ozone::mojom::WaylandBufferManagerHost, // Called by the GPU and asks to import a wl_buffer based on a gbm file // descriptor using zwp_linux_dmabuf protocol. Check comments in the // ui/ozone/public/mojom/wayland/wayland_connection.mojom. - void CreateDmabufBasedBuffer(mojo::ScopedHandle dmabuf_fd, + void CreateDmabufBasedBuffer(mojo::PlatformHandle dmabuf_fd, const gfx::Size& size, const std::vector<uint32_t>& strides, const std::vector<uint32_t>& offsets, @@ -128,7 +120,7 @@ class WaylandBufferManagerHost : public ozone::mojom::WaylandBufferManagerHost, // Called by the GPU and asks to import a wl_buffer based on a shared memory // file descriptor using wl_shm protocol. Check comments in the // ui/ozone/public/mojom/wayland/wayland_connection.mojom. - void CreateShmBasedBuffer(mojo::ScopedHandle shm_fd, + void CreateShmBasedBuffer(mojo::PlatformHandle shm_fd, uint64_t length, const gfx::Size& size, uint32_t buffer_id) override; diff --git a/chromium/ui/ozone/platform/wayland/host/wayland_clipboard.cc b/chromium/ui/ozone/platform/wayland/host/wayland_clipboard.cc index dd8c23269b1..0191f14247c 100644 --- a/chromium/ui/ozone/platform/wayland/host/wayland_clipboard.cc +++ b/chromium/ui/ozone/platform/wayland/host/wayland_clipboard.cc @@ -4,6 +4,8 @@ #include "ui/ozone/platform/wayland/host/wayland_clipboard.h" +#include <string> + #include "ui/ozone/platform/wayland/host/gtk_primary_selection_device.h" #include "ui/ozone/platform/wayland/host/gtk_primary_selection_device_manager.h" #include "ui/ozone/platform/wayland/host/gtk_primary_selection_source.h" @@ -38,7 +40,7 @@ void WaylandClipboard::OfferClipboardData( clipboard_data_source_ = data_device_manager_->CreateSource(); data_source = clipboard_data_source_.get(); } else { - if (!primary_selection_device_manager_) { + if (!IsPrimarySelectionSupported()) { std::move(callback).Run(); return; } @@ -66,8 +68,10 @@ void WaylandClipboard::RequestClipboardData( if (!data_device_->RequestSelectionData(mime_type)) SetData({}, mime_type); } else { - if (!primary_selection_device_->RequestSelectionData(mime_type)) + if (!IsPrimarySelectionSupported() || + !primary_selection_device_->RequestSelectionData(mime_type)) { SetData({}, mime_type); + } } } @@ -91,8 +95,10 @@ void WaylandClipboard::GetAvailableMimeTypes( if (buffer == ClipboardBuffer::kCopyPaste) { std::move(callback).Run(data_device_->GetAvailableMimeTypes()); } else { - DCHECK(primary_selection_device_); - std::move(callback).Run(primary_selection_device_->GetAvailableMimeTypes()); + std::move(callback).Run( + IsPrimarySelectionSupported() + ? primary_selection_device_->GetAvailableMimeTypes() + : std::vector<std::string>{}); } } @@ -128,4 +134,8 @@ void WaylandClipboard::UpdateSequenceNumber(ClipboardBuffer buffer) { update_sequence_cb_.Run(buffer); } +bool WaylandClipboard::IsPrimarySelectionSupported() const { + return primary_selection_device_manager_ && primary_selection_device_; +} + } // namespace ui diff --git a/chromium/ui/ozone/platform/wayland/host/wayland_clipboard.h b/chromium/ui/ozone/platform/wayland/host/wayland_clipboard.h index cd95b60ec74..a4482490071 100644 --- a/chromium/ui/ozone/platform/wayland/host/wayland_clipboard.h +++ b/chromium/ui/ozone/platform/wayland/host/wayland_clipboard.h @@ -57,6 +57,8 @@ class WaylandClipboard : public PlatformClipboard { void UpdateSequenceNumber(ClipboardBuffer buffer); private: + bool IsPrimarySelectionSupported() const; + // Holds a temporary instance of the client's clipboard content // so that we can asynchronously write to it. PlatformClipboard::DataMap* data_map_ = nullptr; diff --git a/chromium/ui/ozone/platform/wayland/host/wayland_connection.cc b/chromium/ui/ozone/platform/wayland/host/wayland_connection.cc index bb0ab87a01d..21590d85a26 100644 --- a/chromium/ui/ozone/platform/wayland/host/wayland_connection.cc +++ b/chromium/ui/ozone/platform/wayland/host/wayland_connection.cc @@ -83,15 +83,16 @@ bool WaylandConnection::Initialize() { LOG(ERROR) << "No wl_shm object"; return false; } - if (!seat_) { - LOG(ERROR) << "No wl_seat object"; - return false; - } if (!shell_v6_ && !shell_) { LOG(ERROR) << "No Wayland shell found"; return false; } + // When we are running tests with weston in headless mode, the seat is not + // announced. + if (!seat_) + LOG(WARNING) << "No wl_seat object. The functionality may suffer."; + return true; } @@ -122,13 +123,17 @@ void WaylandConnection::MaybePrepareReadQueue() { } void WaylandConnection::ScheduleFlush() { - if (scheduled_flush_) - return; - DCHECK(base::MessageLoopCurrentForUI::IsSet()); - base::ThreadTaskRunnerHandle::Get()->PostTask( - FROM_HERE, - base::BindOnce(&WaylandConnection::Flush, base::Unretained(this))); - scheduled_flush_ = true; + // When we are in tests, the message loop is set later when the + // initialization of the OzonePlatform complete. Thus, just + // flush directly. This doesn't happen in normal run. + if (!base::MessageLoopCurrentForUI::IsSet()) { + Flush(); + } else if (!scheduled_flush_) { + base::ThreadTaskRunnerHandle::Get()->PostTask( + FROM_HERE, + base::BindOnce(&WaylandConnection::Flush, base::Unretained(this))); + scheduled_flush_ = true; + } } void WaylandConnection::SetCursorBitmap(const std::vector<SkBitmap>& bitmaps, @@ -174,6 +179,9 @@ void WaylandConnection::RequestDragData( } bool WaylandConnection::IsDragInProgress() { + // |data_device_| can be null when running on headless weston. + if (!data_device_) + return false; return data_device_->IsDragEntered() || drag_data_source(); } @@ -281,6 +289,7 @@ void WaylandConnection::Global(void* data, if (!connection->compositor_ && strcmp(interface, "wl_compositor") == 0) { connection->compositor_ = wl::Bind<wl_compositor>( registry, name, std::min(version, kMaxCompositorVersion)); + connection->compositor_version_ = version; if (!connection->compositor_) LOG(ERROR) << "Failed to bind to wl_compositor global"; } else if (!connection->subcompositor_ && diff --git a/chromium/ui/ozone/platform/wayland/host/wayland_connection.h b/chromium/ui/ozone/platform/wayland/host/wayland_connection.h index d6a985fc0fe..9adc5be026a 100644 --- a/chromium/ui/ozone/platform/wayland/host/wayland_connection.h +++ b/chromium/ui/ozone/platform/wayland/host/wayland_connection.h @@ -52,6 +52,7 @@ class WaylandConnection : public PlatformEventSource, 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(); } xdg_wm_base* shell() const { return shell_.get(); } zxdg_shell_v6* shell_v6() const { return shell_v6_.get(); } @@ -108,6 +109,8 @@ class WaylandConnection : public PlatformEventSource, return &wayland_window_manager_; } + WaylandDataDevice* wayland_data_device() const { return data_device_.get(); } + // Starts drag with |data| to be delivered, |operation| supported by the // source side initiated the dragging. void StartDrag(const ui::OSExchangeData& data, int operation); @@ -177,6 +180,7 @@ class WaylandConnection : public PlatformEventSource, wl::Object<wl_display> display_; wl::Object<wl_registry> registry_; wl::Object<wl_compositor> compositor_; + uint32_t compositor_version_ = 0; wl::Object<wl_subcompositor> subcompositor_; wl::Object<wl_seat> seat_; wl::Object<xdg_wm_base> shell_; diff --git a/chromium/ui/ozone/platform/wayland/host/wayland_cursor.cc b/chromium/ui/ozone/platform/wayland/host/wayland_cursor.cc index 85b16dc3c68..3e0fc6562a7 100644 --- a/chromium/ui/ozone/platform/wayland/host/wayland_cursor.cc +++ b/chromium/ui/ozone/platform/wayland/host/wayland_cursor.cc @@ -35,6 +35,8 @@ void WaylandCursor::Init(wl_pointer* pointer, WaylandConnection* connection) { shm_ = connection->shm(); pointer_surface_.reset( wl_compositor_create_surface(connection->compositor())); + + connection_ = connection; } void WaylandCursor::UpdateBitmap(const std::vector<SkBitmap>& cursor_image, @@ -79,6 +81,11 @@ void WaylandCursor::UpdateBitmap(const std::vector<SkBitmap>& cursor_image, void WaylandCursor::HideCursor(uint32_t serial) { DCHECK(input_pointer_); wl_pointer_set_cursor(input_pointer_, serial, nullptr, 0, 0); + + wl_surface_attach(pointer_surface_.get(), nullptr, 0, 0); + wl_surface_commit(pointer_surface_.get()); + + connection_->ScheduleFlush(); } } // 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 c2890f96e7a..2d53782ed68 100644 --- a/chromium/ui/ozone/platform/wayland/host/wayland_cursor.h +++ b/chromium/ui/ozone/platform/wayland/host/wayland_cursor.h @@ -57,6 +57,7 @@ class WaylandCursor { WaylandShm* shm_ = nullptr; // Owned by WaylandConnection. wl_pointer* input_pointer_ = nullptr; // Owned by WaylandPointer. + WaylandConnection* connection_ = nullptr; // Holds the buffers and their memory until the compositor releases them. base::flat_map<wl_buffer*, WaylandShmBuffer> buffers_; 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 20a347a592b..4c5008dd42b 100644 --- a/chromium/ui/ozone/platform/wayland/host/wayland_data_device.cc +++ b/chromium/ui/ozone/platform/wayland/host/wayland_data_device.cc @@ -15,7 +15,7 @@ #include "third_party/skia/include/core/SkCanvas.h" #include "ui/base/clipboard/clipboard_constants.h" #include "ui/base/dragdrop/drag_drop_types.h" -#include "ui/base/dragdrop/file_info.h" +#include "ui/base/dragdrop/file_info/file_info.h" #include "ui/base/dragdrop/os_exchange_data.h" #include "ui/base/dragdrop/os_exchange_data_provider_aura.h" #include "ui/ozone/platform/wayland/common/wayland_util.h" 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 0bd746513c3..3f4ade9c4ea 100644 --- a/chromium/ui/ozone/platform/wayland/host/wayland_data_device.h +++ b/chromium/ui/ozone/platform/wayland/host/wayland_data_device.h @@ -58,6 +58,8 @@ class WaylandDataDevice : public internal::WaylandDataDeviceBase { bool IsDragEntered() { return drag_offer_ != nullptr; } + WaylandWindow* entered_window() const { return window_; } + private: void ReadDragDataFromFD( base::ScopedFD fd, diff --git a/chromium/ui/ozone/platform/wayland/host/wayland_data_device_unittest.cc b/chromium/ui/ozone/platform/wayland/host/wayland_data_device_unittest.cc index 6ffe6a94b3e..cfd1eca7b26 100644 --- a/chromium/ui/ozone/platform/wayland/host/wayland_data_device_unittest.cc +++ b/chromium/ui/ozone/platform/wayland/host/wayland_data_device_unittest.cc @@ -15,7 +15,7 @@ #include "testing/gtest/include/gtest/gtest.h" #include "ui/base/clipboard/clipboard_constants.h" #include "ui/base/dragdrop/drag_drop_types.h" -#include "ui/base/dragdrop/file_info.h" +#include "ui/base/dragdrop/file_info/file_info.h" #include "ui/base/dragdrop/os_exchange_data.h" #include "ui/events/base_event_utils.h" #include "ui/ozone/platform/wayland/test/constants.h" diff --git a/chromium/ui/ozone/platform/wayland/host/wayland_drm.cc b/chromium/ui/ozone/platform/wayland/host/wayland_drm.cc index 7b551543430..12a91eed83a 100644 --- a/chromium/ui/ozone/platform/wayland/host/wayland_drm.cc +++ b/chromium/ui/ozone/platform/wayland/host/wayland_drm.cc @@ -9,7 +9,7 @@ #include "base/files/scoped_file.h" #include "ui/gfx/buffer_format_util.h" -#include "ui/ozone/common/linux/drm_util_linux.h" +#include "ui/gfx/linux/drm_util_linux.h" #include "ui/ozone/platform/wayland/host/wayland_connection.h" #include "ui/ozone/platform/wayland/host/wayland_drm.h" 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 37feebecc9d..81a75d4661a 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 @@ -90,9 +90,9 @@ void WaylandInputMethodContext::UpdatePreeditText( auto length = preedit.text.size(); preedit.selection = gfx::Range(length); - preedit.ime_text_spans.push_back( - ImeTextSpan(ImeTextSpan::Type::kComposition, 0, length, - ImeTextSpan::Thickness::kThin, SK_ColorTRANSPARENT)); + preedit.ime_text_spans.push_back(ImeTextSpan( + ImeTextSpan::Type::kComposition, 0, length, ImeTextSpan::Thickness::kThin, + ImeTextSpan::UnderlineStyle::kSolid, SK_ColorTRANSPARENT)); delegate_->OnPreeditChanged(preedit); } diff --git a/chromium/ui/ozone/platform/wayland/host/wayland_input_method_context_unittest.cc b/chromium/ui/ozone/platform/wayland/host/wayland_input_method_context_unittest.cc index 08b2ddb20a5..09936ef8d2f 100644 --- a/chromium/ui/ozone/platform/wayland/host/wayland_input_method_context_unittest.cc +++ b/chromium/ui/ozone/platform/wayland/host/wayland_input_method_context_unittest.cc @@ -6,7 +6,6 @@ #include <wayland-server.h> #include <memory> -#include "mojo/public/cpp/bindings/binding.h" #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" #include "ui/base/ime/linux/linux_input_method_context.h" diff --git a/chromium/ui/ozone/platform/wayland/host/wayland_keyboard.cc b/chromium/ui/ozone/platform/wayland/host/wayland_keyboard.cc index fbadb0e3b1e..7da3270a9e3 100644 --- a/chromium/ui/ozone/platform/wayland/host/wayland_keyboard.cc +++ b/chromium/ui/ozone/platform/wayland/host/wayland_keyboard.cc @@ -125,7 +125,7 @@ void WaylandKeyboard::Key(void* data, // TODO(tonikitoo,msisov): Handler 'repeat' parameter below. keyboard->DispatchKey(key, down, false /*repeat*/, EventTimeForNow(), - device_id); + device_id, EF_NONE); } void WaylandKeyboard::Modifiers(void* data, @@ -174,7 +174,8 @@ void WaylandKeyboard::DispatchKey(uint32_t key, bool down, bool repeat, base::TimeTicks timestamp, - int device_id) { + int device_id, + int flags) { DomCode dom_code = KeycodeConverter::NativeKeycodeToDomCode(EvdevCodeToNativeCode(key)); if (dom_code == ui::DomCode::NONE) diff --git a/chromium/ui/ozone/platform/wayland/host/wayland_keyboard.h b/chromium/ui/ozone/platform/wayland/host/wayland_keyboard.h index 1e5fd7a4038..497a95506b1 100644 --- a/chromium/ui/ozone/platform/wayland/host/wayland_keyboard.h +++ b/chromium/ui/ozone/platform/wayland/host/wayland_keyboard.h @@ -77,7 +77,8 @@ class WaylandKeyboard : public EventAutoRepeatHandler::Delegate { bool down, bool repeat, base::TimeTicks timestamp, - int device_id) override; + int device_id, + int flags) override; WaylandConnection* connection_ = nullptr; wl::Object<wl_keyboard> obj_; diff --git a/chromium/ui/ozone/platform/wayland/host/wayland_pointer.cc b/chromium/ui/ozone/platform/wayland/host/wayland_pointer.cc index 4731b684565..c1620cedac0 100644 --- a/chromium/ui/ozone/platform/wayland/host/wayland_pointer.cc +++ b/chromium/ui/ozone/platform/wayland/host/wayland_pointer.cc @@ -117,9 +117,11 @@ void WaylandPointer::Button(void* data, changed_button = EF_RIGHT_MOUSE_BUTTON; break; case BTN_BACK: + case BTN_SIDE: changed_button = EF_BACK_MOUSE_BUTTON; break; case BTN_FORWARD: + case BTN_EXTRA: changed_button = EF_FORWARD_MOUSE_BUTTON; break; default: 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 be9cd942d6e..b96f2e6f73f 100644 --- a/chromium/ui/ozone/platform/wayland/host/wayland_pointer_unittest.cc +++ b/chromium/ui/ozone/platform/wayland/host/wayland_pointer_unittest.cc @@ -72,14 +72,15 @@ TEST_P(WaylandPointerTest, Enter) { TEST_P(WaylandPointerTest, Leave) { MockPlatformWindowDelegate other_delegate; - WaylandWindow other_window(&other_delegate, connection_.get()); gfx::AcceleratedWidget other_widget = gfx::kNullAcceleratedWidget; EXPECT_CALL(other_delegate, OnAcceleratedWidgetAvailable(_)) .WillOnce(SaveArg<0>(&other_widget)); + PlatformWindowInitProperties properties; properties.bounds = gfx::Rect(0, 0, 10, 10); properties.type = PlatformWindowType::kWindow; - ASSERT_TRUE(other_window.Initialize(std::move(properties))); + auto other_window = WaylandWindow::Create(&other_delegate, connection_.get(), + std::move(properties)); ASSERT_NE(other_widget, gfx::kNullAcceleratedWidget); Sync(); diff --git a/chromium/ui/ozone/platform/wayland/host/wayland_popup.cc b/chromium/ui/ozone/platform/wayland/host/wayland_popup.cc new file mode 100644 index 00000000000..dd9e6c268ab --- /dev/null +++ b/chromium/ui/ozone/platform/wayland/host/wayland_popup.cc @@ -0,0 +1,202 @@ +// Copyright 2019 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/wayland_popup.h" + +#include "ui/ozone/platform/wayland/common/wayland_util.h" +#include "ui/ozone/platform/wayland/host/shell_object_factory.h" +#include "ui/ozone/platform/wayland/host/shell_popup_wrapper.h" +#include "ui/ozone/platform/wayland/host/wayland_buffer_manager_host.h" +#include "ui/ozone/platform/wayland/host/wayland_connection.h" + +namespace ui { + +WaylandPopup::WaylandPopup(PlatformWindowDelegate* delegate, + WaylandConnection* connection) + : WaylandWindow(delegate, connection) {} + +WaylandPopup::~WaylandPopup() = default; + +bool WaylandPopup::CreateShellPopup() { + if (GetBounds().IsEmpty()) + return false; + + DCHECK(parent_window() && !shell_popup_); + + auto bounds_px = AdjustPopupWindowPosition(); + + ShellObjectFactory factory; + shell_popup_ = factory.CreateShellPopupWrapper(connection(), this, bounds_px); + if (!shell_popup_) { + LOG(ERROR) << "Failed to create Wayland shell popup"; + return false; + } + + parent_window()->set_child_window(this); + return true; +} + +void WaylandPopup::Show(bool inactive) { + if (shell_popup_) + return; + + set_keyboard_focus(true); + + if (!CreateShellPopup()) { + Close(); + return; + } + + UpdateBufferScale(false); + connection()->ScheduleFlush(); +} + +void WaylandPopup::Hide() { + if (!shell_popup_) + return; + + if (child_window()) + child_window()->Hide(); + + if (shell_popup_) { + parent_window()->set_child_window(nullptr); + shell_popup_.reset(); + } + + // Detach buffer from surface in order to completely shutdown popups and + // tooltips, and release resources. + connection()->buffer_manager_host()->ResetSurfaceContents(GetWidget()); +} + +bool WaylandPopup::IsVisible() const { + return !!shell_popup_; +} + +bool WaylandPopup::HasCapture() const { + // WaylandPopups always have captures. + return shell_popup(); +} + +void WaylandPopup::HandlePopupConfigure(const gfx::Rect& bounds_dip) { + DCHECK(shell_popup()); + DCHECK(parent_window()); + + SetBufferScale(parent_window()->buffer_scale(), true); + + gfx::Rect new_bounds_dip = bounds_dip; + + // It's not enough to just set new bounds. If it is a menu window, whose + // parent is a top level window a.k.a browser window, it can be flipped + // vertically along y-axis and have negative values set. Chromium cannot + // understand that and starts to position nested menu windows incorrectly. To + // fix that, we have to bear in mind that Wayland compositor does not share + // global coordinates for any surfaces, and Chromium assumes the top level + // window is always located at 0,0 origin. What is more, child windows must + // always be positioned relative to parent window local surface coordinates. + // Thus, if the menu window is flipped along y-axis by Wayland and its origin + // is above the top level parent window, the origin of the top level window + // has to be shifted by that value on y-axis so that the origin of the menu + // becomes x,0, and events can be handled normally. + if (!wl::IsMenuType(parent_window()->type())) { + gfx::Rect parent_bounds = parent_window()->GetBounds(); + // The menu window is flipped along y-axis and have x,-y origin. Shift the + // parent top level window instead. + if (new_bounds_dip.y() < 0) { + // Move parent bounds along y-axis. + parent_bounds.set_y(-(new_bounds_dip.y() * buffer_scale())); + new_bounds_dip.set_y(0); + } else { + // If the menu window is located at correct origin from the browser point + // of view, return the top level window back to 0,0. + parent_bounds.set_y(0); + } + parent_window()->SetBounds(parent_bounds); + } else { + // The nested menu windows are located relative to the parent menu windows. + // Thus, the location must be translated to be relative to the top level + // window, which automatically becomes the same as relative to an origin of + // a display. + new_bounds_dip = gfx::ScaleToRoundedRect( + wl::TranslateBoundsToTopLevelCoordinates( + gfx::ScaleToRoundedRect(new_bounds_dip, buffer_scale()), + parent_window()->GetBounds()), + 1.0 / buffer_scale()); + DCHECK(new_bounds_dip.y() >= 0); + } + + SetBoundsDip(new_bounds_dip); +} + +void WaylandPopup::OnCloseRequest() { + // Before calling OnCloseRequest, the |shell_popup_| must become hidden and + // only then call OnCloseRequest(). + DCHECK(!shell_popup_); + WaylandWindow::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. + SetBufferScale(parent_window()->buffer_scale(), false); + set_ui_scale(parent_window()->ui_scale()); + return true; +} + +gfx::Rect WaylandPopup::AdjustPopupWindowPosition() { + auto* top_level_parent = wl::IsMenuType(parent_window()->type()) + ? parent_window()->parent_window() + : parent_window(); + DCHECK(top_level_parent); + DCHECK(buffer_scale() == top_level_parent->buffer_scale()); + DCHECK(ui_scale() == top_level_parent->ui_scale()); + + // Chromium positions windows in screen coordinates, but Wayland requires them + // to be in local surface coordinates a.k.a relative to parent window. + const gfx::Rect parent_bounds_dip = + gfx::ScaleToRoundedRect(parent_window()->GetBounds(), 1.0 / ui_scale()); + gfx::Rect new_bounds_dip = wl::TranslateBoundsToParentCoordinates( + gfx::ScaleToRoundedRect(GetBounds(), 1.0 / ui_scale()), + parent_bounds_dip); + + // Chromium may decide to position nested menu windows on the left side + // instead of the right side of parent menu windows when the size of the + // window becomes larger than the display it is shown on. It's correct when + // the window is located on one display and occupies the whole work area, but + // as soon as it's moved and there is space on the right side, Chromium + // continues positioning the nested menus on the left side relative to the + // parent menu (Wayland does not provide clients with global coordinates). + // Instead, reposition that window to be on the right side of the parent menu + // window and let the compositor decide how to position it if it does not fit + // a single display. However, there is one exception - if the window is + // maximized, let Chromium position it on the left side as long as the Wayland + // compositor may decide to position the nested window on the right side of + // the parent menu window, which results in showing it on a second display if + // more than one display is used. + if (wl::IsMenuType(parent_window()->type()) && + parent_window()->parent_window() && + (parent_window()->parent_window()->GetPlatformWindowState() != + PlatformWindowState::kMaximized)) { + auto* top_level_window = parent_window()->parent_window(); + DCHECK(top_level_window && !wl::IsMenuType(top_level_window->type())); + if (new_bounds_dip.x() <= 0 && top_level_window->GetPlatformWindowState() != + PlatformWindowState::kMaximized) { + // Position the child menu window on the right side of the parent window + // and let the Wayland compositor decide how to do constraint + // adjustments. + int new_x = parent_bounds_dip.width() - + (new_bounds_dip.width() + new_bounds_dip.x()); + new_bounds_dip.set_x(new_x); + } + } + return gfx::ScaleToRoundedRect(new_bounds_dip, ui_scale() / buffer_scale()); +} + +} // namespace ui diff --git a/chromium/ui/ozone/platform/wayland/host/wayland_popup.h b/chromium/ui/ozone/platform/wayland/host/wayland_popup.h new file mode 100644 index 00000000000..7bc48bb29a0 --- /dev/null +++ b/chromium/ui/ozone/platform/wayland/host/wayland_popup.h @@ -0,0 +1,49 @@ +// Copyright 2019 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_WAYLAND_POPUP_H_ +#define UI_OZONE_PLATFORM_WAYLAND_HOST_WAYLAND_POPUP_H_ + +#include "ui/ozone/platform/wayland/host/wayland_window.h" + +namespace ui { + +class WaylandConnection; +class ShellPopupWrapper; + +class WaylandPopup : public WaylandWindow { + public: + WaylandPopup(PlatformWindowDelegate* delegate, WaylandConnection* connection); + ~WaylandPopup() override; + + ShellPopupWrapper* shell_popup() const { return shell_popup_.get(); } + + // PlatformWindow + void Show(bool inactive) override; + void Hide() override; + bool IsVisible() const override; + bool HasCapture() const override; + + private: + // WaylandWindow overrides: + void HandlePopupConfigure(const gfx::Rect& bounds) override; + void OnCloseRequest() override; + bool OnInitialize(PlatformWindowInitProperties properties) override; + + // Creates a popup window, which is visible as a menu window. + bool CreateShellPopup(); + + // Returns bounds with origin relative to parent window's origin. + gfx::Rect AdjustPopupWindowPosition(); + + // Wrappers around xdg v5 and xdg v6 objects. WaylandPopup doesn't + // know anything about the version. + std::unique_ptr<ShellPopupWrapper> shell_popup_; + + DISALLOW_COPY_AND_ASSIGN(WaylandPopup); +}; + +} // namespace ui + +#endif // UI_OZONE_PLATFORM_WAYLAND_HOST_WAYLAND_POPUP_H_ diff --git a/chromium/ui/ozone/platform/wayland/host/wayland_screen_unittest.cc b/chromium/ui/ozone/platform/wayland/host/wayland_screen_unittest.cc index e1e3cc823ac..9198aa88e05 100644 --- a/chromium/ui/ozone/platform/wayland/host/wayland_screen_unittest.cc +++ b/chromium/ui/ozone/platform/wayland/host/wayland_screen_unittest.cc @@ -89,13 +89,12 @@ class WaylandScreenTest : public WaylandTest { PlatformWindowType window_type, gfx::AcceleratedWidget parent_widget, MockPlatformWindowDelegate* delegate) { - auto window = std::make_unique<WaylandWindow>(delegate, connection_.get()); PlatformWindowInitProperties properties; properties.bounds = bounds; properties.type = window_type; properties.parent_widget = parent_widget; - EXPECT_TRUE(window->Initialize(std::move(properties))); - return window; + return WaylandWindow::Create(delegate, connection_.get(), + std::move(properties)); } void UpdateOutputGeometry(wl_resource* output_resource, diff --git a/chromium/ui/ozone/platform/wayland/host/wayland_subsurface.cc b/chromium/ui/ozone/platform/wayland/host/wayland_subsurface.cc new file mode 100644 index 00000000000..28f435f39de --- /dev/null +++ b/chromium/ui/ozone/platform/wayland/host/wayland_subsurface.cc @@ -0,0 +1,130 @@ +// Copyright 2019 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/wayland_subsurface.h" + +#include "ui/ozone/platform/wayland/common/wayland_util.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_window_manager.h" + +namespace ui { + +namespace { + +gfx::Rect AdjustSubsurfaceBounds(const gfx::Rect& bounds_px, + const gfx::Rect& parent_bounds_px, + int32_t ui_scale, + int32_t buffer_scale) { + const auto parent_bounds_dip = + gfx::ScaleToRoundedRect(parent_bounds_px, 1.0 / ui_scale); + auto new_bounds_dip = + wl::TranslateBoundsToParentCoordinates(bounds_px, parent_bounds_dip); + return gfx::ScaleToRoundedRect(new_bounds_dip, ui_scale / buffer_scale); +} + +} // namespace + +WaylandSubsurface::WaylandSubsurface(PlatformWindowDelegate* delegate, + WaylandConnection* connection) + : WaylandWindow(delegate, connection) {} + +WaylandSubsurface::~WaylandSubsurface() = default; + +void WaylandSubsurface::Show(bool inactive) { + if (subsurface_) + return; + + CreateSubsurface(); + UpdateBufferScale(false); +} + +void WaylandSubsurface::Hide() { + if (!subsurface_) + return; + + subsurface_.reset(); + + // Detach buffer from surface in order to completely shutdown menus and + // tooltips, and release resources. + connection()->buffer_manager_host()->ResetSurfaceContents(GetWidget()); +} + +bool WaylandSubsurface::IsVisible() const { + return !!subsurface_; +} + +void WaylandSubsurface::SetBounds(const gfx::Rect& bounds) { + auto old_bounds = GetBounds(); + WaylandWindow::SetBounds(bounds); + + if (old_bounds == bounds || !parent_window()) + return; + + // Translate location from screen to surface coordinates. + auto bounds_px = AdjustSubsurfaceBounds( + GetBounds(), parent_window()->GetBounds(), ui_scale(), buffer_scale()); + wl_subsurface_set_position(subsurface_.get(), bounds_px.x() / buffer_scale(), + bounds_px.y() / buffer_scale()); + wl_surface_commit(surface()); + connection()->ScheduleFlush(); +} + +void WaylandSubsurface::CreateSubsurface() { + auto* parent = parent_window(); + if (!parent) { + // wl_subsurface can be used for several purposes: tooltips and drag arrow + // windows. If we are in a drag process, use the entered window. Otherwise, + // it must be a tooltip. + if (connection()->IsDragInProgress()) { + parent = connection()->wayland_data_device()->entered_window(); + set_parent_window(parent); + } else { + // If Aura does not not provide a reference parent window, needed by + // Wayland, we get the current focused window to place and show the + // tooltips. + parent = + connection()->wayland_window_manager()->GetCurrentFocusedWindow(); + } + } + + // Tooltip and drag arrow creation is an async operation. By the time Aura + // actually creates them, it is possible that the user has already moved the + // mouse/pointer out of the window that triggered the tooltip, or user is no + // longer in a drag/drop process. In this case, parent is NULL. + if (!parent) + return; + + wl_subcompositor* subcompositor = connection()->subcompositor(); + DCHECK(subcompositor); + subsurface_.reset(wl_subcompositor_get_subsurface(subcompositor, surface(), + parent->surface())); + + // Chromium positions tooltip windows in screen coordinates, but Wayland + // requires them to be in local surface coordinates a.k.a relative to parent + // window. + auto bounds_px = AdjustSubsurfaceBounds(GetBounds(), parent->GetBounds(), + ui_scale(), buffer_scale()); + + DCHECK(subsurface_); + // Convert position to DIP. + wl_subsurface_set_position(subsurface_.get(), bounds_px.x() / buffer_scale(), + bounds_px.y() / buffer_scale()); + wl_subsurface_set_desync(subsurface_.get()); + wl_surface_commit(parent->surface()); + connection()->ScheduleFlush(); +} + +bool WaylandSubsurface::OnInitialize(PlatformWindowInitProperties properties) { + // 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()); + return true; + } + set_parent_window(GetParentWindow(properties.parent_widget)); + return true; +} + +} // namespace ui diff --git a/chromium/ui/ozone/platform/wayland/host/wayland_subsurface.h b/chromium/ui/ozone/platform/wayland/host/wayland_subsurface.h new file mode 100644 index 00000000000..e5c8bed26f8 --- /dev/null +++ b/chromium/ui/ozone/platform/wayland/host/wayland_subsurface.h @@ -0,0 +1,38 @@ +// Copyright 2019 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_WAYLAND_SUBSURFACE_H_ +#define UI_OZONE_PLATFORM_WAYLAND_HOST_WAYLAND_SUBSURFACE_H_ + +#include "ui/ozone/platform/wayland/host/wayland_window.h" + +namespace ui { + +class WaylandSubsurface : public WaylandWindow { + public: + WaylandSubsurface(PlatformWindowDelegate* delegate, + WaylandConnection* connection); + ~WaylandSubsurface() override; + + // PlatformWindow overrides: + void Show(bool inactive) override; + void Hide() override; + bool IsVisible() const override; + void SetBounds(const gfx::Rect& bounds) override; + + private: + // WaylandWindow overrides: + bool OnInitialize(PlatformWindowInitProperties properties) override; + + // Creates (if necessary) and shows a subsurface window. + void CreateSubsurface(); + + wl::Object<wl_subsurface> subsurface_; + + DISALLOW_COPY_AND_ASSIGN(WaylandSubsurface); +}; + +} // namespace ui + +#endif // UI_OZONE_PLATFORM_WAYLAND_HOST_WAYLAND_SUBSURFACE_H_ diff --git a/chromium/ui/ozone/platform/wayland/host/wayland_surface.cc b/chromium/ui/ozone/platform/wayland/host/wayland_surface.cc new file mode 100644 index 00000000000..bc45f677a75 --- /dev/null +++ b/chromium/ui/ozone/platform/wayland/host/wayland_surface.cc @@ -0,0 +1,353 @@ +// Copyright 2019 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/wayland_surface.h" + +#include "ui/base/dragdrop/drag_drop_types.h" +#include "ui/base/dragdrop/os_exchange_data.h" +#include "ui/base/hit_test.h" +#include "ui/gfx/native_widget_types.h" +#include "ui/ozone/platform/wayland/host/shell_object_factory.h" +#include "ui/ozone/platform/wayland/host/shell_surface_wrapper.h" +#include "ui/ozone/platform/wayland/host/wayland_buffer_manager_host.h" +#include "ui/ozone/platform/wayland/host/wayland_connection.h" +#include "ui/platform_window/platform_window_handler/wm_drop_handler.h" + +namespace ui { + +WaylandSurface::WaylandSurface(PlatformWindowDelegate* delegate, + WaylandConnection* connection) + : WaylandWindow(delegate, connection), + state_(PlatformWindowState::kNormal) { + // Set a class property key, which allows |this| to be used for interactive + // events, e.g. move or resize. + SetWmMoveResizeHandler(this, AsWmMoveResizeHandler()); + + // Set a class property key, which allows |this| to be used for drag action. + SetWmDragHandler(this, this); +} + +WaylandSurface::~WaylandSurface() { + if (drag_closed_callback_) { + std::move(drag_closed_callback_) + .Run(DragDropTypes::DragOperation::DRAG_NONE); + } +} + +bool WaylandSurface::CreateShellSurface() { + ShellObjectFactory factory; + shell_surface_ = factory.CreateShellSurfaceWrapper(connection(), this); + if (!shell_surface_) { + LOG(ERROR) << "Failed to create a ShellSurface."; + return false; + } + + shell_surface_->SetAppId(app_id_); + shell_surface_->SetTitle(window_title_); + SetSizeConstraints(); + TriggerStateChanges(); + return true; +} + +void WaylandSurface::ApplyPendingBounds() { + if (pending_bounds_dip_.IsEmpty()) + return; + DCHECK(shell_surface_); + + SetBoundsDip(pending_bounds_dip_); + shell_surface_->SetWindowGeometry(pending_bounds_dip_); + pending_bounds_dip_ = gfx::Rect(); + connection()->ScheduleFlush(); +} + +void WaylandSurface::DispatchHostWindowDragMovement( + int hittest, + const gfx::Point& pointer_location_in_px) { + DCHECK(shell_surface_); + + connection()->ResetPointerFlags(); + if (hittest == HTCAPTION) + shell_surface_->SurfaceMove(connection()); + else + shell_surface_->SurfaceResize(connection(), hittest); + + connection()->ScheduleFlush(); +} + +void WaylandSurface::StartDrag(const ui::OSExchangeData& data, + int operation, + gfx::NativeCursor cursor, + base::OnceCallback<void(int)> callback) { + DCHECK(!drag_closed_callback_); + drag_closed_callback_ = std::move(callback); + connection()->StartDrag(data, operation); +} + +void WaylandSurface::Show(bool inactive) { + if (shell_surface_) + return; + + if (!CreateShellSurface()) { + Close(); + return; + } + + set_keyboard_focus(true); + UpdateBufferScale(false); +} + +void WaylandSurface::Hide() { + if (!shell_surface_) + return; + + if (child_window()) { + child_window()->Hide(); + set_child_window(nullptr); + } + + shell_surface_.reset(); + connection()->ScheduleFlush(); + + // Detach buffer from surface in order to completely shutdown menus and + // tooltips, and release resources. + connection()->buffer_manager_host()->ResetSurfaceContents(GetWidget()); +} + +bool WaylandSurface::IsVisible() const { + // X and Windows return true if the window is minimized. For consistency, do + // the same. + return !!shell_surface_ || state_ == PlatformWindowState::kMinimized; +} + +void WaylandSurface::SetTitle(const base::string16& title) { + if (window_title_ == title) + return; + + window_title_ = title; + + if (shell_surface_) { + shell_surface_->SetTitle(title); + connection()->ScheduleFlush(); + } +} + +void WaylandSurface::ToggleFullscreen() { + // TODO(msisov, tonikitoo): add multiscreen support. As the documentation says + // if xdg_toplevel_set_fullscreen() is not provided with wl_output, it's up + // to the compositor to choose which display will be used to map this surface. + + // We must track the previous state to correctly say our state as long as it + // can be the maximized instead of normal one. + PlatformWindowState new_state = PlatformWindowState::kUnknown; + if (state_ == PlatformWindowState::kFullScreen) { + if (previous_state_ == PlatformWindowState::kMaximized) + new_state = previous_state_; + else + new_state = PlatformWindowState::kNormal; + } else { + new_state = PlatformWindowState::kFullScreen; + } + + SetWindowState(new_state); +} + +void WaylandSurface::Maximize() { + SetWindowState(PlatformWindowState::kMaximized); +} + +void WaylandSurface::Minimize() { + SetWindowState(PlatformWindowState::kMinimized); +} + +void WaylandSurface::Restore() { + DCHECK(shell_surface_); + SetWindowState(PlatformWindowState::kNormal); +} + +PlatformWindowState WaylandSurface::GetPlatformWindowState() const { + return state_; +} + +void WaylandSurface::SizeConstraintsChanged() { + // Size constraints only make sense for normal windows. + if (!shell_surface_) + return; + + DCHECK(delegate()); + min_size_ = delegate()->GetMinimumSizeForWindow(); + max_size_ = delegate()->GetMaximumSizeForWindow(); + SetSizeConstraints(); +} + +void WaylandSurface::HandleSurfaceConfigure(int32_t width, + int32_t height, + bool is_maximized, + bool is_fullscreen, + bool is_activated) { + // Store the old state to propagte state changes if Wayland decides to change + // the state to something else. + PlatformWindowState old_state = state_; + if (state_ == PlatformWindowState::kMinimized && !is_activated) { + state_ = PlatformWindowState::kMinimized; + } else if (is_fullscreen) { + state_ = PlatformWindowState::kFullScreen; + } else if (is_maximized) { + state_ = PlatformWindowState::kMaximized; + } else { + state_ = PlatformWindowState::kNormal; + } + + const bool state_changed = old_state != state_; + const bool is_normal = state_ == PlatformWindowState::kNormal; + + // Update state before notifying delegate. + const bool did_active_change = is_active_ != is_activated; + is_active_ = is_activated; + + // Rather than call SetBounds here for every configure event, just save the + // most recent bounds, and have WaylandConnection call ApplyPendingBounds + // when it has finished processing events. We may get many configure events + // in a row during an interactive resize, and only the last one matters. + // + // Width or height set to 0 means that we should decide on width and height by + // ourselves, but we don't want to set them to anything else. Use restored + // bounds size or the current bounds iff the current state is normal (neither + // maximized nor fullscreen). + // + // Note: if the browser was started with --start-fullscreen and a user exits + // the fullscreen mode, wayland may set the width and height to be 1. Instead, + // explicitly set the bounds to the current desired ones or the previous + // bounds. + if (width > 1 && height > 1) { + pending_bounds_dip_ = gfx::Rect(0, 0, width, height); + } else if (is_normal) { + pending_bounds_dip_.set_size( + gfx::ScaleToRoundedSize(GetRestoredBoundsInPixels().IsEmpty() + ? GetBounds().size() + : GetRestoredBoundsInPixels().size(), + + 1.0 / buffer_scale())); + } + + // Store the restored bounds of current state differs from the normal state. + // It can be client or compositor side change from normal to something else. + // Thus, we must store previous bounds to restore later. + SetOrResetRestoredBounds(); + ApplyPendingBounds(); + + if (state_changed) + delegate()->OnWindowStateChanged(state_); + + if (did_active_change) + delegate()->OnActivationChanged(is_active_); +} + +void WaylandSurface::OnDragEnter(const gfx::PointF& point, + std::unique_ptr<OSExchangeData> data, + int operation) { + WmDropHandler* drop_handler = GetWmDropHandler(*this); + if (!drop_handler) + return; + + // Wayland sends locations in DIP so they need to be translated to + // physical pixels. + drop_handler->OnDragEnter( + gfx::ScalePoint(point, buffer_scale(), buffer_scale()), std::move(data), + operation); +} + +int WaylandSurface::OnDragMotion(const gfx::PointF& point, + uint32_t time, + int operation) { + WmDropHandler* drop_handler = GetWmDropHandler(*this); + if (!drop_handler) + return 0; + + // Wayland sends locations in DIP so they need to be translated to + // physical pixels. + return drop_handler->OnDragMotion( + gfx::ScalePoint(point, buffer_scale(), buffer_scale()), operation); +} + +void WaylandSurface::OnDragDrop(std::unique_ptr<OSExchangeData> data) { + WmDropHandler* drop_handler = GetWmDropHandler(*this); + if (!drop_handler) + return; + drop_handler->OnDragDrop(std::move(data)); +} + +void WaylandSurface::OnDragLeave() { + WmDropHandler* drop_handler = GetWmDropHandler(*this); + if (!drop_handler) + return; + drop_handler->OnDragLeave(); +} + +void WaylandSurface::OnDragSessionClose(uint32_t dnd_action) { + std::move(drag_closed_callback_).Run(dnd_action); + connection()->ResetPointerFlags(); +} + +bool WaylandSurface::OnInitialize(PlatformWindowInitProperties properties) { + app_id_ = properties.wm_class_class; + return true; +} + +void WaylandSurface::TriggerStateChanges() { + if (!shell_surface_) + return; + + if (state_ == PlatformWindowState::kFullScreen) + shell_surface_->SetFullscreen(); + else + shell_surface_->UnSetFullscreen(); + + // Call UnSetMaximized only if current state is normal. Otherwise, if the + // current state is fullscreen and the previous is maximized, calling + // UnSetMaximized may result in wrong restored window position that clients + // are not allowed to know about. + if (state_ == PlatformWindowState::kMaximized) + shell_surface_->SetMaximized(); + else if (state_ == PlatformWindowState::kNormal) + shell_surface_->UnSetMaximized(); + + if (state_ == PlatformWindowState::kMinimized) + shell_surface_->SetMinimized(); + + connection()->ScheduleFlush(); +} + +void WaylandSurface::SetWindowState(PlatformWindowState state) { + previous_state_ = state_; + state_ = state; + TriggerStateChanges(); +} + +WmMoveResizeHandler* WaylandSurface::AsWmMoveResizeHandler() { + return static_cast<WmMoveResizeHandler*>(this); +} + +void WaylandSurface::SetSizeConstraints() { + if (min_size_.has_value()) + shell_surface_->SetMinSize(min_size_->width(), min_size_->height()); + if (max_size_.has_value()) + shell_surface_->SetMaxSize(max_size_->width(), max_size_->height()); + + connection()->ScheduleFlush(); +} + +void WaylandSurface::SetOrResetRestoredBounds() { + // The |restored_bounds_| are used when the window gets back to normal + // state after it went maximized or fullscreen. So we reset these if the + // window has just become normal and store the current bounds if it is + // either going out of normal state or simply changes the state and we don't + // have any meaningful value stored. + if (GetPlatformWindowState() == PlatformWindowState::kNormal) { + SetRestoredBoundsInPixels({}); + } else if (GetRestoredBoundsInPixels().IsEmpty()) { + SetRestoredBoundsInPixels(GetBounds()); + } +} + +} // namespace ui diff --git a/chromium/ui/ozone/platform/wayland/host/wayland_surface.h b/chromium/ui/ozone/platform/wayland/host/wayland_surface.h new file mode 100644 index 00000000000..ceda32d24a7 --- /dev/null +++ b/chromium/ui/ozone/platform/wayland/host/wayland_surface.h @@ -0,0 +1,127 @@ +// Copyright 2019 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_WAYLAND_SURFACE_H_ +#define UI_OZONE_PLATFORM_WAYLAND_HOST_WAYLAND_SURFACE_H_ + +#include "ui/ozone/platform/wayland/host/wayland_window.h" + +#include "ui/platform_window/platform_window_handler/wm_drag_handler.h" +#include "ui/platform_window/platform_window_handler/wm_move_resize_handler.h" + +namespace ui { + +class ShellSurfaceWrapper; + +class WaylandSurface : public WaylandWindow, + public WmMoveResizeHandler, + public WmDragHandler { + public: + WaylandSurface(PlatformWindowDelegate* delegate, + WaylandConnection* connection); + ~WaylandSurface() override; + + ShellSurfaceWrapper* shell_surface() const { return shell_surface_.get(); } + + // Apply the bounds specified in the most recent configure event. This should + // be called after processing all pending events in the wayland connection. + void ApplyPendingBounds(); + + // WmMoveResizeHandler + void DispatchHostWindowDragMovement( + int hittest, + const gfx::Point& pointer_location_in_px) override; + + // WmDragHandler + void StartDrag(const ui::OSExchangeData& data, + int operation, + gfx::NativeCursor cursor, + base::OnceCallback<void(int)> callback) override; + + // PlatformWindow + void Show(bool inactive) override; + void Hide() override; + bool IsVisible() const override; + void SetTitle(const base::string16& title) override; + void ToggleFullscreen() override; + void Maximize() override; + void Minimize() override; + void Restore() override; + PlatformWindowState GetPlatformWindowState() const override; + void SizeConstraintsChanged() override; + + private: + // WaylandWindow overrides: + void HandleSurfaceConfigure(int32_t widht, + int32_t height, + bool is_maximized, + bool is_fullscreen, + bool is_activated) override; + void OnDragEnter(const gfx::PointF& point, + std::unique_ptr<OSExchangeData> data, + int operation) override; + int OnDragMotion(const gfx::PointF& point, + uint32_t time, + int operation) override; + void OnDragDrop(std::unique_ptr<OSExchangeData> data) override; + void OnDragLeave() override; + void OnDragSessionClose(uint32_t dnd_action) override; + bool OnInitialize(PlatformWindowInitProperties properties) override; + + void TriggerStateChanges(); + void SetWindowState(PlatformWindowState state); + + // Creates a surface window, which is visible as a main window. + bool CreateShellSurface(); + + WmMoveResizeHandler* AsWmMoveResizeHandler(); + + // Propagates the |min_size_| and |max_size_| to the ShellSurface. + void SetSizeConstraints(); + + void SetOrResetRestoredBounds(); + + // Wrappers around shell surface. + std::unique_ptr<ShellSurfaceWrapper> shell_surface_; + + base::OnceCallback<void(int)> drag_closed_callback_; + + // These bounds attributes below have suffices that indicate units used. + // Wayland operates in DIP but the platform operates in physical pixels so + // our WaylandSurface is the link that has to translate the units. See also + // comments in the implementation. + // + // Bounds that will be applied when the window state is finalized. The window + // may get several configuration events that update the pending bounds, and + // only upon finalizing the state is the latest value stored as the current + // bounds via |ApplyPendingBounds|. Measured in DIP because updated in the + // handler that receives DIP from Wayland. + gfx::Rect pending_bounds_dip_; + + // Contains the current state of the window. + PlatformWindowState state_; + // Contains the previous state of the window. + PlatformWindowState previous_state_; + + bool is_active_ = false; + + // Id of the chromium app passed through + // PlatformWindowInitProperties::wm_class_class. This is used by Wayland + // compositor to identify the app, unite it's windows into the same stack of + // windows and find *.desktop file to set various preferences including icons. + std::string app_id_; + + // Title of the ShellSurface. + base::string16 window_title_; + + // Max and min sizes of the WaylandSurface window. + base::Optional<gfx::Size> min_size_; + base::Optional<gfx::Size> max_size_; + + DISALLOW_COPY_AND_ASSIGN(WaylandSurface); +}; + +} // namespace ui + +#endif // UI_OZONE_PLATFORM_WAYLAND_HOST_WAYLAND_SURFACE_H_ diff --git a/chromium/ui/ozone/platform/wayland/host/wayland_window.cc b/chromium/ui/ozone/platform/wayland/host/wayland_window.cc index 4787a1f3b39..cfb9644b1f5 100644 --- a/chromium/ui/ozone/platform/wayland/host/wayland_window.cc +++ b/chromium/ui/ozone/platform/wayland/host/wayland_window.cc @@ -9,103 +9,24 @@ #include "base/bind.h" #include "ui/base/cursor/ozone/bitmap_cursor_factory_ozone.h" -#include "ui/base/dragdrop/drag_drop_types.h" -#include "ui/base/dragdrop/os_exchange_data.h" -#include "ui/base/hit_test.h" #include "ui/events/event.h" #include "ui/events/event_utils.h" #include "ui/events/ozone/events_ozone.h" #include "ui/gfx/geometry/point_f.h" -#include "ui/ozone/platform/wayland/host/shell_popup_wrapper.h" -#include "ui/ozone/platform/wayland/host/shell_surface_wrapper.h" +#include "ui/ozone/platform/wayland/common/wayland_util.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_output_manager.h" #include "ui/ozone/platform/wayland/host/wayland_pointer.h" -#include "ui/ozone/platform/wayland/host/xdg_popup_wrapper_impl.h" -#include "ui/ozone/platform/wayland/host/xdg_surface_wrapper_impl.h" -#include "ui/platform_window/platform_window_handler/wm_drop_handler.h" namespace ui { -namespace { - -// Factory, which decides which version type of xdg object to build. -class XDGShellObjectFactory { - public: - XDGShellObjectFactory() = default; - ~XDGShellObjectFactory() = default; - - std::unique_ptr<ShellPopupWrapper> CreateXDGPopup( - WaylandConnection* connection, - WaylandWindow* wayland_window, - const gfx::Rect& bounds) { - std::unique_ptr<XDGSurfaceWrapperImpl> surface = - std::make_unique<XDGSurfaceWrapperImpl>(wayland_window); - if (connection->shell()) { - surface->InitializeStable(connection, wayland_window->surface(), false); - std::unique_ptr<XDGPopupWrapperImpl> popup = - std::make_unique<XDGPopupWrapperImpl>(std::move(surface), - wayland_window); - popup->InitializeStable(connection, wayland_window->surface(), - wayland_window->parent_window(), bounds); - return popup; - } - DCHECK(connection->shell_v6()); - - surface->InitializeV6(connection, wayland_window->surface(), false); - std::unique_ptr<XDGPopupWrapperImpl> popup = - std::make_unique<XDGPopupWrapperImpl>(std::move(surface), - wayland_window); - popup->InitializeV6(connection, wayland_window->surface(), - wayland_window->parent_window(), bounds); - return popup; - } - - private: - DISALLOW_COPY_AND_ASSIGN(XDGShellObjectFactory); -}; - -// Translates bounds relative to top level window to specified parent. -gfx::Rect TranslateBoundsToParentCoordinates(const gfx::Rect& child_bounds, - const gfx::Rect& parent_bounds) { - return gfx::Rect(gfx::Point(child_bounds.x() - parent_bounds.x(), - child_bounds.y() - parent_bounds.y()), - child_bounds.size()); -} - -// Translates bounds relative to parent window to top level window. -gfx::Rect TranslateBoundsToTopLevelCoordinates(const gfx::Rect& child_bounds, - const gfx::Rect& parent_bounds) { - return gfx::Rect(gfx::Point(child_bounds.x() + parent_bounds.x(), - child_bounds.y() + parent_bounds.y()), - child_bounds.size()); -} - -} // namespace - WaylandWindow::WaylandWindow(PlatformWindowDelegate* delegate, WaylandConnection* connection) - : delegate_(delegate), - connection_(connection), - xdg_shell_objects_factory_(new XDGShellObjectFactory()), - state_(PlatformWindowState::kNormal), - pending_state_(PlatformWindowState::kUnknown) { - // Set a class property key, which allows |this| to be used for interactive - // events, e.g. move or resize. - SetWmMoveResizeHandler(this, AsWmMoveResizeHandler()); - - // Set a class property key, which allows |this| to be used for drag action. - SetWmDragHandler(this, this); -} + : delegate_(delegate), connection_(connection) {} WaylandWindow::~WaylandWindow() { - if (drag_closed_callback_) { - std::move(drag_closed_callback_) - .Run(DragDropTypes::DragOperation::DRAG_NONE); - } - PlatformEventSource::GetInstance()->RemovePlatformEventDispatcher(this); if (surface_) connection_->wayland_window_manager()->RemoveWindow(GetWidget()); @@ -123,78 +44,14 @@ WaylandWindow* WaylandWindow::FromSurface(wl_surface* surface) { wl_proxy_get_user_data(reinterpret_cast<wl_proxy*>(surface))); } -bool WaylandWindow::Initialize(PlatformWindowInitProperties properties) { - DCHECK(xdg_shell_objects_factory_); - - // Properties contain DIP bounds but the buffer scale is initially 1 so it's - // OK to assign. The bounds will be recalculated when the buffer scale - // changes. - DCHECK_EQ(buffer_scale_, 1); - bounds_px_ = properties.bounds; - opacity_ = properties.opacity; - - surface_.reset(wl_compositor_create_surface(connection_->compositor())); - if (!surface_) { - LOG(ERROR) << "Failed to create wl_surface"; - return false; - } - wl_surface_set_user_data(surface_.get(), this); - AddSurfaceListener(); - - connection_->wayland_window_manager()->AddWindow(GetWidget(), this); - - ui::PlatformWindowType ui_window_type = properties.type; - switch (ui_window_type) { - case ui::PlatformWindowType::kMenu: - case ui::PlatformWindowType::kPopup: - parent_window_ = GetParentWindow(properties.parent_widget); - - // Popups need to know their scale earlier to position themselves. - if (!parent_window_) { - LOG(ERROR) << "Failed to get a parent window for this popup"; - return false; - } - - SetBufferScale(parent_window_->buffer_scale_, false); - ui_scale_ = parent_window_->ui_scale_; - - // TODO(msisov, jkim): Handle notification windows, which are marked - // as popup windows as well. Those are the windows that do not have - // parents and pop up when the browser receives a notification. - CreateShellPopup(); - break; - case ui::PlatformWindowType::kTooltip: - // Tooltips subsurfaces are created on demand, upon ::Show calls. - is_tooltip_ = true; - break; - case ui::PlatformWindowType::kWindow: - case ui::PlatformWindowType::kBubble: - case ui::PlatformWindowType::kDrag: - // TODO(msisov): Figure out what kind of surface we need to create for - // bubble and drag windows. - CreateShellSurface(); - break; - } - - if (shell_surface_ && !properties.wm_class_class.empty()) - shell_surface_->SetAppId(properties.wm_class_class); - - connection_->ScheduleFlush(); - - PlatformEventSource::GetInstance()->AddPlatformEventDispatcher(this); - delegate_->OnAcceleratedWidgetAvailable(GetWidget()); - - // Will do nothing for popups because they have got their scale above. - UpdateBufferScale(false); - - MaybeUpdateOpaqueRegion(); - return true; -} - void WaylandWindow::UpdateBufferScale(bool update_bounds) { DCHECK(connection_->wayland_output_manager()); const auto* screen = connection_->wayland_output_manager()->wayland_screen(); - DCHECK(screen); + + // The client might not create screen at all. + if (!screen) + return; + const auto widget = GetWidget(); int32_t new_scale = 0; @@ -222,112 +79,6 @@ gfx::AcceleratedWidget WaylandWindow::GetWidget() const { return gfx::kNullAcceleratedWidget; return surface_.id(); } - -void WaylandWindow::CreateShellPopup() { - if (bounds_px_.IsEmpty()) - return; - - // TODO(jkim): Consider how to support DropArrow window on tabstrip. - // When it starts dragging, as described the protocol, https://goo.gl/1Mskq3, - // the client must have an active implicit grab. If we try to create a popup - // window while dragging is executed, it gets 'popup_done' directly from - // Wayland compositor and it's destroyed through 'popup_done'. It causes - // a crash when aura::Window is destroyed. - // https://crbug.com/875164 - if (connection_->IsDragInProgress()) { - surface_.reset(); - LOG(ERROR) << "Wayland can't create a popup window during dragging."; - return; - } - - DCHECK(parent_window_ && !shell_popup_); - - auto bounds_px = AdjustPopupWindowPosition(); - - shell_popup_ = - xdg_shell_objects_factory_->CreateXDGPopup(connection_, this, bounds_px); - - if (!shell_popup_) { - CHECK(false) << "Failed to create Wayland shell popup"; - } - - parent_window_->set_child_window(this); -} - -void WaylandWindow::CreateShellSurface() { - std::unique_ptr<XDGSurfaceWrapperImpl> xdg_surface = - std::make_unique<XDGSurfaceWrapperImpl>(this); - if (!xdg_surface) { - CHECK(false) << "Failed to create Wayland shell surface"; - return; - } - - if (connection_->shell()) { - if (!xdg_surface->InitializeStable(connection_, surface_.get())) { - CHECK(false) << "Failed to initialize Wayland shell surface"; - } - } else { - DCHECK(connection_->shell_v6()); - if (!xdg_surface->InitializeV6(connection_, surface_.get())) { - CHECK(false) << "Failed to initialize Wayland shell surface"; - } - } - shell_surface_ = std::move(xdg_surface); -} - -void WaylandWindow::CreateAndShowTooltipSubSurface() { - // Since Aura does not not provide a reference parent window, needed by - // Wayland, we get the current focused window to place and show the tooltips. - auto* parent_window = - connection_->wayland_window_manager()->GetCurrentFocusedWindow(); - - // Tooltip creation is an async operation. By the time Aura actually creates - // the tooltip, it is possible that the user has already moved the - // mouse/pointer out of the window that triggered the tooptip. In this case, - // parent_window is NULL. - if (!parent_window) - return; - - wl_subcompositor* subcompositor = connection_->subcompositor(); - DCHECK(subcompositor); - tooltip_subsurface_.reset(wl_subcompositor_get_subsurface( - subcompositor, surface_.get(), parent_window->surface())); - - // Chromium positions tooltip windows in screen coordinates, but Wayland - // requires them to be in local surface coordinates aka relative to parent - // window. - const auto parent_bounds_dip = - gfx::ScaleToRoundedRect(parent_window->GetBounds(), 1.0 / ui_scale_); - auto new_bounds_dip = - TranslateBoundsToParentCoordinates(bounds_px_, parent_bounds_dip); - auto bounds_px = - gfx::ScaleToRoundedRect(new_bounds_dip, ui_scale_ / buffer_scale_); - - DCHECK(tooltip_subsurface_); - // Convert position to DIP. - wl_subsurface_set_position(tooltip_subsurface_.get(), - bounds_px.x() / buffer_scale_, - bounds_px.y() / buffer_scale_); - wl_subsurface_set_desync(tooltip_subsurface_.get()); - wl_surface_commit(parent_window->surface()); - connection_->ScheduleFlush(); -} - -void WaylandWindow::ApplyPendingBounds() { - if (pending_bounds_dip_.IsEmpty()) - return; - DCHECK(shell_surface_); - - SetBoundsDip(pending_bounds_dip_); - shell_surface_->SetWindowGeometry(pending_bounds_dip_); - pending_bounds_dip_ = gfx::Rect(); - connection_->ScheduleFlush(); - - // Opaque region is based on the size of the window. Thus, update the region - // on each update. - MaybeUpdateOpaqueRegion(); -} - void WaylandWindow::SetPointerFocus(bool focus) { has_pointer_focus_ = focus; @@ -338,71 +89,12 @@ void WaylandWindow::SetPointerFocus(bool focus) { connection_->SetCursorBitmap(bitmap_->bitmaps(), bitmap_->hotspot()); } -void WaylandWindow::DispatchHostWindowDragMovement( - int hittest, - const gfx::Point& pointer_location_in_px) { - DCHECK(shell_surface_); - - connection_->ResetPointerFlags(); - if (hittest == HTCAPTION) - shell_surface_->SurfaceMove(connection_); - else - shell_surface_->SurfaceResize(connection_, hittest); - - connection_->ScheduleFlush(); -} - -void WaylandWindow::StartDrag(const ui::OSExchangeData& data, - int operation, - gfx::NativeCursor cursor, - base::OnceCallback<void(int)> callback) { - DCHECK(!drag_closed_callback_); - drag_closed_callback_ = std::move(callback); - connection_->StartDrag(data, operation); -} - void WaylandWindow::Show(bool inactive) { - if (!is_tooltip_) // Tooltip windows should not get keyboard focus - set_keyboard_focus(true); - - if (shell_surface_) - return; - - if (is_tooltip_) { - CreateAndShowTooltipSubSurface(); - return; - } - - if (!shell_popup_) { - // When showing a sub-menu after it has been previously shown and hidden, - // Wayland sends SetBounds prior to Show, and |bounds_px| takes the pixel - // bounds. This makes a difference against the normal flow when the - // window is created (see |Initialize|). To equalize things, rescale - // |bounds_px_| to DIP. It will be adjusted while creating the popup. - bounds_px_ = gfx::ScaleToRoundedRect(bounds_px_, 1.0 / ui_scale_); - CreateShellPopup(); - connection_->ScheduleFlush(); - } - - UpdateBufferScale(false); + NOTREACHED(); } void WaylandWindow::Hide() { - if (!is_tooltip_) { - tooltip_subsurface_.reset(); - } else { - if (child_window_) - child_window_->Hide(); - if (shell_popup_) { - parent_window_->set_child_window(nullptr); - shell_popup_.reset(); - } - } - - // Detach buffer from surface in order to completely shutdown popups and - // tooltips, and release resources. - if (!shell_surface()) - connection_->buffer_manager_host()->ResetSurfaceContents(GetWidget()); + NOTREACHED(); } void WaylandWindow::Close() { @@ -410,9 +102,8 @@ void WaylandWindow::Close() { } bool WaylandWindow::IsVisible() const { - // X and Windows return true if the window is minimized. For consistency, do - // the same. - return (!!shell_surface_ || !!shell_popup_) || IsMinimized(); + NOTREACHED(); + return false; } void WaylandWindow::PrepareForShutdown() {} @@ -422,6 +113,10 @@ void WaylandWindow::SetBounds(const gfx::Rect& bounds_px) { return; bounds_px_ = bounds_px; + // Opaque region is based on the size of the window. Thus, update the region + // on each update. + MaybeUpdateOpaqueRegion(); + delegate_->OnBoundsChanged(bounds_px_); } @@ -429,16 +124,12 @@ gfx::Rect WaylandWindow::GetBounds() { return bounds_px_; } -void WaylandWindow::SetTitle(const base::string16& title) { - DCHECK(shell_surface_); - shell_surface_->SetTitle(title); - connection_->ScheduleFlush(); -} +void WaylandWindow::SetTitle(const base::string16& title) {} void WaylandWindow::SetCapture() { // Wayland does implicit grabs, and doesn't allow for explicit grabs. The - // exception to that are popups, but we explicitly send events to a - // parent popup if such exists. + // exception to that are menus, but we explicitly send events to a + // parent menu if such exists. } void WaylandWindow::ReleaseCapture() { @@ -446,83 +137,21 @@ void WaylandWindow::ReleaseCapture() { } bool WaylandWindow::HasCapture() const { - // If WaylandWindow is a popup window, assume it has the capture. - return shell_popup() ? true : has_implicit_grab_; + return has_implicit_grab_; } -void WaylandWindow::ToggleFullscreen() { - DCHECK(shell_surface_); - - // There are some cases, when Chromium triggers a fullscreen state change - // before the surface is activated. In such cases, Wayland may ignore state - // changes and such flags as --kiosk or --start-fullscreen will be ignored. - // To overcome this, set a pending state, and once the surface is activated, - // trigger the change. - if (!is_active_) { - DCHECK(!IsFullscreen()); - pending_state_ = PlatformWindowState::kFullScreen; - return; - } +void WaylandWindow::ToggleFullscreen() {} - // TODO(msisov, tonikitoo): add multiscreen support. As the documentation says - // if shell_surface_set_fullscreen() is not provided with wl_output, it's up - // to the compositor to choose which display will be used to map this surface. - if (!IsFullscreen()) { - // Fullscreen state changes have to be handled manually and then checked - // against configuration events, which come from a compositor. The reason - // of manually changing the |state_| is that the compositor answers about - // state changes asynchronously, which leads to a wrong return value in - // DesktopWindowTreeHostPlatform::IsFullscreen, for example, and media - // files can never be set to fullscreen. - state_ = PlatformWindowState::kFullScreen; - shell_surface_->SetFullscreen(); - } else { - // Check the comment above. If it's not handled synchronously, media files - // may not leave the fullscreen mode. - state_ = PlatformWindowState::kUnknown; - shell_surface_->UnSetFullscreen(); - } +void WaylandWindow::Maximize() {} - connection_->ScheduleFlush(); -} +void WaylandWindow::Minimize() {} -void WaylandWindow::Maximize() { - DCHECK(shell_surface_); - - if (IsFullscreen()) - ToggleFullscreen(); - - shell_surface_->SetMaximized(); - connection_->ScheduleFlush(); -} - -void WaylandWindow::Minimize() { - DCHECK(shell_surface_); - DCHECK(!is_minimizing_); - // Wayland doesn't explicitly say if a window is minimized. Instead, it - // notifies that the window is not activated. But there are many cases, when - // the window is not minimized and deactivated. In order to properly record - // the minimized state, mark this window as being minimized. And as soon as a - // configuration event comes, check if the window has been deactivated and has - // |is_minimizing_| set. - is_minimizing_ = true; - shell_surface_->SetMinimized(); - connection_->ScheduleFlush(); -} - -void WaylandWindow::Restore() { - DCHECK(shell_surface_); - - // Unfullscreen the window if it is fullscreen. - if (IsFullscreen()) - ToggleFullscreen(); - - shell_surface_->UnSetMaximized(); - connection_->ScheduleFlush(); -} +void WaylandWindow::Restore() {} PlatformWindowState WaylandWindow::GetPlatformWindowState() const { - return state_; + // Remove normal state for all the other types of windows as it's only the + // WaylandSurface that supports state changes. + return PlatformWindowState::kNormal; } void WaylandWindow::Activate() { @@ -589,32 +218,17 @@ void WaylandWindow::SetWindowIcons(const gfx::ImageSkia& window_icon, NOTIMPLEMENTED_LOG_ONCE(); } -void WaylandWindow::SizeConstraintsChanged() { - // Size constraints only make sense for normal windows. - if (!shell_surface_) - return; - - DCHECK(delegate_); - auto min_size = delegate_->GetMinimumSizeForWindow(); - auto max_size = delegate_->GetMaximumSizeForWindow(); - - if (min_size.has_value()) - shell_surface_->SetMinSize(min_size->width(), min_size->height()); - if (max_size.has_value()) - shell_surface_->SetMaxSize(max_size->width(), max_size->height()); - - connection_->ScheduleFlush(); -} +void WaylandWindow::SizeConstraintsChanged() {} bool WaylandWindow::CanDispatchEvent(const PlatformEvent& event) { - // This window is a nested popup window, all the events must be forwarded - // to the main popup window. - if (child_window_ && child_window_->shell_popup()) - return !!shell_popup_.get(); + // This window is a nested menu window, all the events must be forwarded + // to the main menu window. + if (child_window_ && wl::IsMenuType(child_window_->type())) + return wl::IsMenuType(type()); // If this is a nested menu window with a parent, it mustn't recieve any // events. - if (parent_window_ && parent_window_->shell_popup()) + if (parent_window_ && wl::IsMenuType(parent_window_->type())) return false; // If another window has capture, return early before checking focus. @@ -632,7 +246,6 @@ bool WaylandWindow::CanDispatchEvent(const PlatformEvent& event) { uint32_t WaylandWindow::DispatchEvent(const PlatformEvent& native_event) { Event* event = static_cast<Event*>(native_event); - if (event->IsLocatedEvent()) { // Wayland sends locations in DIP so they need to be translated to // physical pixels. @@ -643,13 +256,14 @@ uint32_t WaylandWindow::DispatchEvent(const PlatformEvent& native_event) { } // If the window does not have a pointer focus, but received this event, it - // means the window is a popup window with a child popup window. In this case, - // the location of the event must be converted from the nested popup to the - // main popup, which the menu controller needs to properly handle events. - if (event->IsLocatedEvent() && shell_popup()) { - // Parent window of the main menu window is not a popup, but rather an + // means the window is a menu window with a child menu window. In this case, + // the location of the event must be converted from the nested menu to the + // main menu, which the menu controller needs to properly handle events. + if (event->IsLocatedEvent() && wl::IsMenuType(type())) { + // Parent window of the main menu window is not a menu, but rather an // xdg surface. - DCHECK(!parent_window_->shell_popup() && parent_window_->shell_surface()); + DCHECK(!wl::IsMenuType(parent_window_->type()) || + parent_window_->type() != PlatformWindowType::kTooltip); auto* window = connection_->wayland_window_manager()->GetCurrentFocusedWindow(); if (window) { @@ -665,193 +279,77 @@ uint32_t WaylandWindow::DispatchEvent(const PlatformEvent& native_event) { return POST_DISPATCH_STOP_PROPAGATION; } -void WaylandWindow::HandleSurfaceConfigure(int32_t width, +void WaylandWindow::HandleSurfaceConfigure(int32_t widht, int32_t height, bool is_maximized, bool is_fullscreen, bool is_activated) { - DCHECK(!shell_popup()); - - // Propagate the window state information to the client. - PlatformWindowState old_state = state_; - - // Ensure that manually handled state changes to fullscreen correspond to the - // configuration events from a compositor. - DCHECK_EQ(is_fullscreen, IsFullscreen()); - - // There are two cases, which must be handled for the minimized state. - // The first one is the case, when the surface goes into the minimized state - // (check comment in WaylandWindow::Minimize), and the second case is when the - // surface still has been minimized, but another cofiguration event with - // !is_activated comes. For this, check if the WaylandWindow has been - // minimized before and !is_activated is sent. - if ((is_minimizing_ || IsMinimized()) && !is_activated) { - is_minimizing_ = false; - state_ = PlatformWindowState::kMinimized; - } else if (is_fullscreen) { - // To ensure the |delegate_| is notified about state changes to fullscreen, - // assume the old_state is UNKNOWN (check comment in ToggleFullscreen). - old_state = PlatformWindowState::kUnknown; - DCHECK(state_ == PlatformWindowState::kFullScreen); - } else if (is_maximized) { - state_ = PlatformWindowState::kMaximized; - } else { - state_ = PlatformWindowState::kNormal; - } - const bool state_changed = old_state != state_; - const bool is_normal = !IsFullscreen() && !IsMaximized(); - - // Update state before notifying delegate. - const bool did_active_change = is_active_ != is_activated; - is_active_ = is_activated; - - // Rather than call SetBounds here for every configure event, just save the - // most recent bounds, and have WaylandConnection call ApplyPendingBounds - // when it has finished processing events. We may get many configure events - // in a row during an interactive resize, and only the last one matters. - // - // Width or height set to 0 means that we should decide on width and height by - // ourselves, but we don't want to set them to anything else. Use restored - // bounds size or the current bounds iff the current state is normal (neither - // maximized nor fullscreen). - // - // Note: if the browser was started with --start-fullscreen and a user exits - // the fullscreen mode, wayland may set the width and height to be 1. Instead, - // explicitly set the bounds to the current desired ones or the previous - // bounds. - if (width > 1 && height > 1) { - pending_bounds_dip_ = gfx::Rect(0, 0, width, height); - } else if (is_normal) { - pending_bounds_dip_.set_size(gfx::ScaleToRoundedSize( - restored_bounds_px_.IsEmpty() ? GetBounds().size() - : restored_bounds_px_.size(), - - 1.0 / buffer_scale_)); - } - - if (state_changed) { - // The |restored_bounds_| are used when the window gets back to normal - // state after it went maximized or fullscreen. So we reset these if the - // window has just become normal and store the current bounds if it is - // either going out of normal state or simply changes the state and we don't - // have any meaningful value stored. - if (is_normal) { - SetRestoredBoundsInPixels({}); - } else if (old_state == PlatformWindowState::kNormal || - restored_bounds_px_.IsEmpty()) { - SetRestoredBoundsInPixels(bounds_px_); - } - - delegate_->OnWindowStateChanged(state_); - } - - ApplyPendingBounds(); - - if (did_active_change) - delegate_->OnActivationChanged(is_active_); - - MaybeTriggerPendingStateChange(); + NOTREACHED() + << "Only shell surfaces must receive HandleSurfaceConfigure calls."; } void WaylandWindow::HandlePopupConfigure(const gfx::Rect& bounds_dip) { - DCHECK(shell_popup()); - DCHECK(parent_window_); - - SetBufferScale(parent_window_->buffer_scale_, true); - - gfx::Rect new_bounds_dip = bounds_dip; - - // It's not enough to just set new bounds. If it is a menu window, whose - // parent is a top level window aka browser window, it can be flipped - // vertically along y-axis and have negative values set. Chromium cannot - // understand that and starts to position nested menu windows incorrectly. To - // fix that, we have to bear in mind that Wayland compositor does not share - // global coordinates for any surfaces, and Chromium assumes the top level - // window is always located at 0,0 origin. What is more, child windows must - // always be positioned relative to parent window local surface coordinates. - // Thus, if the menu window is flipped along y-axis by Wayland and its origin - // is above the top level parent window, the origin of the top level window - // has to be shifted by that value on y-axis so that the origin of the menu - // becomes x,0, and events can be handled normally. - if (!parent_window_->shell_popup()) { - gfx::Rect parent_bounds = parent_window_->GetBounds(); - // The menu window is flipped along y-axis and have x,-y origin. Shift the - // parent top level window instead. - if (new_bounds_dip.y() < 0) { - // Move parent bounds along y-axis. - parent_bounds.set_y(-(new_bounds_dip.y() * buffer_scale_)); - new_bounds_dip.set_y(0); - } else { - // If the menu window is located at correct origin from the browser point - // of view, return the top level window back to 0,0. - parent_bounds.set_y(0); - } - parent_window_->SetBounds(parent_bounds); - } else { - // The nested menu windows are located relative to the parent menu windows. - // Thus, the location must be translated to be relative to the top level - // window, which automatically becomes the same as relative to an origin of - // a display. - new_bounds_dip = gfx::ScaleToRoundedRect( - TranslateBoundsToTopLevelCoordinates( - gfx::ScaleToRoundedRect(new_bounds_dip, buffer_scale_), - parent_window_->GetBounds()), - 1.0 / buffer_scale_); - DCHECK(new_bounds_dip.y() >= 0); - } - - SetBoundsDip(new_bounds_dip); + NOTREACHED() << "Only shell popups must receive HandlePopupConfigure calls."; } void WaylandWindow::OnCloseRequest() { - // Before calling OnCloseRequest, the |shell_popup_| must become hidden and - // only then call OnCloseRequest(). - DCHECK(!shell_popup_); delegate_->OnCloseRequest(); } void WaylandWindow::OnDragEnter(const gfx::PointF& point, std::unique_ptr<OSExchangeData> data, - int operation) { - WmDropHandler* drop_handler = GetWmDropHandler(*this); - if (!drop_handler) - return; - drop_handler->OnDragEnter(point, std::move(data), operation); -} + int operation) {} int WaylandWindow::OnDragMotion(const gfx::PointF& point, uint32_t time, int operation) { - WmDropHandler* drop_handler = GetWmDropHandler(*this); - if (!drop_handler) - return 0; - - return drop_handler->OnDragMotion(point, operation); + return -1; } -void WaylandWindow::OnDragDrop(std::unique_ptr<OSExchangeData> data) { - WmDropHandler* drop_handler = GetWmDropHandler(*this); - if (!drop_handler) - return; - drop_handler->OnDragDrop(std::move(data)); -} +void WaylandWindow::OnDragDrop(std::unique_ptr<OSExchangeData> data) {} -void WaylandWindow::OnDragLeave() { - WmDropHandler* drop_handler = GetWmDropHandler(*this); - if (!drop_handler) - return; - drop_handler->OnDragLeave(); -} +void WaylandWindow::OnDragLeave() {} -void WaylandWindow::OnDragSessionClose(uint32_t dnd_action) { - std::move(drag_closed_callback_).Run(dnd_action); - connection_->ResetPointerFlags(); -} +void WaylandWindow::OnDragSessionClose(uint32_t dnd_action) {} void WaylandWindow::SetBoundsDip(const gfx::Rect& bounds_dip) { SetBounds(gfx::ScaleToRoundedRect(bounds_dip, buffer_scale_)); } +bool WaylandWindow::Initialize(PlatformWindowInitProperties properties) { + // Properties contain DIP bounds but the buffer scale is initially 1 so it's + // OK to assign. The bounds will be recalculated when the buffer scale + // changes. + DCHECK_EQ(buffer_scale_, 1); + bounds_px_ = properties.bounds; + opacity_ = properties.opacity; + type_ = properties.type; + + surface_.reset(wl_compositor_create_surface(connection_->compositor())); + if (!surface_) { + LOG(ERROR) << "Failed to create wl_surface"; + return false; + } + wl_surface_set_user_data(surface_.get(), this); + AddSurfaceListener(); + + connection_->wayland_window_manager()->AddWindow(GetWidget(), this); + + if (!OnInitialize(std::move(properties))) + return false; + + connection_->ScheduleFlush(); + + PlatformEventSource::GetInstance()->AddPlatformEventDispatcher(this); + delegate_->OnAcceleratedWidgetAvailable(GetWidget()); + + // Will do nothing for menus because they have got their scale above. + UpdateBufferScale(false); + + MaybeUpdateOpaqueRegion(); + return true; +} + void WaylandWindow::SetBufferScale(int32_t new_scale, bool update_bounds) { DCHECK_GT(new_scale, 0); @@ -868,26 +366,6 @@ void WaylandWindow::SetBufferScale(int32_t new_scale, bool update_bounds) { connection_->ScheduleFlush(); } -bool WaylandWindow::IsMinimized() const { - return state_ == PlatformWindowState::kMinimized; -} - -bool WaylandWindow::IsMaximized() const { - return state_ == PlatformWindowState::kMaximized; -} - -bool WaylandWindow::IsFullscreen() const { - return state_ == PlatformWindowState::kFullScreen; -} - -void WaylandWindow::MaybeTriggerPendingStateChange() { - if (pending_state_ == PlatformWindowState::kUnknown || !is_active_) - return; - DCHECK_EQ(pending_state_, PlatformWindowState::kFullScreen); - pending_state_ = PlatformWindowState::kUnknown; - ToggleFullscreen(); -} - WaylandWindow* WaylandWindow::GetParentWindow( gfx::AcceleratedWidget parent_widget) { auto* parent_window = @@ -913,10 +391,6 @@ WaylandWindow* WaylandWindow::GetRootParentWindow() { return parent_window_ ? parent_window_->GetRootParentWindow() : this; } -WmMoveResizeHandler* WaylandWindow::AsWmMoveResizeHandler() { - return static_cast<WmMoveResizeHandler*>(this); -} - void WaylandWindow::AddSurfaceListener() { static struct wl_surface_listener surface_listener = { &WaylandWindow::Enter, @@ -926,10 +400,10 @@ void WaylandWindow::AddSurfaceListener() { } void WaylandWindow::AddEnteredOutputId(struct wl_output* output) { - // Wayland does weird things for popups so instead of tracking outputs that + // Wayland does weird things for menus so instead of tracking outputs that // we entered or left, we take that from the parent window and ignore this // event. - if (shell_popup()) + if (wl::IsMenuType(type())) return; const uint32_t entered_output_id = @@ -942,10 +416,10 @@ void WaylandWindow::AddEnteredOutputId(struct wl_output* output) { } void WaylandWindow::RemoveEnteredOutputId(struct wl_output* output) { - // Wayland does weird things for popups so instead of tracking outputs that + // Wayland does weird things for menus so instead of tracking outputs that // we entered or left, we take that from the parent window and ignore this // event. - if (shell_popup()) + if (wl::IsMenuType(type())) return; const uint32_t left_output_id = @@ -1005,51 +479,6 @@ void WaylandWindow::UpdateCursorPositionFromEvent( } } -gfx::Rect WaylandWindow::AdjustPopupWindowPosition() const { - auto* parent_window = parent_window_->shell_popup() - ? parent_window_->parent_window_ - : parent_window_; - DCHECK(parent_window); - DCHECK(buffer_scale_ == parent_window->buffer_scale_); - DCHECK(ui_scale_ == parent_window->ui_scale_); - - // Chromium positions windows in screen coordinates, but Wayland requires them - // to be in local surface coordinates aka relative to parent window. - const gfx::Rect parent_bounds_dip = - gfx::ScaleToRoundedRect(parent_window_->GetBounds(), 1.0 / ui_scale_); - gfx::Rect new_bounds_dip = - TranslateBoundsToParentCoordinates(bounds_px_, parent_bounds_dip); - - // Chromium may decide to position nested menu windows on the left side - // instead of the right side of parent menu windows when the size of the - // window becomes larger than the display it is shown on. It's correct when - // the window is located on one display and occupies the whole work area, but - // as soon as it's moved and there is space on the right side, Chromium - // continues positioning the nested menus on the left side relative to the - // parent menu (Wayland does not provide clients with global coordinates). - // Instead, reposition that window to be on the right side of the parent menu - // window and let the compositor decide how to position it if it does not fit - // a single display. However, there is one exception - if the window is - // maximized, let Chromium position it on the left side as long as the Wayland - // compositor may decide to position the nested window on the right side of - // the parent menu window, which results in showing it on a second display if - // more than one display is used. - if (parent_window_->shell_popup() && parent_window_->parent_window_ && - !parent_window_->parent_window_->IsMaximized()) { - auto* top_level_window = parent_window_->parent_window_; - DCHECK(top_level_window && !top_level_window->shell_popup()); - if (new_bounds_dip.x() <= 0 && !top_level_window->IsMaximized()) { - // Position the child menu window on the right side of the parent window - // and let the Wayland compositor decide how to do constraint - // adjustements. - int new_x = parent_bounds_dip.width() - - (new_bounds_dip.width() + new_bounds_dip.x()); - new_bounds_dip.set_x(new_x); - } - } - return gfx::ScaleToRoundedRect(new_bounds_dip, ui_scale_ / buffer_scale_); -} - WaylandWindow* WaylandWindow::GetTopLevelWindow() { return parent_window_ ? parent_window_->GetTopLevelWindow() : this; } diff --git a/chromium/ui/ozone/platform/wayland/host/wayland_window.h b/chromium/ui/ozone/platform/wayland/host/wayland_window.h index 2745dde85c3..08658f1df87 100644 --- a/chromium/ui/ozone/platform/wayland/host/wayland_window.h +++ b/chromium/ui/ozone/platform/wayland/host/wayland_window.h @@ -19,8 +19,6 @@ #include "ui/ozone/platform/wayland/common/wayland_object.h" #include "ui/platform_window/platform_window.h" #include "ui/platform_window/platform_window_delegate.h" -#include "ui/platform_window/platform_window_handler/wm_drag_handler.h" -#include "ui/platform_window/platform_window_handler/wm_move_resize_handler.h" #include "ui/platform_window/platform_window_init_properties.h" namespace gfx { @@ -32,25 +30,19 @@ namespace ui { class BitmapCursorOzone; class OSExchangeData; class WaylandConnection; -class ShellPopupWrapper; -class ShellSurfaceWrapper; -namespace { -class XDGShellObjectFactory; -} // namespace - -class WaylandWindow : public PlatformWindow, - public PlatformEventDispatcher, - public WmMoveResizeHandler, - public WmDragHandler { +class WaylandWindow : public PlatformWindow, public PlatformEventDispatcher { public: - WaylandWindow(PlatformWindowDelegate* delegate, - WaylandConnection* connection); ~WaylandWindow() override; - static WaylandWindow* FromSurface(wl_surface* surface); + // A factory method that can create any of the derived types of WaylandWindow + // (WaylandSurface, WaylandPopup and WaylandSubsurface). + static std::unique_ptr<WaylandWindow> Create( + PlatformWindowDelegate* delegate, + WaylandConnection* connection, + PlatformWindowInitProperties properties); - bool Initialize(PlatformWindowInitProperties properties); + static WaylandWindow* FromSurface(wl_surface* surface); // Updates the surface buffer scale of the window. Top level windows take // scale from the output attached to either their current display or the @@ -60,17 +52,14 @@ class WaylandWindow : public PlatformWindow, void UpdateBufferScale(bool update_bounds); wl_surface* surface() const { return surface_.get(); } - ShellSurfaceWrapper* shell_surface() const { return shell_surface_.get(); } - ShellPopupWrapper* shell_popup() const { return shell_popup_.get(); } + void set_parent_window(WaylandWindow* parent_window) { + parent_window_ = parent_window; + } WaylandWindow* parent_window() const { return parent_window_; } gfx::AcceleratedWidget GetWidget() const; - // Apply the bounds specified in the most recent configure event. This should - // be called after processing all pending events in the wayland connection. - void ApplyPendingBounds(); - // Set whether this window has pointer focus and should dispatch mouse events. void SetPointerFocus(bool focus); bool has_pointer_focus() const { return has_pointer_focus_; } @@ -87,6 +76,7 @@ class WaylandWindow : public PlatformWindow, // Set a child of this window. It is very important in case of nested // shell_popups as long as they must be destroyed in the back order. void set_child_window(WaylandWindow* window) { child_window_ = window; } + WaylandWindow* child_window() const { return child_window_; } // Set whether this window has an implicit grab (often referred to as capture // in Chrome code). Implicit grabs happen while a pointer is down. @@ -94,23 +84,14 @@ class WaylandWindow : public PlatformWindow, bool has_implicit_grab() const { return has_implicit_grab_; } int32_t buffer_scale() const { return buffer_scale_; } - - bool is_active() const { return is_active_; } + int32_t ui_scale() const { return ui_scale_; } const base::flat_set<uint32_t>& entered_outputs_ids() const { return entered_outputs_ids_; } - // WmMoveResizeHandler - void DispatchHostWindowDragMovement( - int hittest, - const gfx::Point& pointer_location_in_px) override; - - // WmDragHandler - void StartDrag(const ui::OSExchangeData& data, - int operation, - gfx::NativeCursor cursor, - base::OnceCallback<void(int)> callback) override; + // Returns current type of the window. + PlatformWindowType type() const { return type_; } // PlatformWindow void Show(bool inactive) override; @@ -148,55 +129,58 @@ class WaylandWindow : public PlatformWindow, bool CanDispatchEvent(const PlatformEvent& event) override; uint32_t DispatchEvent(const PlatformEvent& event) override; - // Handles the configuration events coming from the surface (see - // |XDGSurfaceWrapperStable::ConfigureTopLevel| and - // |XDGSurfaceWrapperV6::ConfigureTopLevel|. The width and height come in - // DIP of the output that the surface is currently bound to. - void HandleSurfaceConfigure(int32_t widht, - int32_t height, - bool is_maximized, - bool is_fullscreen, - bool is_activated); - void HandlePopupConfigure(const gfx::Rect& bounds); - - void OnCloseRequest(); - - void OnDragEnter(const gfx::PointF& point, - std::unique_ptr<OSExchangeData> data, - int operation); - int OnDragMotion(const gfx::PointF& point, uint32_t time, int operation); - void OnDragDrop(std::unique_ptr<OSExchangeData> data); - void OnDragLeave(); - void OnDragSessionClose(uint32_t dnd_action); + // Handles the configuration events coming from the shell objects. + // The width and height come in DIP of the output that the surface is + // currently bound to. + virtual void HandleSurfaceConfigure(int32_t widht, + int32_t height, + bool is_maximized, + bool is_fullscreen, + bool is_activated); + virtual void HandlePopupConfigure(const gfx::Rect& bounds); + + // Handles close requests. + virtual void OnCloseRequest(); + + // Notifies about drag/drop session events. + virtual void OnDragEnter(const gfx::PointF& point, + std::unique_ptr<OSExchangeData> data, + int operation); + virtual int OnDragMotion(const gfx::PointF& point, + uint32_t time, + int operation); + virtual void OnDragDrop(std::unique_ptr<OSExchangeData> data); + virtual void OnDragLeave(); + virtual void OnDragSessionClose(uint32_t dnd_action); + + protected: + WaylandWindow(PlatformWindowDelegate* delegate, + WaylandConnection* connection); - private: - FRIEND_TEST_ALL_PREFIXES(WaylandScreenTest, SetBufferScale); + WaylandConnection* connection() { return connection_; } + PlatformWindowDelegate* delegate() { return delegate_; } + // Sets bounds in dip. void SetBoundsDip(const gfx::Rect& bounds_dip); - void SetBufferScale(int32_t scale, bool update_bounds); - bool IsMinimized() const; - bool IsMaximized() const; - bool IsFullscreen() const; + // Gets a parent window for this window. + WaylandWindow* GetParentWindow(gfx::AcceleratedWidget parent_widget); - void MaybeTriggerPendingStateChange(); + // Sets the buffer scale. + void SetBufferScale(int32_t scale, bool update_bounds); - // Creates a popup window, which is visible as a menu window. - void CreateShellPopup(); - // Creates a surface window, which is visible as a main window. - void CreateShellSurface(); - // Creates (if necessary) and show subsurface window, to host - // tooltip's content. - void CreateAndShowTooltipSubSurface(); + // Sets the ui scale. + void set_ui_scale(int32_t ui_scale) { ui_scale_ = ui_scale; } - // Gets a parent window for this window. - WaylandWindow* GetParentWindow(gfx::AcceleratedWidget parent_widget); + private: + FRIEND_TEST_ALL_PREFIXES(WaylandScreenTest, SetBufferScale); + + // Initializes the WaylandWindow with supplied properties. + bool Initialize(PlatformWindowInitProperties properties); // Returns a root parent window. WaylandWindow* GetRootParentWindow(); - WmMoveResizeHandler* AsWmMoveResizeHandler(); - // Install a surface listener and start getting wl_output enter/leave events. void AddSurfaceListener(); @@ -205,9 +189,6 @@ class WaylandWindow : public PlatformWindow, void UpdateCursorPositionFromEvent(std::unique_ptr<Event> event); - // Returns bounds with origin relative to parent window's origin. - gfx::Rect AdjustPopupWindowPosition() const; - WaylandWindow* GetTopLevelWindow(); // It's important to set opaque region for opaque windows (provides @@ -216,6 +197,9 @@ class WaylandWindow : public PlatformWindow, bool IsOpaqueWindow() const; + // Additional initialization of derived classes. + virtual bool OnInitialize(PlatformWindowInitProperties properties) = 0; + // wl_surface_listener static void Enter(void* data, struct wl_surface* wl_surface, @@ -229,33 +213,11 @@ class WaylandWindow : public PlatformWindow, WaylandWindow* parent_window_ = nullptr; WaylandWindow* child_window_ = nullptr; - // Creates xdg objects based on xdg shell version. - std::unique_ptr<XDGShellObjectFactory> xdg_shell_objects_factory_; - wl::Object<wl_surface> surface_; - wl::Object<wl_subsurface> tooltip_subsurface_; - - // Wrappers around xdg v5 and xdg v6 objects. WaylandWindow doesn't - // know anything about the version. - std::unique_ptr<ShellSurfaceWrapper> shell_surface_; - std::unique_ptr<ShellPopupWrapper> shell_popup_; // The current cursor bitmap (immutable). scoped_refptr<BitmapCursorOzone> bitmap_; - base::OnceCallback<void(int)> drag_closed_callback_; - - // These bounds attributes below have suffices that indicate units used. - // Wayland operates in DIP but the platform operates in physical pixels so - // our WaylandWindow is the link that has to translate the units. See also - // comments in the implementation. - // - // Bounds that will be applied when the window state is finalized. The window - // may get several configuration events that update the pending bounds, and - // only upon finalizing the state is the latest value stored as the current - // bounds via |ApplyPendingBounds|. Measured in DIP because updated in the - // handler that receives DIP from Wayland. - gfx::Rect pending_bounds_dip_; // Current bounds of the platform window. gfx::Rect bounds_px_; // The bounds of the platform window before it went maximized or fullscreen. @@ -273,20 +235,9 @@ class WaylandWindow : public PlatformWindow, // We need it to place and size the menus properly. float ui_scale_ = 1.0; - // Stores current states of the window. - PlatformWindowState state_; - // Stores a pending state of the window, which is used before the surface is - // activated. - PlatformWindowState pending_state_; - // Stores current opacity of the window. Set on ::Initialize call. ui::PlatformWindowOpacity opacity_; - bool is_active_ = false; - bool is_minimizing_ = false; - - bool is_tooltip_ = false; - // For top level window, stores IDs of outputs that the window is currently // rendered at. // @@ -297,6 +248,9 @@ class WaylandWindow : public PlatformWindow, // we ask its parent. base::flat_set<uint32_t> entered_outputs_ids_; + // The type of the current WaylandWindow object. + ui::PlatformWindowType type_ = ui::PlatformWindowType::kWindow; + DISALLOW_COPY_AND_ASSIGN(WaylandWindow); }; diff --git a/chromium/ui/ozone/platform/wayland/host/wayland_window_factory.cc b/chromium/ui/ozone/platform/wayland/host/wayland_window_factory.cc new file mode 100644 index 00000000000..16db3567652 --- /dev/null +++ b/chromium/ui/ozone/platform/wayland/host/wayland_window_factory.cc @@ -0,0 +1,57 @@ +// Copyright 2019 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/wayland_window.h" + +#include <memory> + +#include "ui/gfx/native_widget_types.h" +#include "ui/ozone/platform/wayland/host/wayland_connection.h" +#include "ui/ozone/platform/wayland/host/wayland_popup.h" +#include "ui/ozone/platform/wayland/host/wayland_subsurface.h" +#include "ui/ozone/platform/wayland/host/wayland_surface.h" + +namespace ui { + +// static +std::unique_ptr<WaylandWindow> WaylandWindow::Create( + PlatformWindowDelegate* delegate, + WaylandConnection* connection, + PlatformWindowInitProperties properties) { + std::unique_ptr<WaylandWindow> window; + 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 WaylandSurface(delegate, connection)); + } else if (connection->IsDragInProgress()) { + // We are in the process of drag and requested a popup. Most probably, + // it is an arrow window. + window.reset(new WaylandSubsurface(delegate, connection)); + } else { + window.reset(new WaylandPopup(delegate, connection)); + } + break; + case PlatformWindowType::kTooltip: + window.reset(new WaylandSubsurface(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 WaylandSurface(delegate, connection)); + break; + default: + NOTREACHED(); + break; + } + return window && window->Initialize(std::move(properties)) ? std::move(window) + : nullptr; +} + +} // namespace ui
\ No newline at end of file diff --git a/chromium/ui/ozone/platform/wayland/host/wayland_window_manager_unittests.cc b/chromium/ui/ozone/platform/wayland/host/wayland_window_manager_unittests.cc index 737c7cdd25d..a4b1fc7d943 100644 --- a/chromium/ui/ozone/platform/wayland/host/wayland_window_manager_unittests.cc +++ b/chromium/ui/ozone/platform/wayland/host/wayland_window_manager_unittests.cc @@ -36,11 +36,10 @@ class WaylandWindowManagerTest : public WaylandTest { PlatformWindowInitProperties properties; properties.bounds = bounds; properties.type = type; - - std::unique_ptr<WaylandWindow> window = - std::make_unique<WaylandWindow>(delegate, connection_.get()); - - EXPECT_TRUE(window->Initialize(std::move(properties))); + auto window = WaylandWindow::Create(delegate, connection_.get(), + std::move(properties)); + if (window) + window->Show(false); return window; } @@ -91,6 +90,9 @@ TEST_P(WaylandWindowManagerTest, GetCurrentFocusedWindow) { auto window1 = CreateWaylandWindowWithParams(PlatformWindowType::kWindow, kDefaultBounds, &delegate); + // When window is shown, it automatically gets keyboard focus. Reset it. + window_->set_keyboard_focus(false); + window1->set_keyboard_focus(false); Sync(); @@ -125,6 +127,9 @@ TEST_P(WaylandWindowManagerTest, GetCurrentKeyboardFocusedWindow) { auto window1 = CreateWaylandWindowWithParams(PlatformWindowType::kWindow, kDefaultBounds, &delegate); + // When window is shown, it automatically gets keyboard focus. Reset it. + window_->set_keyboard_focus(false); + window1->set_keyboard_focus(false); Sync(); 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 f8dc4429c07..3162fcf30ed 100644 --- a/chromium/ui/ozone/platform/wayland/host/wayland_window_unittest.cc +++ b/chromium/ui/ozone/platform/wayland/host/wayland_window_unittest.cc @@ -26,6 +26,7 @@ #include "ui/ozone/platform/wayland/test/test_wayland_server_thread.h" #include "ui/ozone/platform/wayland/test/wayland_test.h" #include "ui/ozone/test/mock_platform_window_delegate.h" +#include "ui/platform_window/platform_window_handler/wm_move_resize_handler.h" #include "ui/platform_window/platform_window_init_properties.h" using ::testing::_; @@ -127,11 +128,7 @@ class WaylandWindowTest : public WaylandTest { } } - // Depending on a shell version, xdg_surface_ or xdg_toplevel surface should - // get the mock calls. This method decided, which surface to use. - wl::MockXdgSurface* GetXdgSurface() { - return xdg_surface_->xdg_toplevel(); - } + wl::MockXdgTopLevel* GetXdgToplevel() { return xdg_surface_->xdg_toplevel(); } void AddStateToWlArray(uint32_t state, wl_array* states) { *static_cast<uint32_t*>(wl_array_add(states, sizeof state)) = state; @@ -150,20 +147,22 @@ class WaylandWindowTest : public WaylandTest { return result; } - bool CreateWaylandWindowWithParams(PlatformWindowType type, - gfx::AcceleratedWidget parent_widget, - const gfx::Rect bounds, - MockPlatformWindowDelegate* delegate, - std::unique_ptr<WaylandWindow>* window) { + std::unique_ptr<WaylandWindow> CreateWaylandWindowWithParams( + PlatformWindowType type, + gfx::AcceleratedWidget parent_widget, + const gfx::Rect bounds, + MockPlatformWindowDelegate* delegate) { PlatformWindowInitProperties properties; // TODO(msisov): use a fancy method to calculate position of a popup window. properties.bounds = bounds; properties.type = type; properties.parent_widget = parent_widget; - *window = std::make_unique<WaylandWindow>(delegate, connection_.get()); - - return (*window)->Initialize(std::move(properties)); + auto window = WaylandWindow::Create(delegate, connection_.get(), + std::move(properties)); + if (window) + window->Show(false); + return window; } void InitializeWithSupportedHitTestValues(std::vector<int>* hit_tests) { @@ -213,7 +212,7 @@ class WaylandWindowTest : public WaylandTest { }; TEST_P(WaylandWindowTest, SetTitle) { - EXPECT_CALL(*GetXdgSurface(), SetTitle(StrEq("hello"))); + EXPECT_CALL(*GetXdgToplevel(), SetTitle(StrEq("hello"))); window_->SetTitle(base::ASCIIToUTF16("hello")); } @@ -229,13 +228,12 @@ TEST_P(WaylandWindowTest, MaximizeAndRestore) { auto active_maximized = MakeStateArray( {XDG_TOPLEVEL_STATE_ACTIVATED, XDG_TOPLEVEL_STATE_MAXIMIZED}); - EXPECT_CALL(*GetXdgSurface(), SetMaximized()); + EXPECT_CALL(*GetXdgToplevel(), SetMaximized()); EXPECT_CALL(*xdg_surface_, SetWindowGeometry(0, 0, kMaximizedBounds.width(), kMaximizedBounds.height())); EXPECT_CALL(delegate_, OnActivationChanged(Eq(true))); EXPECT_CALL(delegate_, OnBoundsChanged(kMaximizedBounds)); - EXPECT_CALL(delegate_, - OnWindowStateChanged(Eq(PlatformWindowState::kMaximized))); + EXPECT_CALL(delegate_, OnWindowStateChanged(_)).Times(0); window_->Maximize(); SendConfigureEvent(kMaximizedBounds.width(), kMaximizedBounds.height(), 1, active_maximized.get()); @@ -250,7 +248,6 @@ TEST_P(WaylandWindowTest, MaximizeAndRestore) { SendConfigureEvent(kMaximizedBounds.width(), kMaximizedBounds.height(), 2, inactive_maximized.get()); Sync(); - EXPECT_FALSE(window_->is_active()); VerifyAndClearExpectations(); EXPECT_CALL(*xdg_surface_, SetWindowGeometry(0, 0, kMaximizedBounds.width(), @@ -260,16 +257,14 @@ TEST_P(WaylandWindowTest, MaximizeAndRestore) { SendConfigureEvent(kMaximizedBounds.width(), kMaximizedBounds.height(), 3, active_maximized.get()); Sync(); - EXPECT_TRUE(window_->is_active()); VerifyAndClearExpectations(); EXPECT_CALL(*xdg_surface_, SetWindowGeometry(0, 0, kNormalBounds.width(), kNormalBounds.height())); - EXPECT_CALL(delegate_, - OnWindowStateChanged(Eq(PlatformWindowState::kNormal))); + EXPECT_CALL(delegate_, OnWindowStateChanged(_)).Times(0); EXPECT_CALL(delegate_, OnActivationChanged(_)).Times(0); EXPECT_CALL(delegate_, OnBoundsChanged(kNormalBounds)); - EXPECT_CALL(*GetXdgSurface(), UnsetMaximized()); + EXPECT_CALL(*GetXdgToplevel(), UnsetMaximized()); window_->Restore(); // Reinitialize wl_array, which removes previous old states. auto active = InitializeWlArrayWithActivatedState(); @@ -285,20 +280,22 @@ TEST_P(WaylandWindowTest, Minimize) { SendConfigureEvent(0, 0, 1, states.get()); Sync(); - EXPECT_CALL(*GetXdgSurface(), SetMinimized()); - // Wayland compositor doesn't notify clients about minimized state, but rather - // if a window is not activated. Thus, a WaylandWindow marks itself as being - // minimized and as soon as a configuration event with not activated state - // comes, its state is changed to minimized. This EXPECT_CALL ensures this - // behaviour. - EXPECT_CALL(delegate_, - OnWindowStateChanged(Eq(PlatformWindowState::kMinimized))); + EXPECT_CALL(*GetXdgToplevel(), SetMinimized()); + EXPECT_CALL(delegate_, OnWindowStateChanged(_)).Times(0); window_->Minimize(); + EXPECT_EQ(window_->GetPlatformWindowState(), PlatformWindowState::kMinimized); + // Reinitialize wl_array, which removes previous old states. states = ScopedWlArray(); SendConfigureEvent(0, 0, 2, states.get()); Sync(); + // Wayland compositor doesn't notify clients about minimized state, but rather + // if a window is not activated. Thus, a WaylandSurface marks itself as being + // minimized and and sets state to minimized. Thus, the state mustn't change + // after the configuration event is sent. + EXPECT_EQ(window_->GetPlatformWindowState(), PlatformWindowState::kMinimized); + // Send one additional empty configuration event (which means the surface is // not maximized, fullscreen or activated) to ensure, WaylandWindow stays in // the same minimized state and doesn't notify its delegate. @@ -321,9 +318,8 @@ TEST_P(WaylandWindowTest, SetFullscreenAndRestore) { AddStateToWlArray(XDG_TOPLEVEL_STATE_FULLSCREEN, states.get()); - EXPECT_CALL(*GetXdgSurface(), SetFullscreen()); - EXPECT_CALL(delegate_, - OnWindowStateChanged(Eq(PlatformWindowState::kFullScreen))); + EXPECT_CALL(*GetXdgToplevel(), SetFullscreen()); + EXPECT_CALL(delegate_, OnWindowStateChanged(_)).Times(0); window_->ToggleFullscreen(); // Make sure than WaylandWindow manually handles fullscreen states. Check the // comment in the WaylandWindow::ToggleFullscreen. @@ -332,52 +328,182 @@ TEST_P(WaylandWindowTest, SetFullscreenAndRestore) { SendConfigureEvent(0, 0, 2, states.get()); Sync(); - EXPECT_CALL(*GetXdgSurface(), UnsetFullscreen()); - EXPECT_CALL(delegate_, - OnWindowStateChanged(Eq(PlatformWindowState::kNormal))); + EXPECT_CALL(*GetXdgToplevel(), UnsetFullscreen()); + EXPECT_CALL(delegate_, OnWindowStateChanged(_)).Times(0); window_->Restore(); - EXPECT_EQ(window_->GetPlatformWindowState(), PlatformWindowState::kUnknown); + EXPECT_EQ(window_->GetPlatformWindowState(), PlatformWindowState::kNormal); // Reinitialize wl_array, which removes previous old states. states = InitializeWlArrayWithActivatedState(); SendConfigureEvent(0, 0, 3, states.get()); Sync(); + EXPECT_EQ(window_->GetPlatformWindowState(), PlatformWindowState::kNormal); } TEST_P(WaylandWindowTest, StartWithFullscreen) { + MockPlatformWindowDelegate delegate; + PlatformWindowInitProperties properties; + properties.bounds = gfx::Rect(0, 0, 100, 100); + properties.type = PlatformWindowType::kWindow; + // We need to create a window avoid calling Show() on it as it is what upper + // views layer does - when Widget initialize DesktopWindowTreeHost, the Show() + // is called later down the road, but Maximize may be called earlier. We + // cannot process them and set a pending state instead, because ShellSurface + // is not created by that moment. + auto window = WaylandWindow::Create(&delegate, connection_.get(), + std::move(properties)); + + Sync(); + + // Make sure the window is initialized to normal state from the beginning. + EXPECT_EQ(PlatformWindowState::kNormal, window->GetPlatformWindowState()); + + // The state must not be changed to the fullscreen before the surface is + // activated. + auto* mock_surface = server_.GetObject<wl::MockSurface>(window->GetWidget()); + EXPECT_FALSE(mock_surface->xdg_surface()); + EXPECT_CALL(delegate, OnWindowStateChanged(_)).Times(0); + window->ToggleFullscreen(); + // The state of the window must already be fullscreen one. + EXPECT_EQ(window->GetPlatformWindowState(), PlatformWindowState::kFullScreen); + + Sync(); + + // We mustn't receive any state changes if that does not differ from the last + // state. + EXPECT_CALL(delegate, OnWindowStateChanged(_)).Times(0); + + // Activate the surface. + ScopedWlArray states = InitializeWlArrayWithActivatedState(); + AddStateToWlArray(XDG_TOPLEVEL_STATE_FULLSCREEN, states.get()); + SendConfigureEvent(0, 0, 1, states.get()); + + Sync(); + + // It must be still the same state. + EXPECT_EQ(window->GetPlatformWindowState(), PlatformWindowState::kFullScreen); +} + +TEST_P(WaylandWindowTest, StartMaximized) { + MockPlatformWindowDelegate delegate; + PlatformWindowInitProperties properties; + properties.bounds = gfx::Rect(0, 0, 100, 100); + properties.type = PlatformWindowType::kWindow; + // We need to create a window avoid calling Show() on it as it is what upper + // views layer does - when Widget initialize DesktopWindowTreeHost, the Show() + // is called later down the road, but Maximize may be called earlier. We + // cannot process them and set a pending state instead, because ShellSurface + // is not created by that moment. + auto window = WaylandWindow::Create(&delegate, connection_.get(), + std::move(properties)); + + Sync(); + // Make sure the window is initialized to normal state from the beginning. EXPECT_EQ(PlatformWindowState::kNormal, window_->GetPlatformWindowState()); // The state must not be changed to the fullscreen before the surface is // activated. - EXPECT_CALL(*GetXdgSurface(), SetFullscreen()).Times(0); + auto* mock_surface = server_.GetObject<wl::MockSurface>(window->GetWidget()); + EXPECT_FALSE(mock_surface->xdg_surface()); EXPECT_CALL(delegate_, OnWindowStateChanged(_)).Times(0); - window_->ToggleFullscreen(); - // The state of the window must still be a normal one. - EXPECT_EQ(window_->GetPlatformWindowState(), PlatformWindowState::kNormal); + + window_->Maximize(); + // The state of the window must already be fullscreen one. + EXPECT_EQ(window_->GetPlatformWindowState(), PlatformWindowState::kMaximized); Sync(); - // Once the surface will be activated, the window will automatically trigger - // the state change. - EXPECT_CALL(*GetXdgSurface(), SetFullscreen()); - EXPECT_CALL(delegate_, - OnWindowStateChanged(Eq(PlatformWindowState::kFullScreen))); + // Once the surface will be activated, the window state mustn't be changed + // and retain the same. + EXPECT_CALL(delegate_, OnWindowStateChanged(_)).Times(0); + EXPECT_EQ(window_->GetPlatformWindowState(), PlatformWindowState::kMaximized); // Activate the surface. ScopedWlArray states = InitializeWlArrayWithActivatedState(); + AddStateToWlArray(XDG_TOPLEVEL_STATE_MAXIMIZED, states.get()); SendConfigureEvent(0, 0, 1, states.get()); Sync(); - // The wayland window manually handles the fullscreen state changes, and it - // must change to a fullscreen before the state change is confirmed by the - // wayland. See comment in the WaylandWindow::ToggleFullscreen. - EXPECT_EQ(window_->GetPlatformWindowState(), - PlatformWindowState::kFullScreen); + EXPECT_EQ(window_->GetPlatformWindowState(), PlatformWindowState::kMaximized); +} - AddStateToWlArray(XDG_TOPLEVEL_STATE_FULLSCREEN, states.get()); +TEST_P(WaylandWindowTest, CompositorSideStateChanges) { + EXPECT_EQ(window_->GetPlatformWindowState(), PlatformWindowState::kNormal); + auto normal_bounds = window_->GetBounds(); + + ScopedWlArray states = InitializeWlArrayWithActivatedState(); + AddStateToWlArray(XDG_TOPLEVEL_STATE_MAXIMIZED, states.get()); + SendConfigureEvent(2000, 2000, 1, states.get()); + + EXPECT_CALL(delegate_, + OnWindowStateChanged(Eq(PlatformWindowState::kMaximized))) + .Times(1); + EXPECT_CALL(*xdg_surface_, SetWindowGeometry(0, 0, 2000, 2000)); + + Sync(); + + EXPECT_EQ(window_->GetPlatformWindowState(), PlatformWindowState::kMaximized); + + // Unmaximize + states = InitializeWlArrayWithActivatedState(); SendConfigureEvent(0, 0, 2, states.get()); + EXPECT_CALL(delegate_, OnWindowStateChanged(Eq(PlatformWindowState::kNormal))) + .Times(1); + EXPECT_CALL(*xdg_surface_, SetWindowGeometry(0, 0, normal_bounds.width(), + normal_bounds.height())); + + // Now, set to fullscreen. + AddStateToWlArray(XDG_TOPLEVEL_STATE_FULLSCREEN, states.get()); + SendConfigureEvent(2005, 2005, 3, states.get()); + EXPECT_CALL(delegate_, + OnWindowStateChanged(Eq(PlatformWindowState::kFullScreen))) + .Times(1); + EXPECT_CALL(*xdg_surface_, SetWindowGeometry(0, 0, 2005, 2005)); + + Sync(); + + // Unfullscreen + states = InitializeWlArrayWithActivatedState(); + SendConfigureEvent(0, 0, 4, states.get()); + + EXPECT_CALL(delegate_, OnWindowStateChanged(Eq(PlatformWindowState::kNormal))) + .Times(1); + EXPECT_CALL(*xdg_surface_, SetWindowGeometry(0, 0, normal_bounds.width(), + normal_bounds.height())); + + Sync(); + + // Now, maximize, fullscreen and restore. + states = InitializeWlArrayWithActivatedState(); + AddStateToWlArray(XDG_TOPLEVEL_STATE_MAXIMIZED, states.get()); + SendConfigureEvent(2000, 2000, 1, states.get()); + + EXPECT_CALL(delegate_, + OnWindowStateChanged(Eq(PlatformWindowState::kMaximized))) + .Times(1); + EXPECT_CALL(*xdg_surface_, SetWindowGeometry(0, 0, 2000, 2000)); + + Sync(); + + AddStateToWlArray(XDG_TOPLEVEL_STATE_FULLSCREEN, states.get()); + SendConfigureEvent(2005, 2005, 1, states.get()); + + EXPECT_CALL(delegate_, + OnWindowStateChanged(Eq(PlatformWindowState::kFullScreen))) + .Times(1); + EXPECT_CALL(*xdg_surface_, SetWindowGeometry(0, 0, 2005, 2005)); + + // Restore + states = InitializeWlArrayWithActivatedState(); + SendConfigureEvent(0, 0, 4, states.get()); + + EXPECT_CALL(delegate_, OnWindowStateChanged(Eq(PlatformWindowState::kNormal))) + .Times(1); + EXPECT_CALL(*xdg_surface_, SetWindowGeometry(0, 0, normal_bounds.width(), + normal_bounds.height())); + Sync(); } @@ -393,44 +519,53 @@ TEST_P(WaylandWindowTest, SetMaximizedFullscreenAndRestore) { auto active_maximized = MakeStateArray( {XDG_TOPLEVEL_STATE_ACTIVATED, XDG_TOPLEVEL_STATE_MAXIMIZED}); - EXPECT_CALL(*GetXdgSurface(), SetMaximized()); + EXPECT_CALL(*GetXdgToplevel(), SetMaximized()); EXPECT_CALL(*xdg_surface_, SetWindowGeometry(0, 0, kMaximizedBounds.width(), kMaximizedBounds.height())); EXPECT_CALL(delegate_, OnActivationChanged(Eq(true))); EXPECT_CALL(delegate_, OnBoundsChanged(kMaximizedBounds)); - EXPECT_CALL(delegate_, - OnWindowStateChanged(Eq(PlatformWindowState::kMaximized))); + EXPECT_CALL(delegate_, OnWindowStateChanged(_)).Times(0); window_->Maximize(); + // State changes are synchronous. + EXPECT_EQ(PlatformWindowState::kMaximized, window_->GetPlatformWindowState()); SendConfigureEvent(kMaximizedBounds.width(), kMaximizedBounds.height(), 2, active_maximized.get()); Sync(); + // Verify that the state has not been changed. + EXPECT_EQ(PlatformWindowState::kMaximized, window_->GetPlatformWindowState()); VerifyAndClearExpectations(); - EXPECT_CALL(*GetXdgSurface(), SetFullscreen()); + EXPECT_CALL(*GetXdgToplevel(), SetFullscreen()); EXPECT_CALL(*xdg_surface_, SetWindowGeometry(0, 0, kMaximizedBounds.width(), kMaximizedBounds.height())); EXPECT_CALL(delegate_, OnBoundsChanged(_)).Times(0); - EXPECT_CALL(delegate_, - OnWindowStateChanged(Eq(PlatformWindowState::kFullScreen))); + EXPECT_CALL(delegate_, OnWindowStateChanged(_)).Times(0); window_->ToggleFullscreen(); + // State changes are synchronous. + EXPECT_EQ(PlatformWindowState::kFullScreen, + window_->GetPlatformWindowState()); AddStateToWlArray(XDG_TOPLEVEL_STATE_FULLSCREEN, active_maximized.get()); SendConfigureEvent(kMaximizedBounds.width(), kMaximizedBounds.height(), 3, active_maximized.get()); Sync(); + // Verify that the state has not been changed. + EXPECT_EQ(PlatformWindowState::kFullScreen, + window_->GetPlatformWindowState()); VerifyAndClearExpectations(); EXPECT_CALL(*xdg_surface_, SetWindowGeometry(0, 0, kNormalBounds.width(), kNormalBounds.height())); - EXPECT_CALL(*GetXdgSurface(), UnsetFullscreen()); - EXPECT_CALL(*GetXdgSurface(), UnsetMaximized()); + EXPECT_CALL(*GetXdgToplevel(), UnsetFullscreen()); + EXPECT_CALL(*GetXdgToplevel(), UnsetMaximized()); EXPECT_CALL(delegate_, OnBoundsChanged(kNormalBounds)); - EXPECT_CALL(delegate_, - OnWindowStateChanged(Eq(PlatformWindowState::kNormal))); + EXPECT_CALL(delegate_, OnWindowStateChanged(_)).Times(0); window_->Restore(); + EXPECT_EQ(PlatformWindowState::kNormal, window_->GetPlatformWindowState()); // Reinitialize wl_array, which removes previous old states. auto active = InitializeWlArrayWithActivatedState(); SendConfigureEvent(0, 0, 4, active.get()); Sync(); + EXPECT_EQ(PlatformWindowState::kNormal, window_->GetPlatformWindowState()); } TEST_P(WaylandWindowTest, RestoreBoundsAfterMaximize) { @@ -704,21 +839,17 @@ TEST_P(WaylandWindowTest, ConfigureEventWithNulledSize) { } TEST_P(WaylandWindowTest, OnActivationChanged) { - EXPECT_FALSE(window_->is_active()); - { ScopedWlArray states = InitializeWlArrayWithActivatedState(); EXPECT_CALL(delegate_, OnActivationChanged(Eq(true))); SendConfigureEvent(0, 0, 1, states.get()); Sync(); - EXPECT_TRUE(window_->is_active()); } ScopedWlArray states; EXPECT_CALL(delegate_, OnActivationChanged(Eq(false))); SendConfigureEvent(0, 0, 2, states.get()); Sync(); - EXPECT_FALSE(window_->is_active()); } TEST_P(WaylandWindowTest, OnAcceleratedWidgetDestroy) { @@ -736,27 +867,31 @@ TEST_P(WaylandWindowTest, CanCreateMenuWindow) { ASSERT_TRUE(connection_->pointer() && connection_->touch()); window_->SetPointerFocus(true); - std::unique_ptr<WaylandWindow> menu_window; - EXPECT_TRUE(CreateWaylandWindowWithParams( + std::unique_ptr<WaylandWindow> menu_window = CreateWaylandWindowWithParams( PlatformWindowType::kMenu, gfx::kNullAcceleratedWidget, - gfx::Rect(0, 0, 10, 10), &menu_window_delegate, &menu_window)); + gfx::Rect(0, 0, 10, 10), &menu_window_delegate); + EXPECT_TRUE(menu_window); Sync(); window_->SetPointerFocus(false); window_->set_touch_focus(false); - EXPECT_FALSE(CreateWaylandWindowWithParams( + // Given that there is no parent passed and we don't have any focused windows, + // Wayland must still create a window. + menu_window = CreateWaylandWindowWithParams( PlatformWindowType::kMenu, gfx::kNullAcceleratedWidget, - gfx::Rect(0, 0, 10, 10), &menu_window_delegate, &menu_window)); + gfx::Rect(0, 0, 10, 10), &menu_window_delegate); + EXPECT_TRUE(menu_window); Sync(); window_->set_touch_focus(true); - EXPECT_TRUE(CreateWaylandWindowWithParams( + menu_window = CreateWaylandWindowWithParams( PlatformWindowType::kMenu, gfx::kNullAcceleratedWidget, - gfx::Rect(0, 0, 10, 10), &menu_window_delegate, &menu_window)); + gfx::Rect(0, 0, 10, 10), &menu_window_delegate); + EXPECT_TRUE(menu_window); Sync(); } @@ -767,29 +902,30 @@ TEST_P(WaylandWindowTest, CreateAndDestroyNestedMenuWindow) { EXPECT_CALL(menu_window_delegate, OnAcceleratedWidgetAvailable(_)) .WillOnce(SaveArg<0>(&menu_window_widget)); - std::unique_ptr<WaylandWindow> menu_window; - EXPECT_TRUE(CreateWaylandWindowWithParams( + std::unique_ptr<WaylandWindow> menu_window = CreateWaylandWindowWithParams( PlatformWindowType::kMenu, widget_, gfx::Rect(0, 0, 10, 10), - &menu_window_delegate, &menu_window)); + &menu_window_delegate); + EXPECT_TRUE(menu_window); ASSERT_NE(menu_window_widget, gfx::kNullAcceleratedWidget); Sync(); MockPlatformWindowDelegate nested_menu_window_delegate; - std::unique_ptr<WaylandWindow> nested_menu_window; - EXPECT_TRUE(CreateWaylandWindowWithParams( - PlatformWindowType::kMenu, menu_window_widget, gfx::Rect(20, 0, 10, 10), - &nested_menu_window_delegate, &nested_menu_window)); + std::unique_ptr<WaylandWindow> nested_menu_window = + CreateWaylandWindowWithParams( + PlatformWindowType::kMenu, menu_window_widget, + gfx::Rect(20, 0, 10, 10), &nested_menu_window_delegate); + EXPECT_TRUE(nested_menu_window); Sync(); } TEST_P(WaylandWindowTest, CanDispatchEventToMenuWindowNonNested) { MockPlatformWindowDelegate menu_window_delegate; - std::unique_ptr<WaylandWindow> menu_window; - EXPECT_TRUE(CreateWaylandWindowWithParams( + std::unique_ptr<WaylandWindow> menu_window = CreateWaylandWindowWithParams( PlatformWindowType::kMenu, widget_, gfx::Rect(0, 0, 10, 10), - &menu_window_delegate, &menu_window)); + &menu_window_delegate); + EXPECT_TRUE(menu_window); wl_seat_send_capabilities(server_.seat()->resource(), WL_SEAT_CAPABILITY_POINTER); @@ -812,18 +948,19 @@ TEST_P(WaylandWindowTest, CanDispatchEventToMenuWindowNested) { EXPECT_CALL(menu_window_delegate, OnAcceleratedWidgetAvailable(_)) .WillOnce(SaveArg<0>(&menu_window_widget)); - std::unique_ptr<WaylandWindow> menu_window; - EXPECT_TRUE(CreateWaylandWindowWithParams( + std::unique_ptr<WaylandWindow> menu_window = CreateWaylandWindowWithParams( PlatformWindowType::kMenu, widget_, gfx::Rect(0, 0, 10, 10), - &menu_window_delegate, &menu_window)); + &menu_window_delegate); + EXPECT_TRUE(menu_window); Sync(); MockPlatformWindowDelegate nested_menu_window_delegate; - std::unique_ptr<WaylandWindow> nested_menu_window; - EXPECT_TRUE(CreateWaylandWindowWithParams( - PlatformWindowType::kMenu, menu_window_widget, gfx::Rect(20, 0, 10, 10), - &nested_menu_window_delegate, &nested_menu_window)); + std::unique_ptr<WaylandWindow> nested_menu_window = + CreateWaylandWindowWithParams( + PlatformWindowType::kMenu, menu_window_widget, + gfx::Rect(20, 0, 10, 10), &nested_menu_window_delegate); + EXPECT_TRUE(nested_menu_window); Sync(); @@ -843,8 +980,8 @@ TEST_P(WaylandWindowTest, CanDispatchEventToMenuWindowNested) { } TEST_P(WaylandWindowTest, DispatchWindowMove) { - EXPECT_CALL(*GetXdgSurface(), Move(_)); - window_->DispatchHostWindowDragMovement(HTCAPTION, gfx::Point()); + EXPECT_CALL(*GetXdgToplevel(), Move(_)); + ui::GetWmMoveResizeHandler(*window_)->DispatchHostWindowDragMovement(HTCAPTION, gfx::Point()); } // Makes sure hit tests are converted into right edges. @@ -852,11 +989,14 @@ TEST_P(WaylandWindowTest, DispatchWindowResize) { std::vector<int> hit_test_values; InitializeWithSupportedHitTestValues(&hit_test_values); + auto* wm_move_resize_handler = ui::GetWmMoveResizeHandler(*window_); + for (const int value : hit_test_values) { { uint32_t direction = wl::IdentifyDirection(*(connection_.get()), value); - EXPECT_CALL(*GetXdgSurface(), Resize(_, Eq(direction))); - window_->DispatchHostWindowDragMovement(value, gfx::Point()); + EXPECT_CALL(*GetXdgToplevel(), Resize(_, Eq(direction))); + wm_move_resize_handler->DispatchHostWindowDragMovement(value, + gfx::Point()); } } } @@ -903,10 +1043,10 @@ TEST_P(WaylandWindowTest, AdjustPopupBounds) { MockPlatformWindowDelegate menu_window_delegate; gfx::Rect menu_window_bounds(gfx::Point(440, 76), menu_window_positioner.size); - std::unique_ptr<WaylandWindow> menu_window; - EXPECT_TRUE(CreateWaylandWindowWithParams( + std::unique_ptr<WaylandWindow> menu_window = CreateWaylandWindowWithParams( PlatformWindowType::kMenu, toplevel_window->GetWidget(), - menu_window_bounds, &menu_window_delegate, &menu_window)); + menu_window_bounds, &menu_window_delegate); + EXPECT_TRUE(menu_window); Sync(); @@ -924,10 +1064,11 @@ TEST_P(WaylandWindowTest, AdjustPopupBounds) { MockPlatformWindowDelegate nested_menu_window_delegate; gfx::Rect nested_menu_window_bounds(gfx::Point(723, 156), nested_menu_window_positioner.size); - std::unique_ptr<WaylandWindow> nested_menu_window; - EXPECT_TRUE(CreateWaylandWindowWithParams( - PlatformWindowType::kMenu, menu_window_widget, nested_menu_window_bounds, - &nested_menu_window_delegate, &nested_menu_window)); + std::unique_ptr<WaylandWindow> nested_menu_window = + CreateWaylandWindowWithParams( + PlatformWindowType::kMenu, menu_window_widget, + nested_menu_window_bounds, &nested_menu_window_delegate); + EXPECT_TRUE(nested_menu_window); Sync(); @@ -985,9 +1126,10 @@ TEST_P(WaylandWindowTest, AdjustPopupBounds) { // side. Thus, we have to check that anchor rect is correct. nested_menu_window.reset(); nested_menu_window_bounds.set_origin({723, 258}); - EXPECT_TRUE(CreateWaylandWindowWithParams( + nested_menu_window = CreateWaylandWindowWithParams( PlatformWindowType::kMenu, menu_window_widget, nested_menu_window_bounds, - &nested_menu_window_delegate, &nested_menu_window)); + &nested_menu_window_delegate); + EXPECT_TRUE(nested_menu_window); Sync(); @@ -1050,9 +1192,10 @@ TEST_P(WaylandWindowTest, AdjustPopupBounds) { window_->SetBounds(gfx::Rect(0, 0, 2493, 1413)); menu_window_bounds.set_origin({2206, 67}); - EXPECT_TRUE(CreateWaylandWindowWithParams( + menu_window = CreateWaylandWindowWithParams( PlatformWindowType::kMenu, toplevel_window->GetWidget(), - menu_window_bounds, &menu_window_delegate, &menu_window)); + menu_window_bounds, &menu_window_delegate); + EXPECT_TRUE(menu_window); Sync(); @@ -1066,9 +1209,10 @@ TEST_P(WaylandWindowTest, AdjustPopupBounds) { Sync(); nested_menu_window_bounds.set_origin({1905, 147}); - EXPECT_TRUE(CreateWaylandWindowWithParams( + nested_menu_window = CreateWaylandWindowWithParams( PlatformWindowType::kMenu, menu_window_widget, nested_menu_window_bounds, - &nested_menu_window_delegate, &nested_menu_window)); + &nested_menu_window_delegate); + EXPECT_TRUE(nested_menu_window); Sync(); @@ -1087,7 +1231,7 @@ TEST_P(WaylandWindowTest, AdjustPopupBounds) { // shown on another display. auto active_maximized = MakeStateArray( {XDG_TOPLEVEL_STATE_ACTIVATED, XDG_TOPLEVEL_STATE_MAXIMIZED}); - EXPECT_CALL(*GetXdgSurface(), SetMaximized()); + EXPECT_CALL(*GetXdgToplevel(), SetMaximized()); window_->Maximize(); SendConfigureEvent(2493, 1413, 1, active_maximized.get()); @@ -1096,9 +1240,10 @@ TEST_P(WaylandWindowTest, AdjustPopupBounds) { nested_menu_window.reset(); - EXPECT_TRUE(CreateWaylandWindowWithParams( + nested_menu_window = CreateWaylandWindowWithParams( PlatformWindowType::kMenu, menu_window_widget, nested_menu_window_bounds, - &nested_menu_window_delegate, &nested_menu_window)); + &nested_menu_window_delegate); + EXPECT_TRUE(nested_menu_window); Sync(); @@ -1170,61 +1315,114 @@ TEST_P(WaylandWindowTest, OnCloseRequest) { Sync(); } -TEST_P(WaylandWindowTest, TooltipSimpleParent) { +TEST_P(WaylandWindowTest, SubsurfaceSimpleParent) { VerifyAndClearExpectations(); - gfx::Rect tooltip_window_bounds(gfx::Point(15, 15), gfx::Size(10, 10)); - std::unique_ptr<WaylandWindow> tooltip_window; - EXPECT_TRUE(CreateWaylandWindowWithParams( - PlatformWindowType::kTooltip, window_->GetWidget(), tooltip_window_bounds, - &delegate_, &tooltip_window)); + std::unique_ptr<WaylandWindow> second_window = CreateWaylandWindowWithParams( + PlatformWindowType::kWindow, gfx::kNullAcceleratedWidget, + gfx::Rect(0, 0, 640, 480), &delegate_); + EXPECT_TRUE(second_window); - window_->SetPointerFocus(true); + // Test case 1: if the subsurface is provided with a parent widget, it must + // always use that as a parent. + gfx::Rect subsurface_bounds(gfx::Point(15, 15), gfx::Size(10, 10)); + std::unique_ptr<WaylandWindow> subsuface_window = + CreateWaylandWindowWithParams(PlatformWindowType::kTooltip, + window_->GetWidget(), subsurface_bounds, + &delegate_); + EXPECT_TRUE(subsuface_window); - tooltip_window->Show(false); + // The subsurface mustn't take the focused window as a parent, but use the + // provided one. + second_window->SetPointerFocus(true); + subsuface_window->Show(false); Sync(); - auto* mock_tooltip_surface = - server_.GetObject<wl::MockSurface>(tooltip_window->GetWidget()); - auto* test_subsurface = mock_tooltip_surface->sub_surface(); + auto* mock_surface_subsurface = + server_.GetObject<wl::MockSurface>(subsuface_window->GetWidget()); + auto* test_subsurface = mock_surface_subsurface->sub_surface(); - EXPECT_EQ(test_subsurface->position(), tooltip_window_bounds.origin()); + EXPECT_EQ(test_subsurface->position(), subsurface_bounds.origin()); EXPECT_FALSE(test_subsurface->sync()); + auto* parent_resource = + server_.GetObject<wl::MockSurface>(window_->GetWidget())->resource(); + EXPECT_EQ(parent_resource, test_subsurface->parent_resource()); + + // Test case 2: the subsurface must use the focused window as its parent. + subsuface_window = CreateWaylandWindowWithParams( + PlatformWindowType::kTooltip, gfx::kNullAcceleratedWidget, + subsurface_bounds, &delegate_); + EXPECT_TRUE(subsuface_window); + + // The tooltip must take the focused window. + second_window->SetPointerFocus(true); + subsuface_window->Show(false); + + Sync(); + + // Get new surface after recreating the WaylandSubsurface. + mock_surface_subsurface = + server_.GetObject<wl::MockSurface>(subsuface_window->GetWidget()); + test_subsurface = mock_surface_subsurface->sub_surface(); + + auto* second_parent_resource = + server_.GetObject<wl::MockSurface>(second_window->GetWidget()) + ->resource(); + EXPECT_EQ(second_parent_resource, test_subsurface->parent_resource()); + + subsuface_window->Hide(); + + Sync(); + + // The subsurface must take the focused window. + second_window->SetPointerFocus(false); + window_->SetPointerFocus(true); + subsuface_window->Show(false); + + Sync(); + + // The subsurface is invalidated on each Hide call. + test_subsurface = mock_surface_subsurface->sub_surface(); + + // The |window_|'s resource must be the parent resource. + EXPECT_EQ(parent_resource, test_subsurface->parent_resource()); + window_->SetPointerFocus(false); } -TEST_P(WaylandWindowTest, TooltipNestedParent) { +TEST_P(WaylandWindowTest, SubsurfaceNestedParent) { VerifyAndClearExpectations(); gfx::Rect menu_window_bounds(gfx::Point(10, 10), gfx::Size(100, 100)); - std::unique_ptr<WaylandWindow> menu_window; - EXPECT_TRUE(CreateWaylandWindowWithParams( + std::unique_ptr<WaylandWindow> menu_window = CreateWaylandWindowWithParams( PlatformWindowType::kMenu, window_->GetWidget(), menu_window_bounds, - &delegate_, &menu_window)); + &delegate_); + EXPECT_TRUE(menu_window); VerifyAndClearExpectations(); - gfx::Rect tooltip_window_bounds(gfx::Point(15, 15), gfx::Size(10, 10)); - std::unique_ptr<WaylandWindow> tooltip_window; - EXPECT_TRUE(CreateWaylandWindowWithParams( - PlatformWindowType::kTooltip, menu_window->GetWidget(), - tooltip_window_bounds, &delegate_, &tooltip_window)); + gfx::Rect subsurface_bounds(gfx::Point(15, 15), gfx::Size(10, 10)); + std::unique_ptr<WaylandWindow> subsuface_window = + CreateWaylandWindowWithParams(PlatformWindowType::kTooltip, + menu_window->GetWidget(), subsurface_bounds, + &delegate_); + EXPECT_TRUE(subsuface_window); VerifyAndClearExpectations(); menu_window->SetPointerFocus(true); - tooltip_window->Show(false); + subsuface_window->Show(false); Sync(); - auto* mock_tooltip_surface = - server_.GetObject<wl::MockSurface>(tooltip_window->GetWidget()); - auto* test_subsurface = mock_tooltip_surface->sub_surface(); + auto* mock_surface_subsurface = + server_.GetObject<wl::MockSurface>(subsuface_window->GetWidget()); + auto* test_subsurface = mock_surface_subsurface->sub_surface(); - auto new_origin = tooltip_window_bounds.origin() - + auto new_origin = subsurface_bounds.origin() - menu_window_bounds.origin().OffsetFromOrigin(); EXPECT_EQ(test_subsurface->position(), new_origin); @@ -1246,9 +1444,9 @@ TEST_P(WaylandWindowTest, OnSizeConstraintsChanged) { EXPECT_CALL(delegate_, GetMaximumSizeForWindow()) .WillOnce(Return(max_size)); - EXPECT_CALL(*GetXdgSurface(), SetMinSize(100, 200)) + EXPECT_CALL(*GetXdgToplevel(), SetMinSize(100, 200)) .Times(has_min_size ? 1 : 0); - EXPECT_CALL(*GetXdgSurface(), SetMaxSize(300, 400)) + EXPECT_CALL(*GetXdgToplevel(), SetMaxSize(300, 400)) .Times(has_max_size ? 1 : 0); window_->SizeConstraintsChanged(); @@ -1259,6 +1457,129 @@ TEST_P(WaylandWindowTest, OnSizeConstraintsChanged) { } } +TEST_P(WaylandWindowTest, DestroysCreatesSurfaceOnHideShow) { + MockPlatformWindowDelegate delegate; + auto window = CreateWaylandWindowWithParams( + PlatformWindowType::kWindow, gfx::kNullAcceleratedWidget, + gfx::Rect(0, 0, 100, 100), &delegate); + ASSERT_TRUE(window); + + Sync(); + + auto* mock_surface = server_.GetObject<wl::MockSurface>(window->GetWidget()); + EXPECT_TRUE(mock_surface->xdg_surface()); + EXPECT_TRUE(mock_surface->xdg_surface()->xdg_toplevel()); + + Sync(); + + window->Hide(); + + Sync(); + + EXPECT_FALSE(mock_surface->xdg_surface()); + + window->Show(false); + + Sync(); + + EXPECT_TRUE(mock_surface->xdg_surface()); + EXPECT_TRUE(mock_surface->xdg_surface()->xdg_toplevel()); +} + +TEST_P(WaylandWindowTest, DestroysCreatesPopupsOnHideShow) { + MockPlatformWindowDelegate delegate; + auto window = CreateWaylandWindowWithParams( + PlatformWindowType::kMenu, window_->GetWidget(), gfx::Rect(0, 0, 50, 50), + &delegate); + ASSERT_TRUE(window); + + Sync(); + + auto* mock_surface = server_.GetObject<wl::MockSurface>(window->GetWidget()); + EXPECT_TRUE(mock_surface->xdg_surface()); + EXPECT_TRUE(mock_surface->xdg_surface()->xdg_popup()); + + Sync(); + + window->Hide(); + + Sync(); + + EXPECT_FALSE(mock_surface->xdg_surface()); + + window->Show(false); + + Sync(); + + EXPECT_TRUE(mock_surface->xdg_surface()); + EXPECT_TRUE(mock_surface->xdg_surface()->xdg_popup()); +} + +// Tests that if the window gets hidden and shown again, the title, app id and +// size constraints remain the same. +TEST_P(WaylandWindowTest, SetsPropertiesOnShow) { + constexpr char kAppId[] = "wayland_test"; + const base::string16 kTitle(base::UTF8ToUTF16("WaylandWindowTest")); + + PlatformWindowInitProperties properties; + properties.bounds = gfx::Rect(0, 0, 100, 100); + properties.type = PlatformWindowType::kWindow; + properties.wm_class_class = kAppId; + + MockPlatformWindowDelegate delegate; + auto window = WaylandWindow::Create(&delegate, connection_.get(), + std::move(properties)); + DCHECK(window); + window->Show(false); + + Sync(); + + auto* mock_surface = server_.GetObject<wl::MockSurface>(window->GetWidget()); + auto* mock_xdg_toplevel = mock_surface->xdg_surface()->xdg_toplevel(); + + // Only app id must be set now. + EXPECT_EQ(std::string(kAppId), mock_xdg_toplevel->app_id()); + EXPECT_TRUE(mock_xdg_toplevel->title().empty()); + EXPECT_TRUE(mock_xdg_toplevel->min_size().IsEmpty()); + EXPECT_TRUE(mock_xdg_toplevel->max_size().IsEmpty()); + + // Now, propagate size constraints and title. + base::Optional<gfx::Size> min_size(gfx::Size(1, 1)); + base::Optional<gfx::Size> max_size(gfx::Size(100, 100)); + EXPECT_CALL(delegate, GetMinimumSizeForWindow()).WillOnce(Return(min_size)); + EXPECT_CALL(delegate, GetMaximumSizeForWindow()).WillOnce(Return(max_size)); + + EXPECT_CALL(*mock_xdg_toplevel, + SetMinSize(min_size.value().width(), min_size.value().height())); + EXPECT_CALL(*mock_xdg_toplevel, + SetMaxSize(max_size.value().width(), max_size.value().height())); + EXPECT_CALL(*mock_xdg_toplevel, SetTitle(base::UTF16ToUTF8(kTitle))); + + window->SetTitle(kTitle); + window->SizeConstraintsChanged(); + + Sync(); + + window->Hide(); + + Sync(); + + window->Show(false); + + Sync(); + + mock_xdg_toplevel = mock_surface->xdg_surface()->xdg_toplevel(); + + // We can't mock all those methods above as long as the xdg_toplevel is + // created and destroyed on each show and hide call. However, it is the same + // WaylandSurface object that cached the values we set and must restore them + // on Show(). + EXPECT_EQ(mock_xdg_toplevel->min_size(), min_size.value()); + EXPECT_EQ(mock_xdg_toplevel->max_size(), max_size.value()); + EXPECT_EQ(std::string(kAppId), mock_xdg_toplevel->app_id()); + EXPECT_EQ(mock_xdg_toplevel->title(), base::UTF16ToUTF8(kTitle)); +} + 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 c5fc7a317c7..991ae63fc1c 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 @@ -7,7 +7,7 @@ #include <drm_fourcc.h> #include <linux-dmabuf-unstable-v1-client-protocol.h> -#include "ui/ozone/common/linux/drm_util_linux.h" +#include "ui/gfx/linux/drm_util_linux.h" #include "ui/ozone/platform/wayland/host/wayland_connection.h" namespace ui { 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 0c6683828e7..35ab0875304 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 @@ -12,9 +12,11 @@ #include "base/nix/xdg_util.h" #include "ui/events/event_constants.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" #include "ui/ozone/platform/wayland/host/wayland_pointer.h" -#include "ui/ozone/platform/wayland/host/wayland_window.h" +#include "ui/ozone/platform/wayland/host/wayland_popup.h" +#include "ui/ozone/platform/wayland/host/wayland_surface.h" #include "ui/ozone/platform/wayland/host/xdg_surface_wrapper_impl.h" namespace ui { @@ -260,40 +262,55 @@ XDGPopupWrapperImpl::XDGPopupWrapperImpl( WaylandWindow* wayland_window) : wayland_window_(wayland_window), xdg_surface_(std::move(surface)) { DCHECK(xdg_surface_); + DCHECK(wayland_window_ && wayland_window_->parent_window()); } -XDGPopupWrapperImpl::~XDGPopupWrapperImpl() {} +XDGPopupWrapperImpl::~XDGPopupWrapperImpl() = default; -bool XDGPopupWrapperImpl::InitializeStable(WaylandConnection* connection, - wl_surface* surface, - WaylandWindow* parent_window, - const gfx::Rect& bounds) { - DCHECK(connection && surface && parent_window); - static const struct xdg_popup_listener xdg_popup_listener = { - &XDGPopupWrapperImpl::ConfigureStable, - &XDGPopupWrapperImpl::PopupDoneStable, - }; - - if (!xdg_surface_) +bool XDGPopupWrapperImpl::Initialize(WaylandConnection* connection, + const gfx::Rect& bounds) { + if (!connection->shell() && !connection->shell_v6()) { + NOTREACHED() << "Wrong shell protocol"; return false; + } - XDGSurfaceWrapperImpl* parent_xdg_surface; + XDGSurfaceWrapperImpl* parent_xdg_surface = nullptr; // If the parent window is a popup, the surface of that popup must be used as // a parent. - if (parent_window->shell_popup()) { + if (wl::IsMenuType(wayland_window_->parent_window()->type())) { + auto* wayland_popup = + static_cast<WaylandPopup*>(wayland_window_->parent_window()); XDGPopupWrapperImpl* popup = - reinterpret_cast<XDGPopupWrapperImpl*>(parent_window->shell_popup()); + static_cast<XDGPopupWrapperImpl*>(wayland_popup->shell_popup()); parent_xdg_surface = popup->xdg_surface(); } else { - parent_xdg_surface = reinterpret_cast<XDGSurfaceWrapperImpl*>( - parent_window->shell_surface()); + WaylandSurface* wayland_surface = + static_cast<WaylandSurface*>(wayland_window_->parent_window()); + parent_xdg_surface = + static_cast<XDGSurfaceWrapperImpl*>(wayland_surface->shell_surface()); } - if (!parent_xdg_surface) + if (!xdg_surface_ || !parent_xdg_surface) return false; - struct xdg_positioner* positioner = - CreatePositionerStable(connection, parent_window, bounds); + if (connection->shell()) + return InitializeStable(connection, bounds, parent_xdg_surface); + else if (connection->shell_v6()) + return InitializeV6(connection, bounds, parent_xdg_surface); + return false; +} + +bool XDGPopupWrapperImpl::InitializeStable( + WaylandConnection* connection, + const gfx::Rect& bounds, + XDGSurfaceWrapperImpl* parent_xdg_surface) { + static const struct xdg_popup_listener xdg_popup_listener = { + &XDGPopupWrapperImpl::ConfigureStable, + &XDGPopupWrapperImpl::PopupDoneStable, + }; + + struct xdg_positioner* positioner = CreatePositionerStable( + connection, wayland_window_->parent_window(), bounds); if (!positioner) return false; @@ -333,11 +350,17 @@ bool XDGPopupWrapperImpl::InitializeStable(WaylandConnection* connection, base::nix::DESKTOP_ENVIRONMENT_GNOME) || (wayland_window_->parent_window()->has_pointer_focus() || wayland_window_->parent_window()->has_keyboard_focus())) { - xdg_popup_grab(xdg_popup_.get(), connection->seat(), connection->serial()); + // When drag process starts, as described the protocol - + // https://goo.gl/1Mskq3, the client must have an active implicit grab. If + // we try to create a popup and grab it, it will be immediately dismissed. + // Thus, do not take explicit grab during drag process. + if (!connection->IsDragInProgress()) + xdg_popup_grab(xdg_popup_.get(), connection->seat(), + connection->serial()); } xdg_popup_add_listener(xdg_popup_.get(), &xdg_popup_listener, this); - wl_surface_commit(surface); + wl_surface_commit(wayland_window_->surface()); return true; } @@ -361,7 +384,7 @@ struct xdg_positioner* XDGPopupWrapperImpl::CreatePositionerStable( MenuType menu_type = MenuType::TYPE_UNKNOWN; if (is_right_click_menu) menu_type = MenuType::TYPE_RIGHT_CLICK; - else if (parent_window->shell_popup()) + else if (wl::IsMenuType(parent_window->type())) menu_type = MenuType::TYPE_3DOT_CHILD_MENU; else menu_type = MenuType::TYPE_3DOT_PARENT_MENU; @@ -382,36 +405,17 @@ struct xdg_positioner* XDGPopupWrapperImpl::CreatePositionerStable( return positioner; } -bool XDGPopupWrapperImpl::InitializeV6(WaylandConnection* connection, - wl_surface* surface, - WaylandWindow* parent_window, - const gfx::Rect& bounds) { - DCHECK(connection && surface && parent_window); +bool XDGPopupWrapperImpl::InitializeV6( + WaylandConnection* connection, + const gfx::Rect& bounds, + XDGSurfaceWrapperImpl* parent_xdg_surface) { static const struct zxdg_popup_v6_listener zxdg_popup_v6_listener = { &XDGPopupWrapperImpl::ConfigureV6, &XDGPopupWrapperImpl::PopupDoneV6, }; - if (!xdg_surface_) - return false; - - XDGSurfaceWrapperImpl* parent_xdg_surface; - // If the parent window is a popup, the surface of that popup must be used as - // a parent. - if (parent_window->shell_popup()) { - XDGPopupWrapperImpl* popup = - reinterpret_cast<XDGPopupWrapperImpl*>(parent_window->shell_popup()); - parent_xdg_surface = popup->xdg_surface(); - } else { - parent_xdg_surface = reinterpret_cast<XDGSurfaceWrapperImpl*>( - parent_window->shell_surface()); - } - - if (!parent_xdg_surface) - return false; - zxdg_positioner_v6* positioner = - CreatePositionerV6(connection, parent_window, bounds); + CreatePositionerV6(connection, wayland_window_->parent_window(), bounds); if (!positioner) return false; @@ -457,7 +461,7 @@ bool XDGPopupWrapperImpl::InitializeV6(WaylandConnection* connection, zxdg_popup_v6_add_listener(zxdg_popup_v6_.get(), &zxdg_popup_v6_listener, this); - wl_surface_commit(surface); + wl_surface_commit(wayland_window_->surface()); return true; } @@ -481,7 +485,7 @@ zxdg_positioner_v6* XDGPopupWrapperImpl::CreatePositionerV6( MenuType menu_type = MenuType::TYPE_UNKNOWN; if (is_right_click_menu) menu_type = MenuType::TYPE_RIGHT_CLICK; - else if (parent_window->shell_popup()) + else if (wl::IsMenuType(parent_window->type())) menu_type = MenuType::TYPE_3DOT_CHILD_MENU; else menu_type = MenuType::TYPE_3DOT_PARENT_MENU; diff --git a/chromium/ui/ozone/platform/wayland/host/xdg_popup_wrapper_impl.h b/chromium/ui/ozone/platform/wayland/host/xdg_popup_wrapper_impl.h index 371f18157d7..c0479cfff7f 100644 --- a/chromium/ui/ozone/platform/wayland/host/xdg_popup_wrapper_impl.h +++ b/chromium/ui/ozone/platform/wayland/host/xdg_popup_wrapper_impl.h @@ -23,19 +23,20 @@ class XDGPopupWrapperImpl : public ShellPopupWrapper { ~XDGPopupWrapperImpl() override; // XDGPopupWrapper: - bool InitializeStable(WaylandConnection* connection, - wl_surface* surface, - WaylandWindow* parent_window, - const gfx::Rect& bounds); - bool InitializeV6(WaylandConnection* connection, - wl_surface* surface, - WaylandWindow* parent_window, - const gfx::Rect& bounds); + bool Initialize(WaylandConnection* connection, + const gfx::Rect& bounds) override; private: + bool InitializeStable(WaylandConnection* connection, + const gfx::Rect& bounds, + XDGSurfaceWrapperImpl* parent_xdg_surface); struct xdg_positioner* CreatePositionerStable(WaylandConnection* connection, WaylandWindow* parent_window, const gfx::Rect& bounds); + + bool InitializeV6(WaylandConnection* connection, + const gfx::Rect& bounds, + XDGSurfaceWrapperImpl* parent_xdg_surface); struct zxdg_positioner_v6* CreatePositionerV6(WaylandConnection* connection, WaylandWindow* parent_window, const gfx::Rect& bounds); @@ -64,9 +65,15 @@ class XDGPopupWrapperImpl : public ShellPopupWrapper { XDGSurfaceWrapperImpl* xdg_surface(); + // Non-owned WaylandWindow that uses this popup. WaylandWindow* const wayland_window_; + + // Ground surface for this popup. std::unique_ptr<XDGSurfaceWrapperImpl> xdg_surface_; + + // XDG Shell Stable object. wl::Object<xdg_popup> xdg_popup_; + // XDG Shell V6 object. wl::Object<zxdg_popup_v6> zxdg_popup_v6_; DISALLOW_COPY_AND_ASSIGN(XDGPopupWrapperImpl); 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 d4078e1bc13..e7df772ae47 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 @@ -15,84 +15,19 @@ namespace ui { -XDGSurfaceWrapperImpl::XDGSurfaceWrapperImpl(WaylandWindow* wayland_window) - : wayland_window_(wayland_window) {} +XDGSurfaceWrapperImpl::XDGSurfaceWrapperImpl(WaylandWindow* wayland_window, + WaylandConnection* connection) + : wayland_window_(wayland_window), connection_(connection) {} XDGSurfaceWrapperImpl::~XDGSurfaceWrapperImpl() {} -bool XDGSurfaceWrapperImpl::InitializeStable(WaylandConnection* connection, - wl_surface* surface, - bool with_toplevel) { - static const xdg_surface_listener xdg_surface_listener = { - &XDGSurfaceWrapperImpl::ConfigureStable, - }; - static const xdg_toplevel_listener xdg_toplevel_listener = { - &XDGSurfaceWrapperImpl::ConfigureTopLevelStable, - &XDGSurfaceWrapperImpl::CloseTopLevelStable, - }; - - // if this surface is created for the popup role, mark that it requires - // configuration acknowledgement on each configure event. - surface_for_popup_ = !with_toplevel; - - xdg_surface_.reset(xdg_wm_base_get_xdg_surface(connection->shell(), surface)); - if (!xdg_surface_) { - LOG(ERROR) << "Failed to create xdg_surface"; - return false; - } - xdg_surface_add_listener(xdg_surface_.get(), &xdg_surface_listener, this); - // XDGPopup requires a separate surface to be created, so this is just a - // request to get an xdg_surface for it. - if (surface_for_popup_) - return true; - - xdg_toplevel_.reset(xdg_surface_get_toplevel(xdg_surface_.get())); - if (!xdg_toplevel_) { - LOG(ERROR) << "Failed to create xdg_toplevel"; - return false; - } - xdg_toplevel_add_listener(xdg_toplevel_.get(), &xdg_toplevel_listener, this); - wl_surface_commit(surface); - return true; -} - -bool XDGSurfaceWrapperImpl::InitializeV6(WaylandConnection* connection, - wl_surface* surface, - bool with_toplevel) { - static const zxdg_surface_v6_listener zxdg_surface_v6_listener = { - &XDGSurfaceWrapperImpl::ConfigureV6, - }; - static const zxdg_toplevel_v6_listener zxdg_toplevel_v6_listener = { - &XDGSurfaceWrapperImpl::ConfigureTopLevelV6, - &XDGSurfaceWrapperImpl::CloseTopLevelV6, - }; - - // if this surface is created for the popup role, mark that it requires - // configuration acknowledgement on each configure event. - surface_for_popup_ = !with_toplevel; - - zxdg_surface_v6_.reset( - zxdg_shell_v6_get_xdg_surface(connection->shell_v6(), surface)); - if (!zxdg_surface_v6_) { - LOG(ERROR) << "Failed to create zxdg_surface"; - return false; - } - zxdg_surface_v6_add_listener(zxdg_surface_v6_.get(), - &zxdg_surface_v6_listener, this); - // XDGPopupV6 requires a separate surface to be created, so this is just a - // request to get an xdg_surface for it. - if (surface_for_popup_) - return true; - - zxdg_toplevel_v6_.reset(zxdg_surface_v6_get_toplevel(zxdg_surface_v6_.get())); - if (!zxdg_toplevel_v6_) { - LOG(ERROR) << "Failed to create zxdg_toplevel"; - return false; - } - zxdg_toplevel_v6_add_listener(zxdg_toplevel_v6_.get(), - &zxdg_toplevel_v6_listener, this); - wl_surface_commit(surface); - return true; +bool XDGSurfaceWrapperImpl::Initialize(bool with_toplevel) { + if (connection_->shell()) + return InitializeStable(with_toplevel); + else if (connection_->shell_v6()) + return InitializeV6(with_toplevel); + NOTREACHED() << "Wrong shell protocol"; + return false; } void XDGSurfaceWrapperImpl::SetMaximized() { @@ -142,25 +77,25 @@ void XDGSurfaceWrapperImpl::SetMinimized() { void XDGSurfaceWrapperImpl::SurfaceMove(WaylandConnection* connection) { if (xdg_toplevel_) { - xdg_toplevel_move(xdg_toplevel_.get(), connection->seat(), - connection->serial()); + xdg_toplevel_move(xdg_toplevel_.get(), connection_->seat(), + connection_->serial()); } else { DCHECK(zxdg_toplevel_v6_); - zxdg_toplevel_v6_move(zxdg_toplevel_v6_.get(), connection->seat(), - connection->serial()); + zxdg_toplevel_v6_move(zxdg_toplevel_v6_.get(), connection_->seat(), + connection_->serial()); } } void XDGSurfaceWrapperImpl::SurfaceResize(WaylandConnection* connection, uint32_t hittest) { if (xdg_toplevel_) { - xdg_toplevel_resize(xdg_toplevel_.get(), connection->seat(), - connection->serial(), + xdg_toplevel_resize(xdg_toplevel_.get(), connection_->seat(), + connection_->serial(), wl::IdentifyDirection(*connection, hittest)); } else { DCHECK(zxdg_toplevel_v6_); - zxdg_toplevel_v6_resize(zxdg_toplevel_v6_.get(), connection->seat(), - connection->serial(), + zxdg_toplevel_v6_resize(zxdg_toplevel_v6_.get(), connection_->seat(), + connection_->serial(), wl::IdentifyDirection(*connection, hittest)); } } @@ -317,4 +252,84 @@ xdg_surface* XDGSurfaceWrapperImpl::xdg_surface() const { return xdg_surface_.get(); } +bool XDGSurfaceWrapperImpl::InitializeStable(bool with_toplevel) { + static const xdg_surface_listener xdg_surface_listener = { + &XDGSurfaceWrapperImpl::ConfigureStable, + }; + static const xdg_toplevel_listener xdg_toplevel_listener = { + &XDGSurfaceWrapperImpl::ConfigureTopLevelStable, + &XDGSurfaceWrapperImpl::CloseTopLevelStable, + }; + + // if this surface is created for the popup role, mark that it requires + // configuration acknowledgement on each configure event. + surface_for_popup_ = !with_toplevel; + + xdg_surface_.reset(xdg_wm_base_get_xdg_surface(connection_->shell(), + wayland_window_->surface())); + if (!xdg_surface_) { + LOG(ERROR) << "Failed to create xdg_surface"; + return false; + } + xdg_surface_add_listener(xdg_surface_.get(), &xdg_surface_listener, this); + // XDGPopup requires a separate surface to be created, so this is just a + // request to get an xdg_surface for it. + if (surface_for_popup_) { + connection_->ScheduleFlush(); + return true; + } + + xdg_toplevel_.reset(xdg_surface_get_toplevel(xdg_surface_.get())); + if (!xdg_toplevel_) { + LOG(ERROR) << "Failed to create xdg_toplevel"; + return false; + } + xdg_toplevel_add_listener(xdg_toplevel_.get(), &xdg_toplevel_listener, this); + wl_surface_commit(wayland_window_->surface()); + + connection_->ScheduleFlush(); + return true; +} + +bool XDGSurfaceWrapperImpl::InitializeV6(bool with_toplevel) { + static const zxdg_surface_v6_listener zxdg_surface_v6_listener = { + &XDGSurfaceWrapperImpl::ConfigureV6, + }; + static const zxdg_toplevel_v6_listener zxdg_toplevel_v6_listener = { + &XDGSurfaceWrapperImpl::ConfigureTopLevelV6, + &XDGSurfaceWrapperImpl::CloseTopLevelV6, + }; + + // if this surface is created for the popup role, mark that it requires + // configuration acknowledgement on each configure event. + surface_for_popup_ = !with_toplevel; + + zxdg_surface_v6_.reset(zxdg_shell_v6_get_xdg_surface( + connection_->shell_v6(), wayland_window_->surface())); + if (!zxdg_surface_v6_) { + LOG(ERROR) << "Failed to create zxdg_surface"; + return false; + } + zxdg_surface_v6_add_listener(zxdg_surface_v6_.get(), + &zxdg_surface_v6_listener, this); + // XDGPopupV6 requires a separate surface to be created, so this is just a + // request to get an xdg_surface for it. + if (surface_for_popup_) { + connection_->ScheduleFlush(); + return true; + } + + zxdg_toplevel_v6_.reset(zxdg_surface_v6_get_toplevel(zxdg_surface_v6_.get())); + if (!zxdg_toplevel_v6_) { + LOG(ERROR) << "Failed to create zxdg_toplevel"; + return false; + } + zxdg_toplevel_v6_add_listener(zxdg_toplevel_v6_.get(), + &zxdg_toplevel_v6_listener, this); + wl_surface_commit(wayland_window_->surface()); + + connection_->ScheduleFlush(); + return true; +} + } // 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 e14956ebe3e..b34f4b2281e 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,11 +7,10 @@ #include "ui/ozone/platform/wayland/host/shell_surface_wrapper.h" +#include "base/macros.h" #include "base/strings/string16.h" #include "ui/ozone/platform/wayland/common/wayland_object.h" -#include "base/macros.h" - namespace gfx { class Rect; } @@ -24,15 +23,12 @@ class WaylandWindow; // Surface wrapper for xdg-shell stable and xdg-shell-unstable-v6 class XDGSurfaceWrapperImpl : public ShellSurfaceWrapper { public: - XDGSurfaceWrapperImpl(WaylandWindow* wayland_window); + XDGSurfaceWrapperImpl(WaylandWindow* wayland_window, + WaylandConnection* connection); ~XDGSurfaceWrapperImpl() override; - bool InitializeV6(WaylandConnection* connection, - wl_surface* surface, - bool with_toplevel = true); - bool InitializeStable(WaylandConnection* connection, - wl_surface* surface, - bool with_toplevel = true); + // ShellSurfaceWrapper overrides: + bool Initialize(bool with_toplevel) override; void SetMaximized() override; void UnSetMaximized() override; void SetFullscreen() override; @@ -76,8 +72,17 @@ class XDGSurfaceWrapperImpl : public ShellSurfaceWrapper { zxdg_surface_v6* zxdg_surface() const; private: - WaylandWindow* wayland_window_; - uint32_t pending_configure_serial_; + // Initializes using XDG Shell Stable protocol. + bool InitializeStable(bool with_toplevel); + // Initializes using XDG Shell V6 protocol. + bool InitializeV6(bool with_toplevel); + + // Non-owing WaylandWindow that uses this surface wrapper. + WaylandWindow* const wayland_window_; + WaylandConnection* const connection_; + + uint32_t pending_configure_serial_ = 0; + wl::Object<zxdg_surface_v6> zxdg_surface_v6_; wl::Object<zxdg_toplevel_v6> zxdg_toplevel_v6_; wl::Object<struct xdg_surface> xdg_surface_; diff --git a/chromium/ui/ozone/platform/wayland/ozone_platform_wayland.cc b/chromium/ui/ozone/platform/wayland/ozone_platform_wayland.cc index 541d9c4848d..949df2ac040 100644 --- a/chromium/ui/ozone/platform/wayland/ozone_platform_wayland.cc +++ b/chromium/ui/ozone/platform/wayland/ozone_platform_wayland.cc @@ -18,6 +18,7 @@ #include "ui/base/ime/linux/input_method_auralinux.h" #include "ui/events/ozone/layout/keyboard_layout_engine_manager.h" #include "ui/gfx/linux/client_native_pixmap_dmabuf.h" +#include "ui/gfx/native_widget_types.h" #include "ui/ozone/common/stub_overlay_manager.h" #include "ui/ozone/platform/wayland/common/wayland_util.h" #include "ui/ozone/platform/wayland/gpu/drm_render_node_path_finder.h" @@ -46,10 +47,15 @@ #if defined(WAYLAND_GBM) #include "ui/base/ui_base_features.h" -#include "ui/ozone/common/linux/gbm_wrapper.h" +#include "ui/gfx/linux/gbm_wrapper.h" #include "ui/ozone/platform/wayland/gpu/drm_render_node_handle.h" #endif +#if BUILDFLAG(USE_GTK) +#include "ui/gtk/gtk_ui_delegate.h" // nogncheck +#include "ui/ozone/platform/wayland/host/gtk_ui_delegate_wayland.h" //nogncheck +#endif + namespace ui { namespace { @@ -107,10 +113,8 @@ class OzonePlatformWayland : public OzonePlatform { std::unique_ptr<PlatformWindow> CreatePlatformWindow( PlatformWindowDelegate* delegate, PlatformWindowInitProperties properties) override { - auto window = std::make_unique<WaylandWindow>(delegate, connection_.get()); - if (!window->Initialize(std::move(properties))) - return nullptr; - return std::move(window); + return WaylandWindow::Create(delegate, connection_.get(), + std::move(properties)); } std::unique_ptr<display::NativeDisplayDelegate> CreateNativeDisplayDelegate() @@ -132,7 +136,18 @@ class OzonePlatformWayland : public OzonePlatform { } std::unique_ptr<InputMethod> CreateInputMethod( - internal::InputMethodDelegate* delegate) override { + internal::InputMethodDelegate* delegate, + gfx::AcceleratedWidget widget) override { + // Instantiate and set LinuxInputMethodContextFactory unless it is already + // set (e.g: tests may have already set it). + if (!LinuxInputMethodContextFactory::instance() && + !input_method_context_factory_) { + input_method_context_factory_ = + std::make_unique<WaylandInputMethodContextFactory>(connection_.get()); + LinuxInputMethodContextFactory::SetInstance( + input_method_context_factory_.get()); + } + return std::make_unique<InputMethodAuraLinux>(delegate); } @@ -174,16 +189,12 @@ class OzonePlatformWayland : public OzonePlatform { supported_buffer_formats_ = connection_->buffer_manager_host()->GetSupportedBufferFormats(); - - // Instantiate and set LinuxInputMethodContextFactory unless it is already - // set (e.g: tests may have already set it). - if (!LinuxInputMethodContextFactory::instance() && - !input_method_context_factory_) { - input_method_context_factory_ = - std::make_unique<WaylandInputMethodContextFactory>(connection_.get()); - LinuxInputMethodContextFactory::SetInstance( - input_method_context_factory_.get()); - } +#if BUILDFLAG(USE_GTK) + DCHECK(!GtkUiDelegate::instance()); + gtk_ui_delegate_ = + std::make_unique<GtkUiDelegateWayland>(connection_.get()); + GtkUiDelegate::SetInstance(gtk_ui_delegate_.get()); +#endif } void InitializeGPU(const InitParams& args) override { @@ -252,6 +263,10 @@ class OzonePlatformWayland : public OzonePlatform { // render node is available. DrmRenderNodePathFinder path_finder_; +#if BUILDFLAG(USE_GTK) + std::unique_ptr<GtkUiDelegateWayland> gtk_ui_delegate_; +#endif + DISALLOW_COPY_AND_ASSIGN(OzonePlatformWayland); }; diff --git a/chromium/ui/ozone/platform/wayland/test/mock_surface.cc b/chromium/ui/ozone/platform/wayland/test/mock_surface.cc index fa53a037669..20557517f99 100644 --- a/chromium/ui/ozone/platform/wayland/test/mock_surface.cc +++ b/chromium/ui/ozone/platform/wayland/test/mock_surface.cc @@ -108,6 +108,11 @@ void MockSurface::AttachNewBuffer(wl_resource* buffer_resource, Attach(buffer_resource, x, y); } +void MockSurface::DestroyPrevAttachedBuffer() { + DCHECK(prev_attached_buffer_); + prev_attached_buffer_ = nullptr; +} + void MockSurface::ReleasePrevAttachedBuffer() { if (!prev_attached_buffer_) return; diff --git a/chromium/ui/ozone/platform/wayland/test/mock_surface.h b/chromium/ui/ozone/platform/wayland/test/mock_surface.h index 27f7a2c09aa..bbf63e41ea2 100644 --- a/chromium/ui/ozone/platform/wayland/test/mock_surface.h +++ b/chromium/ui/ozone/platform/wayland/test/mock_surface.h @@ -42,15 +42,10 @@ class MockSurface : public ServerObject { MOCK_METHOD4(DamageBuffer, void(int32_t x, int32_t y, int32_t width, int32_t height)); - void set_xdg_surface(std::unique_ptr<MockXdgSurface> xdg_surface) { - xdg_surface_ = std::move(xdg_surface); + void set_xdg_surface(MockXdgSurface* xdg_surface) { + xdg_surface_ = xdg_surface; } - MockXdgSurface* xdg_surface() const { return xdg_surface_.get(); } - - void set_xdg_popup(std::unique_ptr<MockXdgPopup> xdg_popup) { - xdg_popup_ = std::move(xdg_popup); - } - MockXdgPopup* xdg_popup() const { return xdg_popup_.get(); } + MockXdgSurface* xdg_surface() const { return xdg_surface_; } void set_sub_surface(TestSubSurface* sub_surface) { sub_surface_ = sub_surface; @@ -62,17 +57,15 @@ class MockSurface : public ServerObject { frame_callback_ = callback_resource; } - bool has_role() const { - return !!xdg_surface_ || !!xdg_popup_ || !!sub_surface_; - } + bool has_role() const { return !!xdg_surface_ || !!sub_surface_; } void AttachNewBuffer(wl_resource* buffer_resource, int32_t x, int32_t y); + void DestroyPrevAttachedBuffer(); void ReleasePrevAttachedBuffer(); void SendFrameCallback(); private: - std::unique_ptr<MockXdgSurface> xdg_surface_; - std::unique_ptr<MockXdgPopup> xdg_popup_; + MockXdgSurface* xdg_surface_ = nullptr; TestSubSurface* sub_surface_ = nullptr; wl_resource* frame_callback_ = nullptr; diff --git a/chromium/ui/ozone/platform/wayland/test/mock_wp_presentation.h b/chromium/ui/ozone/platform/wayland/test/mock_wp_presentation.h index a1bb344fd5f..616cd6e3fe1 100644 --- a/chromium/ui/ozone/platform/wayland/test/mock_wp_presentation.h +++ b/chromium/ui/ozone/platform/wayland/test/mock_wp_presentation.h @@ -30,7 +30,7 @@ class MockWpPresentation : public GlobalObject { uint32_t callback)); void set_presentation_callback(wl_resource* callback_resource) { - DCHECK(!presentation_callback_); + DCHECK(!presentation_callback_ || callback_resource == nullptr); presentation_callback_ = callback_resource; } diff --git a/chromium/ui/ozone/platform/wayland/test/mock_xdg_popup.cc b/chromium/ui/ozone/platform/wayland/test/mock_xdg_popup.cc index ebf449ca3e5..4a92c79edab 100644 --- a/chromium/ui/ozone/platform/wayland/test/mock_xdg_popup.cc +++ b/chromium/ui/ozone/platform/wayland/test/mock_xdg_popup.cc @@ -4,6 +4,8 @@ #include "ui/ozone/platform/wayland/test/mock_xdg_popup.h" +#include "ui/ozone/platform/wayland/test/mock_xdg_surface.h" + namespace wl { namespace { @@ -27,9 +29,11 @@ const struct zxdg_popup_v6_interface kZxdgPopupV6Impl = { &Grab, // grab }; -MockXdgPopup::MockXdgPopup(wl_resource* resource, const void* implementation) - : ServerObject(resource) { - SetImplementationUnretained(resource, implementation, this); +MockXdgPopup::MockXdgPopup(wl_resource* resource, wl_resource* surface) + : ServerObject(resource), surface_(surface) { + auto* mock_xdg_surface = GetUserDataAs<MockXdgSurface>(surface_); + if (mock_xdg_surface) + mock_xdg_surface->set_xdg_popup(nullptr); } MockXdgPopup::~MockXdgPopup() {} diff --git a/chromium/ui/ozone/platform/wayland/test/mock_xdg_popup.h b/chromium/ui/ozone/platform/wayland/test/mock_xdg_popup.h index 27b02361d89..61a80513020 100644 --- a/chromium/ui/ozone/platform/wayland/test/mock_xdg_popup.h +++ b/chromium/ui/ozone/platform/wayland/test/mock_xdg_popup.h @@ -24,7 +24,7 @@ extern const struct zxdg_popup_v6_interface kZxdgPopupV6Impl; class MockXdgPopup : public ServerObject { public: - MockXdgPopup(wl_resource* resource, const void* implementation); + MockXdgPopup(wl_resource* resource, wl_resource* surface); ~MockXdgPopup() override; MOCK_METHOD1(Grab, void(uint32_t serial)); @@ -42,9 +42,11 @@ class MockXdgPopup : public ServerObject { } private: - // Position of the popup. Used only with V6. struct TestPositioner::PopupPosition position_; + // Ground surface for this popup. + wl_resource* surface_ = nullptr; + DISALLOW_COPY_AND_ASSIGN(MockXdgPopup); }; diff --git a/chromium/ui/ozone/platform/wayland/test/mock_xdg_shell.cc b/chromium/ui/ozone/platform/wayland/test/mock_xdg_shell.cc index 1ba63d43101..cd76626a124 100644 --- a/chromium/ui/ozone/platform/wayland/test/mock_xdg_shell.cc +++ b/chromium/ui/ozone/platform/wayland/test/mock_xdg_shell.cc @@ -29,15 +29,16 @@ void GetXdgSurfaceImpl(wl_client* client, wl_resource_post_error(resource, xdg_error, "surface already has a role"); return; } - wl_resource* xdg_surface_resource = wl_resource_create( - client, interface, wl_resource_get_version(resource), id); + wl_resource* xdg_surface_resource = + CreateResourceWithImpl<::testing::NiceMock<MockXdgSurface>>( + client, interface, wl_resource_get_version(resource), implementation, + id, surface_resource); if (!xdg_surface_resource) { wl_client_post_no_memory(client); return; } - surface->set_xdg_surface( - std::make_unique<MockXdgSurface>(xdg_surface_resource, implementation)); + surface->set_xdg_surface(GetUserDataAs<MockXdgSurface>(xdg_surface_resource)); } void CreatePositioner(wl_client* client, diff --git a/chromium/ui/ozone/platform/wayland/test/mock_xdg_surface.cc b/chromium/ui/ozone/platform/wayland/test/mock_xdg_surface.cc index 35963f84b96..d0bd03add2b 100644 --- a/chromium/ui/ozone/platform/wayland/test/mock_xdg_surface.cc +++ b/chromium/ui/ozone/platform/wayland/test/mock_xdg_surface.cc @@ -4,6 +4,7 @@ #include <xdg-shell-unstable-v6-server-protocol.h> +#include "ui/ozone/platform/wayland/test/mock_surface.h" #include "ui/ozone/platform/wayland/test/mock_xdg_popup.h" #include "ui/ozone/platform/wayland/test/mock_xdg_surface.h" #include "ui/ozone/platform/wayland/test/test_positioner.h" @@ -11,18 +12,26 @@ namespace wl { void SetTitle(wl_client* client, wl_resource* resource, const char* title) { - GetUserDataAs<MockXdgSurface>(resource)->SetTitle(title); + auto* toplevel = GetUserDataAs<MockXdgTopLevel>(resource); + // As it this can be envoked during construction of the XdgSurface, cache the + // result so that tests are able to access that information. + toplevel->set_title(title); + toplevel->SetTitle(toplevel->title()); } void SetAppId(wl_client* client, wl_resource* resource, const char* app_id) { - GetUserDataAs<MockXdgSurface>(resource)->SetAppId(app_id); + auto* toplevel = GetUserDataAs<MockXdgTopLevel>(resource); + toplevel->SetAppId(app_id); + // As it this can be envoked during construction of the XdgSurface, cache the + // result so that tests are able to access that information. + toplevel->set_app_id(app_id); } void Move(wl_client* client, wl_resource* resource, wl_resource* seat, uint32_t serial) { - GetUserDataAs<MockXdgSurface>(resource)->Move(serial); + GetUserDataAs<MockXdgTopLevel>(resource)->Move(serial); } void Resize(wl_client* client, @@ -30,7 +39,7 @@ void Resize(wl_client* client, wl_resource* seat, uint32_t serial, uint32_t edges) { - GetUserDataAs<MockXdgSurface>(resource)->Resize(serial, edges); + GetUserDataAs<MockXdgTopLevel>(resource)->Resize(serial, edges); } void AckConfigure(wl_client* client, wl_resource* resource, uint32_t serial) { @@ -48,25 +57,47 @@ void SetWindowGeometry(wl_client* client, } void SetMaximized(wl_client* client, wl_resource* resource) { - GetUserDataAs<MockXdgSurface>(resource)->SetMaximized(); + GetUserDataAs<MockXdgTopLevel>(resource)->SetMaximized(); } void UnsetMaximized(wl_client* client, wl_resource* resource) { - GetUserDataAs<MockXdgSurface>(resource)->UnsetMaximized(); + GetUserDataAs<MockXdgTopLevel>(resource)->UnsetMaximized(); } void SetFullscreen(wl_client* client, wl_resource* resource, wl_resource* output) { - GetUserDataAs<MockXdgSurface>(resource)->SetFullscreen(); + GetUserDataAs<MockXdgTopLevel>(resource)->SetFullscreen(); } void UnsetFullscreen(wl_client* client, wl_resource* resource) { - GetUserDataAs<MockXdgSurface>(resource)->UnsetFullscreen(); + GetUserDataAs<MockXdgTopLevel>(resource)->UnsetFullscreen(); } void SetMinimized(wl_client* client, wl_resource* resource) { - GetUserDataAs<MockXdgSurface>(resource)->SetMinimized(); + GetUserDataAs<MockXdgTopLevel>(resource)->SetMinimized(); +} + +void SetMaxSize(wl_client* client, + wl_resource* resource, + int32_t width, + int32_t height) { + auto* toplevel = GetUserDataAs<MockXdgTopLevel>(resource); + toplevel->SetMaxSize(width, height); + // As it this can be envoked during construction of the XdgSurface, cache the + // result so that tests are able to access that information. + toplevel->set_max_size(gfx::Size(width, height)); +} + +void SetMinSize(wl_client* client, + wl_resource* resource, + int32_t width, + int32_t height) { + auto* toplevel = GetUserDataAs<MockXdgTopLevel>(resource); + toplevel->SetMinSize(width, height); + // As it this can be envoked during construction of the XdgSurface, cache the + // result so that tests are able to access that information. + toplevel->set_min_size(gfx::Size(width, height)); } void GetTopLevel(wl_client* client, wl_resource* resource, uint32_t id) { @@ -120,13 +151,22 @@ void GetXdgPopup(struct wl_client* client, return; } - wl_resource* xdg_popup_resource = wl_resource_create( - client, &xdg_popup_interface, wl_resource_get_version(resource), id); + wl_resource* xdg_popup_resource = + CreateResourceWithImpl<::testing::NiceMock<MockXdgPopup>>( + client, &xdg_popup_interface, wl_resource_get_version(resource), + &kXdgPopupImpl, id, resource); + + if (!xdg_popup_resource) { + wl_client_post_no_memory(client); + return; + } + + auto* mock_xdg_popup = GetUserDataAs<MockXdgPopup>(xdg_popup_resource); + DCHECK(mock_xdg_popup); + auto* positioner = GetUserDataAs<TestPositioner>(positioner_resource); DCHECK(positioner); - auto mock_xdg_popup = - std::make_unique<MockXdgPopup>(xdg_popup_resource, &kXdgPopupImpl); mock_xdg_popup->set_position(positioner->position()); if (mock_xdg_popup->size().IsEmpty() || mock_xdg_popup->anchor_rect().IsEmpty()) { @@ -135,7 +175,7 @@ void GetXdgPopup(struct wl_client* client, return; } - mock_xdg_surface->set_xdg_popup(std::move(mock_xdg_popup)); + mock_xdg_surface->set_xdg_popup(mock_xdg_popup); } void GetZXdgPopupV6(struct wl_client* client, @@ -156,13 +196,22 @@ void GetZXdgPopupV6(struct wl_client* client, return; } - wl_resource* xdg_popup_resource = wl_resource_create( - client, &zxdg_popup_v6_interface, wl_resource_get_version(resource), id); + wl_resource* xdg_popup_resource = + CreateResourceWithImpl<::testing::NiceMock<MockXdgPopup>>( + client, &zxdg_popup_v6_interface, wl_resource_get_version(resource), + &kZxdgPopupV6Impl, id, resource); + + if (!xdg_popup_resource) { + wl_client_post_no_memory(client); + return; + } + + auto* mock_xdg_popup = GetUserDataAs<MockXdgPopup>(xdg_popup_resource); + DCHECK(mock_xdg_popup); + auto* positioner = GetUserDataAs<TestPositioner>(positioner_resource); DCHECK(positioner); - auto mock_xdg_popup = - std::make_unique<MockXdgPopup>(xdg_popup_resource, &kZxdgPopupV6Impl); mock_xdg_popup->set_position(positioner->position()); if (mock_xdg_popup->size().IsEmpty() || mock_xdg_popup->anchor_rect().IsEmpty()) { @@ -171,21 +220,7 @@ void GetZXdgPopupV6(struct wl_client* client, return; } - mock_xdg_surface->set_xdg_popup(std::move(mock_xdg_popup)); -} - -void SetMaxSize(wl_client* client, - wl_resource* resource, - int32_t width, - int32_t height) { - GetUserDataAs<MockXdgSurface>(resource)->SetMaxSize(width, height); -} - -void SetMinSize(wl_client* client, - wl_resource* resource, - int32_t width, - int32_t height) { - GetUserDataAs<MockXdgSurface>(resource)->SetMinSize(width, height); + mock_xdg_surface->set_xdg_popup(mock_xdg_popup); } const struct xdg_surface_interface kMockXdgSurfaceImpl = { @@ -238,17 +273,18 @@ const struct zxdg_toplevel_v6_interface kMockZxdgToplevelV6Impl = { &SetMinimized, // set_minimized }; -MockXdgSurface::MockXdgSurface(wl_resource* resource, - const void* implementation) - : ServerObject(resource) { - SetImplementationUnretained(resource, implementation, this); -} +MockXdgSurface::MockXdgSurface(wl_resource* resource, wl_resource* surface) + : ServerObject(resource), surface_(surface) {} -MockXdgSurface::~MockXdgSurface() {} +MockXdgSurface::~MockXdgSurface() { + auto* mock_surface = GetUserDataAs<MockSurface>(surface_); + if (mock_surface) + mock_surface->set_xdg_surface(nullptr); +} MockXdgTopLevel::MockXdgTopLevel(wl_resource* resource, const void* implementation) - : MockXdgSurface(resource, implementation) { + : ServerObject(resource) { SetImplementationUnretained(resource, implementation, this); } diff --git a/chromium/ui/ozone/platform/wayland/test/mock_xdg_surface.h b/chromium/ui/ozone/platform/wayland/test/mock_xdg_surface.h index 20e0f96bdfc..c41a6ed8fa3 100644 --- a/chromium/ui/ozone/platform/wayland/test/mock_xdg_surface.h +++ b/chromium/ui/ozone/platform/wayland/test/mock_xdg_surface.h @@ -30,60 +30,71 @@ class MockXdgTopLevel; // UI. class MockXdgSurface : public ServerObject { public: - MockXdgSurface(wl_resource* resource, const void* implementation); + MockXdgSurface(wl_resource* resource, wl_resource* surface); ~MockXdgSurface() override; - // These mock methods are shared between xdg_surface and zxdg_toplevel - // surface. - MOCK_METHOD1(SetParent, void(wl_resource* parent)); - MOCK_METHOD1(SetTitle, void(const char* title)); - MOCK_METHOD1(SetAppId, void(const char* app_id)); - MOCK_METHOD1(Move, void(uint32_t serial)); - MOCK_METHOD2(Resize, void(uint32_t serial, uint32_t edges)); MOCK_METHOD1(AckConfigure, void(uint32_t serial)); MOCK_METHOD4(SetWindowGeometry, void(int32_t x, int32_t y, int32_t width, int32_t height)); - MOCK_METHOD0(SetMaximized, void()); - MOCK_METHOD0(UnsetMaximized, void()); - MOCK_METHOD0(SetFullscreen, void()); - MOCK_METHOD0(UnsetFullscreen, void()); - MOCK_METHOD0(SetMinimized, void()); - - // These methods are for zxdg_toplevel only. - MOCK_METHOD2(SetMaxSize, void(int32_t width, int32_t height)); - MOCK_METHOD2(SetMinSize, void(int32_t width, int32_t height)); void set_xdg_toplevel(std::unique_ptr<MockXdgTopLevel> xdg_toplevel) { xdg_toplevel_ = std::move(xdg_toplevel); } MockXdgTopLevel* xdg_toplevel() const { return xdg_toplevel_.get(); } - void set_xdg_popup(std::unique_ptr<MockXdgPopup> xdg_popup) { - xdg_popup_ = std::move(xdg_popup); - } - MockXdgPopup* xdg_popup() const { return xdg_popup_.get(); } + void set_xdg_popup(MockXdgPopup* xdg_popup) { xdg_popup_ = xdg_popup; } + MockXdgPopup* xdg_popup() const { return xdg_popup_; } private: - // Used when xdg v6 is used. + // Has either toplevel role.. std::unique_ptr<MockXdgTopLevel> xdg_toplevel_; + // Or popup role. + MockXdgPopup* xdg_popup_ = nullptr; - std::unique_ptr<MockXdgPopup> xdg_popup_; + // MockSurface that is the ground for this xdg_surface. + wl_resource* surface_ = nullptr; DISALLOW_COPY_AND_ASSIGN(MockXdgSurface); }; // Manage zxdg_toplevel for providing desktop UI. -class MockXdgTopLevel : public MockXdgSurface { +class MockXdgTopLevel : public ServerObject { public: - explicit MockXdgTopLevel(wl_resource* resource, const void* implementation); + MockXdgTopLevel(wl_resource* resource, const void* implementation); ~MockXdgTopLevel() override; - // TODO(msisov): mock other zxdg_toplevel specific methods once - // implementation - // is done. example: MOCK_METHOD2(SetMaxSize, void(int32_t width, int32_t - // height()); + MOCK_METHOD1(SetParent, void(wl_resource* parent)); + MOCK_METHOD1(SetTitle, void(const std::string& title)); + MOCK_METHOD1(SetAppId, void(const char* app_id)); + MOCK_METHOD1(Move, void(uint32_t serial)); + MOCK_METHOD2(Resize, void(uint32_t serial, uint32_t edges)); + MOCK_METHOD0(SetMaximized, void()); + MOCK_METHOD0(UnsetMaximized, void()); + MOCK_METHOD0(SetFullscreen, void()); + MOCK_METHOD0(UnsetFullscreen, void()); + MOCK_METHOD0(SetMinimized, void()); + MOCK_METHOD2(SetMaxSize, void(int32_t width, int32_t height)); + MOCK_METHOD2(SetMinSize, void(int32_t width, int32_t height)); + + const std::string& app_id() const { return app_id_; } + void set_app_id(const char* app_id) { app_id_ = std::string(app_id); } + + std::string title() const { return title_; } + void set_title(const char* title) { title_ = std::string(title); } + + const gfx::Size& min_size() const { return min_size_; } + void set_min_size(const gfx::Size& min_size) { min_size_ = min_size; } + + const gfx::Size& max_size() const { return max_size_; } + void set_max_size(const gfx::Size& max_size) { max_size_ = max_size; } private: + gfx::Size min_size_; + gfx::Size max_size_; + + std::string title_; + std::string app_id_; + DISALLOW_COPY_AND_ASSIGN(MockXdgTopLevel); }; diff --git a/chromium/ui/ozone/platform/wayland/test/test_data_offer.cc b/chromium/ui/ozone/platform/wayland/test/test_data_offer.cc index 456945f314c..b830dada81e 100644 --- a/chromium/ui/ozone/platform/wayland/test/test_data_offer.cc +++ b/chromium/ui/ozone/platform/wayland/test/test_data_offer.cc @@ -13,6 +13,7 @@ #include "base/sequenced_task_runner.h" #include "base/task/post_task.h" #include "base/task/task_traits.h" +#include "base/task/thread_pool.h" #include "ui/ozone/platform/wayland/test/constants.h" namespace wl { @@ -65,8 +66,8 @@ const struct wl_data_offer_interface kTestDataOfferImpl = { TestDataOffer::TestDataOffer(wl_resource* resource) : ServerObject(resource), - task_runner_(base::CreateSequencedTaskRunner( - {base::ThreadPool(), base::MayBlock()})), + task_runner_( + base::ThreadPool::CreateSequencedTaskRunner({base::MayBlock()})), write_data_weak_ptr_factory_(this) {} TestDataOffer::~TestDataOffer() {} diff --git a/chromium/ui/ozone/platform/wayland/test/test_data_source.cc b/chromium/ui/ozone/platform/wayland/test/test_data_source.cc index 6757ff33750..530a2e443c7 100644 --- a/chromium/ui/ozone/platform/wayland/test/test_data_source.cc +++ b/chromium/ui/ozone/platform/wayland/test/test_data_source.cc @@ -14,6 +14,7 @@ #include "base/sequenced_task_runner.h" #include "base/task/post_task.h" #include "base/task/task_traits.h" +#include "base/task/thread_pool.h" #include "base/task_runner_util.h" #include "ui/ozone/platform/wayland/test/constants.h" @@ -63,8 +64,8 @@ const struct wl_data_source_interface kTestDataSourceImpl = { TestDataSource::TestDataSource(wl_resource* resource) : ServerObject(resource), - task_runner_(base::CreateSequencedTaskRunner( - {base::ThreadPool(), base::MayBlock()})) {} + task_runner_( + base::ThreadPool::CreateSequencedTaskRunner({base::MayBlock()})) {} TestDataSource::~TestDataSource() {} diff --git a/chromium/ui/ozone/platform/wayland/test/test_subcompositor.cc b/chromium/ui/ozone/platform/wayland/test/test_subcompositor.cc index 7d78fdf7e14..cbb66349ada 100644 --- a/chromium/ui/ozone/platform/wayland/test/test_subcompositor.cc +++ b/chromium/ui/ozone/platform/wayland/test/test_subcompositor.cc @@ -33,7 +33,7 @@ void GetSubsurface(struct wl_client* client, wl_resource* subsurface_resource = CreateResourceWithImpl<::testing::NiceMock<TestSubSurface>>( client, &wl_subsurface_interface, wl_resource_get_version(resource), - &kTestSubSurfaceImpl, id); + &kTestSubSurfaceImpl, id, surface, parent); DCHECK(subsurface_resource); mock_surface->set_sub_surface( GetUserDataAs<TestSubSurface>(subsurface_resource)); diff --git a/chromium/ui/ozone/platform/wayland/test/test_subsurface.cc b/chromium/ui/ozone/platform/wayland/test/test_subsurface.cc index 7d569eab43e..1609bb2012a 100644 --- a/chromium/ui/ozone/platform/wayland/test/test_subsurface.cc +++ b/chromium/ui/ozone/platform/wayland/test/test_subsurface.cc @@ -43,10 +43,20 @@ const struct wl_subsurface_interface kTestSubSurfaceImpl = { DestroyResource, SetPosition, PlaceAbove, PlaceBelow, SetSync, SetDesync, }; -TestSubSurface::TestSubSurface(wl_resource* resource) - : ServerObject(resource) {} +TestSubSurface::TestSubSurface(wl_resource* resource, + wl_resource* surface, + wl_resource* parent_resource) + : ServerObject(resource), + surface_(surface), + parent_resource_(parent_resource) { + DCHECK(surface_); +} -TestSubSurface::~TestSubSurface() = default; +TestSubSurface::~TestSubSurface() { + auto* mock_surface = GetUserDataAs<MockSurface>(surface_); + if (mock_surface) + mock_surface->set_sub_surface(nullptr); +} void TestSubSurface::SetPosition(int x, int y) { position_ = gfx::Point(x, y); diff --git a/chromium/ui/ozone/platform/wayland/test/test_subsurface.h b/chromium/ui/ozone/platform/wayland/test/test_subsurface.h index 4f984a5eccd..abf806500ca 100644 --- a/chromium/ui/ozone/platform/wayland/test/test_subsurface.h +++ b/chromium/ui/ozone/platform/wayland/test/test_subsurface.h @@ -22,7 +22,9 @@ extern const struct wl_subsurface_interface kTestSubSurfaceImpl; class TestSubSurface : public ServerObject { public: - explicit TestSubSurface(wl_resource* resource); + explicit TestSubSurface(wl_resource* resource, + wl_resource* surface, + wl_resource* parent_resource); ~TestSubSurface() override; TestSubSurface(const TestSubSurface& rhs) = delete; TestSubSurface& operator=(const TestSubSurface& rhs) = delete; @@ -33,9 +35,17 @@ class TestSubSurface : public ServerObject { void set_sync(bool sync) { sync_ = sync; } bool sync() const { return sync_; } + wl_resource* parent_resource() const { return parent_resource_; } + private: gfx::Point position_; bool sync_ = false; + + // Surface resource that is the ground for this subsurface. + wl_resource* surface_ = nullptr; + + // Parent surface resource. + wl_resource* parent_resource_ = nullptr; }; } // namespace wl diff --git a/chromium/ui/ozone/platform/wayland/test/wayland_test.cc b/chromium/ui/ozone/platform/wayland/test/wayland_test.cc index 2bd8c38219c..2866ab6a07f 100644 --- a/chromium/ui/ozone/platform/wayland/test/wayland_test.cc +++ b/chromium/ui/ozone/platform/wayland/test/wayland_test.cc @@ -37,7 +37,6 @@ WaylandTest::WaylandTest() buffer_manager_gpu_ = std::make_unique<WaylandBufferManagerGpu>(); surface_factory_ = std::make_unique<WaylandSurfaceFactory>( connection_.get(), buffer_manager_gpu_.get()); - window_ = std::make_unique<WaylandWindow>(&delegate_, connection_.get()); } WaylandTest::~WaylandTest() {} @@ -52,9 +51,12 @@ void WaylandTest::SetUp() { PlatformWindowInitProperties properties; properties.bounds = gfx::Rect(0, 0, 800, 600); properties.type = PlatformWindowType::kWindow; - ASSERT_TRUE(window_->Initialize(std::move(properties))); + window_ = WaylandWindow::Create(&delegate_, connection_.get(), + std::move(properties)); ASSERT_NE(widget_, gfx::kNullAcceleratedWidget); + window_->Show(false); + // Wait for the client to flush all pending requests from initialization. base::RunLoop().RunUntilIdle(); diff --git a/chromium/ui/ozone/platform/wayland/wayland.gni b/chromium/ui/ozone/platform/wayland/wayland.gni index 8cfdc4cc1cb..e9200e6daa8 100644 --- a/chromium/ui/ozone/platform/wayland/wayland.gni +++ b/chromium/ui/ozone/platform/wayland/wayland.gni @@ -9,4 +9,7 @@ declare_args() { # Checks if Wayland must be compiled with dmabuf/gbm feature, which allows a # multi-process hardware accelerated mode. use_wayland_gbm = true + + # Checks if Weston must be compiled + use_bundled_weston = false } diff --git a/chromium/ui/ozone/platform/wayland/wayland_buffer_manager_unittest.cc b/chromium/ui/ozone/platform/wayland/wayland_buffer_manager_unittest.cc index 21b0c3eefd9..de10370fe69 100644 --- a/chromium/ui/ozone/platform/wayland/wayland_buffer_manager_unittest.cc +++ b/chromium/ui/ozone/platform/wayland/wayland_buffer_manager_unittest.cc @@ -14,7 +14,7 @@ #include "mojo/public/cpp/system/platform_handle.h" #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" -#include "ui/ozone/common/linux/drm_util_linux.h" +#include "ui/gfx/linux/drm_util_linux.h" #include "ui/ozone/platform/wayland/gpu/wayland_surface_gpu.h" #include "ui/ozone/platform/wayland/host/wayland_connection.h" #include "ui/ozone/platform/wayland/host/wayland_zwp_linux_dmabuf.h" @@ -189,12 +189,12 @@ class WaylandBufferManagerTest : public WaylandTest { std::unique_ptr<WaylandWindow> CreateWindow() { testing::Mock::VerifyAndClearExpectations(&delegate_); - auto new_window = - std::make_unique<WaylandWindow>(&delegate_, connection_.get()); PlatformWindowInitProperties properties; properties.bounds = gfx::Rect(0, 0, 800, 600); properties.type = PlatformWindowType::kWindow; - EXPECT_TRUE(new_window->Initialize(std::move(properties))); + auto new_window = WaylandWindow::Create(&delegate_, connection_.get(), + std::move(properties)); + EXPECT_TRUE(new_window); Sync(); @@ -537,6 +537,121 @@ TEST_P(WaylandBufferManagerTest, EnsureCorrectOrderOfCallbacks) { DestroyBufferAndSetTerminateExpectation(widget, kBufferId2, false /*fail*/); } +TEST_P(WaylandBufferManagerTest, + DestroyedBuffersGeneratePresentationFeedbackFailure) { + constexpr uint32_t kBufferId1 = 1; + constexpr uint32_t kBufferId2 = 2; + constexpr uint32_t kBufferId3 = 3; + + const gfx::AcceleratedWidget widget = window_->GetWidget(); + const gfx::Rect bounds = gfx::Rect({0, 0}, kDefaultSize); + window_->SetBounds(bounds); + + MockSurfaceGpu mock_surface_gpu(buffer_manager_gpu_.get(), widget_); + + auto* linux_dmabuf = server_.zwp_linux_dmabuf_v1(); + EXPECT_CALL(*linux_dmabuf, CreateParams(_, _, _)).Times(3); + CreateDmabufBasedBufferAndSetTerminateExpecation(false /*fail*/, kBufferId1); + CreateDmabufBasedBufferAndSetTerminateExpecation(false /*fail*/, kBufferId2); + CreateDmabufBasedBufferAndSetTerminateExpecation(false /*fail*/, kBufferId3); + + Sync(); + + ProcessCreatedBufferResourcesWithExpectation(3u /* expected size */, + false /* fail */); + + auto* mock_surface = server_.GetObject<wl::MockSurface>(widget); + auto* mock_wp_presentation = server_.EnsureWpPresentation(); + ASSERT_TRUE(mock_wp_presentation); + + constexpr uint32_t kNumberOfCommits = 3; + EXPECT_CALL(*mock_surface, Attach(_, _, _)).Times(kNumberOfCommits); + EXPECT_CALL(*mock_surface, Frame(_)).Times(kNumberOfCommits); + EXPECT_CALL(*mock_surface, Commit()).Times(kNumberOfCommits); + EXPECT_CALL(*mock_wp_presentation, + Feedback(_, _, mock_surface->resource(), _)) + .Times(3); + + Sync(); + + ::testing::InSequence s; + + // wp_presentation_feedback should work now. + ASSERT_TRUE(connection_->presentation()); + + // Commit the first buffer and expect OnSubmission immediately. + EXPECT_CALL(mock_surface_gpu, OnPresentation(_, _)).Times(0); + EXPECT_CALL(mock_surface_gpu, + OnSubmission(kBufferId1, gfx::SwapResult::SWAP_ACK)) + .Times(1); + buffer_manager_gpu_->CommitBuffer(widget, kBufferId1, bounds); + mock_surface->SendFrameCallback(); + Sync(); + + // Deliberately drop the presentation feedback for the first buffer, + // since we will destroy it. + mock_wp_presentation->set_presentation_callback(nullptr); + + // Commit second buffer now. + buffer_manager_gpu_->CommitBuffer(widget, kBufferId2, bounds); + mock_surface->SendFrameCallback(); + Sync(); + + // Destroy the first buffer, which should trigger submission for the second + // buffer. + EXPECT_CALL(mock_surface_gpu, + OnSubmission(kBufferId2, gfx::SwapResult::SWAP_ACK)) + .Times(1); + DestroyBufferAndSetTerminateExpectation(widget, kBufferId1, /*fail=*/false); + mock_surface->DestroyPrevAttachedBuffer(); + mock_surface->SendFrameCallback(); + Sync(); + + // Deliberately drop the presentation feedback for the second buffer, + // since we will destroy it. + mock_wp_presentation->set_presentation_callback(nullptr); + + // Commit buffer 3 then send the presentation callback for it. This should + // not call OnPresentation as OnSubmission hasn't been called yet. + EXPECT_CALL(mock_surface_gpu, OnPresentation(_, _)).Times(0); + buffer_manager_gpu_->CommitBuffer(widget, kBufferId3, bounds); + mock_surface->SendFrameCallback(); + mock_wp_presentation->SendPresentationCallback(); + Sync(); + + // Destroy buffer 2, which should trigger OnSubmission for buffer 3, and + // OnPresentation for buffer 1, 2, and 3. + EXPECT_CALL(mock_surface_gpu, + OnSubmission(kBufferId3, gfx::SwapResult::SWAP_ACK)) + .Times(1); + EXPECT_CALL( + mock_surface_gpu, + OnPresentation( + kBufferId1, + ::testing::Field( + &gfx::PresentationFeedback::flags, + ::testing::Eq(gfx::PresentationFeedback::Flags::kFailure)))) + .Times(1); + EXPECT_CALL( + mock_surface_gpu, + OnPresentation( + kBufferId2, + ::testing::Field( + &gfx::PresentationFeedback::flags, + ::testing::Eq(gfx::PresentationFeedback::Flags::kFailure)))) + .Times(1); + EXPECT_CALL(mock_surface_gpu, OnPresentation(kBufferId3, _)).Times(1); + DestroyBufferAndSetTerminateExpectation(widget, kBufferId2, /*fail=*/false); + mock_surface->DestroyPrevAttachedBuffer(); + mock_surface->SendFrameCallback(); + mock_wp_presentation->SendPresentationCallback(); + Sync(); + + DestroyBufferAndSetTerminateExpectation(widget, kBufferId3, false /*fail*/); +} + +TEST_P(WaylandBufferManagerTest, MultiplePendingPresentationsForSameBuffer) {} + TEST_P(WaylandBufferManagerTest, TestCommitBufferConditions) { constexpr uint32_t kDmabufBufferId = 1; constexpr uint32_t kDmabufBufferId2 = 2; @@ -837,6 +952,166 @@ TEST_P(WaylandBufferManagerTest, DestroyedWindowNoSubmissionMultipleBuffers) { DestroyBufferAndSetTerminateExpectation(widget, kBufferId2, false /*fail*/); } +// This test verifies that submitting the buffer more than once results in +// OnSubmission callback as Wayland compositor is not supposed to release the +// buffer committed twice. +TEST_P(WaylandBufferManagerTest, SubmitSameBufferMultipleTimes) { + constexpr uint32_t kBufferId1 = 1; + constexpr uint32_t kBufferId2 = 2; + + const gfx::AcceleratedWidget widget = window_->GetWidget(); + const gfx::Rect bounds = window_->GetBounds(); + + MockSurfaceGpu mock_surface_gpu(buffer_manager_gpu_.get(), widget); + + auto* linux_dmabuf = server_.zwp_linux_dmabuf_v1(); + EXPECT_CALL(*linux_dmabuf, CreateParams(_, _, _)).Times(2); + CreateDmabufBasedBufferAndSetTerminateExpecation(false /*fail*/, kBufferId1); + CreateDmabufBasedBufferAndSetTerminateExpecation(false /*fail*/, kBufferId2); + + Sync(); + + ProcessCreatedBufferResourcesWithExpectation(2u /* expected size */, + false /* fail */); + + EXPECT_CALL(mock_surface_gpu, + OnSubmission(kBufferId1, gfx::SwapResult::SWAP_ACK)) + .Times(1); + ASSERT_TRUE(!connection_->presentation()); + EXPECT_CALL(mock_surface_gpu, OnPresentation(kBufferId1, _)).Times(1); + auto* mock_surface = server_.GetObject<wl::MockSurface>(widget); + EXPECT_CALL(*mock_surface, Attach(_, _, _)).Times(1); + EXPECT_CALL(*mock_surface, Frame(_)).Times(1); + EXPECT_CALL(*mock_surface, + DamageBuffer(0, 0, bounds.width(), bounds.height())) + .Times(1); + EXPECT_CALL(*mock_surface, Commit()).Times(1); + + buffer_manager_gpu_->CommitBuffer(widget, kBufferId1, bounds); + + Sync(); + + testing::Mock::VerifyAndClearExpectations(&mock_surface_gpu); + testing::Mock::VerifyAndClearExpectations(mock_surface); + + EXPECT_CALL(mock_surface_gpu, OnSubmission(_, _)).Times(0); + EXPECT_CALL(mock_surface_gpu, OnPresentation(_, _)).Times(0); + + mock_surface->SendFrameCallback(); + + Sync(); + + EXPECT_CALL(*mock_surface, Attach(_, _, _)).Times(1); + EXPECT_CALL(*mock_surface, Frame(_)).Times(1); + EXPECT_CALL(*mock_surface, + DamageBuffer(0, 0, bounds.width(), bounds.height())) + .Times(1); + EXPECT_CALL(*mock_surface, Commit()).Times(1); + + // Commit second buffer now. + buffer_manager_gpu_->CommitBuffer(widget, kBufferId2, bounds); + + Sync(); + + testing::Mock::VerifyAndClearExpectations(&mock_surface_gpu); + testing::Mock::VerifyAndClearExpectations(mock_surface); + + EXPECT_CALL(mock_surface_gpu, + OnSubmission(kBufferId2, gfx::SwapResult::SWAP_ACK)) + .Times(1); + EXPECT_CALL(mock_surface_gpu, OnPresentation(kBufferId2, _)).Times(1); + + EXPECT_CALL(*mock_surface, Attach(_, _, _)).Times(0); + EXPECT_CALL(*mock_surface, Frame(_)).Times(0); + EXPECT_CALL(*mock_surface, DamageBuffer(_, _, _, _)).Times(0); + EXPECT_CALL(*mock_surface, Commit()).Times(0); + + mock_surface->ReleasePrevAttachedBuffer(); + mock_surface->SendFrameCallback(); + + Sync(); + + testing::Mock::VerifyAndClearExpectations(&mock_surface_gpu); + testing::Mock::VerifyAndClearExpectations(mock_surface); + + // Now, commit the buffer with the |kBufferId2| again and make sure the + // manager manually sends the submission callback as long as the compositor is + // not going to release a buffer as it was the same buffer submitted more than + // once. + EXPECT_CALL(mock_surface_gpu, + OnSubmission(kBufferId2, gfx::SwapResult::SWAP_ACK)) + .Times(1); + EXPECT_CALL(mock_surface_gpu, OnPresentation(kBufferId2, _)).Times(1); + + EXPECT_CALL(*mock_surface, Attach(_, _, _)).Times(0); + EXPECT_CALL(*mock_surface, Frame(_)).Times(1); + EXPECT_CALL(*mock_surface, + DamageBuffer(0, 0, bounds.width(), bounds.height())) + .Times(1); + EXPECT_CALL(*mock_surface, Commit()).Times(1); + + // Commit second buffer now. + buffer_manager_gpu_->CommitBuffer(widget, kBufferId2, bounds); + + Sync(); + + testing::Mock::VerifyAndClearExpectations(&mock_surface_gpu); + testing::Mock::VerifyAndClearExpectations(mock_surface); + + EXPECT_CALL(mock_surface_gpu, OnSubmission(_, _)).Times(0); + EXPECT_CALL(mock_surface_gpu, OnPresentation(_, _)).Times(0); + + EXPECT_CALL(*mock_surface, Attach(_, _, _)).Times(0); + EXPECT_CALL(*mock_surface, Frame(_)).Times(0); + EXPECT_CALL(*mock_surface, DamageBuffer(_, _, _, _)).Times(0); + EXPECT_CALL(*mock_surface, Commit()).Times(0); + + // It must be ok if Wayland compositor decides to release the buffer at some + // point. + mock_surface->ReleasePrevAttachedBuffer(); + mock_surface->SendFrameCallback(); + + Sync(); + + testing::Mock::VerifyAndClearExpectations(&mock_surface_gpu); + testing::Mock::VerifyAndClearExpectations(mock_surface); + + // If we commit another buffer now, the manager host must not automatically + // trigger OnSubmission and OnPresentation callbacks. + EXPECT_CALL(mock_surface_gpu, OnSubmission(_, _)).Times(0); + EXPECT_CALL(mock_surface_gpu, OnPresentation(_, _)).Times(0); + + EXPECT_CALL(*mock_surface, Attach(_, _, _)).Times(1); + EXPECT_CALL(*mock_surface, Frame(_)).Times(1); + EXPECT_CALL(*mock_surface, + DamageBuffer(0, 0, bounds.width(), bounds.height())) + .Times(1); + EXPECT_CALL(*mock_surface, Commit()).Times(1); + + buffer_manager_gpu_->CommitBuffer(widget, kBufferId1, bounds); + + Sync(); + + testing::Mock::VerifyAndClearExpectations(&mock_surface_gpu); + testing::Mock::VerifyAndClearExpectations(mock_surface); + + // Now, they must be triggered once the buffer is released. + EXPECT_CALL(mock_surface_gpu, + OnSubmission(kBufferId1, gfx::SwapResult::SWAP_ACK)) + .Times(1); + EXPECT_CALL(mock_surface_gpu, OnPresentation(kBufferId1, _)).Times(1); + + mock_surface->ReleasePrevAttachedBuffer(); + mock_surface->SendFrameCallback(); + + Sync(); + + testing::Mock::VerifyAndClearExpectations(&mock_surface_gpu); + + DestroyBufferAndSetTerminateExpectation(widget, kBufferId1, false /*fail*/); + DestroyBufferAndSetTerminateExpectation(widget, kBufferId2, false /*fail*/); +} + INSTANTIATE_TEST_SUITE_P(XdgVersionStableTest, WaylandBufferManagerTest, ::testing::Values(kXdgShellStable)); diff --git a/chromium/ui/ozone/platform/windows/ozone_platform_windows.cc b/chromium/ui/ozone/platform/windows/ozone_platform_windows.cc index 5f3f010241d..d6dee8a511c 100644 --- a/chromium/ui/ozone/platform/windows/ozone_platform_windows.cc +++ b/chromium/ui/ozone/platform/windows/ozone_platform_windows.cc @@ -15,6 +15,7 @@ #include "ui/events/ozone/layout/keyboard_layout_engine_manager.h" #include "ui/events/ozone/layout/stub/stub_keyboard_layout_engine.h" #include "ui/events/platform/platform_event_source.h" +#include "ui/gfx/native_widget_types.h" #include "ui/ozone/common/stub_overlay_manager.h" #include "ui/ozone/platform/windows/windows_surface_factory.h" #include "ui/ozone/platform/windows/windows_window.h" @@ -77,7 +78,8 @@ class OzonePlatformWindows : public OzonePlatform { return std::make_unique<display::FakeDisplayDelegate>(); } std::unique_ptr<InputMethod> CreateInputMethod( - internal::InputMethodDelegate* delegate) override { + internal::InputMethodDelegate* delegate, + gfx::AcceleratedWidget) override { NOTREACHED(); return nullptr; } diff --git a/chromium/ui/ozone/platform/windows/windows_surface_factory.cc b/chromium/ui/ozone/platform/windows/windows_surface_factory.cc index 11700e93a2d..83b51fb2dba 100644 --- a/chromium/ui/ozone/platform/windows/windows_surface_factory.cc +++ b/chromium/ui/ozone/platform/windows/windows_surface_factory.cc @@ -46,8 +46,8 @@ class GLOzoneEGLWindows : public GLOzoneEGL { protected: // GLOzoneEGL: - HDC GetNativeDisplay() override { - return GetWindowDC(nullptr); + gl::EGLDisplayPlatform GetNativeDisplay() override { + return gl::EGLDisplayPlatform(GetWindowDC(nullptr)); } bool LoadGLES2Bindings(gl::GLImplementation implementation) override { diff --git a/chromium/ui/ozone/platform/x11/BUILD.gn b/chromium/ui/ozone/platform/x11/BUILD.gn index daf322b4893..f1941921e42 100644 --- a/chromium/ui/ozone/platform/x11/BUILD.gn +++ b/chromium/ui/ozone/platform/x11/BUILD.gn @@ -2,7 +2,9 @@ # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. +import("//build/config/linux/gtk/gtk.gni") import("//gpu/vulkan/features.gni") +import("//ui/base/ui_features.gni") visibility = [ "//ui/ozone/*" ] @@ -36,11 +38,15 @@ source_set("x11") { "x11_window_ozone.h", ] + public_deps = [ "//ui/base/mojom:cursor_type" ] + deps = [ "//base", + "//build:chromecast_buildflags", "//gpu/vulkan:buildflags", "//skia", - "//ui/base", + "//ui/base:base", + "//ui/base:buildflags", "//ui/base/clipboard:clipboard_types", "//ui/base/ime", "//ui/base/x", @@ -73,6 +79,14 @@ source_set("x11") { deps += [ "//gpu/vulkan/x" ] } + if (use_gtk) { + deps += [ "//ui/gtk:x" ] + } + + if (use_xkbcommon) { + configs += [ "//ui/events/ozone/layout:xkbcommon" ] + } + configs += [ "//build/config/linux:x11", "//build/config/linux:xrandr", @@ -97,6 +111,7 @@ source_set("x11_unittests") { "//ui/events:test_support", "//ui/events/devices/x11", "//ui/events/platform/x11", + "//ui/events/x:unittests", "//ui/ozone:platform", "//ui/ozone:test_support", "//ui/ozone/common", diff --git a/chromium/ui/ozone/platform/x11/DEPS b/chromium/ui/ozone/platform/x11/DEPS index 3b6346a6153..c4251a75884 100644 --- a/chromium/ui/ozone/platform/x11/DEPS +++ b/chromium/ui/ozone/platform/x11/DEPS @@ -1,4 +1,6 @@ include_rules = [ "+ui/base/x", "+ui/base", + "+ui/gtk/gtk_ui_delegate.h", + "+ui/gtk/gtk_ui_delegate_x11.h", ] diff --git a/chromium/ui/ozone/platform/x11/gl_ozone_glx.cc b/chromium/ui/ozone/platform/x11/gl_ozone_glx.cc index 422c58ee776..520c5223457 100644 --- a/chromium/ui/ozone/platform/x11/gl_ozone_glx.cc +++ b/chromium/ui/ozone/platform/x11/gl_ozone_glx.cc @@ -67,11 +67,6 @@ bool GLOzoneGLX::InitializeStaticGLBindings( return true; } -void GLOzoneGLX::InitializeLogGLBindings() { - gl::InitializeLogGLBindingsGL(); - gl::InitializeLogGLBindingsGLX(); -} - void GLOzoneGLX::SetDisabledExtensionsPlatform( const std::string& disabled_extensions) { gl::SetDisabledExtensionsGLX(disabled_extensions); diff --git a/chromium/ui/ozone/platform/x11/gl_ozone_glx.h b/chromium/ui/ozone/platform/x11/gl_ozone_glx.h index 2ffa0f45527..7af963f6a74 100644 --- a/chromium/ui/ozone/platform/x11/gl_ozone_glx.h +++ b/chromium/ui/ozone/platform/x11/gl_ozone_glx.h @@ -18,7 +18,6 @@ class GLOzoneGLX : public GLOzone { bool InitializeGLOneOffPlatform() override; bool InitializeStaticGLBindings(gl::GLImplementation implementation) override; - void InitializeLogGLBindings() override; void SetDisabledExtensionsPlatform( const std::string& disabled_extensions) override; bool InitializeExtensionSettingsOneOffPlatform() override; diff --git a/chromium/ui/ozone/platform/x11/gl_surface_egl_ozone_x11.cc b/chromium/ui/ozone/platform/x11/gl_surface_egl_ozone_x11.cc index b33cfb1f6f0..71d50ffa607 100644 --- a/chromium/ui/ozone/platform/x11/gl_surface_egl_ozone_x11.cc +++ b/chromium/ui/ozone/platform/x11/gl_surface_egl_ozone_x11.cc @@ -79,7 +79,7 @@ EGLConfig GLSurfaceEGLOzoneX11::GetConfig() { bool GLSurfaceEGLOzoneX11::Resize(const gfx::Size& size, float scale_factor, - ColorSpace color_space, + const gfx::ColorSpace& color_space, bool has_alpha) { if (size == GetSize()) return true; diff --git a/chromium/ui/ozone/platform/x11/gl_surface_egl_ozone_x11.h b/chromium/ui/ozone/platform/x11/gl_surface_egl_ozone_x11.h index dcb419083b9..eab987a95b1 100644 --- a/chromium/ui/ozone/platform/x11/gl_surface_egl_ozone_x11.h +++ b/chromium/ui/ozone/platform/x11/gl_surface_egl_ozone_x11.h @@ -21,7 +21,7 @@ class GLSurfaceEGLOzoneX11 : public gl::NativeViewGLSurfaceEGL { EGLConfig GetConfig() override; bool Resize(const gfx::Size& size, float scale_factor, - ColorSpace color_space, + const gfx::ColorSpace& color_space, bool has_alpha) override; private: diff --git a/chromium/ui/ozone/platform/x11/gl_surface_egl_readback_x11.cc b/chromium/ui/ozone/platform/x11/gl_surface_egl_readback_x11.cc index 3a38c4d6996..1806337fff4 100644 --- a/chromium/ui/ozone/platform/x11/gl_surface_egl_readback_x11.cc +++ b/chromium/ui/ozone/platform/x11/gl_surface_egl_readback_x11.cc @@ -52,7 +52,7 @@ void GLSurfaceEglReadbackX11::Destroy() { bool GLSurfaceEglReadbackX11::Resize(const gfx::Size& size, float scale_factor, - ColorSpace color_space, + const gfx::ColorSpace& color_space, bool has_alpha) { if (!GLSurfaceEglReadback::Resize(size, scale_factor, color_space, has_alpha)) { diff --git a/chromium/ui/ozone/platform/x11/gl_surface_egl_readback_x11.h b/chromium/ui/ozone/platform/x11/gl_surface_egl_readback_x11.h index 7bd5662cfc5..ed56bcaa4f4 100644 --- a/chromium/ui/ozone/platform/x11/gl_surface_egl_readback_x11.h +++ b/chromium/ui/ozone/platform/x11/gl_surface_egl_readback_x11.h @@ -20,7 +20,7 @@ class GLSurfaceEglReadbackX11 : public GLSurfaceEglReadback { void Destroy() override; bool Resize(const gfx::Size& size, float scale_factor, - ColorSpace color_space, + const gfx::ColorSpace& color_space, bool has_alpha) override; private: diff --git a/chromium/ui/ozone/platform/x11/ozone_platform_x11.cc b/chromium/ui/ozone/platform/x11/ozone_platform_x11.cc index 67e1e41dc40..78ea2a95e7e 100644 --- a/chromium/ui/ozone/platform/x11/ozone_platform_x11.cc +++ b/chromium/ui/ozone/platform/x11/ozone_platform_x11.cc @@ -9,12 +9,15 @@ #include "base/message_loop/message_pump_type.h" #include "base/strings/utf_string_conversions.h" +#include "ui/base/buildflags.h" +#include "ui/base/ime/linux/linux_input_method_context_factory.h" #include "ui/base/x/x11_util.h" #include "ui/display/fake/fake_display_delegate.h" #include "ui/events/devices/x11/touch_factory_x11.h" #include "ui/events/ozone/layout/keyboard_layout_engine_manager.h" #include "ui/events/ozone/layout/stub/stub_keyboard_layout_engine.h" -#include "ui/events/platform/x11/x11_event_source_default.h" +#include "ui/events/platform/x11/x11_event_source.h" +#include "ui/gfx/native_widget_types.h" #include "ui/gfx/x/x11_connection.h" #include "ui/gfx/x/x11_types.h" #include "ui/ozone/common/stub_overlay_manager.h" @@ -36,6 +39,18 @@ #include "ui/base/ime/linux/input_method_auralinux.h" #endif +#if BUILDFLAG(USE_GTK) +#include "ui/gtk/gtk_ui_delegate.h" // nogncheck +#include "ui/gtk/gtk_ui_delegate_x11.h" // nogncheck +#endif + +#if BUILDFLAG(USE_XKBCOMMON) +#include "ui/events/ozone/layout/xkb/xkb_evdev_codes.h" +#include "ui/events/ozone/layout/xkb/xkb_keyboard_layout_engine.h" +#else +#include "ui/events/ozone/layout/stub/stub_keyboard_layout_engine.h" +#endif + namespace ui { namespace { @@ -108,10 +123,17 @@ class OzonePlatformX11 : public OzonePlatform { } std::unique_ptr<InputMethod> CreateInputMethod( - internal::InputMethodDelegate* delegate) override { + internal::InputMethodDelegate* delegate, + gfx::AcceleratedWidget) override { #if defined(OS_CHROMEOS) return std::make_unique<InputMethodChromeOS>(delegate); #else + // This method is used by upper layer components (e.g: GtkUi) to determine + // if the LinuxInputMethodContextFactory instance is provided by the Ozone + // platform implementation, so we must consider the case that it is still + // not set at this point. + if (!ui::LinuxInputMethodContextFactory::instance()) + return nullptr; return std::make_unique<InputMethodAuraLinux>(delegate); #endif } @@ -129,12 +151,24 @@ class OzonePlatformX11 : public OzonePlatform { cursor_factory_ozone_ = std::make_unique<X11CursorFactoryOzone>(); gpu_platform_support_host_.reset(CreateStubGpuPlatformSupportHost()); - // TODO(spang): Support XKB. +#if BUILDFLAG(USE_XKBCOMMON) + keyboard_layout_engine_ = + std::make_unique<XkbKeyboardLayoutEngine>(xkb_evdev_code_converter_); + // TODO(nickdiego): debugging.. + keyboard_layout_engine_ = std::make_unique<StubKeyboardLayoutEngine>(); +#else keyboard_layout_engine_ = std::make_unique<StubKeyboardLayoutEngine>(); +#endif KeyboardLayoutEngineManager::SetKeyboardLayoutEngine( keyboard_layout_engine_.get()); TouchFactory::SetTouchDeviceListFromCommandLine(); + +#if BUILDFLAG(USE_GTK) + DCHECK(!GtkUiDelegate::instance()); + gtk_ui_delegate_ = std::make_unique<GtkUiDelegateX11>(gfx::GetXDisplay()); + GtkUiDelegate::SetInstance(gtk_ui_delegate_.get()); +#endif } void InitializeGPU(const InitParams& params) override { @@ -175,11 +209,15 @@ class OzonePlatformX11 : public OzonePlatform { return; XDisplay* display = gfx::GetXDisplay(); - event_source_ = std::make_unique<X11EventSourceDefault>(display); + event_source_ = std::make_unique<X11EventSource>(display); } bool common_initialized_ = false; +#if BUILDFLAG(USE_XKBCOMMON) + XkbEvdevCodes xkb_evdev_code_converter_; +#endif + // Objects in the UI process. std::unique_ptr<KeyboardLayoutEngine> keyboard_layout_engine_; std::unique_ptr<OverlayManagerOzone> overlay_manager_; @@ -192,7 +230,11 @@ class OzonePlatformX11 : public OzonePlatform { std::unique_ptr<X11SurfaceFactory> surface_factory_ozone_; // Objects in both UI and GPU process. - std::unique_ptr<X11EventSourceDefault> event_source_; + std::unique_ptr<X11EventSource> event_source_; + +#if BUILDFLAG(USE_GTK) + std::unique_ptr<GtkUiDelegate> gtk_ui_delegate_; +#endif DISALLOW_COPY_AND_ASSIGN(OzonePlatformX11); }; diff --git a/chromium/ui/ozone/platform/x11/x11_canvas_surface.cc b/chromium/ui/ozone/platform/x11/x11_canvas_surface.cc index 49afa733b9b..59cd3740d63 100644 --- a/chromium/ui/ozone/platform/x11/x11_canvas_surface.cc +++ b/chromium/ui/ozone/platform/x11/x11_canvas_surface.cc @@ -11,25 +11,22 @@ namespace ui { -X11CanvasSurface::X11CanvasSurface(gfx::AcceleratedWidget widget, - base::TaskRunner* gpu_task_runner) +X11CanvasSurface::X11CanvasSurface( + gfx::AcceleratedWidget widget, + scoped_refptr<base::SequencedTaskRunner> gpu_task_runner) : task_runner_(base::SequencedTaskRunnerHandle::Get()), x11_software_bitmap_presenter_(widget, task_runner_.get(), - gpu_task_runner) {} + std::move(gpu_task_runner)) {} X11CanvasSurface::~X11CanvasSurface() = default; -sk_sp<SkSurface> X11CanvasSurface::GetSurface() { - DCHECK(surface_); - return surface_; +SkCanvas* X11CanvasSurface::GetCanvas() { + return x11_software_bitmap_presenter_.GetSkCanvas(); } void X11CanvasSurface::ResizeCanvas(const gfx::Size& viewport_size) { x11_software_bitmap_presenter_.Resize(viewport_size); - SkImageInfo info = SkImageInfo::MakeN32( - viewport_size.width(), viewport_size.height(), kOpaque_SkAlphaType); - surface_ = x11_software_bitmap_presenter_.GetSkCanvas()->makeSurface(info); } void X11CanvasSurface::PresentCanvas(const gfx::Rect& damage) { diff --git a/chromium/ui/ozone/platform/x11/x11_canvas_surface.h b/chromium/ui/ozone/platform/x11/x11_canvas_surface.h index b6371f5cf71..a93e22677a0 100644 --- a/chromium/ui/ozone/platform/x11/x11_canvas_surface.h +++ b/chromium/ui/ozone/platform/x11/x11_canvas_surface.h @@ -8,6 +8,8 @@ #include <memory> #include "base/macros.h" +#include "base/memory/scoped_refptr.h" +#include "base/sequenced_task_runner.h" #include "base/threading/sequenced_task_runner_handle.h" #include "third_party/skia/include/core/SkRefCnt.h" #include "third_party/skia/include/core/SkSurface.h" @@ -16,6 +18,8 @@ #include "ui/gfx/native_widget_types.h" #include "ui/ozone/public/surface_ozone_canvas.h" +class SkSurface; + namespace ui { // The platform-specific part of an software output. The class is intended @@ -25,11 +29,11 @@ namespace ui { class X11CanvasSurface : public SurfaceOzoneCanvas { public: X11CanvasSurface(gfx::AcceleratedWidget widget, - base::TaskRunner* gpu_task_runner); + scoped_refptr<base::SequencedTaskRunner> gpu_task_runner); ~X11CanvasSurface() override; // SurfaceOzoneCanvas overrides: - sk_sp<SkSurface> GetSurface() override; + SkCanvas* GetCanvas() override; void ResizeCanvas(const gfx::Size& viewport_size) override; void PresentCanvas(const gfx::Rect& damage) override; std::unique_ptr<gfx::VSyncProvider> CreateVSyncProvider() override; diff --git a/chromium/ui/ozone/platform/x11/x11_cursor_factory_ozone.cc b/chromium/ui/ozone/platform/x11/x11_cursor_factory_ozone.cc index e7d91ab8626..e981ade21b6 100644 --- a/chromium/ui/ozone/platform/x11/x11_cursor_factory_ozone.cc +++ b/chromium/ui/ozone/platform/x11/x11_cursor_factory_ozone.cc @@ -5,7 +5,9 @@ #include "ui/ozone/platform/x11/x11_cursor_factory_ozone.h" #include "third_party/skia/include/core/SkBitmap.h" +#include "ui/base/cursor/cursor_lookup.h" #include "ui/base/cursor/cursors_aura.h" +#include "ui/base/mojom/cursor_type.mojom-shared.h" #include "ui/gfx/geometry/point.h" namespace ui { @@ -21,11 +23,11 @@ PlatformCursor ToPlatformCursor(X11CursorOzone* cursor) { } // Gets default aura cursor bitmap/hotspot and creates a X11CursorOzone with it. -scoped_refptr<X11CursorOzone> CreateAuraX11Cursor(CursorType type) { +scoped_refptr<X11CursorOzone> CreateAuraX11Cursor(mojom::CursorType type) { Cursor cursor(type); - cursor.set_device_scale_factor(1); - SkBitmap bitmap = cursor.GetBitmap(); - gfx::Point hotspot = cursor.GetHotspot(); + cursor.set_image_scale_factor(1); + SkBitmap bitmap = GetCursorBitmap(cursor); + gfx::Point hotspot = GetCursorHotspot(cursor); if (!bitmap.isNull()) return new X11CursorOzone(bitmap, hotspot); return nullptr; @@ -38,7 +40,7 @@ X11CursorFactoryOzone::X11CursorFactoryOzone() X11CursorFactoryOzone::~X11CursorFactoryOzone() {} -PlatformCursor X11CursorFactoryOzone::GetDefaultCursor(CursorType type) { +PlatformCursor X11CursorFactoryOzone::GetDefaultCursor(mojom::CursorType type) { return ToPlatformCursor(GetDefaultCursorInternal(type).get()); } @@ -83,8 +85,8 @@ void X11CursorFactoryOzone::UnrefImageCursor(PlatformCursor cursor) { } scoped_refptr<X11CursorOzone> X11CursorFactoryOzone::GetDefaultCursorInternal( - CursorType type) { - if (type == CursorType::kNone) + mojom::CursorType type) { + if (type == mojom::CursorType::kNone) return invisible_cursor_; if (!default_cursors_.count(type)) { @@ -100,8 +102,8 @@ scoped_refptr<X11CursorOzone> X11CursorFactoryOzone::GetDefaultCursorInternal( // pointer cursor then invisible cursor if this fails. cursor = CreateAuraX11Cursor(type); if (!cursor.get()) { - if (type != CursorType::kPointer) { - cursor = GetDefaultCursorInternal(CursorType::kPointer); + if (type != mojom::CursorType::kPointer) { + cursor = GetDefaultCursorInternal(mojom::CursorType::kPointer); } else { NOTREACHED() << "Failed to load default cursor bitmap"; } diff --git a/chromium/ui/ozone/platform/x11/x11_cursor_factory_ozone.h b/chromium/ui/ozone/platform/x11/x11_cursor_factory_ozone.h index 48859f4bfd5..05347bd6cd8 100644 --- a/chromium/ui/ozone/platform/x11/x11_cursor_factory_ozone.h +++ b/chromium/ui/ozone/platform/x11/x11_cursor_factory_ozone.h @@ -11,6 +11,7 @@ #include "base/macros.h" #include "ui/base/cursor/cursor.h" +#include "ui/base/mojom/cursor_type.mojom-forward.h" #include "ui/gfx/x/x11.h" #include "ui/ozone/platform/x11/x11_cursor_ozone.h" #include "ui/ozone/public/cursor_factory_ozone.h" @@ -24,7 +25,7 @@ class X11CursorFactoryOzone : public CursorFactoryOzone { ~X11CursorFactoryOzone() override; // CursorFactoryOzone: - PlatformCursor GetDefaultCursor(CursorType type) override; + PlatformCursor GetDefaultCursor(mojom::CursorType type) override; PlatformCursor CreateImageCursor(const SkBitmap& bitmap, const gfx::Point& hotspot, float bitmap_dpi) override; @@ -37,13 +38,14 @@ class X11CursorFactoryOzone : public CursorFactoryOzone { private: // Loads/caches default cursor or returns cached version. - scoped_refptr<X11CursorOzone> GetDefaultCursorInternal(CursorType type); + scoped_refptr<X11CursorOzone> GetDefaultCursorInternal( + mojom::CursorType type); // Holds a single instance of the invisible cursor. X11 has no way to hide // the cursor so an invisible cursor mimics that. scoped_refptr<X11CursorOzone> invisible_cursor_; - std::map<CursorType, scoped_refptr<X11CursorOzone>> default_cursors_; + std::map<mojom::CursorType, scoped_refptr<X11CursorOzone>> default_cursors_; DISALLOW_COPY_AND_ASSIGN(X11CursorFactoryOzone); }; diff --git a/chromium/ui/ozone/platform/x11/x11_screen_ozone.cc b/chromium/ui/ozone/platform/x11/x11_screen_ozone.cc index 034831fee00..5d5b60fdd1f 100644 --- a/chromium/ui/ozone/platform/x11/x11_screen_ozone.cc +++ b/chromium/ui/ozone/platform/x11/x11_screen_ozone.cc @@ -173,6 +173,10 @@ void X11ScreenOzone::RemoveObserver(display::DisplayObserver* observer) { x11_display_manager_->RemoveObserver(observer); } +std::string X11ScreenOzone::GetCurrentWorkspace() { + return x11_display_manager_->GetCurrentWorkspace(); +} + bool X11ScreenOzone::DispatchXEvent(XEvent* xev) { return x11_display_manager_->ProcessEvent(xev); } @@ -187,7 +191,7 @@ void X11ScreenOzone::OnXDisplayListUpdated() { gfx::SetFontRenderParamsDeviceScaleFactor(scale_factor); } -float X11ScreenOzone::GetXDisplayScaleFactor() { +float X11ScreenOzone::GetXDisplayScaleFactor() const { return GetDeviceScaleFactor(); } diff --git a/chromium/ui/ozone/platform/x11/x11_screen_ozone.h b/chromium/ui/ozone/platform/x11/x11_screen_ozone.h index fb214b1544f..32493fca0c6 100644 --- a/chromium/ui/ozone/platform/x11/x11_screen_ozone.h +++ b/chromium/ui/ozone/platform/x11/x11_screen_ozone.h @@ -45,6 +45,7 @@ class X11ScreenOzone : public PlatformScreen, const gfx::Rect& match_rect) const override; void AddObserver(display::DisplayObserver* observer) override; void RemoveObserver(display::DisplayObserver* observer) override; + std::string GetCurrentWorkspace() override; // Overridden from ui::XEventDispatcher: bool DispatchXEvent(XEvent* event) override; @@ -54,7 +55,7 @@ class X11ScreenOzone : public PlatformScreen, // Overridden from ui::XDisplayManager::Delegate: void OnXDisplayListUpdated() override; - float GetXDisplayScaleFactor() override; + float GetXDisplayScaleFactor() const override; gfx::Point GetCursorLocation() const; diff --git a/chromium/ui/ozone/platform/x11/x11_screen_ozone_unittest.cc b/chromium/ui/ozone/platform/x11/x11_screen_ozone_unittest.cc index 87ae05c85f2..121a6ccc77c 100644 --- a/chromium/ui/ozone/platform/x11/x11_screen_ozone_unittest.cc +++ b/chromium/ui/ozone/platform/x11/x11_screen_ozone_unittest.cc @@ -12,7 +12,7 @@ #include "ui/base/x/x11_display_manager.h" #include "ui/display/display.h" #include "ui/display/display_observer.h" -#include "ui/events/platform/x11/x11_event_source_default.h" +#include "ui/events/platform/x11/x11_event_source.h" #include "ui/ozone/platform/x11/x11_window_ozone.h" #include "ui/ozone/test/mock_platform_window_delegate.h" #include "ui/platform_window/platform_window_delegate.h" @@ -56,7 +56,7 @@ class X11ScreenOzoneTest : public testing::Test { void SetUp() override { XDisplay* display = gfx::GetXDisplay(); - event_source_ = std::make_unique<X11EventSourceDefault>(display); + event_source_ = std::make_unique<X11EventSource>(display); primary_display_ = std::make_unique<display::Display>( NextDisplayId(), kPrimaryDisplayBounds); screen_ = std::make_unique<X11ScreenOzone>(); @@ -112,7 +112,7 @@ class X11ScreenOzoneTest : public testing::Test { private: std::unique_ptr<display::Display> primary_display_; std::unique_ptr<X11ScreenOzone> screen_; - std::unique_ptr<X11EventSourceDefault> event_source_; + std::unique_ptr<X11EventSource> event_source_; std::unique_ptr<base::test::TaskEnvironment> task_env_; DISALLOW_COPY_AND_ASSIGN(X11ScreenOzoneTest); diff --git a/chromium/ui/ozone/platform/x11/x11_surface_factory.cc b/chromium/ui/ozone/platform/x11/x11_surface_factory.cc index c231ba2964b..fa2289015ef 100644 --- a/chromium/ui/ozone/platform/x11/x11_surface_factory.cc +++ b/chromium/ui/ozone/platform/x11/x11_surface_factory.cc @@ -55,8 +55,9 @@ class GLOzoneEGLX11 : public GLOzoneEGL { protected: // GLOzoneEGL: - intptr_t GetNativeDisplay() override { - return reinterpret_cast<intptr_t>(gfx::GetXDisplay()); + gl::EGLDisplayPlatform GetNativeDisplay() override { + return gl::EGLDisplayPlatform( + reinterpret_cast<EGLNativeDisplayType>(gfx::GetXDisplay())); } bool LoadGLES2Bindings(gl::GLImplementation implementation) override { @@ -106,8 +107,8 @@ X11SurfaceFactory::CreateVulkanImplementation(bool allow_protected_memory, std::unique_ptr<SurfaceOzoneCanvas> X11SurfaceFactory::CreateCanvasForWidget( gfx::AcceleratedWidget widget, - base::TaskRunner* task_runner) { - return std::make_unique<X11CanvasSurface>(widget, task_runner); + scoped_refptr<base::SequencedTaskRunner> task_runner) { + return std::make_unique<X11CanvasSurface>(widget, std::move(task_runner)); } } // namespace ui diff --git a/chromium/ui/ozone/platform/x11/x11_surface_factory.h b/chromium/ui/ozone/platform/x11/x11_surface_factory.h index 18a2ee788d6..33dbb696253 100644 --- a/chromium/ui/ozone/platform/x11/x11_surface_factory.h +++ b/chromium/ui/ozone/platform/x11/x11_surface_factory.h @@ -32,7 +32,7 @@ class X11SurfaceFactory : public SurfaceFactoryOzone { #endif std::unique_ptr<SurfaceOzoneCanvas> CreateCanvasForWidget( gfx::AcceleratedWidget widget, - base::TaskRunner* task_runner) override; + scoped_refptr<base::SequencedTaskRunner> task_runner) override; private: std::unique_ptr<GLOzone> glx_implementation_; diff --git a/chromium/ui/ozone/platform/x11/x11_window_ozone.cc b/chromium/ui/ozone/platform/x11/x11_window_ozone.cc index ee9fd3cca72..5334049b13f 100644 --- a/chromium/ui/ozone/platform/x11/x11_window_ozone.cc +++ b/chromium/ui/ozone/platform/x11/x11_window_ozone.cc @@ -4,77 +4,19 @@ #include "ui/ozone/platform/x11/x11_window_ozone.h" -#include <algorithm> -#include <string> -#include <vector> - -#include "base/bind.h" -#include "base/strings/utf_string_conversions.h" -#include "ui/base/x/x11_util.h" -#include "ui/events/event.h" -#include "ui/events/event_utils.h" -#include "ui/events/platform/x11/x11_event_source.h" -#include "ui/gfx/x/x11.h" -#include "ui/gfx/x/x11_atom_cache.h" #include "ui/ozone/platform/x11/x11_cursor_ozone.h" -#include "ui/platform_window/platform_window_init_properties.h" +#include "ui/platform_window/platform_window_delegate.h" namespace ui { X11WindowOzone::X11WindowOzone(PlatformWindowDelegate* delegate) : X11Window(delegate) {} -X11WindowOzone::~X11WindowOzone() { - PrepareForShutdown(); - Close(); -} - -void X11WindowOzone::PrepareForShutdown() { - DCHECK(X11EventSource::GetInstance()); - X11EventSource::GetInstance()->RemoveXEventDispatcher(this); -} +X11WindowOzone::~X11WindowOzone() = default; void X11WindowOzone::SetCursor(PlatformCursor cursor) { X11CursorOzone* cursor_ozone = static_cast<X11CursorOzone*>(cursor); XWindow::SetCursor(cursor_ozone->xcursor()); } -// CheckCanDispatchNextPlatformEvent is called by X11EventSourceLibevent to -// determine whether X11WindowOzone instance (XEventDispatcher implementation) -// is able to process next translated event sent by it. So, it's done through -// |handle_next_event_| internal flag, used in subsequent CanDispatchEvent -// call. -void X11WindowOzone::CheckCanDispatchNextPlatformEvent(XEvent* xev) { - if (is_shutting_down()) - return; - - handle_next_event_ = XWindow::IsTargetedBy(*xev); -} - -void X11WindowOzone::PlatformEventDispatchFinished() { - handle_next_event_ = false; -} - -PlatformEventDispatcher* X11WindowOzone::GetPlatformEventDispatcher() { - return this; -} - -bool X11WindowOzone::DispatchXEvent(XEvent* xev) { - if (!XWindow::IsTargetedBy(*xev)) - return false; - - XWindow::ProcessEvent(xev); - return true; -} - -bool X11WindowOzone::CanDispatchEvent(const PlatformEvent& event) { - DCHECK_NE(XWindow::window(), x11::None); - return handle_next_event_; -} - -void X11WindowOzone::SetPlatformEventDispatcher() { - DCHECK(X11EventSource::GetInstance()); - X11EventSource::GetInstance()->AddXEventDispatcher(this); -} - } // namespace ui diff --git a/chromium/ui/ozone/platform/x11/x11_window_ozone.h b/chromium/ui/ozone/platform/x11/x11_window_ozone.h index 352be12dc2b..edf18b39b76 100644 --- a/chromium/ui/ozone/platform/x11/x11_window_ozone.h +++ b/chromium/ui/ozone/platform/x11/x11_window_ozone.h @@ -5,49 +5,22 @@ #ifndef UI_OZONE_PLATFORM_X11_X11_WINDOW_OZONE_H_ #define UI_OZONE_PLATFORM_X11_X11_WINDOW_OZONE_H_ -#include <array> -#include <memory> - -#include "base/containers/flat_set.h" #include "base/macros.h" -#include "ui/base/x/x11_window.h" -#include "ui/events/platform/platform_event_dispatcher.h" -#include "ui/events/platform/x11/x11_event_source.h" -#include "ui/events/x/x11_window_event_manager.h" -#include "ui/gfx/geometry/rect.h" -#include "ui/gfx/x/x11_types.h" #include "ui/platform_window/x11/x11_window.h" namespace ui { +class PlatformWindowDelegate; + // PlatformWindow implementation for X11 Ozone. PlatformEvents are ui::Events. -class X11WindowOzone : public X11Window, public XEventDispatcher { +class X11WindowOzone : public X11Window { public: explicit X11WindowOzone(PlatformWindowDelegate* delegate); ~X11WindowOzone() override; // Overridden from PlatformWindow: - void PrepareForShutdown() override; void SetCursor(PlatformCursor cursor) override; - // Overridden from ui::XEventDispatcher: - void CheckCanDispatchNextPlatformEvent(XEvent* xev) override; - void PlatformEventDispatchFinished() override; - PlatformEventDispatcher* GetPlatformEventDispatcher() override; - bool DispatchXEvent(XEvent* event) override; - - private: - // X11Window overrides: - void SetPlatformEventDispatcher() override; - - // PlatformEventDispatcher: - bool CanDispatchEvent(const PlatformEvent& event) override; - - // Tells if this dispatcher can process next translated event based on a - // previous check in ::CheckCanDispatchNextPlatformEvent based on a XID - // target. - bool handle_next_event_ = false; - DISALLOW_COPY_AND_ASSIGN(X11WindowOzone); }; diff --git a/chromium/ui/ozone/platform/x11/x11_window_ozone_unittest.cc b/chromium/ui/ozone/platform/x11/x11_window_ozone_unittest.cc index 099e88b847d..e2c5fb1f609 100644 --- a/chromium/ui/ozone/platform/x11/x11_window_ozone_unittest.cc +++ b/chromium/ui/ozone/platform/x11/x11_window_ozone_unittest.cc @@ -11,10 +11,10 @@ #include "base/test/task_environment.h" #include "testing/gtest/include/gtest/gtest.h" #include "ui/display/display.h" -#include "ui/display/screen.h" +#include "ui/display/screen_base.h" #include "ui/events/devices/x11/touch_factory_x11.h" #include "ui/events/event.h" -#include "ui/events/platform/x11/x11_event_source_default.h" +#include "ui/events/platform/x11/x11_event_source.h" #include "ui/events/test/events_test_utils_x11.h" #include "ui/ozone/test/mock_platform_window_delegate.h" #include "ui/platform_window/platform_window_delegate.h" @@ -43,41 +43,21 @@ ACTION_P(CloneEvent, event_ptr) { // ScreenOzone, but it is impossible. // We are not really interested in sending back real displays. Thus, default one // is more than enough. -class TestScreen : public display::Screen { +class TestScreen : public display::ScreenBase { public: - TestScreen() : displays_({}) {} - ~TestScreen() override = default; - - // display::Screen interface. - gfx::Point GetCursorScreenPoint() override { return {}; } - bool IsWindowUnderCursor(gfx::NativeWindow window) override { return false; } - gfx::NativeWindow GetWindowAtScreenPoint(const gfx::Point& point) override { - return gfx::NativeWindow(); - } - int GetNumDisplays() const override { return GetAllDisplays().size(); } - const std::vector<display::Display>& GetAllDisplays() const override { - return displays_; - } - display::Display GetDisplayNearestWindow( - gfx::NativeWindow window) const override { - return {}; - } - display::Display GetDisplayNearestPoint( - const gfx::Point& point) const override { - return {}; + TestScreen() { + ProcessDisplayChanged({}, true); } - display::Display GetDisplayMatching( - const gfx::Rect& match_rect) const override { - return {}; + ~TestScreen() override = default; + TestScreen(const TestScreen& screen) = delete; + TestScreen& operator=(const TestScreen& screen) = delete; + + void SetScaleAndBoundsForPrimaryDisplay(float scale, + const gfx::Rect& bounds_in_pixels) { + auto display = GetPrimaryDisplay(); + display.SetScaleAndBounds(scale, bounds_in_pixels); + ProcessDisplayChanged(display, true); } - display::Display GetPrimaryDisplay() const override { return {}; } - void AddObserver(display::DisplayObserver* observer) override {} - void RemoveObserver(display::DisplayObserver* observer) override {} - - private: - std::vector<display::Display> displays_; - - DISALLOW_COPY_AND_ASSIGN(TestScreen); }; // namespace } // namespace @@ -92,9 +72,10 @@ class X11WindowOzoneTest : public testing::Test { void SetUp() override { XDisplay* display = gfx::GetXDisplay(); - event_source_ = std::make_unique<X11EventSourceDefault>(display); + event_source_ = std::make_unique<X11EventSource>(display); - display::Screen::SetScreenInstance(new TestScreen()); + test_screen_ = new TestScreen(); + display::Screen::SetScreenInstance(test_screen_); TouchFactory::GetInstance()->SetPointerDeviceForTest({kPointerDeviceId}); } @@ -126,9 +107,11 @@ class X11WindowOzoneTest : public testing::Test { return window_manager; } + TestScreen* test_screen_ = nullptr; + private: std::unique_ptr<base::test::TaskEnvironment> task_env_; - std::unique_ptr<X11EventSourceDefault> event_source_; + std::unique_ptr<X11EventSource> event_source_; DISALLOW_COPY_AND_ASSIGN(X11WindowOzoneTest); }; @@ -198,6 +181,7 @@ TEST_F(X11WindowOzoneTest, SendPlatformEventToCapturedWindow) { EXPECT_CALL(delegate_2, DispatchEvent(_)).WillOnce(CloneEvent(&event)); DispatchXEvent(xi_event, widget); + EXPECT_TRUE(event.get()); EXPECT_EQ(ET_MOUSE_PRESSED, event->type()); EXPECT_EQ(gfx::Point(-277, 215), event->AsLocatedEvent()->location()); } @@ -267,4 +251,18 @@ TEST_F(X11WindowOzoneTest, MouseEnterAndDelete) { EXPECT_FALSE(window_manager()->window_mouse_currently_on_for_test()); } +// Verifies X11Window sets fullscreen bounds in pixels when going to fullscreen. +TEST_F(X11WindowOzoneTest, ToggleFullscreen) { + constexpr gfx::Rect screen_bounds_in_px(640, 480, 1280, 720); + test_screen_->SetScaleAndBoundsForPrimaryDisplay(2, screen_bounds_in_px); + + MockPlatformWindowDelegate delegate; + gfx::AcceleratedWidget widget; + constexpr gfx::Rect bounds(30, 80, 800, 600); + auto window = CreatePlatformWindow(&delegate, bounds, &widget); + + EXPECT_CALL(delegate, OnBoundsChanged(screen_bounds_in_px)); + window->ToggleFullscreen(); +} + } // namespace ui diff --git a/chromium/ui/ozone/public/DEPS b/chromium/ui/ozone/public/DEPS index ef8ad28d9d4..6d31ede447e 100644 --- a/chromium/ui/ozone/public/DEPS +++ b/chromium/ui/ozone/public/DEPS @@ -1,3 +1,4 @@ include_rules = [ "+mojo/public", + "+ui/base/mojom/cursor_type.mojom-forward.h", ] diff --git a/chromium/ui/ozone/public/cursor_factory_ozone.cc b/chromium/ui/ozone/public/cursor_factory_ozone.cc index 01b80c66d5d..542dce20aaa 100644 --- a/chromium/ui/ozone/public/cursor_factory_ozone.cc +++ b/chromium/ui/ozone/public/cursor_factory_ozone.cc @@ -30,7 +30,7 @@ CursorFactoryOzone* CursorFactoryOzone::GetInstance() { return g_instance; } -PlatformCursor CursorFactoryOzone::GetDefaultCursor(CursorType type) { +PlatformCursor CursorFactoryOzone::GetDefaultCursor(mojom::CursorType type) { NOTIMPLEMENTED(); return NULL; } diff --git a/chromium/ui/ozone/public/cursor_factory_ozone.h b/chromium/ui/ozone/public/cursor_factory_ozone.h index 7dc9986242c..4492d2404b0 100644 --- a/chromium/ui/ozone/public/cursor_factory_ozone.h +++ b/chromium/ui/ozone/public/cursor_factory_ozone.h @@ -8,6 +8,7 @@ #include <vector> #include "base/component_export.h" +#include "ui/base/mojom/cursor_type.mojom-forward.h" #include "ui/gfx/native_widget_types.h" namespace gfx { @@ -29,7 +30,7 @@ class COMPONENT_EXPORT(OZONE_BASE) CursorFactoryOzone { // Return the default cursor of the specified type. The types are listed in // ui/base/cursor/cursor.h. Default cursors are managed by the implementation // and must live indefinitely; there's no way to know when to free them. - virtual PlatformCursor GetDefaultCursor(CursorType type); + virtual PlatformCursor GetDefaultCursor(mojom::CursorType type); // Return a image cursor from the specified image & hotspot. Image cursors // are referenced counted and have an initial refcount of 1. Therefore, each diff --git a/chromium/ui/ozone/public/gl_ozone.h b/chromium/ui/ozone/public/gl_ozone.h index d280011016e..a12283fdd8c 100644 --- a/chromium/ui/ozone/public/gl_ozone.h +++ b/chromium/ui/ozone/public/gl_ozone.h @@ -40,9 +40,6 @@ class COMPONENT_EXPORT(OZONE_BASE) GLOzone { // Performs any one off initialization for GL implementation. virtual bool InitializeGLOneOffPlatform() = 0; - // Initializes static debug GL bindings. - virtual void InitializeLogGLBindings() = 0; - // Disables the specified extensions in the window system bindings, // e.g., GLX, EGL, etc. This is part of the GPU driver bug workarounds // mechanism. diff --git a/chromium/ui/ozone/public/gpu_platform_support_host.h b/chromium/ui/ozone/public/gpu_platform_support_host.h index 4839359e461..af6da1d2879 100644 --- a/chromium/ui/ozone/public/gpu_platform_support_host.h +++ b/chromium/ui/ozone/public/gpu_platform_support_host.h @@ -12,7 +12,7 @@ #include "base/single_thread_task_runner.h" #include "ipc/ipc_listener.h" #include "ipc/ipc_sender.h" -#include "mojo/public/cpp/bindings/binding.h" +#include "mojo/public/cpp/system/message_pipe.h" namespace ui { diff --git a/chromium/ui/ozone/public/input_controller.cc b/chromium/ui/ozone/public/input_controller.cc index 9ea7cb30a1d..2f2bd8688a3 100644 --- a/chromium/ui/ozone/public/input_controller.cc +++ b/chromium/ui/ozone/public/input_controller.cc @@ -36,15 +36,19 @@ class StubInputController : public InputController { NOTIMPLEMENTED_LOG_ONCE(); } void SetTouchpadSensitivity(int value) override {} + void SetTouchpadScrollSensitivity(int value) override {} void SetTapToClick(bool enabled) override {} void SetThreeFingerClick(bool enabled) override {} void SetTapDragging(bool enabled) override {} void SetNaturalScroll(bool enabled) override {} void SetMouseSensitivity(int value) override {} + void SetMouseScrollSensitivity(int value) override {} void SetPrimaryButtonRight(bool right) override {} void SetMouseReverseScroll(bool enabled) override {} void SetMouseAcceleration(bool enabled) override {} + void SetMouseScrollAcceleration(bool enabled) override {} void SetTouchpadAcceleration(bool enabled) override {} + void SetTouchpadScrollAcceleration(bool enabled) override {} void SetTapToClickPaused(bool state) override {} void GetTouchDeviceStatus(GetTouchDeviceStatusReply reply) override { std::move(reply).Run(std::string()); diff --git a/chromium/ui/ozone/public/input_controller.h b/chromium/ui/ozone/public/input_controller.h index d001a4373a1..cc7c323f683 100644 --- a/chromium/ui/ozone/public/input_controller.h +++ b/chromium/ui/ozone/public/input_controller.h @@ -59,17 +59,21 @@ class COMPONENT_EXPORT(OZONE_BASE) InputController { // Touchpad settings. virtual void SetTouchpadSensitivity(int value) = 0; + virtual void SetTouchpadScrollSensitivity(int value) = 0; virtual void SetTapToClick(bool enabled) = 0; virtual void SetThreeFingerClick(bool enabled) = 0; virtual void SetTapDragging(bool enabled) = 0; virtual void SetNaturalScroll(bool enabled) = 0; virtual void SetTouchpadAcceleration(bool enabled) = 0; + virtual void SetTouchpadScrollAcceleration(bool enabled) = 0; // Mouse settings. virtual void SetMouseSensitivity(int value) = 0; + virtual void SetMouseScrollSensitivity(int value) = 0; virtual void SetPrimaryButtonRight(bool right) = 0; virtual void SetMouseReverseScroll(bool enabled) = 0; virtual void SetMouseAcceleration(bool enabled) = 0; + virtual void SetMouseScrollAcceleration(bool enabled) = 0; // Touch log collection. virtual void GetTouchDeviceStatus(GetTouchDeviceStatusReply reply) = 0; diff --git a/chromium/ui/ozone/public/mojom/BUILD.gn b/chromium/ui/ozone/public/mojom/BUILD.gn index 947b207a407..83bb9451364 100644 --- a/chromium/ui/ozone/public/mojom/BUILD.gn +++ b/chromium/ui/ozone/public/mojom/BUILD.gn @@ -8,7 +8,6 @@ mojom("mojom") { sources = [ "device_cursor.mojom", "drm_device.mojom", - "overlay_surface_candidate.mojom", "scenic_gpu_host.mojom", "scenic_gpu_service.mojom", ] @@ -23,41 +22,7 @@ mojom("mojom") { } mojom("gesture_properties_service") { - sources = [ - "gesture_properties_service.mojom", - ] + sources = [ "gesture_properties_service.mojom" ] - public_deps = [ - "//mojo/public/mojom/base", - ] -} - -source_set("mojom_traits") { - sources = [ - "overlay_surface_candidate_mojom_traits.h", - ] - deps = [ - "//ui/gfx/geometry/mojom", - "//ui/gfx/mojom", - ] - public_deps = [ - ":mojom", - ":mojom_shared_cpp_sources", - "//mojo/public/cpp/bindings", - ] -} - -source_set("mojom_trait_unit_test") { - testonly = true - - sources = [ - "overlay_surface_candidate_mojom_traits_unittest.cc", - ] - - deps = [ - ":mojom", - ":mojom_traits", - "//testing/gtest", - "//ui/gfx/geometry", - ] + public_deps = [ "//mojo/public/mojom/base" ] } diff --git a/chromium/ui/ozone/public/mojom/drm_device.mojom b/chromium/ui/ozone/public/mojom/drm_device.mojom index 56fdb1d180d..c9b31a6c68c 100644 --- a/chromium/ui/ozone/public/mojom/drm_device.mojom +++ b/chromium/ui/ozone/public/mojom/drm_device.mojom @@ -13,8 +13,6 @@ import "ui/display/mojom/gamma_ramp_rgb_entry.mojom"; import "ui/gfx/geometry/mojom/geometry.mojom"; import "ui/gfx/mojom/accelerated_widget.mojom"; import "ui/ozone/public/mojom/device_cursor.mojom"; -import "ui/ozone/public/mojom/overlay_surface_candidate.mojom"; - // The viz process on CrOS implements the DrmDevice // service to let the viz host and clients manage DRM displays. @@ -78,18 +76,11 @@ interface DrmDevice { array<display.mojom.GammaRampRGBEntry> degamma_lut, array<display.mojom.GammaRampRGBEntry> gamma_lut); - // Verifies if the display controller can successfully scanout the given set - // of OverlaySurfaceCandidates and return the status associated with each - // candidate. - CheckOverlayCapabilities(gfx.mojom.AcceleratedWidget widget, - array<ui.ozone.mojom.OverlaySurfaceCandidate> candidates) => - (gfx.mojom.AcceleratedWidget widget, - array<ui.ozone.mojom.OverlaySurfaceCandidate> candidates, - array<ui.ozone.mojom.OverlayStatus> status); + // Sets the state of the privacy screen feature. + SetPrivacyScreen(int64 display_id, bool enabled); // Provides a DeviceCursor interface. The provided interface needs to be // associated because the AcceleratedWidgets referenced by its methods are // registered via CreateWindow() in this interface. GetDeviceCursor(pending_associated_receiver<DeviceCursor> cursor); }; - diff --git a/chromium/ui/ozone/public/mojom/overlay_surface_candidate.mojom b/chromium/ui/ozone/public/mojom/overlay_surface_candidate.mojom deleted file mode 100644 index 8dd6b7eb471..00000000000 --- a/chromium/ui/ozone/public/mojom/overlay_surface_candidate.mojom +++ /dev/null @@ -1,44 +0,0 @@ -// Copyright 2017 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. - -module ui.ozone.mojom; - -import "ui/gfx/geometry/mojom/geometry.mojom"; -import "ui/gfx/mojom/buffer_types.mojom"; -import "ui/gfx/mojom/overlay_transform.mojom"; - -// ui::OverlayStatus -enum OverlayStatus { - OVERLAY_STATUS_PENDING, - OVERLAY_STATUS_ABLE, - OVERLAY_STATUS_NOT, -}; - -struct OverlaySurfaceCandidate { - // Transformation to apply to layer during composition. - gfx.mojom.OverlayTransform transform; - // Format of the buffer to composite. - gfx.mojom.BufferFormat format; - // Size of the buffer, in pixels. - gfx.mojom.Size buffer_size; - // Rect on the display to position the overlay to. Input rectangle may - // not have integer coordinates, but when accepting for overlay, must - // be modified by CheckOverlaySupport to output integer values. - gfx.mojom.RectF display_rect; - // Crop within the buffer to be placed inside |display_rect|. - gfx.mojom.RectF crop_rect; - // Clip rect in the target content space after composition. - gfx.mojom.Rect clip_rect; - // If the quad is clipped after composition. - bool is_clipped; - // If the quad doesn't require blending. - bool is_opaque; - // Stacking order of the overlay plane relative to the main surface, - // which is 0. Signed to allow for "underlays". - int32 plane_z_order = 0; - - // To be modified by the implementer if this candidate can go into - // an overlay. - bool overlay_handled; -}; diff --git a/chromium/ui/ozone/public/mojom/overlay_surface_candidate.typemap b/chromium/ui/ozone/public/mojom/overlay_surface_candidate.typemap deleted file mode 100644 index 10d6f6d02d4..00000000000 --- a/chromium/ui/ozone/public/mojom/overlay_surface_candidate.typemap +++ /dev/null @@ -1,16 +0,0 @@ -# Copyright 2017 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. - -mojom = "//ui/ozone/public/mojom/overlay_surface_candidate.mojom" -public_headers = [ "//ui/ozone/public/overlay_surface_candidate.h" ] -public_deps = [ - "//ui/gfx/geometry/mojom:mojom_traits", - "//ui/ozone:ozone_base", -] -traits_headers = - [ "//ui/ozone/public/mojom/overlay_surface_candidate_mojom_traits.h" ] -type_mappings = [ - "ui.ozone.mojom.OverlaySurfaceCandidate=::ui::OverlaySurfaceCandidate", - "ui.ozone.mojom.OverlayStatus=::ui::OverlayStatus", -] diff --git a/chromium/ui/ozone/public/mojom/overlay_surface_candidate_mojom_traits.h b/chromium/ui/ozone/public/mojom/overlay_surface_candidate_mojom_traits.h deleted file mode 100644 index 26fb433405c..00000000000 --- a/chromium/ui/ozone/public/mojom/overlay_surface_candidate_mojom_traits.h +++ /dev/null @@ -1,112 +0,0 @@ -// Copyright 2017 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_PUBLIC_MOJOM_OVERLAY_SURFACE_CANDIDATE_MOJOM_TRAITS_H_ -#define UI_OZONE_PUBLIC_MOJOM_OVERLAY_SURFACE_CANDIDATE_MOJOM_TRAITS_H_ - -#include "ui/gfx/geometry/mojom/geometry_mojom_traits.h" -#include "ui/gfx/mojom/buffer_types_mojom_traits.h" -#include "ui/gfx/mojom/overlay_transform_mojom_traits.h" -#include "ui/ozone/public/mojom/overlay_surface_candidate.mojom.h" -#include "ui/ozone/public/overlay_surface_candidate.h" - -namespace mojo { - -template <> -struct EnumTraits<ui::ozone::mojom::OverlayStatus, ui::OverlayStatus> { - static ui::ozone::mojom::OverlayStatus ToMojom(ui::OverlayStatus format) { - switch (format) { - case ui::OverlayStatus::OVERLAY_STATUS_PENDING: - return ui::ozone::mojom::OverlayStatus::OVERLAY_STATUS_PENDING; - case ui::OverlayStatus::OVERLAY_STATUS_ABLE: - return ui::ozone::mojom::OverlayStatus::OVERLAY_STATUS_ABLE; - case ui::OverlayStatus::OVERLAY_STATUS_NOT: - return ui::ozone::mojom::OverlayStatus::OVERLAY_STATUS_NOT; - } - NOTREACHED(); - return ui::ozone::mojom::OverlayStatus::OVERLAY_STATUS_NOT; - } - - static bool FromMojom(ui::ozone::mojom::OverlayStatus input, - ui::OverlayStatus* out) { - switch (input) { - case ui::ozone::mojom::OverlayStatus::OVERLAY_STATUS_PENDING: - *out = ui::OverlayStatus::OVERLAY_STATUS_PENDING; - return true; - case ui::ozone::mojom::OverlayStatus::OVERLAY_STATUS_ABLE: - *out = ui::OverlayStatus::OVERLAY_STATUS_ABLE; - return true; - case ui::ozone::mojom::OverlayStatus::OVERLAY_STATUS_NOT: - *out = ui::OverlayStatus::OVERLAY_STATUS_NOT; - return true; - } - NOTREACHED(); - return false; - } -}; - -template <> -struct StructTraits<ui::ozone::mojom::OverlaySurfaceCandidateDataView, - ui::OverlaySurfaceCandidate> { - static const gfx::OverlayTransform& transform( - const ui::OverlaySurfaceCandidate& osc) { - return osc.transform; - } - - static const gfx::BufferFormat& format( - const ui::OverlaySurfaceCandidate& osc) { - return osc.format; - } - - static const gfx::Size& buffer_size(const ui::OverlaySurfaceCandidate& osc) { - return osc.buffer_size; - } - - static const gfx::RectF& display_rect( - const ui::OverlaySurfaceCandidate& osc) { - return osc.display_rect; - } - - static const gfx::RectF& crop_rect(const ui::OverlaySurfaceCandidate& osc) { - return osc.crop_rect; - } - - static const gfx::Rect& clip_rect(const ui::OverlaySurfaceCandidate& osc) { - return osc.clip_rect; - } - - static bool is_clipped(const ui::OverlaySurfaceCandidate& osc) { - return osc.is_clipped; - } - - static bool is_opaque(const ui::OverlaySurfaceCandidate& osc) { - return osc.is_opaque; - } - - static int plane_z_order(const ui::OverlaySurfaceCandidate& osc) { - return osc.plane_z_order; - } - - static bool overlay_handled(const ui::OverlaySurfaceCandidate& osc) { - return osc.overlay_handled; - } - - static bool Read(ui::ozone::mojom::OverlaySurfaceCandidateDataView data, - ui::OverlaySurfaceCandidate* out) { - out->is_clipped = data.is_clipped(); - out->is_opaque = data.is_opaque(); - out->plane_z_order = data.plane_z_order(); - out->overlay_handled = data.overlay_handled(); - return data.ReadTransform(&out->transform) && - data.ReadFormat(&out->format) && - data.ReadBufferSize(&out->buffer_size) && - data.ReadDisplayRect(&out->display_rect) && - data.ReadCropRect(&out->crop_rect) && - data.ReadClipRect(&out->clip_rect); - } -}; - -} // namespace mojo - -#endif // UI_OZONE_PUBLIC_MOJOM_OVERLAY_SURFACE_CANDIDATE_MOJOM_TRAITS_H_ diff --git a/chromium/ui/ozone/public/mojom/overlay_surface_candidate_mojom_traits_unittest.cc b/chromium/ui/ozone/public/mojom/overlay_surface_candidate_mojom_traits_unittest.cc deleted file mode 100644 index 823a4e541e9..00000000000 --- a/chromium/ui/ozone/public/mojom/overlay_surface_candidate_mojom_traits_unittest.cc +++ /dev/null @@ -1,84 +0,0 @@ -// Copyright 2017 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/public/mojom/overlay_surface_candidate_mojom_traits.h" - -#include <utility> - -#include "testing/gtest/include/gtest/gtest.h" -#include "ui/gfx/geometry/point.h" -#include "ui/ozone/public/mojom/overlay_surface_candidate.mojom.h" -#include "ui/ozone/public/overlay_surface_candidate.h" - -namespace ui { - -TEST(OverlaySurfaceCandidateStructTraitsTest, FieldsEqual) { - ui::OverlaySurfaceCandidate input; - - input.transform = gfx::OVERLAY_TRANSFORM_FLIP_HORIZONTAL; - input.format = gfx::BufferFormat::YUV_420_BIPLANAR; - input.buffer_size = gfx::Size(6, 7); - input.display_rect = gfx::RectF(1., 2., 3., 4.); - input.crop_rect = gfx::RectF(10., 20., 30., 40.); - input.clip_rect = gfx::Rect(11, 21, 31, 41); - input.is_clipped = true; - input.is_opaque = true; - input.plane_z_order = 42; - input.overlay_handled = true; - - ui::OverlaySurfaceCandidate output; - - bool success = ui::ozone::mojom::OverlaySurfaceCandidate::Deserialize( - ui::ozone::mojom::OverlaySurfaceCandidate::Serialize(&input), &output); - - EXPECT_TRUE(success); - - EXPECT_EQ(input.transform, output.transform); - EXPECT_EQ(input.format, output.format); - EXPECT_EQ(input.buffer_size, output.buffer_size); - EXPECT_EQ(input.display_rect, output.display_rect); - EXPECT_EQ(input.crop_rect, output.crop_rect); - EXPECT_EQ(input.clip_rect, output.clip_rect); - EXPECT_EQ(input.is_clipped, output.is_clipped); - EXPECT_EQ(input.is_opaque, output.is_opaque); - EXPECT_EQ(input.plane_z_order, output.plane_z_order); - EXPECT_EQ(input.overlay_handled, output.overlay_handled); -} - -TEST(OverlaySurfaceCandidateStructTraitsTest, FalseBools) { - ui::OverlaySurfaceCandidate input; - - input.is_clipped = false; - input.is_opaque = false; - input.overlay_handled = false; - - ui::OverlaySurfaceCandidate output; - - bool success = ui::ozone::mojom::OverlaySurfaceCandidate::Deserialize( - ui::ozone::mojom::OverlaySurfaceCandidate::Serialize(&input), &output); - - EXPECT_TRUE(success); - EXPECT_EQ(input.is_clipped, output.is_clipped); - EXPECT_EQ(input.is_opaque, output.is_opaque); - EXPECT_EQ(input.overlay_handled, output.overlay_handled); -} - -TEST(OverlaySurfaceCandidateStructTraitsTest, OverlayStatus) { - using OverlayStatusTraits = - mojo::EnumTraits<ui::ozone::mojom::OverlayStatus, ui::OverlayStatus>; - - std::vector<OverlayStatus> tests = {OVERLAY_STATUS_PENDING, - OVERLAY_STATUS_ABLE, OVERLAY_STATUS_NOT}; - - for (const OverlayStatus& input : tests) { - ui::OverlayStatus output; - bool success = OverlayStatusTraits::FromMojom( - OverlayStatusTraits::ToMojom(input), &output); - - EXPECT_TRUE(success); - EXPECT_EQ(input, output); - } -} - -} // namespace ui diff --git a/chromium/ui/ozone/public/mojom/scenic_gpu_host.mojom b/chromium/ui/ozone/public/mojom/scenic_gpu_host.mojom index 62189435842..a3de21807f1 100644 --- a/chromium/ui/ozone/public/mojom/scenic_gpu_host.mojom +++ b/chromium/ui/ozone/public/mojom/scenic_gpu_host.mojom @@ -8,5 +8,5 @@ module ui.mojom; interface ScenicGpuHost { // Attaches the surface View identified by |view_holder_token| to the scene // graph for |window_id|. - AttachSurfaceToWindow(int32 window_id, handle view_holder_token); + AttachSurfaceToWindow(int32 window_id, handle<platform> view_holder_token); }; diff --git a/chromium/ui/ozone/public/mojom/typemaps.gni b/chromium/ui/ozone/public/mojom/typemaps.gni deleted file mode 100644 index beff1f5871c..00000000000 --- a/chromium/ui/ozone/public/mojom/typemaps.gni +++ /dev/null @@ -1,5 +0,0 @@ -# Copyright 2017 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. - -typemaps = [ "//ui/ozone/public/mojom/overlay_surface_candidate.typemap" ] diff --git a/chromium/ui/ozone/public/mojom/wayland/BUILD.gn b/chromium/ui/ozone/public/mojom/wayland/BUILD.gn index 280055d2add..fb7f809ebd4 100644 --- a/chromium/ui/ozone/public/mojom/wayland/BUILD.gn +++ b/chromium/ui/ozone/public/mojom/wayland/BUILD.gn @@ -5,9 +5,7 @@ import("//mojo/public/tools/bindings/mojom.gni") mojom("wayland_mojom") { - sources = [ - "wayland_buffer_manager.mojom", - ] + sources = [ "wayland_buffer_manager.mojom" ] public_deps = [ "//mojo/public/mojom/base", diff --git a/chromium/ui/ozone/public/mojom/wayland/wayland_buffer_manager.mojom b/chromium/ui/ozone/public/mojom/wayland/wayland_buffer_manager.mojom index 3808188bc84..46d6a84e024 100644 --- a/chromium/ui/ozone/public/mojom/wayland/wayland_buffer_manager.mojom +++ b/chromium/ui/ozone/public/mojom/wayland/wayland_buffer_manager.mojom @@ -35,7 +35,7 @@ interface WaylandBufferManagerHost { // very first CommitBuffer request comes from viz to browser process. // If the buffer has been committed at least once, it is not possible to // reassign it to another AcceleratedWidget. - CreateDmabufBasedBuffer(handle dmabuf_fd, + CreateDmabufBasedBuffer(handle<platform> dmabuf_fd, gfx.mojom.Size size, array<uint32> strides, array<uint32> offsets, @@ -52,7 +52,7 @@ interface WaylandBufferManagerHost { // very first CommitBuffer request comes from viz to browser process. If // the buffer has been committed at least once, it is not possible to // reassign it to another AcceleratedWidget. - CreateShmBasedBuffer(handle shm_fd, + CreateShmBasedBuffer(handle<platform> shm_fd, uint64 length, gfx.mojom.Size size, uint32 buffer_id); diff --git a/chromium/ui/ozone/public/overlay_surface_candidate.cc b/chromium/ui/ozone/public/overlay_surface_candidate.cc index 40b99ff9346..9a9572ea220 100644 --- a/chromium/ui/ozone/public/overlay_surface_candidate.cc +++ b/chromium/ui/ozone/public/overlay_surface_candidate.cc @@ -28,9 +28,10 @@ bool OverlaySurfaceCandidate::operator<( gfx::Rect rrect = gfx::ToNearestRect(param.display_rect); return std::tie(plane_z_order, format, lrect, lwidth, lheight, transform, - crop_rect, is_opaque) < + crop_rect, is_opaque, native_pixmap_unique_id) < std::tie(param.plane_z_order, param.format, rrect, rwidth, rheight, - param.transform, param.crop_rect, param.is_opaque); + param.transform, param.crop_rect, param.is_opaque, + param.native_pixmap_unique_id); } } // namespace ui diff --git a/chromium/ui/ozone/public/overlay_surface_candidate.h b/chromium/ui/ozone/public/overlay_surface_candidate.h index ab0f1b6031f..ebd82e96706 100644 --- a/chromium/ui/ozone/public/overlay_surface_candidate.h +++ b/chromium/ui/ozone/public/overlay_surface_candidate.h @@ -12,6 +12,7 @@ #include "ui/gfx/geometry/rect.h" #include "ui/gfx/geometry/rect_f.h" #include "ui/gfx/geometry/size.h" +#include "ui/gfx/native_pixmap.h" #include "ui/gfx/overlay_transform.h" namespace ui { @@ -30,8 +31,8 @@ class COMPONENT_EXPORT(OZONE_BASE) OverlaySurfaceCandidate { ~OverlaySurfaceCandidate(); OverlaySurfaceCandidate& operator=(const OverlaySurfaceCandidate& other); - // Note that |clip_rect|, |is_clipped| and |overlay_handled| are - // *not* used as part of the comparison. + // Note that |clip_rect|, |is_clipped|, |overlay_handled| and |native_pixmap| + // are *not* used as part of the comparison. bool operator<(const OverlaySurfaceCandidate& other) const; // Transformation to apply to layer during composition. @@ -55,6 +56,14 @@ class COMPONENT_EXPORT(OZONE_BASE) OverlaySurfaceCandidate { bool is_clipped = false; // If the quad doesn't require blending. bool is_opaque = false; + // Optionally contains a pointer to the NativePixmap corresponding to this + // candidate. + scoped_refptr<gfx::NativePixmap> native_pixmap = nullptr; + // A unique ID corresponding to |native_pixmap|. The ID is not reused even if + // |native_pixmap| is destroyed. Zero if |native_pixmap| is null. + // TODO(samans): This will not be necessary once Ozone/DRM not longer uses a + // cache for overlay testing. https://crbug.com/1034559 + uint32_t native_pixmap_unique_id = 0; // To be modified by the implementer if this candidate can go into // an overlay. bool overlay_handled = false; diff --git a/chromium/ui/ozone/public/ozone_platform.h b/chromium/ui/ozone/public/ozone_platform.h index 80245695a32..c1d82b8ba5c 100644 --- a/chromium/ui/ozone/public/ozone_platform.h +++ b/chromium/ui/ozone/public/ozone_platform.h @@ -14,6 +14,7 @@ #include "base/message_loop/message_pump_type.h" #include "mojo/public/cpp/bindings/binder_map.h" #include "ui/gfx/buffer_types.h" +#include "ui/gfx/native_widget_types.h" #include "ui/platform_window/platform_window.h" #include "ui/platform_window/platform_window_delegate.h" @@ -77,15 +78,6 @@ class COMPONENT_EXPORT(OZONE) OzonePlatform { // regardless of this param. // TODO(crbug.com/806092): Remove after legacy IPC-based Ozone is removed. bool using_mojo = false; - - // Setting this to true indicates the display compositor will run in the GPU - // process (as part of the viz service). Note this param is currently only - // checked in Ozone DRM for overlay support. Other Ozone platforms either - // don't need to change anything or assume that VizDisplayCompositor is - // always enabled. - // TODO(crbug.com/936425): Remove after VizDisplayCompositor feature - // launches. - bool viz_display_compositor = false; }; // Struct used to indicate platform properties. @@ -158,7 +150,8 @@ class COMPONENT_EXPORT(OZONE) OzonePlatform { virtual std::unique_ptr<PlatformScreen> CreateScreen() = 0; virtual PlatformClipboard* GetPlatformClipboard(); virtual std::unique_ptr<InputMethod> CreateInputMethod( - internal::InputMethodDelegate* delegate) = 0; + internal::InputMethodDelegate* delegate, + gfx::AcceleratedWidget widget) = 0; // Returns true if the specified buffer format is supported. virtual bool IsNativePixmapConfigSupported(gfx::BufferFormat format, diff --git a/chromium/ui/ozone/public/platform_screen.cc b/chromium/ui/ozone/public/platform_screen.cc new file mode 100644 index 00000000000..af4dc57fcd1 --- /dev/null +++ b/chromium/ui/ozone/public/platform_screen.cc @@ -0,0 +1,17 @@ +// 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/public/platform_screen.h" + +namespace ui { + +PlatformScreen::PlatformScreen() = default; +PlatformScreen::~PlatformScreen() = default; + +std::string PlatformScreen::GetCurrentWorkspace() { + NOTIMPLEMENTED_LOG_ONCE(); + return {}; +} + +} // namespace ui diff --git a/chromium/ui/ozone/public/platform_screen.h b/chromium/ui/ozone/public/platform_screen.h index d98bed8e901..de464218855 100644 --- a/chromium/ui/ozone/public/platform_screen.h +++ b/chromium/ui/ozone/public/platform_screen.h @@ -5,6 +5,7 @@ #ifndef UI_OZONE_PUBLIC_PLATFORM_SCREEN_H_ #define UI_OZONE_PUBLIC_PLATFORM_SCREEN_H_ +#include "base/component_export.h" #include "ui/gfx/native_widget_types.h" namespace display { @@ -22,6 +23,8 @@ namespace ui { // PlatformScreen is an abstract base class for an interface to an Ozone // platform's functionality exposed to Chrome via display::Screen. // +// Additionally, may notify DisplayObservers with global workspace changes. +// // Recall that in Chrome, a |Screen| is the union of all attached |Display| // instances. The |Screen|'s coordinate system is in DIP pixels (so that // it can reasonably support |Display|s of differing pixel densities.) The @@ -29,10 +32,10 @@ namespace ui { // |Screen|. Coordinates increase down and to the right. // // TODO(rjkroege): Add ascii art? -class PlatformScreen { +class COMPONENT_EXPORT(OZONE_BASE) PlatformScreen { public: - PlatformScreen() = default; - virtual ~PlatformScreen() = default; + PlatformScreen(); + virtual ~PlatformScreen(); // Provide a |display:;Display| for each physical display available to Chrome. virtual const std::vector<display::Display>& GetAllDisplays() const = 0; @@ -68,6 +71,10 @@ class PlatformScreen { virtual void AddObserver(display::DisplayObserver* observer) = 0; virtual void RemoveObserver(display::DisplayObserver* observer) = 0; + // Returns currently used workspace. If a platform does not support this, the + // empty string is returned. + virtual std::string GetCurrentWorkspace(); + private: DISALLOW_COPY_AND_ASSIGN(PlatformScreen); }; diff --git a/chromium/ui/ozone/public/surface_factory_ozone.cc b/chromium/ui/ozone/public/surface_factory_ozone.cc index 3cf24e6b42a..ec4751ef186 100644 --- a/chromium/ui/ozone/public/surface_factory_ozone.cc +++ b/chromium/ui/ozone/public/surface_factory_ozone.cc @@ -67,7 +67,7 @@ std::unique_ptr<OverlaySurface> SurfaceFactoryOzone::CreateOverlaySurface( std::unique_ptr<SurfaceOzoneCanvas> SurfaceFactoryOzone::CreateCanvasForWidget( gfx::AcceleratedWidget widget, - base::TaskRunner* task_runner) { + scoped_refptr<base::SequencedTaskRunner> task_runner) { return nullptr; } @@ -76,7 +76,8 @@ scoped_refptr<gfx::NativePixmap> SurfaceFactoryOzone::CreateNativePixmap( VkDevice vk_device, gfx::Size size, gfx::BufferFormat format, - gfx::BufferUsage usage) { + gfx::BufferUsage usage, + base::Optional<gfx::Size> framebuffer_size) { return nullptr; } diff --git a/chromium/ui/ozone/public/surface_factory_ozone.h b/chromium/ui/ozone/public/surface_factory_ozone.h index a721f994b44..fde22b2d998 100644 --- a/chromium/ui/ozone/public/surface_factory_ozone.h +++ b/chromium/ui/ozone/public/surface_factory_ozone.h @@ -115,18 +115,31 @@ class COMPONENT_EXPORT(OZONE_BASE) SurfaceFactoryOzone { // Browser Process using only the handle contained in gfx::AcceleratedWidget. virtual std::unique_ptr<SurfaceOzoneCanvas> CreateCanvasForWidget( gfx::AcceleratedWidget widget, - base::TaskRunner* task_runner); + scoped_refptr<base::SequencedTaskRunner> task_runner); // Create a single native buffer to be used for overlay planes or zero copy // for |widget| representing a particular display controller or default - // display controller for kNullAcceleratedWidget. - // It can be called on any thread. + // display controller for kNullAcceleratedWidget. |size| corresponds to the + // dimensions used to allocate the buffer. |framebuffer_size| is used to + // create a framebuffer for the allocated buffer when the usage requires one. + // If |framebuffer_size| is not provided, |size| is used instead. In the + // typical case |framebuffer_size| represents a 'visible size', i.e., a buffer + // of size |size| may actually contain visible data only in the subregion of + // size |framebuffer_size|. In more complex cases, it's possible that the + // buffer has a visible rectangle whose origin is not at (0, 0). In this case, + // |framebuffer_size| would also include some of the non-visible area. For + // example, suppose we need to allocate a buffer of size 100x100 for a + // hardware decoder, but the visible rectangle is (10, 10, 80x80). In this + // case, |size| would be 100x100 while |framebuffer_size| would be 90x90. If + // |framebuffer_size| is not contained by |size|, this method returns nullptr. + // This method can be called on any thread. virtual scoped_refptr<gfx::NativePixmap> CreateNativePixmap( gfx::AcceleratedWidget widget, VkDevice vk_device, gfx::Size size, gfx::BufferFormat format, - gfx::BufferUsage usage); + gfx::BufferUsage usage, + base::Optional<gfx::Size> framebuffer_size = base::nullopt); // Similar to CreateNativePixmap, but returns the result asynchronously. using NativePixmapCallback = diff --git a/chromium/ui/ozone/public/surface_ozone_canvas.h b/chromium/ui/ozone/public/surface_ozone_canvas.h index c7269ecb39c..7e4143b16e7 100644 --- a/chromium/ui/ozone/public/surface_ozone_canvas.h +++ b/chromium/ui/ozone/public/surface_ozone_canvas.h @@ -11,7 +11,7 @@ #include "base/component_export.h" #include "third_party/skia/include/core/SkRefCnt.h" -class SkSurface; +class SkCanvas; namespace gfx { class Rect; @@ -29,8 +29,11 @@ class COMPONENT_EXPORT(OZONE_BASE) SurfaceOzoneCanvas { public: virtual ~SurfaceOzoneCanvas(); - // Returns an SkSurface for drawing on the window. - virtual sk_sp<SkSurface> GetSurface() = 0; + // Returns an SkCanvas for drawing on the window. The SurfaceOzoneCanvas keeps + // the SkCanvas alive until the client finishes writing contents and calls + // PresentCanvas. Additionally, the SkCanvas becomes invalid after + // ResizeCanvas is called. See comment at ResizeCanvas. + virtual SkCanvas* GetCanvas() = 0; // Attempts to resize the canvas to match the viewport size. After // resizing, the compositor must call GetSurface() to get the next diff --git a/chromium/ui/ozone/testhelpers/BUILD.gn b/chromium/ui/ozone/testhelpers/BUILD.gn index 3e4412145f4..07b720d9b4d 100644 --- a/chromium/ui/ozone/testhelpers/BUILD.gn +++ b/chromium/ui/ozone/testhelpers/BUILD.gn @@ -4,9 +4,7 @@ static_library("mock_gesture_properties_service") { testonly = true - sources = [ - "mock_gesture_properties_service.h", - ] + sources = [ "mock_gesture_properties_service.h" ] public_deps = [ "//testing/gmock", "//third_party/googletest:gmock", |